blob: 7dd83ceafcce07c8f9057e7445f483fabe3e6e61 [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 "Setup.h"
10
11#include <dirent.h>
12#include <errno.h>
13#include <fcntl.h>
14#include <signal.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
Jon Medhurstb1d07442015-05-08 12:04:18 +010018#include <sys/mount.h>
Jon Medhurst96b56152014-10-30 18:01:15 +000019#include <sys/stat.h>
Jon Medhurstb1d07442015-05-08 12:04:18 +010020#include <sys/syscall.h>
Jon Medhurst96b56152014-10-30 18:01:15 +000021#include <sys/types.h>
22#include <sys/utsname.h>
23#include <sys/wait.h>
24#include <unistd.h>
25
26#include "Config.h"
27#include "DynBuf.h"
28#include "Logging.h"
Jon Medhurstb1d07442015-05-08 12:04:18 +010029#include "SessionData.h"
30
31#define GATOR_MSG "gator: "
32#define GATOR_ERROR "gator: error: "
33#define GATOR_CONFIRM "gator: confirm: "
Jon Medhurst96b56152014-10-30 18:01:15 +000034
35bool getLinuxVersion(int version[3]) {
36 // Check the kernel version
37 struct utsname utsname;
38 if (uname(&utsname) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010039 logg->logMessage("uname failed");
Jon Medhurst96b56152014-10-30 18:01:15 +000040 return false;
41 }
42
43 version[0] = 0;
44 version[1] = 0;
45 version[2] = 0;
46
47 int part = 0;
48 char *ch = utsname.release;
49 while (*ch >= '0' && *ch <= '9' && part < 3) {
50 version[part] = 10*version[part] + *ch - '0';
51
52 ++ch;
53 if (*ch == '.') {
54 ++part;
55 ++ch;
56 }
57 }
58
59 return true;
60}
61
62static int pgrep_gator(DynBuf *const printb) {
63 DynBuf b;
64
65 DIR *proc = opendir("/proc");
66 if (proc == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010067 logg->logError(GATOR_ERROR "opendir failed");
Jon Medhurst96b56152014-10-30 18:01:15 +000068 handleException();
69 }
70
71 int self = getpid();
72
73 struct dirent *dirent;
74 while ((dirent = readdir(proc)) != NULL) {
75 char *endptr;
76 const int pid = strtol(dirent->d_name, &endptr, 10);
77 if (*endptr != '\0' || (pid == self)) {
78 // Ignore proc items that are not integers like ., cpuinfo, etc...
79 continue;
80 }
81
82 if (!printb->printf("/proc/%i/stat", pid)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010083 logg->logError(GATOR_ERROR "DynBuf::printf failed");
Jon Medhurst96b56152014-10-30 18:01:15 +000084 handleException();
85 }
86
87 if (!b.read(printb->getBuf())) {
88 // This is not a fatal error - the thread just doesn't exist any more
89 continue;
90 }
91
92 char *comm = strchr(b.getBuf(), '(');
93 if (comm == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010094 logg->logError(GATOR_ERROR "parsing stat comm begin failed");
Jon Medhurst96b56152014-10-30 18:01:15 +000095 handleException();
96 }
97 ++comm;
98 char *const str = strrchr(comm, ')');
99 if (str == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100100 logg->logError(GATOR_ERROR "parsing stat comm end failed");
Jon Medhurst96b56152014-10-30 18:01:15 +0000101 handleException();
102 }
103 *str = '\0';
104
Jon Medhurstb1d07442015-05-08 12:04:18 +0100105 if (strncmp(comm, "gator", 5) != 0) {
106 continue;
Jon Medhurst96b56152014-10-30 18:01:15 +0000107 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100108
109 char state;
110 const int count = sscanf(str + 2, " %c ", &state);
111 if (count != 1) {
112 logg->logError(GATOR_ERROR "parsing stat state failed");
113 handleException();
114 }
115
116 if (state == 'Z') {
117 // This gator is a zombie, ignore
118 continue;
119 }
120
121 // Assume there is only one gator process
122 return pid;
Jon Medhurst96b56152014-10-30 18:01:15 +0000123 }
124
125 closedir(proc);
126
127 return -1;
128}
129
Jon Medhurstb1d07442015-05-08 12:04:18 +0100130static bool confirm(const char *const message) {
131 char buf[1<<10];
132
133 printf(GATOR_CONFIRM "%s\n", message);
134 while (fgets(buf, sizeof(buf), stdin) != NULL) {
135 if (strcmp(buf, "y\n") == 0) {
136 return true;
137 }
138 if (strcmp(buf, "n\n") == 0) {
139 return false;
140 }
141 // Ignore unrecognized input
142 }
143
144 return false;
145}
146
147void update(const char *const gatorPath) {
148 printf(GATOR_MSG "starting\n");
Jon Medhurst96b56152014-10-30 18:01:15 +0000149
150 int version[3];
151 if (!getLinuxVersion(version)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100152 logg->logError(GATOR_ERROR "getLinuxVersion failed");
Jon Medhurst96b56152014-10-30 18:01:15 +0000153 handleException();
154 }
155
156 if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(2, 6, 32)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100157 logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as this kernel version is not supported. Please upgrade the kernel on your device.");
Jon Medhurst96b56152014-10-30 18:01:15 +0000158 handleException();
159 }
160
161 if (KERNEL_VERSION(version[0], version[1], version[2]) < KERNEL_VERSION(3, 4, 0)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100162 logg->logError(GATOR_ERROR "Streamline can't automatically setup gator as gator.ko is required for this version of Linux. Please build gator.ko and gatord and install them on your device.");
Jon Medhurst96b56152014-10-30 18:01:15 +0000163 handleException();
164 }
165
166 if (geteuid() != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100167 printf(GATOR_MSG "trying sudo\n");
Jon Medhurst96b56152014-10-30 18:01:15 +0000168 execlp("sudo", "sudo", gatorPath, "-u", NULL);
169 // Streamline will provide the password if needed
170
Jon Medhurstb1d07442015-05-08 12:04:18 +0100171 printf(GATOR_MSG "trying su\n");
Jon Medhurst96b56152014-10-30 18:01:15 +0000172 char buf[1<<10];
Jon Medhurstb1d07442015-05-08 12:04:18 +0100173 /*
174 * Different versions of su handle additional -c command line options differently and expect the
175 * arguments in different ways. Try both ways wrapped in a shell.
176 *
177 * Then invoke another shell after su as it avoids odd failures on some Android systems
178 */
179 snprintf(buf, sizeof(buf), "su -c \"sh -c '%s -u'\" || su -c sh -c '%s -u'", gatorPath, gatorPath);
180 execlp("sh", "sh", "-c", buf, NULL);
Jon Medhurst96b56152014-10-30 18:01:15 +0000181 // Streamline will provide the password if needed
182
Jon Medhurstb1d07442015-05-08 12:04:18 +0100183 logg->logError(GATOR_ERROR "Streamline was unable to sudo to root on your device. Please double check passwords, ensure sudo or su work with this user or try a different username.");
Jon Medhurst96b56152014-10-30 18:01:15 +0000184 handleException();
185 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100186 printf(GATOR_MSG "now root\n");
187
188 if (access("/sys/module/gator", F_OK) == 0) {
189 if (!confirm("Streamline has detected that the gator kernel module is loaded on your device. Click yes to switch to user space gator, click no to abort the install.")) {
190 printf("gator: cancel\n");
191 exit(-1);
192 }
193 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000194
195 // setenforce 0 not needed for userspace gator
196
197 // Kill existing gator
Jon Medhurstb1d07442015-05-08 12:04:18 +0100198 DynBuf printb;
199 int gator_main = pgrep_gator(&printb);
Jon Medhurst96b56152014-10-30 18:01:15 +0000200 if (gator_main > 0) {
201 if (kill(gator_main, SIGTERM) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100202 logg->logError(GATOR_ERROR "kill SIGTERM failed");
203 handleException();
204 }
205 if (!printb.printf("/proc/%i/exe", gator_main)) {
206 logg->logError(GATOR_ERROR "DynBuf::printf failed");
Jon Medhurst96b56152014-10-30 18:01:15 +0000207 handleException();
208 }
209 for (int i = 0; ; ++i) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100210 // /proc/<pid>/exe exists but will not be accessible for zombies
211 if (access(printb.getBuf(), F_OK) != 0) {
Jon Medhurst96b56152014-10-30 18:01:15 +0000212 break;
213 }
214 if (i == 5) {
215 if (kill(gator_main, SIGKILL) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100216 logg->logError(GATOR_ERROR "kill SIGKILL failed");
Jon Medhurst96b56152014-10-30 18:01:15 +0000217 handleException();
218 }
219 } else if (i >= 10) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100220 logg->logError(GATOR_ERROR "unable to kill running gator");
Jon Medhurst96b56152014-10-30 18:01:15 +0000221 handleException();
222 }
223 sleep(1);
224 }
225 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100226 printf(GATOR_MSG "no gatord running\n");
227
228 umount("/dev/gator");
229 syscall(__NR_delete_module, "gator", O_NONBLOCK);
Jon Medhurst96b56152014-10-30 18:01:15 +0000230
231 rename("gatord", "gatord.old");
232 rename("gator.ko", "gator.ko.old");
233
234 // Rename gatord.YYYYMMDDHHMMSSMMMM to gatord
235 char *newGatorPath = strdup(gatorPath);
236 char *dot = strrchr(newGatorPath, '.');
237 if (dot != NULL) {
238 *dot = '\0';
239 if (rename(gatorPath, newGatorPath) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100240 logg->logError(GATOR_ERROR "rename failed");
Jon Medhurst96b56152014-10-30 18:01:15 +0000241 handleException();
242 }
243 }
244
Jon Medhurstb1d07442015-05-08 12:04:18 +0100245 char buf[128];
246 int pipefd[2];
247 if (pipe_cloexec(pipefd) != 0) {
248 logg->logError(GATOR_ERROR "pipe failed");
249 handleException();
250 }
251
252 // Fork and start gatord (redirect stdin, stdout and stderr so shell can close)
Jon Medhurst96b56152014-10-30 18:01:15 +0000253 int child = fork();
254 if (child < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100255 logg->logError(GATOR_ERROR "fork failed");
Jon Medhurst96b56152014-10-30 18:01:15 +0000256 handleException();
257 } else if (child == 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100258 int inFd;
259 int outFd;
260 int errFd;
261 int result = -1;
262
263 buf[0] = '\0';
264 close(pipefd[0]);
265
266 inFd = open("/dev/null", O_RDONLY | O_CLOEXEC);
Jon Medhurst96b56152014-10-30 18:01:15 +0000267 if (inFd < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100268 snprintf(buf, sizeof(buf), GATOR_ERROR "open of /dev/null failed");
269 goto fail_exit;
Jon Medhurst96b56152014-10-30 18:01:15 +0000270 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100271 outFd = open("gatord.out", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
Jon Medhurst96b56152014-10-30 18:01:15 +0000272 if (outFd < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100273 snprintf(buf, sizeof(buf), GATOR_ERROR "open of gatord.out failed");
274 goto fail_exit;
Jon Medhurst96b56152014-10-30 18:01:15 +0000275 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100276 errFd = open("gatord.err", O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
Jon Medhurst96b56152014-10-30 18:01:15 +0000277 if (errFd < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100278 snprintf(buf, sizeof(buf), GATOR_ERROR "open of gatord.err failed");
279 goto fail_exit;
Jon Medhurst96b56152014-10-30 18:01:15 +0000280 }
281 if (dup2(inFd, STDIN_FILENO) < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100282 snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stdin failed");
283 goto fail_exit;
Jon Medhurst96b56152014-10-30 18:01:15 +0000284 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100285 fflush(stdout);
Jon Medhurst96b56152014-10-30 18:01:15 +0000286 if (dup2(outFd, STDOUT_FILENO) < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100287 snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stdout failed");
288 goto fail_exit;
Jon Medhurst96b56152014-10-30 18:01:15 +0000289 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100290 fflush(stderr);
Jon Medhurst96b56152014-10-30 18:01:15 +0000291 if (dup2(errFd, STDERR_FILENO) < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100292 snprintf(buf, sizeof(buf), GATOR_ERROR "dup2 for stderr failed");
293 goto fail_exit;
Jon Medhurst96b56152014-10-30 18:01:15 +0000294 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100295
296 snprintf(buf, sizeof(buf), GATOR_MSG "done");
297 result = 0;
298
299 fail_exit:
300 if (buf[0] != '\0') {
301 const ssize_t bytes = write(pipefd[1], buf, sizeof(buf));
302 // Can't do anything if this fails
303 (void)bytes;
304 }
305 close(pipefd[1]);
306
307 if (result == 0) {
308 // Continue to execute gator normally
309 return;
310 }
311 exit(-1);
Jon Medhurst96b56152014-10-30 18:01:15 +0000312 }
313
Jon Medhurstb1d07442015-05-08 12:04:18 +0100314 close(pipefd[1]);
315 const ssize_t bytes = read(pipefd[0], buf, sizeof(buf));
316 if (bytes > 0) {
317 logg->logError("%s", buf);
318 handleException();
319 }
320 close(pipefd[0]);
Jon Medhurst96b56152014-10-30 18:01:15 +0000321
Jon Medhurstb1d07442015-05-08 12:04:18 +0100322 // Exit so parent shell can move on
323 exit(0);
Jon Medhurst96b56152014-10-30 18:01:15 +0000324}