From: Konrad Lipinski Date: Tue, 29 Nov 2016 14:36:25 +0000 (+0100) Subject: kdbus: retrieve SECLABEL anew on each CONN_INFO (efl/launchpad developers' request) X-Git-Tag: submit/tizen/20161205.013353~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4119f2cdcf8ee06fd3b638034e6e9e8acfd0356c;p=platform%2Fkernel%2Flinux-exynos.git kdbus: retrieve SECLABEL anew on each CONN_INFO (efl/launchpad developers' request) 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 --- diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c index 02deba366839..f86ad1f4dcd5 100644 --- a/ipc/kdbus/connection.c +++ b/ipc/kdbus/connection.c @@ -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); } /* diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c index 106ec26f2882..0f586f2a47d3 100644 --- a/ipc/kdbus/metadata.c +++ b/ipc/kdbus/metadata.c @@ -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) { diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h index dba7cc7fdbcb..ea59291165a7 100644 --- a/ipc/kdbus/metadata.h +++ b/ipc/kdbus/metadata.h @@ -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);