aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZbigniew Jasinski <z.jasinski@samsung.com>2015-10-19 12:23:53 -0400
committerCasey Schaufler <casey@schaufler-ca.com>2015-10-19 15:06:47 -0400
commit38416e53936ecf896948fdeffc36b76979117952 (patch)
treeb0ac68de5a0b4a7953ab38e7dcc6fa1d8a83d10a
parent8da4aba5bf9869f58d2a6bb30daaf54b2fa72569 (diff)
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>
-rw-r--r--Documentation/security/Smack.txt10
-rw-r--r--security/smack/smack.h4
-rw-r--r--security/smack/smack_access.c6
-rw-r--r--security/smack/smack_lsm.c58
-rw-r--r--security/smack/smackfs.c202
5 files changed, 239 insertions, 41 deletions
diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt
index 5e6d07fbed07..945cc633d883 100644
--- a/Documentation/security/Smack.txt
+++ b/Documentation/security/Smack.txt
@@ -255,6 +255,16 @@ unconfined
255 the access permitted if it wouldn't be otherwise. Note that this 255 the access permitted if it wouldn't be otherwise. Note that this
256 is dangerous and can ruin the proper labeling of your system. 256 is dangerous and can ruin the proper labeling of your system.
257 It should never be used in production. 257 It should never be used in production.
258relabel-self
259 This interface contains a list of labels to which the process can
260 transition to, by writing to /proc/self/attr/current.
261 Normally a process can change its own label to any legal value, but only
262 if it has CAP_MAC_ADMIN. This interface allows a process without
263 CAP_MAC_ADMIN to relabel itself to one of labels from predefined list.
264 A process without CAP_MAC_ADMIN can change its label only once. When it
265 does, this list will be cleared.
266 The values are set by writing the desired labels, separated
267 by spaces, to the file or cleared by writing "-" to the file.
258 268
259If you are using the smackload utility 269If you are using the smackload utility
260you can add access rules in /etc/smack/accesses. They take the form: 270you can add access rules in /etc/smack/accesses. They take the form:
diff --git a/security/smack/smack.h b/security/smack/smack.h
index fff0c612bbb7..6c91156ae225 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -115,6 +115,7 @@ struct task_smack {
115 struct smack_known *smk_forked; /* label when forked */ 115 struct smack_known *smk_forked; /* label when forked */
116 struct list_head smk_rules; /* per task access rules */ 116 struct list_head smk_rules; /* per task access rules */
117 struct mutex smk_rules_lock; /* lock for the rules */ 117 struct mutex smk_rules_lock; /* lock for the rules */
118 struct list_head smk_relabel; /* transit allowed labels */
118}; 119};
119 120
120#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ 121#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
@@ -169,7 +170,7 @@ struct smk_port_label {
169}; 170};
170#endif /* SMACK_IPV6_PORT_LABELING */ 171#endif /* SMACK_IPV6_PORT_LABELING */
171 172
172struct smack_onlycap { 173struct smack_known_list_elem {
173 struct list_head list; 174 struct list_head list;
174 struct smack_known *smk_label; 175 struct smack_known *smk_label;
175}; 176};
@@ -301,6 +302,7 @@ struct smack_known *smk_import_entry(const char *, int);
301void smk_insert_entry(struct smack_known *skp); 302void smk_insert_entry(struct smack_known *skp);
302struct smack_known *smk_find_entry(const char *); 303struct smack_known *smk_find_entry(const char *);
303int smack_privileged(int cap); 304int smack_privileged(int cap);
305void smk_destroy_label_list(struct list_head *list);
304 306
305/* 307/*
306 * Shared data. 308 * Shared data.
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index bc1053fb5d1d..a283f9e796c1 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -637,7 +637,7 @@ DEFINE_MUTEX(smack_onlycap_lock);
637int smack_privileged(int cap) 637int smack_privileged(int cap)
638{ 638{
639 struct smack_known *skp = smk_of_current(); 639 struct smack_known *skp = smk_of_current();
640 struct smack_onlycap *sop; 640 struct smack_known_list_elem *sklep;
641 641
642 /* 642 /*
643 * All kernel tasks are privileged 643 * All kernel tasks are privileged
@@ -654,8 +654,8 @@ int smack_privileged(int cap)
654 return 1; 654 return 1;
655 } 655 }
656 656
657 list_for_each_entry_rcu(sop, &smack_onlycap_list, list) { 657 list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) {
658 if (sop->smk_label == skp) { 658 if (sklep->smk_label == skp) {
659 rcu_read_unlock(); 659 rcu_read_unlock();
660 return 1; 660 return 1;
661 } 661 }
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,
326 tsp->smk_task = task; 326 tsp->smk_task = task;
327 tsp->smk_forked = forked; 327 tsp->smk_forked = forked;
328 INIT_LIST_HEAD(&tsp->smk_rules); 328 INIT_LIST_HEAD(&tsp->smk_rules);
329 INIT_LIST_HEAD(&tsp->smk_relabel);
329 mutex_init(&tsp->smk_rules_lock); 330 mutex_init(&tsp->smk_rules_lock);
330 331
331 return tsp; 332 return tsp;
@@ -361,6 +362,35 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead,
361} 362}
362 363
363/** 364/**
365 * smk_copy_relabel - copy smk_relabel labels list
366 * @nhead: new rules header pointer
367 * @ohead: old rules header pointer
368 * @gfp: type of the memory for the allocation
369 *
370 * Returns 0 on success, -ENOMEM on error
371 */
372static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead,
373 gfp_t gfp)
374{
375 struct smack_known_list_elem *nklep;
376 struct smack_known_list_elem *oklep;
377
378 INIT_LIST_HEAD(nhead);
379
380 list_for_each_entry(oklep, ohead, list) {
381 nklep = kzalloc(sizeof(struct smack_known_list_elem), gfp);
382 if (nklep == NULL) {
383 smk_destroy_label_list(nhead);
384 return -ENOMEM;
385 }
386 nklep->smk_label = oklep->smk_label;
387 list_add(&nklep->list, nhead);
388 }
389
390 return 0;
391}
392
393/**
364 * smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_* 394 * smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_*
365 * @mode - input mode in form of PTRACE_MODE_* 395 * @mode - input mode in form of PTRACE_MODE_*
366 * 396 *
@@ -1922,6 +1952,8 @@ static void smack_cred_free(struct cred *cred)
1922 return; 1952 return;
1923 cred->security = NULL; 1953 cred->security = NULL;
1924 1954
1955 smk_destroy_label_list(&tsp->smk_relabel);
1956
1925 list_for_each_safe(l, n, &tsp->smk_rules) { 1957 list_for_each_safe(l, n, &tsp->smk_rules) {
1926 rp = list_entry(l, struct smack_rule, list); 1958 rp = list_entry(l, struct smack_rule, list);
1927 list_del(&rp->list); 1959 list_del(&rp->list);
@@ -1953,6 +1985,11 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
1953 if (rc != 0) 1985 if (rc != 0)
1954 return rc; 1986 return rc;
1955 1987
1988 rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel,
1989 gfp);
1990 if (rc != 0)
1991 return rc;
1992
1956 new->security = new_tsp; 1993 new->security = new_tsp;
1957 return 0; 1994 return 0;
1958} 1995}
@@ -3552,9 +3589,11 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
3552static int smack_setprocattr(struct task_struct *p, char *name, 3589static int smack_setprocattr(struct task_struct *p, char *name,
3553 void *value, size_t size) 3590 void *value, size_t size)
3554{ 3591{
3555 struct task_smack *tsp; 3592 struct task_smack *tsp = current_security();
3556 struct cred *new; 3593 struct cred *new;
3557 struct smack_known *skp; 3594 struct smack_known *skp;
3595 struct smack_known_list_elem *sklep;
3596 int rc;
3558 3597
3559 /* 3598 /*
3560 * Changing another process' Smack value is too dangerous 3599 * Changing another process' Smack value is too dangerous
@@ -3563,7 +3602,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
3563 if (p != current) 3602 if (p != current)
3564 return -EPERM; 3603 return -EPERM;
3565 3604
3566 if (!smack_privileged(CAP_MAC_ADMIN)) 3605 if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
3567 return -EPERM; 3606 return -EPERM;
3568 3607
3569 if (value == NULL || size == 0 || size >= SMK_LONGLABEL) 3608 if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
@@ -3582,12 +3621,27 @@ static int smack_setprocattr(struct task_struct *p, char *name,
3582 if (skp == &smack_known_web) 3621 if (skp == &smack_known_web)
3583 return -EPERM; 3622 return -EPERM;
3584 3623
3624 if (!smack_privileged(CAP_MAC_ADMIN)) {
3625 rc = -EPERM;
3626 list_for_each_entry(sklep, &tsp->smk_relabel, list)
3627 if (sklep->smk_label == skp) {
3628 rc = 0;
3629 break;
3630 }
3631 if (rc)
3632 return rc;
3633 }
3634
3585 new = prepare_creds(); 3635 new = prepare_creds();
3586 if (new == NULL) 3636 if (new == NULL)
3587 return -ENOMEM; 3637 return -ENOMEM;
3588 3638
3589 tsp = new->security; 3639 tsp = new->security;
3590 tsp->smk_task = skp; 3640 tsp->smk_task = skp;
3641 /*
3642 * process can change its label only once
3643 */
3644 smk_destroy_label_list(&tsp->smk_relabel);
3591 3645
3592 commit_creds(new); 3646 commit_creds(new);
3593 return size; 3647 return size;
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index ce8d503a18a0..94bd9e41c9ec 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -61,6 +61,7 @@ enum smk_inos {
61#if IS_ENABLED(CONFIG_IPV6) 61#if IS_ENABLED(CONFIG_IPV6)
62 SMK_NET6ADDR = 23, /* single label IPv6 hosts */ 62 SMK_NET6ADDR = 23, /* single label IPv6 hosts */
63#endif /* CONFIG_IPV6 */ 63#endif /* CONFIG_IPV6 */
64 SMK_RELABEL_SELF = 24, /* relabel possible without CAP_MAC_ADMIN */
64}; 65};
65 66
66/* 67/*
@@ -1914,10 +1915,10 @@ static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos)
1914static int onlycap_seq_show(struct seq_file *s, void *v) 1915static int onlycap_seq_show(struct seq_file *s, void *v)
1915{ 1916{
1916 struct list_head *list = v; 1917 struct list_head *list = v;
1917 struct smack_onlycap *sop = 1918 struct smack_known_list_elem *sklep =
1918 list_entry_rcu(list, struct smack_onlycap, list); 1919 list_entry_rcu(list, struct smack_known_list_elem, list);
1919 1920
1920 seq_puts(s, sop->smk_label->smk_known); 1921 seq_puts(s, sklep->smk_label->smk_known);
1921 seq_putc(s, ' '); 1922 seq_putc(s, ' ');
1922 1923
1923 return 0; 1924 return 0;
@@ -1974,6 +1975,54 @@ static void smk_list_swap_rcu(struct list_head *public,
1974} 1975}
1975 1976
1976/** 1977/**
1978 * smk_parse_label_list - parse list of Smack labels, separated by spaces
1979 *
1980 * @data: the string to parse
1981 * @private: destination list
1982 *
1983 * Returns zero on success or error code, as appropriate
1984 */
1985static int smk_parse_label_list(char *data, struct list_head *list)
1986{
1987 char *tok;
1988 struct smack_known *skp;
1989 struct smack_known_list_elem *sklep;
1990
1991 while ((tok = strsep(&data, " ")) != NULL) {
1992 if (!*tok)
1993 continue;
1994
1995 skp = smk_import_entry(tok, 0);
1996 if (IS_ERR(skp))
1997 return PTR_ERR(skp);
1998
1999 sklep = kzalloc(sizeof(*sklep), GFP_KERNEL);
2000 if (sklep == NULL)
2001 return -ENOMEM;
2002
2003 sklep->smk_label = skp;
2004 list_add(&sklep->list, list);
2005 }
2006
2007 return 0;
2008}
2009
2010/**
2011 * smk_destroy_label_list - destroy a list of smack_known_list_elem
2012 * @head: header pointer of the list to destroy
2013 */
2014void smk_destroy_label_list(struct list_head *list)
2015{
2016 struct smack_known_list_elem *sklep;
2017 struct smack_known_list_elem *sklep2;
2018
2019 list_for_each_entry_safe(sklep, sklep2, list, list)
2020 kfree(sklep);
2021
2022 INIT_LIST_HEAD(list);
2023}
2024
2025/**
1977 * smk_write_onlycap - write() for smackfs/onlycap 2026 * smk_write_onlycap - write() for smackfs/onlycap
1978 * @file: file pointer, not actually used 2027 * @file: file pointer, not actually used
1979 * @buf: where to get the data from 2028 * @buf: where to get the data from
@@ -1986,13 +2035,8 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
1986 size_t count, loff_t *ppos) 2035 size_t count, loff_t *ppos)
1987{ 2036{
1988 char *data; 2037 char *data;
1989 char *data_parse;
1990 char *tok;
1991 struct smack_known *skp;
1992 struct smack_onlycap *sop;
1993 struct smack_onlycap *sop2;
1994 LIST_HEAD(list_tmp); 2038 LIST_HEAD(list_tmp);
1995 int rc = count; 2039 int rc;
1996 2040
1997 if (!smack_privileged(CAP_MAC_ADMIN)) 2041 if (!smack_privileged(CAP_MAC_ADMIN))
1998 return -EPERM; 2042 return -EPERM;
@@ -2006,26 +2050,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
2006 return -EFAULT; 2050 return -EFAULT;
2007 } 2051 }
2008 2052
2009 data_parse = data; 2053 rc = smk_parse_label_list(data, &list_tmp);
2010 while ((tok = strsep(&data_parse, " ")) != NULL) {
2011 if (!*tok)
2012 continue;
2013
2014 skp = smk_import_entry(tok, 0);
2015 if (IS_ERR(skp)) {
2016 rc = PTR_ERR(skp);
2017 break;
2018 }
2019
2020 sop = kzalloc(sizeof(*sop), GFP_KERNEL);
2021 if (sop == NULL) {
2022 rc = -ENOMEM;
2023 break;
2024 }
2025
2026 sop->smk_label = skp;
2027 list_add_rcu(&sop->list, &list_tmp);
2028 }
2029 kfree(data); 2054 kfree(data);
2030 2055
2031 /* 2056 /*
@@ -2038,17 +2063,14 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
2038 * But do so only on invalid label, not on system errors. 2063 * But do so only on invalid label, not on system errors.
2039 * The invalid label must be first to count as clearing attempt. 2064 * The invalid label must be first to count as clearing attempt.
2040 */ 2065 */
2041 if (rc == -EINVAL && list_empty(&list_tmp)) 2066 if (!rc || (rc == -EINVAL && list_empty(&list_tmp))) {
2042 rc = count;
2043
2044 if (rc >= 0) {
2045 mutex_lock(&smack_onlycap_lock); 2067 mutex_lock(&smack_onlycap_lock);
2046 smk_list_swap_rcu(&smack_onlycap_list, &list_tmp); 2068 smk_list_swap_rcu(&smack_onlycap_list, &list_tmp);
2047 mutex_unlock(&smack_onlycap_lock); 2069 mutex_unlock(&smack_onlycap_lock);
2070 rc = count;
2048 } 2071 }
2049 2072
2050 list_for_each_entry_safe(sop, sop2, &list_tmp, list) 2073 smk_destroy_label_list(&list_tmp);
2051 kfree(sop);
2052 2074
2053 return rc; 2075 return rc;
2054} 2076}
@@ -2698,6 +2720,113 @@ static const struct file_operations smk_syslog_ops = {
2698 .llseek = default_llseek, 2720 .llseek = default_llseek,
2699}; 2721};
2700 2722
2723/*
2724 * Seq_file read operations for /smack/relabel-self
2725 */
2726
2727static void *relabel_self_seq_start(struct seq_file *s, loff_t *pos)
2728{
2729 struct task_smack *tsp = current_security();
2730
2731 return smk_seq_start(s, pos, &tsp->smk_relabel);
2732}
2733
2734static void *relabel_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
2735{
2736 struct task_smack *tsp = current_security();
2737
2738 return smk_seq_next(s, v, pos, &tsp->smk_relabel);
2739}
2740
2741static int relabel_self_seq_show(struct seq_file *s, void *v)
2742{
2743 struct list_head *list = v;
2744 struct smack_known_list_elem *sklep =
2745 list_entry(list, struct smack_known_list_elem, list);
2746
2747 seq_puts(s, sklep->smk_label->smk_known);
2748 seq_putc(s, ' ');
2749
2750 return 0;
2751}
2752
2753static const struct seq_operations relabel_self_seq_ops = {
2754 .start = relabel_self_seq_start,
2755 .next = relabel_self_seq_next,
2756 .show = relabel_self_seq_show,
2757 .stop = smk_seq_stop,
2758};
2759
2760/**
2761 * smk_open_relabel_self - open() for /smack/relabel-self
2762 * @inode: inode structure representing file
2763 * @file: "relabel-self" file pointer
2764 *
2765 * Connect our relabel_self_seq_* operations with /smack/relabel-self
2766 * file_operations
2767 */
2768static int smk_open_relabel_self(struct inode *inode, struct file *file)
2769{
2770 return seq_open(file, &relabel_self_seq_ops);
2771}
2772
2773/**
2774 * smk_write_relabel_self - write() for /smack/relabel-self
2775 * @file: file pointer, not actually used
2776 * @buf: where to get the data from
2777 * @count: bytes sent
2778 * @ppos: where to start - must be 0
2779 *
2780 */
2781static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf,
2782 size_t count, loff_t *ppos)
2783{
2784 struct task_smack *tsp = current_security();
2785 char *data;
2786 int rc;
2787 LIST_HEAD(list_tmp);
2788
2789 /*
2790 * Must have privilege.
2791 */
2792 if (!smack_privileged(CAP_MAC_ADMIN))
2793 return -EPERM;
2794
2795 /*
2796 * Enough data must be present.
2797 */
2798 if (*ppos != 0)
2799 return -EINVAL;
2800
2801 data = kzalloc(count + 1, GFP_KERNEL);
2802 if (data == NULL)
2803 return -ENOMEM;
2804
2805 if (copy_from_user(data, buf, count) != 0) {
2806 kfree(data);
2807 return -EFAULT;
2808 }
2809
2810 rc = smk_parse_label_list(data, &list_tmp);
2811 kfree(data);
2812
2813 if (!rc || (rc == -EINVAL && list_empty(&list_tmp))) {
2814 smk_destroy_label_list(&tsp->smk_relabel);
2815 list_splice(&list_tmp, &tsp->smk_relabel);
2816 return count;
2817 }
2818
2819 smk_destroy_label_list(&list_tmp);
2820 return rc;
2821}
2822
2823static const struct file_operations smk_relabel_self_ops = {
2824 .open = smk_open_relabel_self,
2825 .read = seq_read,
2826 .llseek = seq_lseek,
2827 .write = smk_write_relabel_self,
2828 .release = seq_release,
2829};
2701 2830
2702/** 2831/**
2703 * smk_read_ptrace - read() for /smack/ptrace 2832 * smk_read_ptrace - read() for /smack/ptrace
@@ -2824,6 +2953,9 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
2824 [SMK_NET6ADDR] = { 2953 [SMK_NET6ADDR] = {
2825 "ipv6host", &smk_net6addr_ops, S_IRUGO|S_IWUSR}, 2954 "ipv6host", &smk_net6addr_ops, S_IRUGO|S_IWUSR},
2826#endif /* CONFIG_IPV6 */ 2955#endif /* CONFIG_IPV6 */
2956 [SMK_RELABEL_SELF] = {
2957 "relabel-self", &smk_relabel_self_ops,
2958 S_IRUGO|S_IWUGO},
2827 /* last one */ 2959 /* last one */
2828 {""} 2960 {""}
2829 }; 2961 };