summaryrefslogtreecommitdiffstats
path: root/security/smack/smackfs.c
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 /security/smack/smackfs.c
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>
Diffstat (limited to 'security/smack/smackfs.c')
-rw-r--r--security/smack/smackfs.c202
1 files changed, 167 insertions, 35 deletions
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 };