Allowed 'sdb root on' command even if the UID of SDBD is non-root. 54/105954/2
authorshingil.kang <shingil.kang@samsung.com>
Wed, 13 Jul 2016 05:20:27 +0000 (14:20 +0900)
committerSooyoung Ha <yoosah.ha@samsung.com>
Mon, 13 Feb 2017 11:18:46 +0000 (20:18 +0900)
 - file IO(pull/push), shell service can be worked by root user with restricted priviliges.

Change-Id: I37f4248443bd7f5231ec99e0d1737cd556b749b3
Signed-off-by: shingil.kang <shingil.kang@samsung.com>
Signed-off-by: Sooyoung Ha <yoosah.ha@samsung.com>
src/file_sync_service.c
src/sdb.c
src/sdb.h
src/services.c

index 81f6841..1675cd2 100644 (file)
@@ -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;
index 692e87f..0e3a297 100644 (file)
--- 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) {
index 2128616..0fe7005 100644 (file)
--- 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
+
index 64dbd11..da73ff6 100644 (file)
@@ -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",