blob: 0a6e3b9901eed43e6c746ad08c18c30e54601165 [file] [log] [blame]
Jon Medhurst96b56152014-10-30 18:01:15 +00001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2014-2015. All rights reserved.
Jon Medhurst96b56152014-10-30 18:01:15 +00003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Command.h"
10
11#include <fcntl.h>
12#include <pwd.h>
13#include <stdio.h>
14#include <sys/prctl.h>
15#include <sys/resource.h>
16#include <sys/stat.h>
17#include <sys/syscall.h>
18#include <sys/time.h>
19#include <sys/types.h>
20#include <sys/wait.h>
21#include <unistd.h>
22
23#include "Logging.h"
24#include "SessionData.h"
25
26static int getUid(const char *const name, char *const shPath, const char *const tmpDir) {
27 // Lookups may fail when using a different libc or a statically compiled executable
28 char gatorTemp[32];
29 snprintf(gatorTemp, sizeof(gatorTemp), "%s/gator_temp", tmpDir);
30
31 const int fd = open(gatorTemp, 600, O_CREAT | O_CLOEXEC);
32 if (fd < 0) {
33 return -1;
34 }
35 close(fd);
36
37 char cmd[128];
38 snprintf(cmd, sizeof(cmd), "chown %s %s || rm %s", name, gatorTemp, gatorTemp);
39
40 const int pid = fork();
41 if (pid < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010042 logg->logError("fork failed");
Jon Medhurst96b56152014-10-30 18:01:15 +000043 handleException();
44 }
45 if (pid == 0) {
46 char cargv1[] = "-c";
47 char *cargv[] = {
48 shPath,
49 cargv1,
50 cmd,
51 NULL,
52 };
53
54 execv(cargv[0], cargv);
55 exit(-1);
56 }
57 while ((waitpid(pid, NULL, 0) < 0) && (errno == EINTR));
58
59 struct stat st;
60 int result = -1;
61 if (stat(gatorTemp, &st) == 0) {
62 result = st.st_uid;
63 }
64 unlink(gatorTemp);
65 return result;
66}
67
68static int getUid(const char *const name) {
69 // Look up the username
70 struct passwd *const user = getpwnam(name);
71 if (user != NULL) {
72 return user->pw_uid;
73 }
74
75
76 // Are we on Linux
77 char cargv0l[] = "/bin/sh";
78 if ((access(cargv0l, X_OK) == 0) && (access("/tmp", W_OK) == 0)) {
79 return getUid(name, cargv0l, "/tmp");
80 }
81
82 // Are we on android
83 char cargv0a[] = "/system/bin/sh";
84 if ((access(cargv0a, X_OK) == 0) && (access("/data", W_OK) == 0)) {
85 return getUid(name, cargv0a, "/data");
86 }
87
88 return -1;
89}
90
91void *commandThread(void *) {
92 prctl(PR_SET_NAME, (unsigned long)&"gatord-command", 0, 0, 0);
93
94 const char *const name = gSessionData->mCaptureUser == NULL ? "nobody" : gSessionData->mCaptureUser;
95 const int uid = getUid(name);
96 if (uid < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010097 logg->logError("Unable to look up the user %s, please double check that the user exists", name);
Jon Medhurst96b56152014-10-30 18:01:15 +000098 handleException();
99 }
100
101 sleep(3);
102
103 char buf[128];
104 int pipefd[2];
105 if (pipe_cloexec(pipefd) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100106 logg->logError("pipe failed");
Jon Medhurst96b56152014-10-30 18:01:15 +0000107 handleException();
108 }
109
110 const int pid = fork();
111 if (pid < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100112 logg->logError("fork failed");
Jon Medhurst96b56152014-10-30 18:01:15 +0000113 handleException();
114 }
115 if (pid == 0) {
116 char cargv0l[] = "/bin/sh";
117 char cargv0a[] = "/system/bin/sh";
118 char cargv1[] = "-c";
119 char *cargv[] = {
120 cargv0l,
121 cargv1,
122 gSessionData->mCaptureCommand,
123 NULL,
124 };
125
126 buf[0] = '\0';
127 close(pipefd[0]);
128
129 // Gator runs at a high priority, reset the priority to the default
130 if (setpriority(PRIO_PROCESS, syscall(__NR_gettid), 0) == -1) {
131 snprintf(buf, sizeof(buf), "setpriority failed");
132 goto fail_exit;
133 }
134
135 if (setuid(uid) != 0) {
136 snprintf(buf, sizeof(buf), "setuid failed");
137 goto fail_exit;
138 }
139
140 {
141 const char *const path = gSessionData->mCaptureWorkingDir == NULL ? "/" : gSessionData->mCaptureWorkingDir;
142 if (chdir(path) != 0) {
143 snprintf(buf, sizeof(buf), "Unable to cd to %s, please verify the directory exists and is accessable to %s", path, name);
144 goto fail_exit;
145 }
146 }
147
148 execv(cargv[0], cargv);
149 cargv[0] = cargv0a;
150 execv(cargv[0], cargv);
151 snprintf(buf, sizeof(buf), "execv failed");
152
153 fail_exit:
154 if (buf[0] != '\0') {
155 const ssize_t bytes = write(pipefd[1], buf, sizeof(buf));
156 // Can't do anything if this fails
157 (void)bytes;
158 }
159
160 exit(-1);
161 }
162
163 close(pipefd[1]);
164 const ssize_t bytes = read(pipefd[0], buf, sizeof(buf));
165 if (bytes > 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100166 logg->logError("%s", buf);
Jon Medhurst96b56152014-10-30 18:01:15 +0000167 handleException();
168 }
169 close(pipefd[0]);
170
171 return NULL;
172}