kdbus: retrieve SECLABEL anew on each CONN_INFO (efl/launchpad developers' request) 04/100904/1
authorKonrad Lipinski <konrad.l@samsung.com>
Tue, 29 Nov 2016 14:36:25 +0000 (15:36 +0100)
committerKonrad Lipinski <konrad.l@samsung.com>
Tue, 29 Nov 2016 14:43:28 +0000 (15:43 +0100)
Tizen code routinely performs the following operation sequence:
1. create kdbus connection
2. update seclabel
3. rely on updated seclabel

CONN_INFO has always returned seclabel collected at HELLO time (behavior
consistent across all kdbus versions and documented in kdbus man). This
would break step 3 of the above sequence.

Change-Id: I659407ab8941efcf8c958e9bf9328ae782a5dac1

ipc/kdbus/connection.c
ipc/kdbus/metadata.c
ipc/kdbus/metadata.h

index 02deba366839b9814252ea3b6ec26eb5521a54ef..f86ad1f4dcd5c4a042e0bf7212696a138c872156 100644 (file)
@@ -212,10 +212,10 @@ static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep,
                                              KDBUS_ATTACH_CMDLINE |
                                              KDBUS_ATTACH_CGROUP |
                                              KDBUS_ATTACH_CAPS |
-                                             KDBUS_ATTACH_SECLABEL |
                                              KDBUS_ATTACH_AUDIT);
                if (ret < 0)
                        goto exit_unref;
