Early rule loading - livebox issue.
authorJanusz Kozerski <j.kozerski@samsung.com>
Wed, 12 Jun 2013 10:40:52 +0000 (12:40 +0200)
committerJanusz Kozerski <j.kozerski@samsung.com>
Mon, 8 Jul 2013 10:03:17 +0000 (12:03 +0200)
[Issue#]        SSDWSSP-298
[Bug/Feature]   Livebox issue fix.
[Cause]         Missing rules while showing homescreen.
[Solution]      Add early-rules loading.
[Verification]  Compile. Install at least 2 widgets,
                then check if /opt/etc/smack-app-early/accesses.d/WRT file contains
                a "livebox.web-provider ~APP~ rwx" rule for every app.
                Then uninstall one app and check if rule for this app is gone.
                Others rules should remain untouched.

Change-Id: Ie94713620038ebbdcab4e2d41fc01550a6a78fdb

include/common.h
packaging/libprivilege-control.spec
src/common.c
src/privilege-control.c

index 512ed1a..e6cc5f2 100644 (file)
@@ -26,6 +26,7 @@
 #include <dlog.h>
 #include <fts.h>
 #include <stdbool.h>
+#include <semaphore.h>
 
 #ifdef LOG_TAG
     #undef LOG_TAG
@@ -86,12 +87,22 @@ void fts_closep(FTS **f);
 #define AUTO_SMACK_FREE __attribute__ ((cleanup(smack_freep))) = NULL
 #define AUTO_FTS_CLOSE  __attribute__ ((cleanup(fts_closep)))   = NULL
 
-#define SMACK_RULES_DIR     "/opt/etc/smack-app/accesses.d/"
-#define SMACK_LOADED_APP_RULES  "/var/run/smack-app/"
+#define SMACK_RULES_DIR          "/opt/etc/smack-app/accesses.d/"
+
+/*
+ * TODO It should be a directory (/opt/etc/smack-app-early/accesses.d/) containing
+ * rules to be loaded for each privilege. In the beginning there will be only
+ * one file for all WRT apps.
+ */
+#define SMACK_STARTUP_RULES_FILE "/opt/etc/smack-app-early/accesses.d/WRT"
+#define SMACK_LOADED_APP_RULES   "/var/run/smack-app/"
+
+#define PRIVILEGE_CONTROL_UNINSTALL_SEM "privilege-control-app-uninstall-semaphore"
 
 int smack_label_is_valid(const char* smack_label);
 
 int load_smack_from_file(const char* app_id, struct smack_accesses** smack, int *fd, char** path);
+int load_smack_from_file_early(const char* app_id, struct smack_accesses** smack, int *fd, char** path);
 int check_if_rules_were_loaded(const char *app_id);
 int add_app_first_run_rules(const char *app_id);
 void mark_rules_as_loaded(const char *app_id);
index 3591ca6..706951c 100644 (file)
@@ -97,6 +97,11 @@ then
        mkdir -p /opt/etc/smack-app/accesses.d
 fi
 
+if [ ! -e "/opt/etc/smack-app-early/accesses.d" ]
+then
+       mkdir -p /opt/etc/smack-app-early/accesses.d
+fi
+
 %files
 %{_libdir}/*.so.*
 %{_bindir}/slp-su
index b86835f..b7a4b77 100644 (file)
@@ -161,14 +161,28 @@ int add_app_first_run_rules(const char *app_id)
        return PC_OPERATION_SUCCESS;
 }
 
-int load_smack_from_file(const char* app_id, struct smack_accesses** smack, int *fd, char** path)
+
+static int load_smack_from_file_generic(const char* app_id, struct smack_accesses** smack, int *fd, char** path, bool is_early)
 {
+       /* Notice that app_id is ignored when flag is_early is set.
+        * It's because the all "early rules" (for all apps) should
+        * be in one common file: SMACK_STARTUP_RULES_FILE
+        */
        C_LOGD("Enter function: %s", __func__);
        int ret;
 
-       ret = smack_file_name(app_id, path);
-       if (ret != PC_OPERATION_SUCCESS)
-               return ret;
+       if (is_early) {
+               if (0 > asprintf(path, "%s", SMACK_STARTUP_RULES_FILE)) {
+                       *path = NULL;
+                       C_LOGE("asprintf failed");
+                       return PC_ERR_MEM_OPERATION;
+               }
+       }
+       else {
+               ret = smack_file_name(app_id, path);
+               if (ret != PC_OPERATION_SUCCESS)
+                       return ret;
+       }
 
        if (smack_accesses_new(smack)) {
                C_LOGE("smack_accesses_new failed");
@@ -200,6 +214,16 @@ int load_smack_from_file(const char* app_id, struct smack_accesses** smack, int
        return PC_OPERATION_SUCCESS;
 }
 
+int load_smack_from_file(const char* app_id, struct smack_accesses** smack, int *fd, char** path)
+{
+       return load_smack_from_file_generic(app_id, smack, fd, path, 0);
+}
+
+int load_smack_from_file_early(const char* app_id, struct smack_accesses** smack, int *fd, char** path)
+{
+       return load_smack_from_file_generic(app_id, smack, fd, path, 1);
+}
+
 int smack_mark_file_name(const char *app_id, char **path)
 {
        if (asprintf(path, SMACK_LOADED_APP_RULES "/%s", app_id) == -1) {
index a86c718..5996ec0 100644 (file)
@@ -70,7 +70,6 @@
 #define TIZEN_PRIVILEGE_ANTIVIRUS "http://tizen.org/privilege/antivirus"
 #define TIZEN_PRIVILEGE_APPSETTING "http://tizen.org/privilege/appsetting"
 
-
 typedef struct {
        char user_name[10];
        int uid;
@@ -752,7 +751,7 @@ static int base_name_from_perm(const char *perm, char **name) {
        return PC_OPERATION_SUCCESS;
 }
 
-static int perm_file_path(char** path, app_type_t app_type, const char* perm, const char *suffix)
+static int perm_file_path(char** path, app_type_t app_type, const char* perm, const char *suffix, bool is_early)
 {
        const char* app_type_prefix = NULL;
        char* perm_basename = NULL;
@@ -771,9 +770,16 @@ static int perm_file_path(char** path, app_type_t app_type, const char* perm, co
                return ret;
        }
 
-       ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s",
-                       app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
-                       perm_basename, suffix);
+       if (is_early) {
+               ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s%s",
+               app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
+               perm_basename, "_early", suffix);
+       }
+       else {
+               ret = asprintf(path, TOSTRING(SHAREDIR) "/%s%s%s%s",
+               app_type_prefix ? app_type_prefix : "", app_type_prefix ? "_" : "",
+               perm_basename, suffix);
+       }
        if (ret == -1) {
                C_LOGE("asprintf failed");
                return PC_ERR_MEM_OPERATION;
@@ -784,9 +790,10 @@ static int perm_file_path(char** path, app_type_t app_type, const char* perm, co
        return PC_OPERATION_SUCCESS;
 }
 
-static int perm_to_smack(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
+static int perm_to_smack_generic(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm, bool is_early)
 {
        C_LOGD("Enter function: %s", __func__);
+
        int ret;
        char* path AUTO_FREE;
        char* format_string AUTO_FREE;
@@ -796,7 +803,7 @@ static int perm_to_smack(struct smack_accesses* smack, const char* app_label, ap
        char smack_accesses[10];
 
        // get file name for permission (devcap)
-       ret = perm_file_path(&path, app_type, perm, ".smack");
+       ret = perm_file_path(&path, app_type, perm, ".smack", is_early);
        if (ret != PC_OPERATION_SUCCESS) {
                C_LOGD("No smack config file for permission %s", perm);
                return ret;
@@ -832,6 +839,20 @@ static int perm_to_smack(struct smack_accesses* smack, const char* app_label, ap
        return PC_OPERATION_SUCCESS;
 }
 
+static int perm_to_smack_early(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
+{
+       C_LOGD("Enter function: %s", __func__);
+
+       return perm_to_smack_generic(smack, app_label, app_type, perm, 1);
+}
+
+static int perm_to_smack(struct smack_accesses* smack, const char* app_label, app_type_t app_type, const char* perm)
+{
+       C_LOGD("Enter function: %s", __func__);
+
+       return perm_to_smack_generic(smack, app_label, app_type, perm, 0);
+}
+
 static int perm_to_dac(const char* app_label, app_type_t app_type, const char* perm)
 {
        C_LOGD("Enter function: %s", __func__);
@@ -840,7 +861,7 @@ static int perm_to_dac(const char* app_label, app_type_t app_type, const char* p
        FILE* file AUTO_FCLOSE;
        int gid;
 
-       ret = perm_file_path(&path, app_type, perm, ".dac");
+       ret = perm_file_path(&path, app_type, perm, ".dac", 0);
        if (ret != PC_OPERATION_SUCCESS) {
                C_LOGD("No dac config file for permission %s", perm);
                return ret;
@@ -1244,10 +1265,13 @@ static int register_app_for_public_dirs(const char *app_id, struct smack_accesse
 static int app_add_permissions_internal(const char* app_id, app_type_t app_type, const char** perm_list, int permanent)
 {
        C_LOGD("Enter function: %s", __func__);
-       char* smack_path AUTO_FREE;
        int i, ret;
+       char* smack_path AUTO_FREE;
+       char* smack_path_early AUTO_FREE;
        int fd AUTO_CLOSE;
+       int fd_early AUTO_CLOSE;
        struct smack_accesses *smack AUTO_SMACK_FREE;
+       struct smack_accesses *smack_early AUTO_SMACK_FREE;
        const char* base_perm = NULL;
 
        if (!smack_label_is_valid(app_id))
@@ -1259,6 +1283,12 @@ static int app_add_permissions_internal(const char* app_id, app_type_t app_type,
                return ret;
        }
 
+       ret = load_smack_from_file_early(app_id, &smack_early, &fd_early, &smack_path_early);
+       if (ret != PC_OPERATION_SUCCESS) {
+               C_LOGE("load_smack_from_file failed");
+               return ret;
+       }
+
        /* Implicitly enable base permission for an app_type */
        base_perm = app_type_name(app_type);
        if (base_perm) {
@@ -1268,6 +1298,15 @@ static int app_add_permissions_internal(const char* app_id, app_type_t app_type,
                        C_LOGE("perm_to_smack failed");
                        return ret;
                }
+
+               // Add early permission - such permissions should be enabled right after system boot
+               SECURE_LOGD("perm_to_smack params: app_id: %s, %s", app_id, base_perm);
+               ret = perm_to_smack_early(smack_early, app_id, APP_TYPE_OTHER, base_perm);
+               if (ret != PC_OPERATION_SUCCESS){
+                       C_LOGE("perm_to_smack failed");
+                       return ret;
+               }
+
        }
        for (i = 0; perm_list[i] != NULL; ++i) {
                SECURE_LOGD("perm_to_smack params: app_id: %s, perm_list[%d]: %s", app_id, i, perm_list[i]);
@@ -1292,6 +1331,12 @@ static int app_add_permissions_internal(const char* app_id, app_type_t app_type,
                        return ret;
                }
 
+               ret = perm_to_smack_early(smack_early, app_id, app_type, perm_list[i]);
+               if (ret != PC_OPERATION_SUCCESS){
+                       C_LOGE("perm_to_smack_early failed");
+                       return ret;
+               }
+
                ret = perm_to_dac(app_id, app_type, perm_list[i]);
                if (ret != PC_OPERATION_SUCCESS){
                        C_LOGE("perm_to_dac failed");
@@ -1304,11 +1349,21 @@ static int app_add_permissions_internal(const char* app_id, app_type_t app_type,
                return PC_ERR_INVALID_OPERATION;
        }
 
+       if (have_smack() && smack_accesses_apply(smack_early)) {
+               C_LOGE("smack_accesses_apply (early) failed");
+               return PC_ERR_INVALID_OPERATION;
+       }
+
        if (permanent && smack_accesses_save(smack, fd)) {
                C_LOGE("smack_accesses_save failed");
                return PC_ERR_INVALID_OPERATION;
        }
 
+       if (permanent && smack_accesses_save(smack_early, fd_early)) {
+               C_LOGE("smack_accesses_save (early) failed");
+               return PC_ERR_INVALID_OPERATION;
+       }
+
        return PC_OPERATION_SUCCESS;
 }
 
@@ -1458,11 +1513,122 @@ int smack_get_access_new(const char* subject, const char* object, char** label)
        return PC_OPERATION_SUCCESS;
 }
 
+static int app_uninstall_remove_early_rules(const char *app_id)
+{
+       C_LOGD("Enter function: %s", __func__);
+
+       int ret = PC_OPERATION_SUCCESS;
+       FILE *file AUTO_FCLOSE;
+       FILE *file_new AUTO_FCLOSE;
+       char *tmp_filename AUTO_FREE;
+       char *single_line_format AUTO_FREE;
+       char subject[SMACK_LABEL_LEN + 1];
+       char object[SMACK_LABEL_LEN + 1];
+       char rule_add[6];    // "rwxat" + '\0'
+       char rule_remove[6]; // "rwxat" + '\0'
+       sem_t *sem = NULL;
+
+       subject[SMACK_LABEL_LEN] = '\0';
+       object[SMACK_LABEL_LEN] = '\0';
+       rule_add[5] = '\0';
+       rule_remove[5] = '\0';
+
+       // Creating (opening) and waiting for semaphore
+       sem = sem_open(PRIVILEGE_CONTROL_UNINSTALL_SEM, O_CREAT, S_IRWXU | S_IRWXU | S_IRWXO, 1);
+       if (sem == SEM_FAILED) {
+               C_LOGE("sem_open failed, error: %s", strerror(errno));
+               ret = PC_ERR_INVALID_OPERATION;
+               goto out;
+       }
+       C_LOGD("Waiting for semaphore");
+       ret = sem_wait(sem);
+       if (ret < 0) {
+               C_LOGE("sem_wait failed, error: %s", strerror(errno));
+               ret = PC_ERR_INVALID_OPERATION;
+               goto out;
+       }
+
+       ret = asprintf(&single_line_format, "%%%ds %%%ds %%5s %%5s\\n", SMACK_LABEL_LEN, SMACK_LABEL_LEN);
+       if (ret < 0) {
+               C_LOGE("asprintf failed");
+               ret = PC_ERR_MEM_OPERATION;
+               goto out;
+       }
+
+       ret = asprintf(&tmp_filename, "%s.tmp", SMACK_STARTUP_RULES_FILE);
+       if (ret < 0) {
+               C_LOGE("asprintf failed");
+               ret = PC_ERR_MEM_OPERATION;
+               goto out;
+       }
+
+       file = fopen(SMACK_STARTUP_RULES_FILE, "r");
+       if (NULL == file) {
+               C_LOGE("fopen failed on %s", SMACK_STARTUP_RULES_FILE);
+               ret = PC_ERR_FILE_OPERATION;
+               goto out;
+       }
+
+       file_new = fopen(tmp_filename, "w");
+       if (NULL == file) {
+               C_LOGE("fopen failed on %s", tmp_filename);
+               ret = PC_ERR_FILE_OPERATION;
+               goto out;
+       }
+
+       while (fscanf(file, single_line_format, subject, object, rule_add, rule_remove) == 4) {
+               C_LOGD("Checking line \"%s %s %s %s\"", subject, object, rule_add, rule_remove);
+
+               if ((strncmp(subject, app_id, SMACK_LABEL_LEN) == 0) || (strncmp(object, app_id, SMACK_LABEL_LEN) == 0)) {
+                       C_LOGD("app_id found - rule will be ignored");
+                       continue; // do not re-write this rule for new file
+               }
+
+               if (0 > fprintf(file_new, "%s %s %s %s\n", subject, object, rule_add, rule_remove)) { // re-writing rule to new file
+                       C_LOGE("Write rule \"%s %s %s %s\" to file failed. %s", subject, object, rule_add, rule_remove, strerror(errno));
+                       // Should we return with error here?
+                       ret = PC_ERR_FILE_OPERATION;
+                       goto out;
+               }
+       }
+
+       fclose(file);
+       file = NULL;
+       fclose(file_new);
+       file_new = NULL;
+
+       if (unlink(SMACK_STARTUP_RULES_FILE)) {
+               C_LOGE("unlink failed %s", strerror(errno));
+               ret = PC_ERR_FILE_OPERATION;
+               goto out;
+       }
+
+       if (rename(tmp_filename, SMACK_STARTUP_RULES_FILE)) {
+               C_LOGE("rename failed. %s", strerror(errno));
+               ret = PC_ERR_FILE_OPERATION;
+               goto out;
+       }
+
+       if (chmod(SMACK_STARTUP_RULES_FILE, 644)) {
+               C_LOGE("chmod failed on %s file. Error: %s", tmp_filename, strerror(errno));
+               ret = PC_ERR_FILE_OPERATION;
+               goto out;
+       }
+
+       ret = PC_OPERATION_SUCCESS;
+
+out:
+
+       sem_post(sem);
+       sem_unlink(PRIVILEGE_CONTROL_UNINSTALL_SEM);
+       return ret;
+}
+
 /*
  * This function will be used to allow direct communication between 2 OSP application.
  * This function requires to store "state" with list of added label.
  *
- * Full implementation requires some kind of database. This implemetation works without
+ * Full implementation requires some kind of database. This implementation works without
  * database so you wont be able to revoke permissions added by different process.
  */
 API int app_give_access(const char* subject, const char* object, const char* permissions)
@@ -1876,6 +2042,11 @@ API int app_uninstall(const char* pkg_id)
                return PC_OPERATION_SUCCESS;
        }
 
+       ret = app_uninstall_remove_early_rules(pkg_id);
+       if (ret != PC_OPERATION_SUCCESS)
+               return ret;
+
+
        return PC_OPERATION_SUCCESS;
 }
 
@@ -1994,7 +2165,7 @@ API int add_api_feature(app_type_t app_type,
        // TODO check process capabilities
 
        // get feature SMACK file name
-       ret = perm_file_path(&smack_file, app_type, api_feature_name, ".smack");
+       ret = perm_file_path(&smack_file, app_type, api_feature_name, ".smack", 0);
        if (ret != PC_OPERATION_SUCCESS || !smack_file ) {
                return ret;
        }
@@ -2008,7 +2179,7 @@ API int add_api_feature(app_type_t app_type,
        // check .dac existence only if gids are supported
        if (list_of_db_gids && list_size > 0) {
                // get feature DAC file name
-               ret = perm_file_path(&dac_file, app_type, api_feature_name, ".dac");
+               ret = perm_file_path(&dac_file, app_type, api_feature_name, ".dac", 0);
                if (ret != PC_OPERATION_SUCCESS || !dac_file ) {
                        return ret;
                }