diff options
author | Zbigniew Jasinski <z.jasinski@samsung.com> | 2015-10-19 18:23:53 +0200 |
---|---|---|
committer | Casey Schaufler <casey@schaufler-ca.com> | 2015-10-19 12:06:47 -0700 |
commit | 38416e53936ecf896948fdeffc36b76979117952 (patch) | |
tree | b0ac68de5a0b4a7953ab38e7dcc6fa1d8a83d10a /security/smack/smack_lsm.c | |
parent | 8da4aba5bf9869f58d2a6bb30daaf54b2fa72569 (diff) | |
download | blackbird-op-linux-38416e53936ecf896948fdeffc36b76979117952.tar.gz blackbird-op-linux-38416e53936ecf896948fdeffc36b76979117952.zip |
Smack: limited capability for changing process label
This feature introduces new kernel interface:
- <smack_fs>/relabel-self - for setting transition labels list
This list is used to control smack label transition mechanism.
List is set by, and per process. Process can transit to new label only if
label is on the list. Only process with CAP_MAC_ADMIN capability can add
labels to this list. With this list, process can change it's label without
CAP_MAC_ADMIN but only once. After label changing, list is unset.
Changes in v2:
* use list_for_each_entry instead of _rcu during label write
* added missing description in security/Smack.txt
Changes in v3:
* squashed into one commit
Changes in v4:
* switch from global list to per-task list
* since the per-task list is accessed only by the task itself
there is no need to use synchronization mechanisms on it
Changes in v5:
* change smackfs interface of relabel-self to the one used for onlycap
multiple labels are accepted, separated by space, which
replace the previous list upon write
Signed-off-by: Zbigniew Jasinski <z.jasinski@samsung.com>
Signed-off-by: Rafal Krypa <r.krypa@samsung.com>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
Diffstat (limited to 'security/smack/smack_lsm.c')
-rw-r--r-- | security/smack/smack_lsm.c | 58 |
1 files changed, 56 insertions, 2 deletions
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c2d66ca1127a..ff81026f6ddb 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -326,6 +326,7 @@ static struct task_smack *new_task_smack(struct smack_known *task, tsp->smk_task = task; tsp->smk_forked = forked; INIT_LIST_HEAD(&tsp->smk_rules); + INIT_LIST_HEAD(&tsp->smk_relabel); mutex_init(&tsp->smk_rules_lock); return tsp; @@ -361,6 +362,35 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead, } /** + * smk_copy_relabel - copy smk_relabel labels list + * @nhead: new rules header pointer + * @ohead: old rules header pointer + * @gfp: type of the memory for the allocation + * + * Returns 0 on success, -ENOMEM on error + */ +static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead, + gfp_t gfp) +{ + struct smack_known_list_elem *nklep; + struct smack_known_list_elem *oklep; + + INIT_LIST_HEAD(nhead); + + list_for_each_entry(oklep, ohead, list) { + nklep = kzalloc(sizeof(struct smack_known_list_elem), gfp); + if (nklep == NULL) { + smk_destroy_label_list(nhead); + return -ENOMEM; + } + nklep->smk_label = oklep->smk_label; + list_add(&nklep->list, nhead); + } + + return 0; +} + +/** * smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_* * @mode - input mode in form of PTRACE_MODE_* * @@ -1922,6 +1952,8 @@ static void smack_cred_free(struct cred *cred) return; cred->security = NULL; + smk_destroy_label_list(&tsp->smk_relabel); + list_for_each_safe(l, n, &tsp->smk_rules) { rp = list_entry(l, struct smack_rule, list); list_del(&rp->list); @@ -1953,6 +1985,11 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old, if (rc != 0) return rc; + rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel, + gfp); + if (rc != 0) + return rc; + new->security = new_tsp; return 0; } @@ -3552,9 +3589,11 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) static int smack_setprocattr(struct task_struct *p, char *name, void *value, size_t size) { - struct task_smack *tsp; + struct task_smack *tsp = current_security(); struct cred *new; struct smack_known *skp; + struct smack_known_list_elem *sklep; + int rc; /* * Changing another process' Smack value is too dangerous @@ -3563,7 +3602,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, if (p != current) return -EPERM; - if (!smack_privileged(CAP_MAC_ADMIN)) + if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel)) return -EPERM; if (value == NULL || size == 0 || size >= SMK_LONGLABEL) @@ -3582,12 +3621,27 @@ static int smack_setprocattr(struct task_struct *p, char *name, if (skp == &smack_known_web) return -EPERM; + if (!smack_privileged(CAP_MAC_ADMIN)) { + rc = -EPERM; + list_for_each_entry(sklep, &tsp->smk_relabel, list) + if (sklep->smk_label == skp) { + rc = 0; + break; + } + if (rc) + return rc; + } + new = prepare_creds(); if (new == NULL) return -ENOMEM; tsp = new->security; tsp->smk_task = skp; + /* + * process can change its label only once + */ + smk_destroy_label_list(&tsp->smk_relabel); commit_creds(new); return size; |