From e51486b368ca9d8ffd57f569903c8bad2d04dcf8 Mon Sep 17 00:00:00 2001 From: "shingil.kang" Date: Wed, 13 Jul 2016 14:20:27 +0900 Subject: [PATCH] Allowed 'sdb root on' command even if the UID of SDBD is non-root. - file IO(pull/push), shell service can be worked by root user with restricted priviliges. Change-Id: I37f4248443bd7f5231ec99e0d1737cd556b749b3 Signed-off-by: shingil.kang Signed-off-by: Sooyoung Ha --- src/file_sync_service.c | 17 +++--- src/sdb.c | 136 ++++++++++++++++++++++++++++++++++++++++-------- src/sdb.h | 17 +++++- src/services.c | 31 +++++------ 4 files changed, 151 insertions(+), 50 deletions(-) diff --git a/src/file_sync_service.c b/src/file_sync_service.c index 81f6841..1675cd2 100644 --- a/src/file_sync_service.c +++ b/src/file_sync_service.c @@ -159,7 +159,7 @@ static void sync_read_label_notify(int s) char *path = buffer; path++; path++; - // set_syncfile_smack_label(path); + //set_syncfile_smack_label(path); } } @@ -653,6 +653,14 @@ void file_sync_service(int fd, void *cookie) goto fail; } + if (should_drop_privileges()) { + if (set_sdk_user_privileges(DROP_CAPABILITIES_AFTER_FORK) < 0) { + goto fail; + } + } else { + set_root_privileges(); + } + for(;;) { D("sync: waiting for command for %d sec\n", SYNC_TIMEOUT); @@ -690,13 +698,6 @@ void file_sync_service(int fd, void *cookie) D("sync: '%s' '%s'\n", (char*) &msg.req, name); - if (should_drop_privileges() && !verify_sync_rule(name)) { - if (getuid() != g_sdk_user_id && set_sdk_user_privileges() < 0) { - fail_message(fd, "failed to set SDK user privileges."); - goto fail; - } - } - switch(msg.req.id) { case ID_STAT: if(do_stat(fd, name)) goto fail; diff --git a/src/sdb.c b/src/sdb.c index 692e87f..0e3a297 100644 --- a/src/sdb.c +++ b/src/sdb.c @@ -73,6 +73,8 @@ SDB_MUTEX_DEFINE( D_lock ); #endif int HOST = 0; + +// sdk user uid_t g_sdk_user_id; gid_t g_sdk_group_id; char* g_sdk_home_dir = NULL; @@ -81,6 +83,12 @@ pcap g_capabilities; int rootshell_mode; // 0: sdk user, 1: root int booting_done; // 0: platform booting is in progess 1: platform booting is done +// root user +uid_t g_root_user_id; +gid_t g_root_group_id; +char* g_root_home_dir = NULL; +char* g_root_home_dir_env = NULL; + struct group_info { const char *name; @@ -93,6 +101,7 @@ struct group_info g_default_groups[] = { {"log", -1}, {NULL, -1} }; + #define SDB_DEFAULT_GROUPS_CNT ((sizeof(g_default_groups)/sizeof(g_default_groups[0]))-1) int is_init_sdk_userinfo = 0; @@ -1565,40 +1574,40 @@ void register_bootdone_cb() { } } -static int sdbd_set_groups() { +static int sdbd_set_groups(const char *name, int gid, struct group_info default_groups[], int default_groups_size) { gid_t *group_ids = NULL; int ngroups = 0; int i, j = 0; int group_match = 0; int added_group_cnt = 0; - getgrouplist(SDK_USER_NAME, g_sdk_group_id, NULL, &ngroups); + getgrouplist(name, gid, NULL, &ngroups); D("group list : ngroups = %d\n", ngroups); - group_ids = malloc((ngroups + SDB_DEFAULT_GROUPS_CNT) * sizeof(gid_t)); + group_ids = malloc((ngroups + default_groups_size) * sizeof(gid_t)); if (group_ids == NULL) { - D("failed to allocate group_ids(%d)\n", (ngroups + SDB_DEFAULT_GROUPS_CNT) * sizeof(gid_t)); + D("failed to allocate group_ids(%d)\n", (ngroups + default_groups_size) * sizeof(gid_t)); return -1; } - if (getgrouplist(SDK_USER_NAME, g_sdk_group_id, group_ids, &ngroups) == -1) { + if (getgrouplist(name, gid, group_ids, &ngroups) == -1) { D("failed to getgrouplist(), ngroups = %d\n", ngroups); free(group_ids); return -1; } - - for (i = 0; g_default_groups[i].name != NULL; i++) { - for (j = 0; j < ngroups; j++) { - if (group_ids[j] == g_default_groups[i].gid) { - group_match = 1; - break; + if(default_groups_size >= 1) { + for (i = 0; default_groups[i].name != NULL; i++) { + for (j = 0; j < ngroups; j++) { + if (group_ids[j] == default_groups[i].gid) { + group_match = 1; + break; + } } + if (group_match == 0 && default_groups[i].gid != -1) { + group_ids[ngroups + added_group_cnt] = default_groups[i].gid; + added_group_cnt ++; + } + group_match = 0; } - if (group_match == 0 && g_default_groups[i].gid != -1) { - group_ids[ngroups + added_group_cnt] = g_default_groups[i].gid; - added_group_cnt ++; - } - group_match = 0; } - if (setgroups(ngroups+added_group_cnt, group_ids) != 0) { D("failed to setgroups().\n"); free(group_ids); @@ -1645,13 +1654,25 @@ static int sdbd_get_group(const char* group_name, struct group* grp, char* buf, return 0; } -int set_sdk_user_privileges() { +int set_sdk_user_privileges(int is_drop_capability_after_fork) { if (!is_init_sdk_userinfo) { D("failed to init sdk user information.\n"); return -1; } - if (sdbd_set_groups() < 0) { + /* + * If a process switches its real, effective, or saved uids from at least one being 0 to all being non-zero, + * then both the permitted and effective capabilities are cleared. + */ + if(is_drop_capability_after_fork) { + + if (setuid(g_root_user_id) != 0) { + D("set root user id failed (errno: %d)\n", errno); + return -1; + } + } + + if (sdbd_set_groups(SDK_USER_NAME, g_sdk_group_id, g_default_groups, SDB_DEFAULT_GROUPS_CNT) < 0) { D("set groups failed (errno: %d)\n", errno); return -1; } @@ -1664,6 +1685,9 @@ int set_sdk_user_privileges() { if (setuid(g_sdk_user_id) != 0) { D("set user id failed (errno: %d)\n", errno); return -1; +// if(is_drop_capability_after_fork) { +// return -1; +// } } if (chdir(g_sdk_home_dir) < 0) { @@ -1678,6 +1702,32 @@ int set_sdk_user_privileges() { return 0; } +int set_root_privileges() { + + if (sdbd_set_groups(ROOT_USER_NAME, g_root_group_id, NULL, 0) < 0) { + D("set root groups failed (errno: %d)\n", errno); + } + + if (setgid(g_root_group_id) != 0) { + D("set root group id failed (errno: %d)\n", errno); + } + + if (setuid(g_root_user_id) != 0) { + D("set root user id failed (errno: %d)\n", errno); + } + + if (chdir(g_root_home_dir) < 0) { + D("unable to change root working directory to %s\n", g_sdk_home_dir); + } + + // TODO: use pam later + if (g_root_home_dir_env) { + putenv(g_root_home_dir_env); + } + + return 0; +} + #define SDB_PW_GR_DEFAULT_SIZE (16*1024) static long get_passwd_bufsize() { long bufsize = 0; @@ -1727,12 +1777,53 @@ static int init_sdb_default_groups() { return 0; } -static void set_static_userinfo() { +static void set_static_root_userinfo() { + g_root_user_id = STATIC_ROOT_USER_ID; + g_root_group_id = STATIC_ROOT_GROUP_ID; + g_root_home_dir = STATIC_ROOT_HOME_DIR; +} + +static void set_static_sdk_userinfo() { g_sdk_user_id = STATIC_SDK_USER_ID; g_sdk_group_id = STATIC_SDK_GROUP_ID; g_sdk_home_dir = STATIC_SDK_HOME_DIR; } +static int init_root_userinfo() { + struct passwd pwd; + char *buf = NULL; + long bufsize = 0; + + bufsize = get_passwd_bufsize(); + buf = malloc(bufsize); + if (buf == NULL) { + D("failed to allocate passwd buf(%ld)\n", bufsize); + set_static_root_userinfo(); + } else { + if (sdbd_get_user_pwd(ROOT_USER_NAME, &pwd, buf, bufsize) < 0) { + D("failed to get root user passwd info.(errno: %d)\n", errno); + set_static_root_userinfo(); + } else { + D("username=%s, uid=%d, gid=%d, dir=%s\n", pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_dir); + + g_root_user_id = pwd.pw_uid; + g_root_group_id = pwd.pw_gid; + g_root_home_dir = strdup(pwd.pw_dir); + } + free(buf); + } + + int env_size = strlen("HOME=") + strlen(g_root_home_dir) + 1; + g_root_home_dir_env = malloc(env_size); + if(g_root_home_dir_env == NULL) { + D("failed to allocate for home dir env string\n"); + } else { + snprintf(g_root_home_dir_env, env_size, "HOME=%s", g_root_home_dir); + } + + return 0; +} + static int init_sdk_userinfo() { struct passwd pwd; char *buf = NULL; @@ -1750,11 +1841,11 @@ static int init_sdk_userinfo() { buf = malloc(bufsize); if (buf == NULL) { D("failed to allocate passwd buf(%ld)\n", bufsize); - set_static_userinfo(); + set_static_sdk_userinfo(); } else { if (sdbd_get_user_pwd(SDK_USER_NAME, &pwd, buf, bufsize) < 0) { D("get user passwd info.(errno: %d)\n", errno); - set_static_userinfo(); + set_static_sdk_userinfo(); } else { D("username=%s, uid=%d, gid=%d, dir=%s\n", pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_dir); @@ -1791,6 +1882,7 @@ static void init_sdk_requirements() { } init_sdk_userinfo(); + init_root_userinfo(); if (g_sdk_home_dir != NULL && stat(g_sdk_home_dir, &st) == 0) { if (st.st_uid != g_sdk_user_id || st.st_gid != g_sdk_group_id) { diff --git a/src/sdb.h b/src/sdb.h index 2128616..0fe7005 100644 --- a/src/sdb.h +++ b/src/sdb.h @@ -419,12 +419,22 @@ extern uid_t g_sdk_user_id; extern gid_t g_sdk_group_id; extern char* g_sdk_home_dir; extern char* g_sdk_home_dir_env; + +#define ROOT_USER_NAME "root" +#define STATIC_ROOT_USER_ID 0 +#define STATIC_ROOT_GROUP_ID 0 +#define STATIC_ROOT_HOME_DIR "/root" +extern uid_t g_root_user_id; +extern gid_t g_root_group_id; +extern char* g_root_home_dir; +extern char* g_root_home_dir_env; + #endif int should_drop_privileges(void); -int set_sdk_user_privileges(); -void set_root_privileges(); void send_device_status(); +int set_sdk_user_privileges(int is_drop_capability_after_fork); +int set_root_privileges(); int get_emulator_forward_port(void); int get_emulator_name(char str[], int str_size); @@ -553,3 +563,6 @@ int read_line(const int fd, char* ptr, const size_t maxlen); int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * const envp[]); void get_env(char *key, char **env); +#define RESERVE_CAPABILITIES_AFTER_FORK 0 +#define DROP_CAPABILITIES_AFTER_FORK 1 + diff --git a/src/services.c b/src/services.c index 64dbd11..da73ff6 100644 --- a/src/services.c +++ b/src/services.c @@ -147,24 +147,17 @@ void rootshell_service(int fd, void *cookie) char *mode = (char*) cookie; if (!strcmp(mode, "on")) { - if (getuid() == 0) { - if (rootshell_mode == 1) { - //snprintf(buf, sizeof(buf), "Already changed to sdk user mode\n"); - // do not show message + if (rootshell_mode == 1) { + //snprintf(buf, sizeof(buf), "Already changed to sdk user mode\n"); + // do not show message + } else { + if (is_support_rootonoff()) { + rootshell_mode = 1; + //allows a permitted user to execute a command as the superuser + snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n"); } else { - if (is_support_rootonoff()) { - rootshell_mode = 1; - //allows a permitted user to execute a command as the superuser - snprintf(buf, sizeof(buf), "Switched to 'root' account mode\n"); - } else { - snprintf(buf, sizeof(buf), "Permission denied\n"); - } - writex(fd, buf, strlen(buf)); + snprintf(buf, sizeof(buf), "Permission denied\n"); } - } else { - D("need root permission for root shell: %d\n", getuid()); - rootshell_mode = 0; - snprintf(buf, sizeof(buf), "Permission denied\n"); writex(fd, buf, strlen(buf)); } } else if (!strcmp(mode, "off")) { @@ -445,15 +438,17 @@ int create_subprocess(const char *cmd, pid_t *pid, char * const argv[], char * c } if (should_drop_privileges()) { - if (argv[2] != NULL && getuid() == 0 && request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_ROOTCMD, argv[2])) { + if (argv[2] != NULL && request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_ROOTCMD, argv[2])) { // do nothing D("sdb: executes root commands!!:%s\n", argv[2]); } else { - if (getuid() != g_sdk_user_id && set_sdk_user_privileges() < 0) { + if (getuid() != g_sdk_user_id && set_sdk_user_privileges(RESERVE_CAPABILITIES_AFTER_FORK) < 0) { fprintf(stderr, "failed to set SDK user privileges\n"); exit(-1); } } + } else { + set_root_privileges(); } redirect_and_exec(pts, cmd, argv, envp); fprintf(stderr, "- exec '%s' failed: (errno:%d) -\n", -- 2.7.4