Merge "Don't use su to when calling am or dumpsys." into nyc-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index ee0df52..5119061 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -27,7 +27,6 @@
#include <stdlib.h>
#include <string>
#include <string.h>
-#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
@@ -1004,49 +1003,6 @@
return std::string(hash_buffer);
}
-/* switch to non-root user and group */
-bool drop_root() {
- /* ensure we will keep capabilities when we drop root */
- if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
- MYLOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
- return false;
- }
-
- gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
- AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC };
- if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
- MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
- return false;
- }
- if (setgid(AID_SHELL) != 0) {
- MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno));
- return false;
- }
- if (setuid(AID_SHELL) != 0) {
- MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno));
- return false;
- }
-
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata[2];
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
- capheader.version = _LINUX_CAPABILITY_VERSION_3;
- capheader.pid = 0;
-
- capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
- capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
- capdata[0].inheritable = 0;
- capdata[1].inheritable = 0;
-
- if (capset(&capheader, &capdata[0]) < 0) {
- MYLOGE("capset failed: %s\n", strerror(errno));
- return false;
- }
-
- return true;
-}
-
int main(int argc, char *argv[]) {
struct sigaction sigact;
int do_add_date = 0;
@@ -1294,8 +1250,8 @@
// Invoking the following dumpsys calls before dump_traces() to try and
// keep the system stats as close to its initial state as possible.
- run_command("DUMPSYS MEMINFO", 30, SU_PATH, "shell", "dumpsys", "meminfo", "-a", NULL);
- run_command("DUMPSYS CPUINFO", 30, SU_PATH, "shell", "dumpsys", "cpuinfo", "-a", NULL);
+ run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "meminfo", "-a", NULL);
+ run_command_as_shell("DUMPSYS CPUINFO", 30, "dumpsys", "cpuinfo", "-a", NULL);
/* collect stack traces from Dalvik and native processes (needs root) */
@@ -1306,7 +1262,7 @@
add_dir(RECOVERY_DIR, true);
add_mountinfo();
- if (!drop_root()) {
+ if (!drop_root_user()) {
return -1;
}
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index cdb2502..02d1256 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -103,13 +103,20 @@
bool (*skip)(const char *path),
int (*dump_from_fd)(const char *title, const char *path, int fd));
+// TODO: need to refactor all those run_command variations; there shold be just one, receiving an
+// optional CommandOptions objects with values such as run_always, drop_root, etc...
+
/* forks a command and waits for it to finish -- terminate args with NULL */
+int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...);
int run_command(const char *title, int timeout_seconds, const char *command, ...);
/* forks a command and waits for it to finish
first element of args is the command, and last must be NULL.
command is always ran, even when _DUMPSTATE_DRY_RUN_ is defined. */
-int run_command_always(const char *title, int timeout_seconds, const char *args[]);
+int run_command_always(const char *title, bool drop_root, int timeout_seconds, const char *args[]);
+
+/* switch to non-root user and group */
+bool drop_root_user();
/* sends a broadcast using Activity Manager */
void send_broadcast(const std::string& action, const std::vector<std::string>& args);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 7ed51ab..89c9653 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <string>
#include <string.h>
+#include <sys/capability.h>
#include <sys/inotify.h>
#include <sys/stat.h>
#include <sys/sysconf.h>
@@ -661,13 +662,48 @@
ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
- int status = run_command_always(title, timeout_seconds, args);
+ int status = run_command_always(title, false, timeout_seconds, args);
+ va_end(ap);
+ return status;
+}
+
+int run_command_as_shell(const char *title, int timeout_seconds, const char *command, ...) {
+ DurationReporter duration_reporter(title);
+ fflush(stdout);
+
+ const char *args[1024] = {command};
+ size_t arg;
+ va_list ap;
+ va_start(ap, command);
+ if (title) printf("------ %s (%s", title, command);
+ bool null_terminated = false;
+ for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
+ args[arg] = va_arg(ap, const char *);
+ if (args[arg] == nullptr) {
+ null_terminated = true;
+ break;
+ }
+ if (title) printf(" %s", args[arg]);
+ }
+ if (title) printf(") ------\n");
+ fflush(stdout);
+ if (!null_terminated) {
+ // Fail now, otherwise execvp() call on run_command_always() might hang.
+ std::string cmd;
+ format_args(command, args, &cmd);
+ MYLOGE("skipping command %s because its args were not NULL-terminated", cmd.c_str());
+ return -1;
+ }
+
+ ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });
+
+ int status = run_command_always(title, true, timeout_seconds, args);
va_end(ap);
return status;
}
/* forks a command and waits for it to finish */
-int run_command_always(const char *title, int timeout_seconds, const char *args[]) {
+int run_command_always(const char *title, bool drop_root, int timeout_seconds, const char *args[]) {
/* TODO: for now we're simplifying the progress calculation by using the timeout as the weight.
* It's a good approximation for most cases, except when calling dumpsys, where its weight
* should be much higher proportionally to its timeout. */
@@ -685,6 +721,10 @@
/* handle child case */
if (pid == 0) {
+ if (drop_root && !drop_root_user()) {
+ printf("*** could not drop root before running %s: %s\n", command, strerror(errno));
+ _exit(-1);
+ }
/* make sure the child dies when dumpstate dies */
prctl(PR_SET_PDEATHSIG, SIGKILL);
@@ -746,14 +786,60 @@
return status;
}
+bool drop_root_user() {
+ if (getgid() == AID_SHELL && getuid() == AID_SHELL) {
+ MYLOGD("drop_root_user(): already running as Shell");
+ return true;
+ }
+ /* ensure we will keep capabilities when we drop root */
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+ MYLOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
+ AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC };
+ if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+ MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
+ return false;
+ }
+ if (setgid(AID_SHELL) != 0) {
+ MYLOGE("Unable to setgid, aborting: %s\n", strerror(errno));
+ return false;
+ }
+ if (setuid(AID_SHELL) != 0) {
+ MYLOGE("Unable to setuid, aborting: %s\n", strerror(errno));
+ return false;
+ }
+
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata[2];
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
+ capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
+ capdata[0].inheritable = 0;
+ capdata[1].inheritable = 0;
+
+ if (capset(&capheader, &capdata[0]) < 0) {
+ MYLOGE("capset failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
void send_broadcast(const std::string& action, const std::vector<std::string>& args) {
if (args.size() > 1000) {
MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size());
return;
}
- const char *am_args[1024] = { SU_PATH, "shell", "/system/bin/am", "broadcast",
- "--user", "0", "-a", action.c_str() };
- size_t am_index = 7; // Starts at the index of last initial value above.
+ const char *am_args[1024] = { "/system/bin/am", "broadcast", "--user", "0", "-a",
+ action.c_str() };
+ size_t am_index = 5; // Starts at the index of last initial value above.
for (const std::string& arg : args) {
am_args[++am_index] = arg.c_str();
}
@@ -762,7 +848,7 @@
std::string args_string;
format_args(am_index + 1, am_args, &args_string);
MYLOGD("send_broadcast command: %s\n", args_string.c_str());
- run_command_always(NULL, 5, am_args);
+ run_command_always(NULL, 5, true, am_args);
}
size_t num_props = 0;
@@ -1101,7 +1187,7 @@
void take_screenshot(const std::string& path) {
const char *args[] = { "/system/bin/screencap", "-p", path.c_str(), NULL };
- run_command_always(NULL, 10, args);
+ run_command_always(NULL, false, 10, args);
}
void vibrate(FILE* vibrator, int ms) {