Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 1 | /** |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 2 | * Copyright (C) ARM Limited 2014-2015. All rights reserved. |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 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) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 42 | logg->logError("fork failed"); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 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) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 97 | logg->logError("Unable to look up the user %s, please double check that the user exists", name); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 98 | handleException(); |
| 99 | } |
| 100 | |
| 101 | sleep(3); |
| 102 | |
| 103 | char buf[128]; |
| 104 | int pipefd[2]; |
| 105 | if (pipe_cloexec(pipefd) != 0) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 106 | logg->logError("pipe failed"); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 107 | handleException(); |
| 108 | } |
| 109 | |
| 110 | const int pid = fork(); |
| 111 | if (pid < 0) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 112 | logg->logError("fork failed"); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 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) { |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 166 | logg->logError("%s", buf); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 167 | handleException(); |
| 168 | } |
| 169 | close(pipefd[0]); |
| 170 | |
| 171 | return NULL; |
| 172 | } |