Loading cmds/dumpstate/dumpstate.cpp +3 −47 Original line number Original line Diff line number Diff line Loading @@ -27,7 +27,6 @@ #include <stdlib.h> #include <stdlib.h> #include <string> #include <string> #include <string.h> #include <string.h> #include <sys/capability.h> #include <sys/prctl.h> #include <sys/prctl.h> #include <sys/resource.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/stat.h> Loading Loading @@ -1004,49 +1003,6 @@ static std::string SHA256_file_hash(std::string filepath) { return std::string(hash_buffer); 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[]) { int main(int argc, char *argv[]) { struct sigaction sigact; struct sigaction sigact; int do_add_date = 0; int do_add_date = 0; Loading Loading @@ -1294,8 +1250,8 @@ int main(int argc, char *argv[]) { // Invoking the following dumpsys calls before dump_traces() to try and // Invoking the following dumpsys calls before dump_traces() to try and // keep the system stats as close to its initial state as possible. // 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_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "meminfo", "-a", NULL); run_command("DUMPSYS CPUINFO", 30, SU_PATH, "shell", "dumpsys", "cpuinfo", "-a", NULL); run_command_as_shell("DUMPSYS CPUINFO", 30, "dumpsys", "cpuinfo", "-a", NULL); /* collect stack traces from Dalvik and native processes (needs root) */ /* collect stack traces from Dalvik and native processes (needs root) */ Loading @@ -1306,7 +1262,7 @@ int main(int argc, char *argv[]) { add_dir(RECOVERY_DIR, true); add_dir(RECOVERY_DIR, true); add_mountinfo(); add_mountinfo(); if (!drop_root()) { if (!drop_root_user()) { return -1; return -1; } } Loading cmds/dumpstate/dumpstate.h +8 −1 Original line number Original line Diff line number Diff line Loading @@ -103,13 +103,20 @@ int dump_files(const char *title, const char *dir, bool (*skip)(const char *path), bool (*skip)(const char *path), int (*dump_from_fd)(const char *title, const char *path, int fd)); 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 */ /* 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, ...); int run_command(const char *title, int timeout_seconds, const char *command, ...); /* forks a command and waits for it to finish /* forks a command and waits for it to finish first element of args is the command, and last must be NULL. first element of args is the command, and last must be NULL. command is always ran, even when _DUMPSTATE_DRY_RUN_ is defined. */ 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 */ /* sends a broadcast using Activity Manager */ void send_broadcast(const std::string& action, const std::vector<std::string>& args); void send_broadcast(const std::string& action, const std::vector<std::string>& args); Loading cmds/dumpstate/utils.cpp +93 −7 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <stdlib.h> #include <stdlib.h> #include <string> #include <string> #include <string.h> #include <string.h> #include <sys/capability.h> #include <sys/inotify.h> #include <sys/inotify.h> #include <sys/stat.h> #include <sys/stat.h> #include <sys/sysconf.h> #include <sys/sysconf.h> Loading Loading @@ -662,13 +663,48 @@ int run_command(const char *title, int timeout_seconds, const char *command, ... ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; }); 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); va_end(ap); return status; return status; } } /* forks a command and waits for it to finish */ /* 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. /* 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 * It's a good approximation for most cases, except when calling dumpsys, where its weight * should be much higher proportionally to its timeout. */ * should be much higher proportionally to its timeout. */ Loading @@ -686,6 +722,10 @@ int run_command_always(const char *title, int timeout_seconds, const char *args[ /* handle child case */ /* handle child case */ if (pid == 0) { 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 */ /* make sure the child dies when dumpstate dies */ prctl(PR_SET_PDEATHSIG, SIGKILL); prctl(PR_SET_PDEATHSIG, SIGKILL); Loading Loading @@ -747,14 +787,60 @@ int run_command_always(const char *title, int timeout_seconds, const char *args[ return status; 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) { void send_broadcast(const std::string& action, const std::vector<std::string>& args) { if (args.size() > 1000) { if (args.size() > 1000) { MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size()); MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size()); return; return; } } const char *am_args[1024] = { SU_PATH, "shell", "/system/bin/am", "broadcast", const char *am_args[1024] = { "/system/bin/am", "broadcast", "--user", "0", "-a", "--user", "0", "-a", action.c_str() }; action.c_str() }; size_t am_index = 7; // Starts at the index of last initial value above. size_t am_index = 5; // Starts at the index of last initial value above. for (const std::string& arg : args) { for (const std::string& arg : args) { am_args[++am_index] = arg.c_str(); am_args[++am_index] = arg.c_str(); } } Loading @@ -763,7 +849,7 @@ void send_broadcast(const std::string& action, const std::vector<std::string>& a std::string args_string; std::string args_string; format_args(am_index + 1, am_args, &args_string); format_args(am_index + 1, am_args, &args_string); MYLOGD("send_broadcast command: %s\n", args_string.c_str()); 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; size_t num_props = 0; Loading Loading @@ -1102,7 +1188,7 @@ void update_progress(int delta) { void take_screenshot(const std::string& path) { void take_screenshot(const std::string& path) { const char *args[] = { "/system/bin/screencap", "-p", path.c_str(), NULL }; 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) { void vibrate(FILE* vibrator, int ms) { Loading Loading
cmds/dumpstate/dumpstate.cpp +3 −47 Original line number Original line Diff line number Diff line Loading @@ -27,7 +27,6 @@ #include <stdlib.h> #include <stdlib.h> #include <string> #include <string> #include <string.h> #include <string.h> #include <sys/capability.h> #include <sys/prctl.h> #include <sys/prctl.h> #include <sys/resource.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/stat.h> Loading Loading @@ -1004,49 +1003,6 @@ static std::string SHA256_file_hash(std::string filepath) { return std::string(hash_buffer); 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[]) { int main(int argc, char *argv[]) { struct sigaction sigact; struct sigaction sigact; int do_add_date = 0; int do_add_date = 0; Loading Loading @@ -1294,8 +1250,8 @@ int main(int argc, char *argv[]) { // Invoking the following dumpsys calls before dump_traces() to try and // Invoking the following dumpsys calls before dump_traces() to try and // keep the system stats as close to its initial state as possible. // 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_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "meminfo", "-a", NULL); run_command("DUMPSYS CPUINFO", 30, SU_PATH, "shell", "dumpsys", "cpuinfo", "-a", NULL); run_command_as_shell("DUMPSYS CPUINFO", 30, "dumpsys", "cpuinfo", "-a", NULL); /* collect stack traces from Dalvik and native processes (needs root) */ /* collect stack traces from Dalvik and native processes (needs root) */ Loading @@ -1306,7 +1262,7 @@ int main(int argc, char *argv[]) { add_dir(RECOVERY_DIR, true); add_dir(RECOVERY_DIR, true); add_mountinfo(); add_mountinfo(); if (!drop_root()) { if (!drop_root_user()) { return -1; return -1; } } Loading
cmds/dumpstate/dumpstate.h +8 −1 Original line number Original line Diff line number Diff line Loading @@ -103,13 +103,20 @@ int dump_files(const char *title, const char *dir, bool (*skip)(const char *path), bool (*skip)(const char *path), int (*dump_from_fd)(const char *title, const char *path, int fd)); 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 */ /* 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, ...); int run_command(const char *title, int timeout_seconds, const char *command, ...); /* forks a command and waits for it to finish /* forks a command and waits for it to finish first element of args is the command, and last must be NULL. first element of args is the command, and last must be NULL. command is always ran, even when _DUMPSTATE_DRY_RUN_ is defined. */ 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 */ /* sends a broadcast using Activity Manager */ void send_broadcast(const std::string& action, const std::vector<std::string>& args); void send_broadcast(const std::string& action, const std::vector<std::string>& args); Loading
cmds/dumpstate/utils.cpp +93 −7 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <stdlib.h> #include <stdlib.h> #include <string> #include <string> #include <string.h> #include <string.h> #include <sys/capability.h> #include <sys/inotify.h> #include <sys/inotify.h> #include <sys/stat.h> #include <sys/stat.h> #include <sys/sysconf.h> #include <sys/sysconf.h> Loading Loading @@ -662,13 +663,48 @@ int run_command(const char *title, int timeout_seconds, const char *command, ... ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; }); 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); va_end(ap); return status; return status; } } /* forks a command and waits for it to finish */ /* 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. /* 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 * It's a good approximation for most cases, except when calling dumpsys, where its weight * should be much higher proportionally to its timeout. */ * should be much higher proportionally to its timeout. */ Loading @@ -686,6 +722,10 @@ int run_command_always(const char *title, int timeout_seconds, const char *args[ /* handle child case */ /* handle child case */ if (pid == 0) { 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 */ /* make sure the child dies when dumpstate dies */ prctl(PR_SET_PDEATHSIG, SIGKILL); prctl(PR_SET_PDEATHSIG, SIGKILL); Loading Loading @@ -747,14 +787,60 @@ int run_command_always(const char *title, int timeout_seconds, const char *args[ return status; 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) { void send_broadcast(const std::string& action, const std::vector<std::string>& args) { if (args.size() > 1000) { if (args.size() > 1000) { MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size()); MYLOGE("send_broadcast: too many arguments (%d)\n", (int) args.size()); return; return; } } const char *am_args[1024] = { SU_PATH, "shell", "/system/bin/am", "broadcast", const char *am_args[1024] = { "/system/bin/am", "broadcast", "--user", "0", "-a", "--user", "0", "-a", action.c_str() }; action.c_str() }; size_t am_index = 7; // Starts at the index of last initial value above. size_t am_index = 5; // Starts at the index of last initial value above. for (const std::string& arg : args) { for (const std::string& arg : args) { am_args[++am_index] = arg.c_str(); am_args[++am_index] = arg.c_str(); } } Loading @@ -763,7 +849,7 @@ void send_broadcast(const std::string& action, const std::vector<std::string>& a std::string args_string; std::string args_string; format_args(am_index + 1, am_args, &args_string); format_args(am_index + 1, am_args, &args_string); MYLOGD("send_broadcast command: %s\n", args_string.c_str()); 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; size_t num_props = 0; Loading Loading @@ -1102,7 +1188,7 @@ void update_progress(int delta) { void take_screenshot(const std::string& path) { void take_screenshot(const std::string& path) { const char *args[] = { "/system/bin/screencap", "-p", path.c_str(), NULL }; 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) { void vibrate(FILE* vibrator, int ms) { Loading