From 9885881d0689e7999f2d7e7558e894dc73a0a0b0 Mon Sep 17 00:00:00 2001 From: Dan Pasanen Date: Mon, 6 Oct 2014 12:57:20 -0500 Subject: adb: add "adb unroot" to restart adb in non-root mode Change-Id: Ice6b94a71a62648ac073d129914a07372411fb25 --- adb/adb.c | 51 ++++++++++++++++++++++++++------------------------- adb/commandline.c | 2 ++ adb/services.c | 18 ++++++++++++++++++ adb/sockets.c | 15 +++++---------- adb/tests/test_adb.py | 21 +++++++++++++++++++-- 5 files changed, 70 insertions(+), 37 deletions(-) mode change 100644 => 100755 adb/tests/test_adb.py diff --git a/adb/adb.c b/adb/adb.c index 4258a01..bfc0336 100644 --- a/adb/adb.c +++ b/adb/adb.c @@ -1261,35 +1261,36 @@ static void drop_capabilities_bounding_set_if_needed() { } } -static int should_drop_privileges() { -#ifndef ALLOW_ADBD_ROOT - return 1; -#else /* ALLOW_ADBD_ROOT */ - int secure = 0; +static bool should_drop_privileges() { +#if defined(ALLOW_ADBD_ROOT) char value[PROPERTY_VALUE_MAX]; - /* run adbd in secure mode if ro.secure is set and - ** we are not in the emulator - */ + // The emulator is never secure, so don't drop privileges there. + // TODO: this seems like a bug --- shouldn't the emulator behave like a device? property_get("ro.kernel.qemu", value, ""); - if (strcmp(value, "1") != 0) { - property_get("ro.secure", value, "1"); - if (strcmp(value, "1") == 0) { - // don't run as root if ro.secure is set... - secure = 1; - - // ... except we allow running as root in userdebug builds if the - // service.adb.root property has been set by the "adb root" command - property_get("ro.debuggable", value, ""); - if (strcmp(value, "1") == 0) { - property_get("service.adb.root", value, ""); - if (strcmp(value, "1") == 0) { - secure = 0; - } - } - } + if (strcmp(value, "1") == 0) { + return false; + } + + // Don't run as root if ro.secure is set... + property_get("ro.secure", value, "1"); + bool ro_secure = (strcmp(value, "1") == 0); + + // ... except we allow running as root in userdebug builds if the + // service.adb.root property has been set by the "adb root" command + property_get("ro.debuggable", value, ""); + bool ro_debuggable = (strcmp(value, "1") == 0); + + property_get("service.adb.root", value, ""); + bool adb_root = (strcmp(value, "1") == 0); + bool adb_unroot = (strcmp(value, "0") == 0); + if (adb_unroot) { + return true; // The user explicitly wants us to drop privileges. } - return secure; + + return ro_secure || !ro_debuggable; +#else + return true; // "adb root" not allowed, always drop privileges. #endif /* ALLOW_ADBD_ROOT */ } #endif /* !ADB_HOST */ diff --git a/adb/commandline.c b/adb/commandline.c index a06885b..830f290 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -210,6 +210,7 @@ void help() " adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n" " adb reboot-bootloader - reboots the device into the bootloader\n" " adb root - restarts the adbd daemon with root permissions\n" + " adb unroot - restarts the adbd daemon without root permissions\n" " adb usb - restarts the adbd daemon listening on USB\n" " adb tcpip - restarts the adbd daemon listening on TCP on the specified port\n" "networking:\n" @@ -1473,6 +1474,7 @@ int adb_commandline(int argc, char **argv) !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb") || !strcmp(argv[0], "root") || + !strcmp(argv[0], "unroot") || !strcmp(argv[0], "disable-verity") || !strcmp(argv[0], "enable-verity")) { char command[100]; diff --git a/adb/services.c b/adb/services.c index e4ce0bc..bd210a8 100644 --- a/adb/services.c +++ b/adb/services.c @@ -82,6 +82,22 @@ void restart_root_service(int fd, void *cookie) } } +void restart_unroot_service(int fd, void *cookie) +{ + char buf[100]; + + if (getuid() != 0) { + snprintf(buf, sizeof(buf), "adbd not running as root\n"); + writex(fd, buf, strlen(buf)); + adb_close(fd); + } else { + property_set("service.adb.root", "0"); + snprintf(buf, sizeof(buf), "restarting adbd as non root\n"); + writex(fd, buf, strlen(buf)); + adb_close(fd); + } +} + void restart_tcp_service(int fd, void *cookie) { char buf[100]; @@ -437,6 +453,8 @@ int service_to_fd(const char *name) ret = create_service_thread(reboot_service, arg); } else if(!strncmp(name, "root:", 5)) { ret = create_service_thread(restart_root_service, NULL); + } else if(!strncmp(name, "unroot:", 7)) { + ret = create_service_thread(restart_unroot_service, NULL); } else if(!strncmp(name, "backup:", 7)) { char* arg = strdup(name + 7); if (arg == NULL) return -1; diff --git a/adb/sockets.c b/adb/sockets.c index faa9564..6cdde97 100644 --- a/adb/sockets.c +++ b/adb/sockets.c @@ -430,12 +430,6 @@ asocket *create_local_socket(int fd) asocket *create_local_service_socket(const char *name) { - asocket *s; - int fd; -#if !ADB_HOST - char debug[PROPERTY_VALUE_MAX]; -#endif - #if !ADB_HOST if (!strcmp(name,"jdwp")) { return create_jdwp_service_socket(); @@ -444,18 +438,19 @@ asocket *create_local_service_socket(const char *name) return create_jdwp_tracker_service_socket(); } #endif - fd = service_to_fd(name); + int fd = service_to_fd(name); if(fd < 0) return 0; - s = create_local_socket(fd); + asocket* s = create_local_socket(fd); D("LS(%d): bound to '%s' via %d\n", s->id, name, fd); #if !ADB_HOST + char debug[PROPERTY_VALUE_MAX]; if (!strncmp(name, "root:", 5)) property_get("ro.debuggable", debug, ""); - if ((!strncmp(name, "root:", 5) && getuid() != 0 - && strcmp(debug, "1") == 0) + if ((!strncmp(name, "root:", 5) && getuid() != 0 && strcmp(debug, "1") == 0) + || (!strncmp(name, "unroot:", 7) && getuid() == 0) || !strncmp(name, "usb:", 4) || !strncmp(name, "tcpip:", 6)) { D("LS(%d): enabling exit_on_close\n", s->id); diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py old mode 100644 new mode 100755 index b0ae07f..4b3baf3 --- a/adb/tests/test_adb.py +++ b/adb/tests/test_adb.py @@ -8,11 +8,11 @@ import hashlib import os import random import re +import shlex import subprocess +import sys import tempfile import unittest -import sys -import shlex def trace(cmd): @@ -181,6 +181,12 @@ class AdbWrapper(object): def usb(self): return call_checked(self.adb_cmd + "usb") + def root(self): + return call_checked(self.adb_cmd + "root") + + def unroot(self): + return call_checked(self.adb_cmd + "unroot") + def forward_remove(self, local): return call_checked(self.adb_cmd + "forward --remove {}".format(local)) @@ -233,6 +239,17 @@ class AdbBasic(unittest.TestCase): version_num = True self.assertTrue(version_num) + def test_root_unroot(self): + """Make sure that adb root and adb unroot work, using id(1).""" + for device in get_device_list(): + adb = AdbWrapper(device) + adb.root() + adb.wait() + self.assertEqual("root", adb.shell("id -un").strip()) + adb.unroot() + adb.wait() + self.assertEqual("shell", adb.shell("id -un").strip()) + class AdbFile(unittest.TestCase): SCRATCH_DIR = "/data/local/tmp" -- cgit v1.1