+               kdbus_meta_proc_mark_dynamic_seclabel(conn->meta_proc);
        }
 
        /*
index 106ec26f2882ec854aaead7a40af7f20cc7ba780..0f586f2a47d33fe7333197bb5e293256d193232e 100644 (file)
@@ -284,9 +284,10 @@ static int kdbus_meta_proc_collect_cgroup(struct kdbus_meta_proc *mp)
        return 0;
 }
 
-static int kdbus_meta_proc_collect_seclabel(struct kdbus_meta_proc *mp)
+static int kdbus_get_current_seclabel(char **pseclabel)
 {
 #ifdef CONFIG_SECURITY
+       char const *label;
        char *ctx = NULL;
        u32 sid, len;
        int ret;
@@ -302,17 +303,41 @@ static int kdbus_meta_proc_collect_seclabel(struct kdbus_meta_proc *mp)
                return (ret == -EOPNOTSUPP) ? 0 : ret;
        }
 
-       mp->seclabel = kstrdup(ctx, GFP_KERNEL);
+       label = kstrdup(ctx, GFP_KERNEL);
        security_release_secctx(ctx, len);
-       if (!mp->seclabel)
+       if (!label)
                return -ENOMEM;
-
-       mp->valid |= KDBUS_ATTACH_SECLABEL;
+       *pseclabel = label;
 #endif
+       return 0;
+}
 
+static int kdbus_meta_proc_collect_seclabel(struct kdbus_meta_proc *mp)
+{
+#ifdef CONFIG_SECURITY
+       char *label;
+       int ret;
+
+       ret = kdbus_get_current_seclabel(&label);
+       if (ret < 0)
+               return ret;
+       if (label) {
+               mp->valid |= KDBUS_ATTACH_SECLABEL;
+               mp->seclabel = label;
+       }
+#endif
        return 0;
 }
 
+void kdbus_meta_proc_mark_dynamic_seclabel(struct kdbus_meta_proc *mp)
+{
+#ifdef CONFIG_SECURITY
+       WARN_ON(mp->valid & KDBUS_ATTACH_SECLABEL);
+       WARN_ON(mp->seclabel);
+       mp->valid |= KDBUS_ATTACH_SECLABEL;
+#endif
+}
+
 static void kdbus_meta_proc_collect_audit(struct kdbus_meta_proc *mp)
 {
 #ifdef CONFIG_AUDITSYSCALL
@@ -806,7 +831,7 @@ struct kdbus_meta_staging {
        const char *exe_path;
 };
 
-static size_t kdbus_meta_measure(struct kdbus_meta_staging *staging)
+static size_t kdbus_meta_measure(struct kdbus_meta_staging *staging, char const *seclabel)
 {
        const struct kdbus_meta_proc *mp = staging->mp;
        const struct kdbus_meta_fake *mf = staging->mf;
@@ -851,7 +876,7 @@ static size_t kdbus_meta_measure(struct kdbus_meta_staging *staging)
        if (mf && (mask & KDBUS_ATTACH_SECLABEL))
                size += KDBUS_ITEM_SIZE(strlen(mf->seclabel) + 1);
        else if (mp && (mask & KDBUS_ATTACH_SECLABEL))
-               size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1);
+               size += KDBUS_ITEM_SIZE(strlen(seclabel ?: mp->seclabel) + 1);
 
        if (mp && (mask & KDBUS_ATTACH_AUDIT))
                size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit));
@@ -899,7 +924,7 @@ static struct kdbus_item *kdbus_write_full(struct kdbus_item **iter,
 }
 
 static size_t kdbus_meta_write(struct kdbus_meta_staging *staging, void *mem,
-                              size_t size)
+                              size_t size, char const *seclabel)
 {
        struct user_namespace *user_ns = staging->conn->cred->user_ns;
        struct pid_namespace *pid_ns = ns_of_pid(staging->conn->pid);
@@ -1005,10 +1030,12 @@ static size_t kdbus_meta_write(struct kdbus_meta_staging *staging, void *mem,
                item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL,
                                        strlen(staging->mf->seclabel) + 1,
                                        staging->mf->seclabel);
-       else if (staging->mp && (staging->mask & KDBUS_ATTACH_SECLABEL))
+       else if (staging->mp && (staging->mask & KDBUS_ATTACH_SECLABEL)) {
+               char const *label = seclabel ?: staging->mp->seclabel;
                item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL,
-                                       strlen(staging->mp->seclabel) + 1,
-                                       staging->mp->seclabel);
+                                       strlen(label) + 1,
+                                       label);
+       }
 
        if (staging->mp && (staging->mask & KDBUS_ATTACH_AUDIT)) {
                item = kdbus_write_head(&items, KDBUS_ITEM_AUDIT,
@@ -1069,6 +1096,7 @@ int kdbus_meta_emit(struct kdbus_meta_proc *mp,
        struct kdbus_item *items = NULL;
        size_t size = 0;
        int ret;
+       char *seclabel = NULL;
 
        if (WARN_ON(mf && mp))
                mp = NULL;
@@ -1082,9 +1110,19 @@ int kdbus_meta_emit(struct kdbus_meta_proc *mp,
        if (mf)
                staging.mask |= mf->valid;
        if (mp) {
+               char const *mp_seclabel;
                mutex_lock(&mp->lock);
                staging.mask |= mp->valid;
+               mp_seclabel = mp->seclabel;
                mutex_unlock(&mp->lock);
+               if (staging.mask & mask & KDBUS_ATTACH_SECLABEL && !mp_seclabel) {
+                       /* dynamic seclabel */
+                       ret = kdbus_get_current_seclabel(&seclabel);
+                       if (ret < 0)
+                               goto exit;
+                       if (!seclabel)
+                               staging.mask &= ~KDBUS_ATTACH_SECLABEL;
+               }
        }
        if (mc) {
                mutex_lock(&mc->lock);
@@ -1131,7 +1169,7 @@ int kdbus_meta_emit(struct kdbus_meta_proc *mp,
                path_put(&p);
        }
 
-       size = kdbus_meta_measure(&staging);
+       size = kdbus_meta_measure(&staging, seclabel);
        if (!size) { /* bail out if nothing to do */
                ret = 0;
                goto exit;
@@ -1143,7 +1181,7 @@ int kdbus_meta_emit(struct kdbus_meta_proc *mp,
                goto exit;
        }
 
-       size = kdbus_meta_write(&staging, items, size);
+       size = kdbus_meta_write(&staging, items, size, seclabel);
        if (!size) {
                kfree(items);
                items = NULL;
@@ -1152,6 +1190,7 @@ int kdbus_meta_emit(struct kdbus_meta_proc *mp,
        ret = 0;
 
 exit:
+       kfree(seclabel);
        if (staging.exe)
                free_page((unsigned long)staging.exe);
        if (ret >= 0) {
index dba7cc7fdbcbb73714ccd76a5bed579d66c5e10a..ea59291165a7e324273e34636c7311f7668ad74a 100644 (file)
@@ -57,6 +57,7 @@ struct kdbus_meta_proc *kdbus_meta_proc_new(void);
 struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp);
 struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp);
 int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what);
+void kdbus_meta_proc_mark_dynamic_seclabel(struct kdbus_meta_proc *mp);
 
 struct kdbus_meta_fake *kdbus_meta_fake_new(void);
 struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf);