Loading cmds/installd/commands.c +118 −10 Original line number Diff line number Diff line Loading @@ -618,14 +618,11 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno)); } static int wait_dexopt(pid_t pid, const char* apk_path) static int wait_child(pid_t pid) { int status; pid_t got_pid; /* * Wait for the optimization process to finish. */ while (1) { got_pid = waitpid(pid, &status, 0); if (got_pid == -1 && errno == EINTR) { Loading @@ -641,11 +638,8 @@ static int wait_dexopt(pid_t pid, const char* apk_path) } if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path); return 0; } else { ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, status); return status; /* always nonzero */ } } Loading Loading @@ -747,9 +741,11 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) } exit(68); /* only get here on exec failure */ } else { res = wait_dexopt(pid, apk_path); if (res != 0) { ALOGE("dexopt in='%s' out='%s' res=%d\n", apk_path, out_path, res); res = wait_child(pid); if (res == 0) { ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path); } else { ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, res); goto fail; } } Loading Loading @@ -1103,3 +1099,115 @@ out: return rc; } static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd) { static const char *IDMAP_BIN = "/system/bin/idmap"; static const size_t MAX_INT_LEN = 32; char idmap_str[MAX_INT_LEN]; snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd); execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL); ALOGE("execl(%s) failed: %s\n", IDMAP_BIN, strerror(errno)); } // Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix) // eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap static int flatten_path(const char *prefix, const char *suffix, const char *overlay_path, char *idmap_path, size_t N) { if (overlay_path == NULL || idmap_path == NULL) { return -1; } const size_t len_overlay_path = strlen(overlay_path); // will access overlay_path + 1 further below; requires absolute path if (len_overlay_path < 2 || *overlay_path != '/') { return -1; } const size_t len_idmap_root = strlen(prefix); const size_t len_suffix = strlen(suffix); if (SIZE_MAX - len_idmap_root < len_overlay_path || SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) { // additions below would cause overflow return -1; } if (N < len_idmap_root + len_overlay_path + len_suffix) { return -1; } memset(idmap_path, 0, N); snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix); char *ch = idmap_path + len_idmap_root; while (*ch != '\0') { if (*ch == '/') { *ch = '@'; } ++ch; } return 0; } int idmap(const char *target_apk, const char *overlay_apk, uid_t uid) { ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid); int idmap_fd = -1; char idmap_path[PATH_MAX]; if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk, idmap_path, sizeof(idmap_path)) == -1) { ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk); goto fail; } unlink(idmap_path); idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644); if (idmap_fd < 0) { ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno)); goto fail; } if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) { ALOGE("idmap cannot chown '%s'\n", idmap_path); goto fail; } if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) { ALOGE("idmap cannot chmod '%s'\n", idmap_path); goto fail; } pid_t pid; pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ if (setgid(uid) != 0) { ALOGE("setgid(%d) failed during idmap\n", uid); exit(1); } if (setuid(uid) != 0) { ALOGE("setuid(%d) failed during idmap\n", uid); exit(1); } if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno)); exit(1); } run_idmap(target_apk, overlay_apk, idmap_fd); exit(1); /* only if exec call to idmap failed */ } else { int status = wait_child(pid); if (status != 0) { ALOGE("idmap failed, status=0x%04x\n", status); goto fail; } } close(idmap_fd); return 0; fail: if (idmap_fd >= 0) { close(idmap_fd); unlink(idmap_path); } return -1; } cmds/installd/installd.c +7 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,11 @@ static int do_linklib(char **arg, char reply[REPLY_MAX]) return linklib(arg[0], arg[1], atoi(arg[2])); } static int do_idmap(char **arg, char reply[REPLY_MAX]) { return idmap(arg[0], arg[1], atoi(arg[2])); } struct cmdinfo { const char *name; unsigned numargs; Loading @@ -147,6 +152,7 @@ struct cmdinfo cmds[] = { { "linklib", 3, do_linklib }, { "mkuserdata", 4, do_mk_user_data }, { "rmuser", 1, do_rm_user }, { "idmap", 3, do_idmap }, }; static int readx(int s, void *_buf, int count) Loading Loading @@ -515,6 +521,7 @@ static void drop_privileges() { 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[CAP_TO_INDEX(CAP_FOWNER)].permitted |= CAP_TO_MASK(CAP_FOWNER); capdata[0].effective = capdata[0].permitted; capdata[1].effective = capdata[1].permitted; Loading cmds/installd/installd.h +4 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,9 @@ #define UPDATE_COMMANDS_DIR_PREFIX "/system/etc/updatecmds/" #define IDMAP_PREFIX "/data/resource-cache/" #define IDMAP_SUFFIX "@idmap" #define PKG_NAME_MAX 128 /* largest allowed package name */ #define PKG_PATH_MAX 256 /* max size of any path we use */ Loading Loading @@ -207,3 +210,4 @@ int free_cache(int64_t free_size); int dexopt(const char *apk_path, uid_t uid, int is_public); int movefiles(); int linklib(const char* target, const char* source, int userId); int idmap(const char *target_path, const char *overlay_path, uid_t uid); Loading
cmds/installd/commands.c +118 −10 Original line number Diff line number Diff line Loading @@ -618,14 +618,11 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno)); } static int wait_dexopt(pid_t pid, const char* apk_path) static int wait_child(pid_t pid) { int status; pid_t got_pid; /* * Wait for the optimization process to finish. */ while (1) { got_pid = waitpid(pid, &status, 0); if (got_pid == -1 && errno == EINTR) { Loading @@ -641,11 +638,8 @@ static int wait_dexopt(pid_t pid, const char* apk_path) } if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path); return 0; } else { ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, status); return status; /* always nonzero */ } } Loading Loading @@ -747,9 +741,11 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) } exit(68); /* only get here on exec failure */ } else { res = wait_dexopt(pid, apk_path); if (res != 0) { ALOGE("dexopt in='%s' out='%s' res=%d\n", apk_path, out_path, res); res = wait_child(pid); if (res == 0) { ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path); } else { ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, res); goto fail; } } Loading Loading @@ -1103,3 +1099,115 @@ out: return rc; } static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd) { static const char *IDMAP_BIN = "/system/bin/idmap"; static const size_t MAX_INT_LEN = 32; char idmap_str[MAX_INT_LEN]; snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd); execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL); ALOGE("execl(%s) failed: %s\n", IDMAP_BIN, strerror(errno)); } // Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix) // eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap static int flatten_path(const char *prefix, const char *suffix, const char *overlay_path, char *idmap_path, size_t N) { if (overlay_path == NULL || idmap_path == NULL) { return -1; } const size_t len_overlay_path = strlen(overlay_path); // will access overlay_path + 1 further below; requires absolute path if (len_overlay_path < 2 || *overlay_path != '/') { return -1; } const size_t len_idmap_root = strlen(prefix); const size_t len_suffix = strlen(suffix); if (SIZE_MAX - len_idmap_root < len_overlay_path || SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) { // additions below would cause overflow return -1; } if (N < len_idmap_root + len_overlay_path + len_suffix) { return -1; } memset(idmap_path, 0, N); snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix); char *ch = idmap_path + len_idmap_root; while (*ch != '\0') { if (*ch == '/') { *ch = '@'; } ++ch; } return 0; } int idmap(const char *target_apk, const char *overlay_apk, uid_t uid) { ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid); int idmap_fd = -1; char idmap_path[PATH_MAX]; if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk, idmap_path, sizeof(idmap_path)) == -1) { ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk); goto fail; } unlink(idmap_path); idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644); if (idmap_fd < 0) { ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno)); goto fail; } if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) { ALOGE("idmap cannot chown '%s'\n", idmap_path); goto fail; } if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) { ALOGE("idmap cannot chmod '%s'\n", idmap_path); goto fail; } pid_t pid; pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ if (setgid(uid) != 0) { ALOGE("setgid(%d) failed during idmap\n", uid); exit(1); } if (setuid(uid) != 0) { ALOGE("setuid(%d) failed during idmap\n", uid); exit(1); } if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno)); exit(1); } run_idmap(target_apk, overlay_apk, idmap_fd); exit(1); /* only if exec call to idmap failed */ } else { int status = wait_child(pid); if (status != 0) { ALOGE("idmap failed, status=0x%04x\n", status); goto fail; } } close(idmap_fd); return 0; fail: if (idmap_fd >= 0) { close(idmap_fd); unlink(idmap_path); } return -1; }
cmds/installd/installd.c +7 −0 Original line number Diff line number Diff line Loading @@ -124,6 +124,11 @@ static int do_linklib(char **arg, char reply[REPLY_MAX]) return linklib(arg[0], arg[1], atoi(arg[2])); } static int do_idmap(char **arg, char reply[REPLY_MAX]) { return idmap(arg[0], arg[1], atoi(arg[2])); } struct cmdinfo { const char *name; unsigned numargs; Loading @@ -147,6 +152,7 @@ struct cmdinfo cmds[] = { { "linklib", 3, do_linklib }, { "mkuserdata", 4, do_mk_user_data }, { "rmuser", 1, do_rm_user }, { "idmap", 3, do_idmap }, }; static int readx(int s, void *_buf, int count) Loading Loading @@ -515,6 +521,7 @@ static void drop_privileges() { 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[CAP_TO_INDEX(CAP_FOWNER)].permitted |= CAP_TO_MASK(CAP_FOWNER); capdata[0].effective = capdata[0].permitted; capdata[1].effective = capdata[1].permitted; Loading
cmds/installd/installd.h +4 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,9 @@ #define UPDATE_COMMANDS_DIR_PREFIX "/system/etc/updatecmds/" #define IDMAP_PREFIX "/data/resource-cache/" #define IDMAP_SUFFIX "@idmap" #define PKG_NAME_MAX 128 /* largest allowed package name */ #define PKG_PATH_MAX 256 /* max size of any path we use */ Loading Loading @@ -207,3 +210,4 @@ int free_cache(int64_t free_size); int dexopt(const char *apk_path, uid_t uid, int is_public); int movefiles(); int linklib(const char* target, const char* source, int userId); int idmap(const char *target_path, const char *overlay_path, uid_t uid);