diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c index 030502f26..486451626 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.c @@ -511,52 +511,61 @@ int initialize_directories() { if (version == 2) { ALOGD("Upgrading to /data/misc/user directories"); + char misc_dir[PATH_MAX]; + snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path); + + char keychain_added_dir[PATH_MAX]; + snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir); + + char keychain_removed_dir[PATH_MAX]; + snprintf(keychain_removed_dir, PATH_MAX, "%s/keychain/cacerts-removed", misc_dir); + DIR *dir; struct dirent *dirent; - char user_data_dir[PATH_MAX]; - dir = opendir(user_data_dir); if (dir != NULL) { while ((dirent = readdir(dir))) { - if (dirent->d_type == DT_DIR) { - const char *name = dirent->d_name; + const char *name = dirent->d_name; - // skip "." and ".." - if (name[0] == '.') { - if (name[1] == 0) continue; - if ((name[1] == '.') && (name[2] == 0)) continue; + // skip "." and ".." + if (name[0] == '.') { + if (name[1] == 0) continue; + if ((name[1] == '.') && (name[2] == 0)) continue; + } + + uint32_t user_id = atoi(name); + + // /data/misc/user/ + if (ensure_config_user_dirs(user_id) == -1) { + goto fail; + } + + char misc_added_dir[PATH_MAX]; + snprintf(misc_added_dir, PATH_MAX, "%s/user/%s/cacerts-added", misc_dir, name); + + char misc_removed_dir[PATH_MAX]; + snprintf(misc_removed_dir, PATH_MAX, "%s/user/%s/cacerts-removed", misc_dir, name); + + uid_t uid = multiuser_get_uid(user_id, AID_SYSTEM); + gid_t gid = uid; + if (access(keychain_added_dir, F_OK) == 0) { + if (copy_dir_files(keychain_added_dir, misc_added_dir, uid, gid) != 0) { + ALOGE("Some files failed to copy"); } - - // /data/misc/user/ - if (ensure_config_user_dirs(atoi(name)) == -1) { - goto fail; + } + if (access(keychain_removed_dir, F_OK) == 0) { + if (copy_dir_files(keychain_removed_dir, misc_removed_dir, uid, gid) != 0) { + ALOGE("Some files failed to copy"); } } } closedir(dir); - } - // Just rename keychain files into user/0; they should already have the right permissions - char misc_dir[PATH_MAX]; - char keychain_added_dir[PATH_MAX]; - char keychain_removed_dir[PATH_MAX]; - char config_added_dir[PATH_MAX]; - char config_removed_dir[PATH_MAX]; - - snprintf(misc_dir, PATH_MAX, "%s/misc", android_data_dir.path); - snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir); - snprintf(keychain_removed_dir, PATH_MAX, "%s/keychain/cacerts-removed", misc_dir); - snprintf(config_added_dir, PATH_MAX, "%s/user/0/cacerts-added", misc_dir); - snprintf(config_removed_dir, PATH_MAX, "%s/user/0/cacerts-removed", misc_dir); - - if (access(keychain_added_dir, F_OK) == 0) { - if (rename(keychain_added_dir, config_added_dir) != 0) { - goto fail; + if (access(keychain_added_dir, F_OK) == 0) { + delete_dir_contents(keychain_added_dir, 1, 0); } - } - if (access(keychain_removed_dir, F_OK) == 0) { - if (rename(keychain_removed_dir, config_removed_dir) != 0) { - goto fail; + if (access(keychain_removed_dir, F_OK) == 0) { + delete_dir_contents(keychain_removed_dir, 1, 0); } } diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index a5cad45fd..36c3e8c3f 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -165,6 +165,8 @@ int delete_dir_contents(const char *pathname, int delete_dir_contents_fd(int dfd, const char *name); +int copy_dir_files(const char *srcname, const char *dstname, uid_t owner, gid_t group); + int lookup_media_dir(char basepath[PATH_MAX], const char *dir); int64_t data_disk_free(); diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c index ae9ba7f80..8f366a01a 100644 --- a/cmds/installd/utils.c +++ b/cmds/installd/utils.c @@ -324,6 +324,104 @@ int delete_dir_contents_fd(int dfd, const char *name) return res; } +static int _copy_owner_permissions(int srcfd, int dstfd) +{ + struct stat st; + if (fstat(srcfd, &st) != 0) { + return -1; + } + if (fchmod(dstfd, st.st_mode) != 0) { + return -1; + } + return 0; +} + +static int _copy_dir_files(int sdfd, int ddfd, uid_t owner, gid_t group) +{ + int result = 0; + if (_copy_owner_permissions(sdfd, ddfd) != 0) { + ALOGE("_copy_dir_files failed to copy dir permissions\n"); + } + if (fchown(ddfd, owner, group) != 0) { + ALOGE("_copy_dir_files failed to change dir owner\n"); + } + + DIR *ds = fdopendir(sdfd); + if (ds == NULL) { + ALOGE("Couldn't fdopendir: %s\n", strerror(errno)); + return -1; + } + struct dirent *de; + while ((de = readdir(ds))) { + if (de->d_type != DT_REG) { + continue; + } + + const char *name = de->d_name; + int fsfd = openat(sdfd, name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); + int fdfd = openat(ddfd, name, O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_CREAT, 0600); + if (fsfd == -1 || fdfd == -1) { + ALOGW("Couldn't copy %s: %s\n", name, strerror(errno)); + } else { + if (_copy_owner_permissions(fsfd, fdfd) != 0) { + ALOGE("Failed to change file permissions\n"); + } + if (fchown(fdfd, owner, group) != 0) { + ALOGE("Failed to change file owner\n"); + } + + char buf[8192]; + ssize_t size; + while ((size = read(fsfd, buf, sizeof(buf))) > 0) { + write(fdfd, buf, size); + } + if (size < 0) { + ALOGW("Couldn't copy %s: %s\n", name, strerror(errno)); + result = -1; + } + } + close(fdfd); + close(fsfd); + } + + return result; +} + +int copy_dir_files(const char *srcname, + const char *dstname, + uid_t owner, + uid_t group) +{ + int res = 0; + DIR *ds = NULL; + DIR *dd = NULL; + + ds = opendir(srcname); + if (ds == NULL) { + ALOGE("Couldn't opendir %s: %s\n", srcname, strerror(errno)); + return -errno; + } + + mkdir(dstname, 0600); + dd = opendir(dstname); + if (dd == NULL) { + ALOGE("Couldn't opendir %s: %s\n", dstname, strerror(errno)); + closedir(ds); + return -errno; + } + + int sdfd = dirfd(ds); + int ddfd = dirfd(dd); + if (sdfd != -1 && ddfd != -1) { + res = _copy_dir_files(sdfd, ddfd, owner, group); + } else { + res = -errno; + } + closedir(dd); + closedir(ds); + return res; +} + int lookup_media_dir(char basepath[PATH_MAX], const char *dir) { DIR *d; @@ -1017,8 +1115,8 @@ int ensure_config_user_dirs(userid_t userid) { char config_user_path[PATH_MAX]; // writable by system, readable by any app within the same user - const int uid = (userid * AID_USER) + AID_SYSTEM; - const int gid = (userid * AID_USER) + AID_EVERYBODY; + const int uid = multiuser_get_uid(userid, AID_SYSTEM); + const int gid = multiuser_get_uid(userid, AID_EVERYBODY); // Ensure /data/misc/user/ exists create_user_config_path(config_user_path, userid);