From 812b19a425b8304ac9e5408cc8ceb9f363c72559 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Fri, 31 Aug 2012 16:08:06 -0700 Subject: [PATCH] installd: reduce privileges. Make installd run with fewer privileges. This will help make exploitation of installd based vulnerabilities more difficult to perform. installd now runs with the following privileges: * CAP_DAC_OVERRIDE * CAP_CHOWN These two capabilities are needed to add and remove files from application's home directories. * CAP_SETUID * CAP_SETGID These permissions are needed to further drop privileges when running dexopt as the application UID. "installd" no longer runs with full root privileges. It cannot, for example, mount and unmount filesystems, install modules, perform direct I/O, etc. Change-Id: Ib407e41e5e4c95f35a5c6a154812c5e8ae3006ed --- cmds/installd/commands.c | 23 ++++++++++++++------ cmds/installd/installd.c | 46 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index ab64747ab8018..9e83a670b44d1 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -14,6 +14,7 @@ ** limitations under the License. */ +#include #include "installd.h" #include @@ -665,16 +666,16 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) ALOGE("dexopt cannot open '%s' for output\n", dex_path); goto fail; } - if (fchown(odex_fd, AID_SYSTEM, uid) < 0) { - ALOGE("dexopt cannot chown '%s'\n", dex_path); - goto fail; - } if (fchmod(odex_fd, S_IRUSR|S_IWUSR|S_IRGRP | (is_public ? S_IROTH : 0)) < 0) { ALOGE("dexopt cannot chmod '%s'\n", dex_path); goto fail; } + if (fchown(odex_fd, AID_SYSTEM, uid) < 0) { + ALOGE("dexopt cannot chown '%s'\n", dex_path); + goto fail; + } ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path); @@ -690,13 +691,23 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) ALOGE("setuid(%d) during dexopt\n", uid); exit(65); } + // drop capabilities + 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; + if (capset(&capheader, &capdata[0]) < 0) { + ALOGE("capset failed: %s\n", strerror(errno)); + exit(66); + } if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno)); - exit(66); + exit(67); } run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags); - exit(67); /* only get here on exec failure */ + exit(68); /* only get here on exec failure */ } else { res = wait_dexopt(pid, apk_path); if (res != 0) { diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c index d559639b160e7..652543fdd957c 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.c @@ -14,6 +14,9 @@ ** limitations under the License. */ +#include +#include + #include "installd.h" @@ -491,12 +494,53 @@ fail: return res; } +static void drop_privileges() { + if (prctl(PR_SET_KEEPCAPS, 1) < 0) { + ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno)); + exit(1); + } + + if (setgid(AID_INSTALL) < 0) { + ALOGE("setgid() can't drop privileges; exiting.\n"); + exit(1); + } + + if (setuid(AID_INSTALL) < 0) { + ALOGE("setuid() can't drop privileges; exiting.\n"); + exit(1); + } + + 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_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE); + capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN); + capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); + capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); + + capdata[0].effective = capdata[0].permitted; + capdata[1].effective = capdata[1].permitted; + capdata[0].inheritable = 0; + capdata[1].inheritable = 0; + + if (capset(&capheader, &capdata[0]) < 0) { + ALOGE("capset failed: %s\n", strerror(errno)); + exit(1); + } +} + int main(const int argc, const char *argv[]) { char buf[BUFFER_MAX]; struct sockaddr addr; socklen_t alen; int lsocket, s, count; + ALOGI("installd firing up\n"); + if (initialize_globals() < 0) { ALOGE("Could not initialize globals; exiting.\n"); exit(1); @@ -507,6 +551,8 @@ int main(const int argc, const char *argv[]) { exit(1); } + drop_privileges(); + lsocket = android_get_control_socket(SOCKET_PATH); if (lsocket < 0) { ALOGE("Failed to get socket from environment: %s\n", strerror(errno));