aboutsummaryrefslogtreecommitdiff
path: root/tools/gator/daemon/Command.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gator/daemon/Command.cpp')
-rw-r--r--tools/gator/daemon/Command.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/tools/gator/daemon/Command.cpp b/tools/gator/daemon/Command.cpp
new file mode 100644
index 000000000000..28d73cf5a905
--- /dev/null
+++ b/tools/gator/daemon/Command.cpp
@@ -0,0 +1,172 @@
+/**
+ * Copyright (C) ARM Limited 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "Command.h"
+
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "Logging.h"
+#include "SessionData.h"
+
+static int getUid(const char *const name, char *const shPath, const char *const tmpDir) {
+ // Lookups may fail when using a different libc or a statically compiled executable
+ char gatorTemp[32];
+ snprintf(gatorTemp, sizeof(gatorTemp), "%s/gator_temp", tmpDir);
+
+ const int fd = open(gatorTemp, 600, O_CREAT | O_CLOEXEC);
+ if (fd < 0) {
+ return -1;
+ }
+ close(fd);
+
+ char cmd[128];
+ snprintf(cmd, sizeof(cmd), "chown %s %s || rm %s", name, gatorTemp, gatorTemp);
+
+ const int pid = fork();
+ if (pid < 0) {
+ logg->logError(__FILE__, __LINE__, "fork failed");
+ handleException();
+ }
+ if (pid == 0) {
+ char cargv1[] = "-c";
+ char *cargv[] = {
+ shPath,
+ cargv1,
+ cmd,
+ NULL,
+ };
+
+ execv(cargv[0], cargv);
+ exit(-1);
+ }
+ while ((waitpid(pid, NULL, 0) < 0) && (errno == EINTR));
+
+ struct stat st;
+ int result = -1;
+ if (stat(gatorTemp, &st) == 0) {
+ result = st.st_uid;
+ }
+ unlink(gatorTemp);
+ return result;
+}
+
+static int getUid(const char *const name) {
+ // Look up the username
+ struct passwd *const user = getpwnam(name);
+ if (user != NULL) {
+ return user->pw_uid;
+ }
+
+
+ // Are we on Linux
+ char cargv0l[] = "/bin/sh";
+ if ((access(cargv0l, X_OK) == 0) && (access("/tmp", W_OK) == 0)) {
+ return getUid(name, cargv0l, "/tmp");
+ }
+
+ // Are we on android
+ char cargv0a[] = "/system/bin/sh";
+ if ((access(cargv0a, X_OK) == 0) && (access("/data", W_OK) == 0)) {
+ return getUid(name, cargv0a, "/data");
+ }
+
+ return -1;
+}
+
+void *commandThread(void *) {
+ prctl(PR_SET_NAME, (unsigned long)&"gatord-command", 0, 0, 0);
+
+ const char *const name = gSessionData->mCaptureUser == NULL ? "nobody" : gSessionData->mCaptureUser;
+ const int uid = getUid(name);
+ if (uid < 0) {
+ logg->logError(__FILE__, __LINE__, "Unable to lookup the user %s, please double check that the user exists", name);
+ handleException();
+ }
+
+ sleep(3);
+
+ char buf[128];
+ int pipefd[2];
+ if (pipe_cloexec(pipefd) != 0) {
+ logg->logError(__FILE__, __LINE__, "pipe failed");
+ handleException();
+ }
+
+ const int pid = fork();
+ if (pid < 0) {
+ logg->logError(__FILE__, __LINE__, "fork failed");
+ handleException();
+ }
+ if (pid == 0) {
+ char cargv0l[] = "/bin/sh";
+ char cargv0a[] = "/system/bin/sh";
+ char cargv1[] = "-c";
+ char *cargv[] = {
+ cargv0l,
+ cargv1,
+ gSessionData->mCaptureCommand,
+ NULL,
+ };
+
+ buf[0] = '\0';
+ close(pipefd[0]);
+
+ // Gator runs at a high priority, reset the priority to the default
+ if (setpriority(PRIO_PROCESS, syscall(__NR_gettid), 0) == -1) {
+ snprintf(buf, sizeof(buf), "setpriority failed");
+ goto fail_exit;
+ }
+
+ if (setuid(uid) != 0) {
+ snprintf(buf, sizeof(buf), "setuid failed");
+ goto fail_exit;
+ }
+
+ {
+ const char *const path = gSessionData->mCaptureWorkingDir == NULL ? "/" : gSessionData->mCaptureWorkingDir;
+ if (chdir(path) != 0) {
+ snprintf(buf, sizeof(buf), "Unable to cd to %s, please verify the directory exists and is accessable to %s", path, name);
+ goto fail_exit;
+ }
+ }
+
+ execv(cargv[0], cargv);
+ cargv[0] = cargv0a;
+ execv(cargv[0], cargv);
+ snprintf(buf, sizeof(buf), "execv failed");
+
+ fail_exit:
+ if (buf[0] != '\0') {
+ const ssize_t bytes = write(pipefd[1], buf, sizeof(buf));
+ // Can't do anything if this fails
+ (void)bytes;
+ }
+
+ exit(-1);
+ }
+
+ close(pipefd[1]);
+ const ssize_t bytes = read(pipefd[0], buf, sizeof(buf));
+ if (bytes > 0) {
+ logg->logError(__FILE__, __LINE__, buf);
+ handleException();
+ }
+ close(pipefd[0]);
+
+ return NULL;
+}