diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp index 7090b3677..57b8c2e4f 100644 --- a/cmds/installd/commands.cpp +++ b/cmds/installd/commands.cpp @@ -1601,43 +1601,58 @@ out: return rc; } -static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd) +static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd, + uint32_t target_hash, uint32_t overlay_hash) { static const char *IDMAP_BIN = "/system/bin/idmap"; static const size_t MAX_INT_LEN = 32; char idmap_str[MAX_INT_LEN]; + char target_hash_str[MAX_INT_LEN]; + char overlay_hash_str[MAX_INT_LEN]; snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd); + snprintf(target_hash_str, sizeof(target_hash_str), "%d", target_hash); + snprintf(overlay_hash_str, sizeof(overlay_hash_str), "%d", overlay_hash); - execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL); + execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, + target_hash_str, overlay_hash_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 +/* Prints to idmap_path (prefix)/(flat_target)@(flat_overerlay)@(suffix) + * Note: "Flat" is a string with '/' changed to @ + * Example input: + * prefix: /data/resource-cache/ + * suffix: idmap + * overlay_path: /data/app/com.theme.apk + * target_path: /data/app/com.target.apk + * Example output: + * idmap_path: /data/resource-cache/data@app@com.target.apk@data@app@theme.apk@idmap + */ static int flatten_path(const char *prefix, const char *suffix, - const char *overlay_path, char *idmap_path, size_t N) + const char *overlay_path, const char *target_path, char *idmap_path, size_t N) { - if (overlay_path == NULL || idmap_path == NULL) { + if (overlay_path == NULL || idmap_path == NULL || target_path == NULL) { return -1; } + + const size_t len_target_path = strlen(target_path); + if (len_target_path < 2 || *target_path != '/') { + 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); + int len = snprintf(idmap_path, N, "%s%s%s%s", prefix, target_path + 1, overlay_path, suffix); + if (len < 0 || (size_t)len >= N) { + return -1; // error or truncated + } char *ch = idmap_path + len_idmap_root; while (*ch != '\0') { if (*ch == '/') { @@ -1648,14 +1663,15 @@ static int flatten_path(const char *prefix, const char *suffix, return 0; } -int idmap(const char *target_apk, const char *overlay_apk, uid_t uid) +int idmap(const char *target_apk, const char *overlay_apk, uid_t uid, + uint32_t target_hash, uint32_t overlay_hash) { 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, + if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk, target_apk, idmap_path, sizeof(idmap_path)) == -1) { ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk); goto fail; @@ -1693,7 +1709,7 @@ int idmap(const char *target_apk, const char *overlay_apk, uid_t uid) exit(1); } - run_idmap(target_apk, overlay_apk, idmap_fd); + run_idmap(target_apk, overlay_apk, idmap_fd, target_hash, overlay_hash); exit(1); /* only if exec call to idmap failed */ } else { int status = wait_child(pid); @@ -1713,6 +1729,161 @@ fail: return -1; } +static void run_aapt(const char *source_apk, const char *internal_path, + int resapk_fd, int pkgId, int min_sdk_version, const char *common_res_path) +{ + static const char *AAPT_BIN = "/system/bin/aapt"; + static const char *MANIFEST = "/data/app/AndroidManifest.xml"; + static const char *FRAMEWORK_RES = "/system/framework/framework-res.apk"; + + static const size_t MAX_INT_LEN = 32; + char resapk_str[MAX_INT_LEN]; + char pkgId_str[MAX_INT_LEN]; + char minSdkVersion_str[MAX_INT_LEN]; + + snprintf(resapk_str, sizeof(resapk_str), "%d", resapk_fd); + snprintf(pkgId_str, sizeof(pkgId_str), "%d", pkgId); + snprintf(minSdkVersion_str, sizeof(minSdkVersion_str), "%d", min_sdk_version); + bool hasCommonResources = (common_res_path != NULL && common_res_path[0] != '\0'); + + if (hasCommonResources) { + execl(AAPT_BIN, AAPT_BIN, "package", + "--min-sdk-version", minSdkVersion_str, + "-M", MANIFEST, + "-S", source_apk, + "-X", internal_path, + "-I", FRAMEWORK_RES, + "-I", common_res_path, + "-r", resapk_str, + "-x", pkgId_str, + (char*)NULL); + } else { + execl(AAPT_BIN, AAPT_BIN, "package", + "--min-sdk-version", minSdkVersion_str, + "-M", MANIFEST, + "-S", source_apk, + "-X", internal_path, + "-I", FRAMEWORK_RES, + "-r", resapk_str, + "-x", pkgId_str, + (char*)NULL); + } + ALOGE("execl(%s) failed: %s\n", AAPT_BIN, strerror(errno)); +} + +int aapt(const char *source_apk, const char *internal_path, const char *out_restable, uid_t uid, + int pkgId, int min_sdk_version, const char *common_res_path) +{ + ALOGD("aapt source_apk=%s internal_path=%s out_restable=%s uid=%d, pkgId=%d, \ + min_sdk_version=%d, common_res_path=%s", + source_apk, internal_path, out_restable, uid, pkgId, min_sdk_version, common_res_path); + static const int PARENT_READ_PIPE = 0; + static const int CHILD_WRITE_PIPE = 1; + + int resapk_fd = -1; + char restable_path[PATH_MAX]; + char resapk_path[PATH_MAX]; + + int pipefd[2]; + pid_t pid = fork(); + + // get file descriptor for resources.arsc + snprintf(restable_path, PATH_MAX, "%s/resources.arsc", out_restable); + unlink(restable_path); + + // get file descriptor for resources.apk + snprintf(resapk_path, PATH_MAX, "%s/resources.apk", out_restable); + unlink(resapk_path); + resapk_fd = open(resapk_path, O_RDWR | O_CREAT | O_EXCL, 0644); + if (resapk_fd < 0) { + ALOGE("aapt cannot open '%s' for output: %s\n", resapk_path, strerror(errno)); + goto fail; + } + if (fchown(resapk_fd, AID_SYSTEM, uid) < 0) { + ALOGE("aapt cannot chown '%s'\n", resapk_path); + goto fail; + } + if (fchmod(resapk_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) { + ALOGE("aapt cannot chmod '%s'\n", resapk_path); + goto fail; + } + + if (pipe(pipefd) != 0) { + pipefd[0] = pipefd[1] = -1; + } + if (pid == 0) { + /* child -- drop privileges before continuing */ + if (setgid(uid) != 0) { + ALOGE("setgid(%d) failed during aapt\n", uid); + exit(1); + } + if (setuid(uid) != 0) { + ALOGE("setuid(%d) failed during aapt\n", uid); + exit(1); + } + + if (flock(resapk_fd, LOCK_EX | LOCK_NB) != 0) { + ALOGE("flock(%s) failed during aapt: %s\n", out_restable, strerror(errno)); + exit(1); + } + + if (pipefd[PARENT_READ_PIPE] > 0 && pipefd[CHILD_WRITE_PIPE] > 0) { + close(pipefd[PARENT_READ_PIPE]); // close unused read end + if (dup2(pipefd[CHILD_WRITE_PIPE], STDERR_FILENO) != STDERR_FILENO) { + pipefd[CHILD_WRITE_PIPE] = -1; + } + } + + run_aapt(source_apk, internal_path, resapk_fd, pkgId, min_sdk_version, common_res_path); + + if (pipefd[CHILD_WRITE_PIPE] > 0) { + close(pipefd[CHILD_WRITE_PIPE]); + } + exit(1); /* only if exec call to idmap failed */ + } else { + int status, i; + char buffer[1024]; + ssize_t readlen; + + if (pipefd[CHILD_WRITE_PIPE] > 0) { + close(pipefd[CHILD_WRITE_PIPE]); // close unused write end + } + + if (pipefd[PARENT_READ_PIPE] > 0) { + while ((readlen = read(pipefd[PARENT_READ_PIPE], buffer, sizeof(buffer) - 1)) > 0) { + // in case buffer has more than one string in it, replace '\0' with '\n' + for (i = 0; i < readlen; i++) { + if (buffer[i] == '\0') buffer[i] = '\n'; + } + // null terminate buffer at readlen + buffer[readlen] = '\0'; + ALOG(LOG_ERROR, "InstallTheme", "%s", buffer); + } + waitpid(pid, &status, 0); + + if (pipefd[PARENT_READ_PIPE] > 0) { + close(pipefd[PARENT_READ_PIPE]); + } + } else { + status = wait_child(pid); + } + + if (status != 0) { + ALOGE("aapt failed, status=0x%04x\n", status); + goto fail; + } + } + + close(resapk_fd); + return 0; +fail: + if (resapk_fd >= 0) { + close(resapk_fd); + unlink(resapk_path); + } + return -1; +} + int restorecon_data(const char* uuid, const char* pkgName, const char* seinfo, uid_t uid) { diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp index 13e316868..e0d9cdb5e 100644 --- a/cmds/installd/installd.cpp +++ b/cmds/installd/installd.cpp @@ -158,7 +158,17 @@ static int do_linklib(char **arg, char reply[REPLY_MAX] __unused) static int do_idmap(char **arg, char reply[REPLY_MAX] __unused) { - return idmap(arg[0], arg[1], atoi(arg[2])); + return idmap(arg[0], arg[1], atoi(arg[2]), atoi(arg[3]), atoi(arg[4])); +} + +static int do_aapt(char **arg, char reply[REPLY_MAX] __unused) +{ + return aapt(arg[0], arg[1], arg[2], atoi(arg[3]), atoi(arg[4]), atoi(arg[5]), ""); +} + +static int do_aapt_with_common(char **arg, char reply[REPLY_MAX] __unused) +{ + return aapt(arg[0], arg[1], arg[2], atoi(arg[3]), atoi(arg[4]), atoi(arg[5]), arg[6]); } static int do_restorecon_data(char **arg, char reply[REPLY_MAX] __attribute__((unused))) @@ -212,7 +222,9 @@ struct cmdinfo cmds[] = { { "mkuserdata", 5, do_mk_user_data }, { "mkuserconfig", 1, do_mk_user_config }, { "rmuser", 2, do_rm_user }, - { "idmap", 3, do_idmap }, + { "idmap", 5, do_idmap }, + { "aapt", 6, do_aapt }, + { "aapt_with_common", 7, do_aapt_with_common }, { "restorecondata", 4, do_restorecon_data }, { "createoatdir", 2, do_create_oat_dir }, { "rmpackagedir", 1, do_rm_package_dir }, diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index 7ec579382..5e4d918f0 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -247,7 +247,10 @@ int dexopt(const char *apk_path, uid_t uid, bool is_public, const char *pkgName, int mark_boot_complete(const char *instruction_set); int movefiles(); int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId); -int idmap(const char *target_path, const char *overlay_path, uid_t uid); +int idmap(const char *target_path, const char *overlay_path, uid_t uid, + uint32_t target_hash, uint32_t overlay_hash); +int aapt(const char *source_apk, const char *internal_path, const char *out_restable, uid_t uid, + int pkgId, int min_sdk_version, const char *common_res_path); int restorecon_data(const char *uuid, const char* pkgName, const char* seinfo, uid_t uid); int create_oat_dir(const char* oat_dir, const char *instruction_set); int rm_package_dir(const char* apk_path);