gator: Version 5.20
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / Command.cpp
1 /**
2  * Copyright (C) ARM Limited 2014. All rights reserved.
3  *
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
26 static 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) {
42                 logg->logError(__FILE__, __LINE__, "fork failed");
43                 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
68 static 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
91 void *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) {
97                 logg->logError(__FILE__, __LINE__, "Unable to lookup the user %s, please double check that the user exists", name);
98                 handleException();
99         }
100
101         sleep(3);
102
103         char buf[128];
104         int pipefd[2];
105         if (pipe_cloexec(pipefd) != 0) {
106                 logg->logError(__FILE__, __LINE__, "pipe failed");
107                 handleException();
108         }
109
110         const int pid = fork();
111         if (pid < 0) {
112                 logg->logError(__FILE__, __LINE__, "fork failed");
113                 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) {
166                 logg->logError(__FILE__, __LINE__, buf);
167                 handleException();
168         }
169         close(pipefd[0]);
170
171         return NULL;
172 }