blob: 28d73cf5a905ae9d75a3553162a6f2fe0429a6e0 [file] [log] [blame]
/**
* 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;
}