diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 2171f4db8..6dec7f689 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -12,7 +12,10 @@ LOCAL_MODULE := libinstalld
LOCAL_MODULE_TAGS := eng tests
LOCAL_SRC_FILES := $(common_src_files)
LOCAL_CFLAGS := $(common_cflags)
-LOCAL_SHARED_LIBRARIES := libbase
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ liblogwrap \
+
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
LOCAL_CLANG := true
include $(BUILD_STATIC_LIBRARY)
@@ -30,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \
libbase \
libcutils \
liblog \
+ liblogwrap \
libselinux \
LOCAL_STATIC_LIBRARIES := libdiskusage
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 32a03f49d..de6fd960f 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -16,15 +16,18 @@
#include "installd.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
#include
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include
using android::base::StringPrintf;
@@ -38,6 +41,8 @@ dir_rec_t android_media_dir;
dir_rec_t android_mnt_expand_dir;
dir_rec_array_t android_system_dirs;
+static const char* kCpPath = "/system/bin/cp";
+
int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
{
if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
@@ -172,6 +177,80 @@ int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t us
return 0;
}
+int move_user_data(const char *from_uuid, const char *to_uuid,
+ const char *package_name, appid_t appid, const char* seinfo) {
+ std::vector users = get_known_users(from_uuid);
+
+ // Copy package private data for all known users
+ for (auto user : users) {
+ std::string from(create_package_data_path(from_uuid, package_name, user));
+ std::string to(create_package_data_path(to_uuid, package_name, user));
+ std::string to_user(create_data_user_path(to_uuid, user));
+
+ // Data source may not exist for all users; that's okay
+ if (access(from.c_str(), F_OK) != 0) {
+ LOG(INFO) << "Missing source " << from;
+ continue;
+ }
+
+ std::string user_path(create_data_user_path(to_uuid, user));
+ if (fs_prepare_dir(user_path.c_str(), 0771, AID_SYSTEM, AID_SYSTEM) != 0) {
+ LOG(ERROR) << "Failed to prepare user target " << user_path;
+ goto fail;
+ }
+
+ uid_t uid = multiuser_get_uid(user, appid);
+ if (make_user_data(to_uuid, package_name, uid, user, seinfo) != 0) {
+ LOG(ERROR) << "Failed to create package target " << to;
+ goto fail;
+ }
+
+ char *argv[] = {
+ (char*) kCpPath,
+ (char*) "-F", /* delete any existing destination file first (--remove-destination) */
+ (char*) "-p", /* preserve timestamps, ownership, and permissions */
+ (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
+ (char*) "-P", /* Do not follow symlinks [default] */
+ (char*) "-d", /* don't dereference symlinks */
+ (char*) from.c_str(),
+ (char*) to_user.c_str()
+ };
+
+ LOG(DEBUG) << "Copying " << from << " to " << to;
+ int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+
+ if (rc != 0) {
+ LOG(ERROR) << "Failed copying " << from << " to " << to
+ << ": status " << rc;
+ goto fail;
+ }
+
+ if (restorecon_data(to_uuid, package_name, seinfo, uid) != 0) {
+ LOG(ERROR) << "Failed to restorecon " << to;
+ goto fail;
+ }
+ }
+
+ // Copy successful, so delete old data
+ for (auto user : users) {
+ std::string from(create_package_data_path(from_uuid, package_name, user));
+ if (delete_dir_contents(from.c_str(), 1, NULL) != 0) {
+ LOG(WARNING) << "Failed to delete " << from;
+ }
+ }
+ return 0;
+
+fail:
+ // Nuke everything we might have already copied
+ for (auto user : users) {
+ std::string to(create_package_data_path(to_uuid, package_name, user));
+ if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to;
+ }
+ }
+ return -1;
+}
+
int make_user_config(userid_t userid)
{
if (ensure_config_user_dirs(userid) == -1) {
@@ -1592,7 +1671,7 @@ int restorecon_data(const char* uuid, const char* pkgName,
continue;
}
- std::string pkgdir(StringPrintf("%s/%s/%s", userdir.c_str(), user, pkgName));
+ std::string pkgdir(StringPrintf("%s%s/%s", userdir.c_str(), user, pkgName));
if (stat(pkgdir.c_str(), &s) < 0) {
continue;
}
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 0f035d00b..3a861812f 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -14,14 +14,15 @@
** limitations under the License.
*/
+#include "installd.h"
+
+#include
+
#include
#include
#include
#include
-#include "installd.h"
-
-
#define BUFFER_MAX 1024 /* input buffer for commands */
#define TOKEN_MAX 16 /* max number of arguments in buffer */
#define REPLY_MAX 256 /* largest reply allowed */
@@ -123,6 +124,12 @@ static int do_rm_user_data(char **arg, char reply[REPLY_MAX] __unused)
return delete_user_data(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
}
+static int do_mv_user_data(char **arg, char reply[REPLY_MAX] __unused)
+{
+ // from_uuid, to_uuid, pkgname, appid, seinfo
+ return move_user_data(parse_null(arg[0]), parse_null(arg[1]), arg[2], atoi(arg[3]), arg[4]);
+}
+
static int do_mk_user_data(char **arg, char reply[REPLY_MAX] __unused)
{
return make_user_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), arg[4]);
@@ -193,6 +200,7 @@ struct cmdinfo cmds[] = {
{ "rmcodecache", 3, do_rm_code_cache },
{ "getsize", 8, do_get_size },
{ "rmuserdata", 3, do_rm_user_data },
+ { "mvuserdata", 5, do_mv_user_data },
{ "movefiles", 0, do_movefiles },
{ "linklib", 4, do_linklib },
{ "mkuserdata", 5, do_mk_user_data },
@@ -621,46 +629,6 @@ 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[CAP_TO_INDEX(CAP_FOWNER)].permitted |= CAP_TO_MASK(CAP_FOWNER);
-
- 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);
- }
-}
-
static int log_callback(int type, const char *fmt, ...) {
va_list ap;
int priority;
@@ -682,13 +650,16 @@ static int log_callback(int type, const char *fmt, ...) {
return 0;
}
-int main(const int argc __unused, const char *argv[] __unused) {
+int main(const int argc __unused, char *argv[]) {
char buf[BUFFER_MAX];
struct sockaddr addr;
socklen_t alen;
int lsocket, s;
int selinux_enabled = (is_selinux_enabled() > 0);
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(argv);
+
ALOGI("installd firing up\n");
union selinux_callback cb;
@@ -710,8 +681,6 @@ int main(const int argc __unused, const char *argv[] __unused) {
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));
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 395d0ea72..f31bf4f2a 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include
#include
@@ -89,6 +90,8 @@
#define DEXOPT_PATCHOAT_NEEDED 2
#define DEXOPT_SELF_PATCHOAT_NEEDED 3
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
/* data structures */
typedef struct {
@@ -154,6 +157,8 @@ std::string create_data_user_path(const char* volume_uuid, userid_t userid);
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
+std::vector get_known_users(const char* volume_uuid);
+
int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
int create_move_path(char path[PKG_PATH_MAX],
@@ -214,7 +219,10 @@ int uninstall(const char *uuid, const char *pkgname, userid_t userid);
int renamepkg(const char *oldpkgname, const char *newpkgname);
int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid);
int delete_user_data(const char *uuid, const char *pkgname, userid_t userid);
-int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, const char* seinfo);
+int make_user_data(const char *uuid, const char *pkgname, uid_t uid,
+ userid_t userid, const char* seinfo);
+int move_user_data(const char* from_uuid, const char *to_uuid,
+ const char *package_name, appid_t appid, const char* seinfo);
int make_user_config(userid_t userid);
int delete_user(const char *uuid, userid_t userid);
int delete_cache(const char *uuid, const char *pkgname, userid_t userid);
@@ -238,3 +246,5 @@ int create_oat_dir(const char* oat_dir, const char *instruction_set);
int rm_package_dir(const char* apk_path);
int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
const char *instruction_set);
+int move_package_dir(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+ const char *instruction_set);
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index e10116eb8..ba411cd47 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -99,6 +99,38 @@ std::string create_data_media_path(const char* volume_uuid, userid_t userid) {
return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid);
}
+std::vector get_known_users(const char* volume_uuid) {
+ std::vector users;
+
+ // We always have an owner
+ users.push_back(0);
+
+ std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX);
+ DIR* dir = opendir(path.c_str());
+ if (dir == NULL) {
+ // Unable to discover other users, but at least return owner
+ PLOG(ERROR) << "Failed to opendir " << path;
+ return users;
+ }
+
+ struct dirent* ent;
+ while ((ent = readdir(dir))) {
+ if (ent->d_type != DT_DIR) {
+ continue;
+ }
+
+ char* end;
+ userid_t user = strtol(ent->d_name, &end, 10);
+ if (*end == '\0' && user != 0) {
+ LOG(DEBUG) << "Found valid user " << user;
+ users.push_back(user);
+ }
+ }
+ closedir(dir);
+
+ return users;
+}
+
/**
* Create the path name for config for a certain userid.
* Returns 0 on success, and -1 on failure.