am e0644327: Fix a TOCTOU and symlink attack in netd.
* commit 'e0644327ffb203e0b45f3192fd888831902e267c':
Fix a TOCTOU and symlink attack in netd.
diff --git a/Android.mk b/Android.mk
index 8b7acf0..e4b6ad6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES:= \
BandwidthController.cpp \
+ ClatdController.cpp \
CommandListener.cpp \
DnsProxyListener.cpp \
FirewallController.cpp \
diff --git a/ClatdController.cpp b/ClatdController.cpp
new file mode 100644
index 0000000..ba4ca27
--- /dev/null
+++ b/ClatdController.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define LOG_TAG "ClatdController"
+#include <cutils/log.h>
+
+#include "ClatdController.h"
+
+ClatdController::ClatdController() {
+ mClatdPid = 0;
+}
+
+ClatdController::~ClatdController() {
+}
+
+int ClatdController::startClatd(char *interface) {
+ pid_t pid;
+
+ if(mClatdPid != 0) {
+ ALOGE("clatd already running");
+ errno = EBUSY;
+ return -1;
+ }
+
+ ALOGD("starting clatd");
+
+ if ((pid = fork()) < 0) {
+ ALOGE("fork failed (%s)", strerror(errno));
+ return -1;
+ }
+
+ if (!pid) {
+ char **args = (char **)malloc(sizeof(char *) * 4);
+ args[0] = (char *)"/system/bin/clatd";
+ args[1] = (char *)"-i";
+ args[2] = interface;
+ args[3] = NULL;
+
+ if (execv(args[0], args)) {
+ ALOGE("execv failed (%s)", strerror(errno));
+ }
+ ALOGE("Should never get here!");
+ free(args);
+ _exit(0);
+ } else {
+ mClatdPid = pid;
+ ALOGD("clatd started");
+ }
+
+ return 0;
+}
+
+int ClatdController::stopClatd() {
+ if (mClatdPid == 0) {
+ ALOGE("clatd already stopped");
+ return -1;
+ }
+
+ ALOGD("Stopping clatd");
+
+ kill(mClatdPid, SIGTERM);
+ waitpid(mClatdPid, NULL, 0);
+ mClatdPid = 0;
+
+ ALOGD("clatd stopped");
+
+ return 0;
+}
+
+bool ClatdController::isClatdStarted() {
+ pid_t waitpid_status;
+ if(mClatdPid == 0) {
+ return false;
+ }
+ waitpid_status = waitpid(mClatdPid, NULL, WNOHANG);
+ if(waitpid_status != 0) {
+ mClatdPid = 0; // child exited, don't call waitpid on it again
+ }
+ return waitpid_status == 0; // 0 while child is running
+}
diff --git a/ClatdController.h b/ClatdController.h
new file mode 100644
index 0000000..f059c31
--- /dev/null
+++ b/ClatdController.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _CLATD_CONTROLLER_H
+#define _CLATD_CONTROLLER_H
+
+class ClatdController {
+ pid_t mClatdPid;
+
+public:
+ ClatdController();
+ virtual ~ClatdController();
+
+ int startClatd(char *interface);
+ int stopClatd();
+ bool isClatdStarted();
+};
+
+#endif
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 7b82682..6f81524 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -53,6 +53,7 @@
ResolverController *CommandListener::sResolverCtrl = NULL;
SecondaryTableController *CommandListener::sSecondaryTableCtrl = NULL;
FirewallController *CommandListener::sFirewallCtrl = NULL;
+ClatdController *CommandListener::sClatdCtrl = NULL;
/**
* List of module chains to be created, along with explicit ordering. ORDERING
@@ -136,6 +137,7 @@
registerCmd(new IdletimerControlCmd());
registerCmd(new ResolverCmd());
registerCmd(new FirewallCmd());
+ registerCmd(new ClatdCmd());
if (!sSecondaryTableCtrl)
sSecondaryTableCtrl = new SecondaryTableController();
@@ -157,6 +159,8 @@
sFirewallCtrl = new FirewallController();
if (!sInterfaceCtrl)
sInterfaceCtrl = new InterfaceController();
+ if (!sClatdCtrl)
+ sClatdCtrl = new ClatdController();
/*
* This is the only time we touch top-level chains in iptables; controllers
@@ -1439,3 +1443,44 @@
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
return 0;
}
+
+CommandListener::ClatdCmd::ClatdCmd() : NetdCommand("clatd") {
+}
+
+int CommandListener::ClatdCmd::runCommand(SocketClient *cli, int argc,
+ char **argv) {
+ int rc = 0;
+ if (argc < 2) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ return 0;
+ }
+
+ if(!strcmp(argv[1], "stop")) {
+ rc = sClatdCtrl->stopClatd();
+ } else if (!strcmp(argv[1], "status")) {
+ char *tmp = NULL;
+
+ asprintf(&tmp, "Clatd status: %s", (sClatdCtrl->isClatdStarted() ?
+ "started" : "stopped"));
+ cli->sendMsg(ResponseCode::ClatdStatusResult, tmp, false);
+ free(tmp);
+ return 0;
+ } else if(!strcmp(argv[1], "start")) {
+ if (argc < 3) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ return 0;
+ }
+ rc = sClatdCtrl->startClatd(argv[2]);
+ } else {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown clatd cmd", false);
+ return 0;
+ }
+
+ if (!rc) {
+ cli->sendMsg(ResponseCode::CommandOkay, "Clatd operation succeeded", false);
+ } else {
+ cli->sendMsg(ResponseCode::OperationFailed, "Clatd operation failed", false);
+ }
+
+ return 0;
+}
diff --git a/CommandListener.h b/CommandListener.h
index 6cae13e..e8d92a8 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -30,6 +30,7 @@
#include "ResolverController.h"
#include "SecondaryTableController.h"
#include "FirewallController.h"
+#include "ClatdController.h"
class CommandListener : public FrameworkListener {
static TetherController *sTetherCtrl;
@@ -42,6 +43,7 @@
static ResolverController *sResolverCtrl;
static SecondaryTableController *sSecondaryTableCtrl;
static FirewallController *sFirewallCtrl;
+ static ClatdController *sClatdCtrl;
public:
CommandListener();
@@ -136,6 +138,13 @@
int sendGenericOkFail(SocketClient *cli, int cond);
static FirewallRule parseRule(const char* arg);
};
+
+ class ClatdCmd : public NetdCommand {
+ public:
+ ClatdCmd();
+ virtual ~ClatdCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
};
#endif
diff --git a/ResponseCode.h b/ResponseCode.h
index c6f5c2d..7689ef8 100644
--- a/ResponseCode.h
+++ b/ResponseCode.h
@@ -44,6 +44,7 @@
static const int QuotaCounterResult = 220;
static const int TetheringStatsResult = 221;
static const int DnsProxyQueryResult = 222;
+ static const int ClatdStatusResult = 223;
// 400 series - The command was accepted but the requested action
// did not take place.