am dfc30ae3
: Merge "Command to move private app data between volumes."
* commit 'dfc30ae393fd610fcbd05a1ecfe7d4834a792de3': Command to move private app data between volumes.
This commit is contained in:
commit
c200d20e32
@ -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
|
||||
|
@ -16,15 +16,18 @@
|
||||
|
||||
#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 <sys/capability.h>
|
||||
#include <sys/file.h>
|
||||
#include <cutils/sched_policy.h>
|
||||
#include <diskusage/dirsize.h>
|
||||
#include <selinux/android.h>
|
||||
#include <system/thread_defs.h>
|
||||
#include <base/stringprintf.h>
|
||||
#include <base/logging.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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<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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -14,14 +14,15 @@
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
#include "installd.h"
|
||||
|
||||
#include <base/logging.h>
|
||||
|
||||
#include <sys/capability.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <selinux/android.h>
|
||||
#include <selinux/avc.h>
|
||||
|
||||
#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));
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cutils/fs.h>
|
||||
#include <cutils/sockets.h>
|
||||
@ -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<userid_t> 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);
|
||||
|
@ -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<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.
|
||||
* Returns 0 on success, and -1 on failure.
|
||||
|
Loading…
Reference in New Issue
Block a user