Merge "Command to move private app data between volumes."

This commit is contained in:
Jeff Sharkey 2015-04-10 21:00:41 +00:00 committed by Gerrit Code Review
commit dfc30ae393
5 changed files with 149 additions and 55 deletions

View File

@ -12,7 +12,10 @@ LOCAL_MODULE := libinstalld
LOCAL_MODULE_TAGS := eng tests LOCAL_MODULE_TAGS := eng tests
LOCAL_SRC_FILES := $(common_src_files) LOCAL_SRC_FILES := $(common_src_files)
LOCAL_CFLAGS := $(common_cflags) LOCAL_CFLAGS := $(common_cflags)
LOCAL_SHARED_LIBRARIES := libbase LOCAL_SHARED_LIBRARIES := \
libbase \
liblogwrap \
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
LOCAL_CLANG := true LOCAL_CLANG := true
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)
@ -30,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \
libbase \ libbase \
libcutils \ libcutils \
liblog \ liblog \
liblogwrap \
libselinux \ libselinux \
LOCAL_STATIC_LIBRARIES := libdiskusage LOCAL_STATIC_LIBRARIES := libdiskusage

View File

@ -16,15 +16,18 @@
#include "installd.h" #include "installd.h"
#include <base/stringprintf.h>
#include <base/logging.h>
#include <cutils/sched_policy.h>
#include <diskusage/dirsize.h>
#include <logwrap/logwrap.h>
#include <system/thread_defs.h>
#include <selinux/android.h>
#include <inttypes.h> #include <inttypes.h>
#include <sys/capability.h> #include <sys/capability.h>
#include <sys/file.h> #include <sys/file.h>
#include <cutils/sched_policy.h> #include <unistd.h>
#include <diskusage/dirsize.h>
#include <selinux/android.h>
#include <system/thread_defs.h>
#include <base/stringprintf.h>
#include <base/logging.h>
using android::base::StringPrintf; using android::base::StringPrintf;
@ -38,6 +41,8 @@ dir_rec_t android_media_dir;
dir_rec_t android_mnt_expand_dir; dir_rec_t android_mnt_expand_dir;
dir_rec_array_t android_system_dirs; 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) int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
{ {
if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) { 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; 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<userid_t> 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) int make_user_config(userid_t userid)
{ {
if (ensure_config_user_dirs(userid) == -1) { if (ensure_config_user_dirs(userid) == -1) {
@ -1592,7 +1671,7 @@ int restorecon_data(const char* uuid, const char* pkgName,
continue; 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) { if (stat(pkgdir.c_str(), &s) < 0) {
continue; continue;
} }

View File

@ -14,14 +14,15 @@
** limitations under the License. ** limitations under the License.
*/ */
#include "installd.h"
#include <base/logging.h>
#include <sys/capability.h> #include <sys/capability.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <selinux/android.h> #include <selinux/android.h>
#include <selinux/avc.h> #include <selinux/avc.h>
#include "installd.h"
#define BUFFER_MAX 1024 /* input buffer for commands */ #define BUFFER_MAX 1024 /* input buffer for commands */
#define TOKEN_MAX 16 /* max number of arguments in buffer */ #define TOKEN_MAX 16 /* max number of arguments in buffer */
#define REPLY_MAX 256 /* largest reply allowed */ #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 */ 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) 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]); 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 }, { "rmcodecache", 3, do_rm_code_cache },
{ "getsize", 8, do_get_size }, { "getsize", 8, do_get_size },
{ "rmuserdata", 3, do_rm_user_data }, { "rmuserdata", 3, do_rm_user_data },
{ "mvuserdata", 5, do_mv_user_data },
{ "movefiles", 0, do_movefiles }, { "movefiles", 0, do_movefiles },
{ "linklib", 4, do_linklib }, { "linklib", 4, do_linklib },
{ "mkuserdata", 5, do_mk_user_data }, { "mkuserdata", 5, do_mk_user_data },
@ -621,46 +629,6 @@ fail:
return res; 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, ...) { static int log_callback(int type, const char *fmt, ...) {
va_list ap; va_list ap;
int priority; int priority;
@ -682,13 +650,16 @@ static int log_callback(int type, const char *fmt, ...) {
return 0; return 0;
} }
int main(const int argc __unused, const char *argv[] __unused) { int main(const int argc __unused, char *argv[]) {
char buf[BUFFER_MAX]; char buf[BUFFER_MAX];
struct sockaddr addr; struct sockaddr addr;
socklen_t alen; socklen_t alen;
int lsocket, s; int lsocket, s;
int selinux_enabled = (is_selinux_enabled() > 0); int selinux_enabled = (is_selinux_enabled() > 0);
setenv("ANDROID_LOG_TAGS", "*:v", 1);
android::base::InitLogging(argv);
ALOGI("installd firing up\n"); ALOGI("installd firing up\n");
union selinux_callback cb; union selinux_callback cb;
@ -710,8 +681,6 @@ int main(const int argc __unused, const char *argv[] __unused) {
exit(1); exit(1);
} }
drop_privileges();
lsocket = android_get_control_socket(SOCKET_PATH); lsocket = android_get_control_socket(SOCKET_PATH);
if (lsocket < 0) { if (lsocket < 0) {
ALOGE("Failed to get socket from environment: %s\n", strerror(errno)); ALOGE("Failed to get socket from environment: %s\n", strerror(errno));

View File

@ -32,6 +32,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <string> #include <string>
#include <vector>
#include <cutils/fs.h> #include <cutils/fs.h>
#include <cutils/sockets.h> #include <cutils/sockets.h>
@ -89,6 +90,8 @@
#define DEXOPT_PATCHOAT_NEEDED 2 #define DEXOPT_PATCHOAT_NEEDED 2
#define DEXOPT_SELF_PATCHOAT_NEEDED 3 #define DEXOPT_SELF_PATCHOAT_NEEDED 3
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
/* data structures */ /* data structures */
typedef struct { 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::string create_data_media_path(const char* volume_uuid, userid_t userid);
std::vector<userid_t> get_known_users(const char* volume_uuid);
int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid); int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
int create_move_path(char path[PKG_PATH_MAX], 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 renamepkg(const char *oldpkgname, const char *newpkgname);
int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid); 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 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 make_user_config(userid_t userid);
int delete_user(const char *uuid, userid_t userid); int delete_user(const char *uuid, userid_t userid);
int delete_cache(const char *uuid, const char *pkgname, 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 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, int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
const char *instruction_set); 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);

View File

@ -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); return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid);
} }
std::vector<userid_t> get_known_users(const char* volume_uuid) {
std::vector<userid_t> 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. * Create the path name for config for a certain userid.
* Returns 0 on success, and -1 on failure. * Returns 0 on success, and -1 on failure.