diff options
author | James Morris <jmorris@namei.org> | 2009-01-06 17:58:22 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-01-06 17:58:22 -0500 |
commit | ac8cc0fa5395fe2278e305a4cbed48e90d88d878 (patch) | |
tree | 515f577bfddd054ee4373228be7c974dfb8133af /security | |
parent | 238c6d54830c624f34ac9cf123ac04aebfca5013 (diff) | |
parent | 3699c53c485bf0168e6500d0ed18bf931584dd7c (diff) |
Merge branch 'next' into for-linus
Diffstat (limited to 'security')
-rw-r--r-- | security/commoncap.c | 29 | ||||
-rw-r--r-- | security/keys/keyctl.c | 2 | ||||
-rw-r--r-- | security/security.c | 26 | ||||
-rw-r--r-- | security/selinux/Kconfig | 27 | ||||
-rw-r--r-- | security/selinux/avc.c | 16 | ||||
-rw-r--r-- | security/selinux/hooks.c | 22 | ||||
-rw-r--r-- | security/selinux/include/avc_ss.h | 4 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 16 | ||||
-rw-r--r-- | security/selinux/ss/context.h | 2 | ||||
-rw-r--r-- | security/smack/smack.h | 31 | ||||
-rw-r--r-- | security/smack/smack_access.c | 28 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 310 | ||||
-rw-r--r-- | security/smack/smackfs.c | 369 |
13 files changed, 616 insertions, 266 deletions
diff --git a/security/commoncap.c b/security/commoncap.c index 69fc9952650..7cd61a5f520 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -45,26 +45,22 @@ EXPORT_SYMBOL(cap_netlink_recv); | |||
45 | /** | 45 | /** |
46 | * cap_capable - Determine whether a task has a particular effective capability | 46 | * cap_capable - Determine whether a task has a particular effective capability |
47 | * @tsk: The task to query | 47 | * @tsk: The task to query |
48 | * @cred: The credentials to use | ||
48 | * @cap: The capability to check for | 49 | * @cap: The capability to check for |
49 | * @audit: Whether to write an audit message or not | 50 | * @audit: Whether to write an audit message or not |
50 | * | 51 | * |
51 | * Determine whether the nominated task has the specified capability amongst | 52 | * Determine whether the nominated task has the specified capability amongst |
52 | * its effective set, returning 0 if it does, -ve if it does not. | 53 | * its effective set, returning 0 if it does, -ve if it does not. |
53 | * | 54 | * |
54 | * NOTE WELL: cap_capable() cannot be used like the kernel's capable() | 55 | * NOTE WELL: cap_has_capability() cannot be used like the kernel's capable() |
55 | * function. That is, it has the reverse semantics: cap_capable() returns 0 | 56 | * and has_capability() functions. That is, it has the reverse semantics: |
56 | * when a task has a capability, but the kernel's capable() returns 1 for this | 57 | * cap_has_capability() returns 0 when a task has a capability, but the |
57 | * case. | 58 | * kernel's capable() and has_capability() returns 1 for this case. |
58 | */ | 59 | */ |
59 | int cap_capable(struct task_struct *tsk, int cap, int audit) | 60 | int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap, |
61 | int audit) | ||
60 | { | 62 | { |
61 | __u32 cap_raised; | 63 | return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; |
62 | |||
63 | /* Derived from include/linux/sched.h:capable. */ | ||
64 | rcu_read_lock(); | ||
65 | cap_raised = cap_raised(__task_cred(tsk)->cap_effective, cap); | ||
66 | rcu_read_unlock(); | ||
67 | return cap_raised ? 0 : -EPERM; | ||
68 | } | 64 | } |
69 | 65 | ||
70 | /** | 66 | /** |
@@ -160,7 +156,8 @@ static inline int cap_inh_is_capped(void) | |||
160 | /* they are so limited unless the current task has the CAP_SETPCAP | 156 | /* they are so limited unless the current task has the CAP_SETPCAP |
161 | * capability | 157 | * capability |
162 | */ | 158 | */ |
163 | if (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) | 159 | if (cap_capable(current, current_cred(), CAP_SETPCAP, |
160 | SECURITY_CAP_AUDIT) == 0) | ||
164 | return 0; | 161 | return 0; |
165 | #endif | 162 | #endif |
166 | return 1; | 163 | return 1; |
@@ -869,7 +866,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
869 | & (new->securebits ^ arg2)) /*[1]*/ | 866 | & (new->securebits ^ arg2)) /*[1]*/ |
870 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ | 867 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ |
871 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | 868 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ |
872 | || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/ | 869 | || (cap_capable(current, current_cred(), CAP_SETPCAP, |
870 | SECURITY_CAP_AUDIT) != 0) /*[4]*/ | ||
873 | /* | 871 | /* |
874 | * [1] no changing of bits that are locked | 872 | * [1] no changing of bits that are locked |
875 | * [2] no unlocking of locks | 873 | * [2] no unlocking of locks |
@@ -950,7 +948,8 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) | |||
950 | { | 948 | { |
951 | int cap_sys_admin = 0; | 949 | int cap_sys_admin = 0; |
952 | 950 | ||
953 | if (cap_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0) | 951 | if (cap_capable(current, current_cred(), CAP_SYS_ADMIN, |
952 | SECURITY_CAP_NOAUDIT) == 0) | ||
954 | cap_sys_admin = 1; | 953 | cap_sys_admin = 1; |
955 | return __vm_enough_memory(mm, pages, cap_sys_admin); | 954 | return __vm_enough_memory(mm, pages, cap_sys_admin); |
956 | } | 955 | } |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 6688765bd8b..09796797d12 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -1294,7 +1294,7 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | |||
1294 | 1294 | ||
1295 | case KEYCTL_GET_SECURITY: | 1295 | case KEYCTL_GET_SECURITY: |
1296 | return keyctl_get_security((key_serial_t) arg2, | 1296 | return keyctl_get_security((key_serial_t) arg2, |
1297 | (char *) arg3, | 1297 | (char __user *) arg3, |
1298 | (size_t) arg4); | 1298 | (size_t) arg4); |
1299 | 1299 | ||
1300 | default: | 1300 | default: |
diff --git a/security/security.c b/security/security.c index 678d4d07b85..c3586c0d97e 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -154,14 +154,32 @@ int security_capset(struct cred *new, const struct cred *old, | |||
154 | effective, inheritable, permitted); | 154 | effective, inheritable, permitted); |
155 | } | 155 | } |
156 | 156 | ||
157 | int security_capable(struct task_struct *tsk, int cap) | 157 | int security_capable(int cap) |
158 | { | 158 | { |
159 | return security_ops->capable(tsk, cap, SECURITY_CAP_AUDIT); | 159 | return security_ops->capable(current, current_cred(), cap, |
160 | SECURITY_CAP_AUDIT); | ||
160 | } | 161 | } |
161 | 162 | ||
162 | int security_capable_noaudit(struct task_struct *tsk, int cap) | 163 | int security_real_capable(struct task_struct *tsk, int cap) |
163 | { | 164 | { |
164 | return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT); | 165 | const struct cred *cred; |
166 | int ret; | ||
167 | |||
168 | cred = get_task_cred(tsk); | ||
169 | ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_AUDIT); | ||
170 | put_cred(cred); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | int security_real_capable_noaudit(struct task_struct *tsk, int cap) | ||
175 | { | ||
176 | const struct cred *cred; | ||
177 | int ret; | ||
178 | |||
179 | cred = get_task_cred(tsk); | ||
180 | ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_NOAUDIT); | ||
181 | put_cred(cred); | ||
182 | return ret; | ||
165 | } | 183 | } |
166 | 184 | ||
167 | int security_acct(struct file *file) | 185 | int security_acct(struct file *file) |
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 26301dd651d..bca1b74a4a2 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig | |||
@@ -94,33 +94,6 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE | |||
94 | 94 | ||
95 | If you are unsure how to answer this question, answer 1. | 95 | If you are unsure how to answer this question, answer 1. |
96 | 96 | ||
97 | config SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT | ||
98 | bool "NSA SELinux enable new secmark network controls by default" | ||
99 | depends on SECURITY_SELINUX | ||
100 | default n | ||
101 | help | ||
102 | This option determines whether the new secmark-based network | ||
103 | controls will be enabled by default. If not, the old internal | ||
104 | per-packet controls will be enabled by default, preserving | ||
105 | old behavior. | ||
106 | |||
107 | If you enable the new controls, you will need updated | ||
108 | SELinux userspace libraries, tools and policy. Typically, | ||
109 | your distribution will provide these and enable the new controls | ||
110 | in the kernel they also distribute. | ||
111 | |||
112 | Note that this option can be overridden at boot with the | ||
113 | selinux_compat_net parameter, and after boot via | ||
114 | /selinux/compat_net. See Documentation/kernel-parameters.txt | ||
115 | for details on this parameter. | ||
116 | |||
117 | If you enable the new network controls, you will likely | ||
118 | also require the SECMARK and CONNSECMARK targets, as | ||
119 | well as any conntrack helpers for protocols which you | ||
120 | wish to control. | ||
121 | |||
122 | If you are unsure what to do here, select N. | ||
123 | |||
124 | config SECURITY_SELINUX_POLICYDB_VERSION_MAX | 97 | config SECURITY_SELINUX_POLICYDB_VERSION_MAX |
125 | bool "NSA SELinux maximum supported policy format version" | 98 | bool "NSA SELinux maximum supported policy format version" |
126 | depends on SECURITY_SELINUX | 99 | depends on SECURITY_SELINUX |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index d43bd6baeea..eb41f43e277 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -53,18 +53,20 @@ static const char *class_to_string[] = { | |||
53 | #undef S_ | 53 | #undef S_ |
54 | 54 | ||
55 | static const struct av_inherit av_inherit[] = { | 55 | static const struct av_inherit av_inherit[] = { |
56 | #define S_(c, i, b) { c, common_##i##_perm_to_string, b }, | 56 | #define S_(c, i, b) { .tclass = c,\ |
57 | .common_pts = common_##i##_perm_to_string,\ | ||
58 | .common_base = b }, | ||
57 | #include "av_inherit.h" | 59 | #include "av_inherit.h" |
58 | #undef S_ | 60 | #undef S_ |
59 | }; | 61 | }; |
60 | 62 | ||
61 | const struct selinux_class_perm selinux_class_perm = { | 63 | const struct selinux_class_perm selinux_class_perm = { |
62 | av_perm_to_string, | 64 | .av_perm_to_string = av_perm_to_string, |
63 | ARRAY_SIZE(av_perm_to_string), | 65 | .av_pts_len = ARRAY_SIZE(av_perm_to_string), |
64 | class_to_string, | 66 | .class_to_string = class_to_string, |
65 | ARRAY_SIZE(class_to_string), | 67 | .cts_len = ARRAY_SIZE(class_to_string), |
66 | av_inherit, | 68 | .av_inherit = av_inherit, |
67 | ARRAY_SIZE(av_inherit) | 69 | .av_inherit_len = ARRAY_SIZE(av_inherit) |
68 | }; | 70 | }; |
69 | 71 | ||
70 | #define AVC_CACHE_SLOTS 512 | 72 | #define AVC_CACHE_SLOTS 512 |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index dbeaa783b2a..00815973d41 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -1433,12 +1433,13 @@ static int current_has_perm(const struct task_struct *tsk, | |||
1433 | 1433 | ||
1434 | /* Check whether a task is allowed to use a capability. */ | 1434 | /* Check whether a task is allowed to use a capability. */ |
1435 | static int task_has_capability(struct task_struct *tsk, | 1435 | static int task_has_capability(struct task_struct *tsk, |
1436 | const struct cred *cred, | ||
1436 | int cap, int audit) | 1437 | int cap, int audit) |
1437 | { | 1438 | { |
1438 | struct avc_audit_data ad; | 1439 | struct avc_audit_data ad; |
1439 | struct av_decision avd; | 1440 | struct av_decision avd; |
1440 | u16 sclass; | 1441 | u16 sclass; |
1441 | u32 sid = task_sid(tsk); | 1442 | u32 sid = cred_sid(cred); |
1442 | u32 av = CAP_TO_MASK(cap); | 1443 | u32 av = CAP_TO_MASK(cap); |
1443 | int rc; | 1444 | int rc; |
1444 | 1445 | ||
@@ -1865,15 +1866,16 @@ static int selinux_capset(struct cred *new, const struct cred *old, | |||
1865 | return cred_has_perm(old, new, PROCESS__SETCAP); | 1866 | return cred_has_perm(old, new, PROCESS__SETCAP); |
1866 | } | 1867 | } |
1867 | 1868 | ||
1868 | static int selinux_capable(struct task_struct *tsk, int cap, int audit) | 1869 | static int selinux_capable(struct task_struct *tsk, const struct cred *cred, |
1870 | int cap, int audit) | ||
1869 | { | 1871 | { |
1870 | int rc; | 1872 | int rc; |
1871 | 1873 | ||
1872 | rc = secondary_ops->capable(tsk, cap, audit); | 1874 | rc = secondary_ops->capable(tsk, cred, cap, audit); |
1873 | if (rc) | 1875 | if (rc) |
1874 | return rc; | 1876 | return rc; |
1875 | 1877 | ||
1876 | return task_has_capability(tsk, cap, audit); | 1878 | return task_has_capability(tsk, cred, cap, audit); |
1877 | } | 1879 | } |
1878 | 1880 | ||
1879 | static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) | 1881 | static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) |
@@ -2037,7 +2039,8 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) | |||
2037 | { | 2039 | { |
2038 | int rc, cap_sys_admin = 0; | 2040 | int rc, cap_sys_admin = 0; |
2039 | 2041 | ||
2040 | rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); | 2042 | rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN, |
2043 | SECURITY_CAP_NOAUDIT); | ||
2041 | if (rc == 0) | 2044 | if (rc == 0) |
2042 | cap_sys_admin = 1; | 2045 | cap_sys_admin = 1; |
2043 | 2046 | ||
@@ -2880,7 +2883,8 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name | |||
2880 | * and lack of permission just means that we fall back to the | 2883 | * and lack of permission just means that we fall back to the |
2881 | * in-core context value, not a denial. | 2884 | * in-core context value, not a denial. |
2882 | */ | 2885 | */ |
2883 | error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); | 2886 | error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN, |
2887 | SECURITY_CAP_NOAUDIT); | ||
2884 | if (!error) | 2888 | if (!error) |
2885 | error = security_sid_to_context_force(isec->sid, &context, | 2889 | error = security_sid_to_context_force(isec->sid, &context, |
2886 | &size); | 2890 | &size); |
@@ -4185,7 +4189,7 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, | |||
4185 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 4189 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
4186 | u16 family) | 4190 | u16 family) |
4187 | { | 4191 | { |
4188 | int err; | 4192 | int err = 0; |
4189 | struct sk_security_struct *sksec = sk->sk_security; | 4193 | struct sk_security_struct *sksec = sk->sk_security; |
4190 | u32 peer_sid; | 4194 | u32 peer_sid; |
4191 | u32 sk_sid = sksec->sid; | 4195 | u32 sk_sid = sksec->sid; |
@@ -4202,7 +4206,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4202 | if (selinux_compat_net) | 4206 | if (selinux_compat_net) |
4203 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, | 4207 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, |
4204 | family, addrp); | 4208 | family, addrp); |
4205 | else | 4209 | else if (selinux_secmark_enabled()) |
4206 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4210 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
4207 | PACKET__RECV, &ad); | 4211 | PACKET__RECV, &ad); |
4208 | if (err) | 4212 | if (err) |
@@ -4705,7 +4709,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
4705 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, | 4709 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, |
4706 | &ad, family, addrp)) | 4710 | &ad, family, addrp)) |
4707 | return NF_DROP; | 4711 | return NF_DROP; |
4708 | } else { | 4712 | } else if (selinux_secmark_enabled()) { |
4709 | if (avc_has_perm(sksec->sid, skb->secmark, | 4713 | if (avc_has_perm(sksec->sid, skb->secmark, |
4710 | SECCLASS_PACKET, PACKET__SEND, &ad)) | 4714 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
4711 | return NF_DROP; | 4715 | return NF_DROP; |
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h index c0d314d9f8e..bb1ec801bdf 100644 --- a/security/selinux/include/avc_ss.h +++ b/security/selinux/include/avc_ss.h | |||
@@ -17,16 +17,16 @@ struct av_perm_to_string { | |||
17 | }; | 17 | }; |
18 | 18 | ||
19 | struct av_inherit { | 19 | struct av_inherit { |
20 | u16 tclass; | ||
21 | const char **common_pts; | 20 | const char **common_pts; |
22 | u32 common_base; | 21 | u32 common_base; |
22 | u16 tclass; | ||
23 | }; | 23 | }; |
24 | 24 | ||
25 | struct selinux_class_perm { | 25 | struct selinux_class_perm { |
26 | const struct av_perm_to_string *av_perm_to_string; | 26 | const struct av_perm_to_string *av_perm_to_string; |
27 | u32 av_pts_len; | 27 | u32 av_pts_len; |
28 | const char **class_to_string; | ||
29 | u32 cts_len; | 28 | u32 cts_len; |
29 | const char **class_to_string; | ||
30 | const struct av_inherit *av_inherit; | 30 | const struct av_inherit *av_inherit; |
31 | u32 av_inherit_len; | 31 | u32 av_inherit_len; |
32 | }; | 32 | }; |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 8f612c8becb..01ec6d2c6b9 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -47,13 +47,7 @@ static char *policycap_names[] = { | |||
47 | 47 | ||
48 | unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; | 48 | unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; |
49 | 49 | ||
50 | #ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT | 50 | int selinux_compat_net = 0; |
51 | #define SELINUX_COMPAT_NET_VALUE 0 | ||
52 | #else | ||
53 | #define SELINUX_COMPAT_NET_VALUE 1 | ||
54 | #endif | ||
55 | |||
56 | int selinux_compat_net = SELINUX_COMPAT_NET_VALUE; | ||
57 | 51 | ||
58 | static int __init checkreqprot_setup(char *str) | 52 | static int __init checkreqprot_setup(char *str) |
59 | { | 53 | { |
@@ -494,7 +488,13 @@ static ssize_t sel_write_compat_net(struct file *file, const char __user *buf, | |||
494 | if (sscanf(page, "%d", &new_value) != 1) | 488 | if (sscanf(page, "%d", &new_value) != 1) |
495 | goto out; | 489 | goto out; |
496 | 490 | ||
497 | selinux_compat_net = new_value ? 1 : 0; | 491 | if (new_value) { |
492 | printk(KERN_NOTICE | ||
493 | "SELinux: compat_net is deprecated, please use secmark" | ||
494 | " instead\n"); | ||
495 | selinux_compat_net = 1; | ||
496 | } else | ||
497 | selinux_compat_net = 0; | ||
498 | length = count; | 498 | length = count; |
499 | out: | 499 | out: |
500 | free_page((unsigned long) page); | 500 | free_page((unsigned long) page); |
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index 658c2bd17da..d9dd7a2f6a8 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h | |||
@@ -27,9 +27,9 @@ struct context { | |||
27 | u32 user; | 27 | u32 user; |
28 | u32 role; | 28 | u32 role; |
29 | u32 type; | 29 | u32 type; |
30 | u32 len; /* length of string in bytes */ | ||
30 | struct mls_range range; | 31 | struct mls_range range; |
31 | char *str; /* string representation if context cannot be mapped. */ | 32 | char *str; /* string representation if context cannot be mapped. */ |
32 | u32 len; /* length of string in bytes */ | ||
33 | }; | 33 | }; |
34 | 34 | ||
35 | static inline void mls_context_init(struct context *c) | 35 | static inline void mls_context_init(struct context *c) |
diff --git a/security/smack/smack.h b/security/smack/smack.h index 31dce559595..b79582e4fbf 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/capability.h> | 16 | #include <linux/capability.h> |
17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
18 | #include <linux/security.h> | 18 | #include <linux/security.h> |
19 | #include <linux/in.h> | ||
19 | #include <net/netlabel.h> | 20 | #include <net/netlabel.h> |
20 | 21 | ||
21 | /* | 22 | /* |
@@ -39,6 +40,7 @@ struct superblock_smack { | |||
39 | struct socket_smack { | 40 | struct socket_smack { |
40 | char *smk_out; /* outbound label */ | 41 | char *smk_out; /* outbound label */ |
41 | char *smk_in; /* inbound label */ | 42 | char *smk_in; /* inbound label */ |
43 | int smk_labeled; /* label scheme */ | ||
42 | char smk_packet[SMK_LABELLEN]; /* TCP peer label */ | 44 | char smk_packet[SMK_LABELLEN]; /* TCP peer label */ |
43 | }; | 45 | }; |
44 | 46 | ||
@@ -80,6 +82,16 @@ struct smack_cipso { | |||
80 | }; | 82 | }; |
81 | 83 | ||
82 | /* | 84 | /* |
85 | * An entry in the table identifying hosts. | ||
86 | */ | ||
87 | struct smk_netlbladdr { | ||
88 | struct smk_netlbladdr *smk_next; | ||
89 | struct sockaddr_in smk_host; /* network address */ | ||
90 | struct in_addr smk_mask; /* network mask */ | ||
91 | char *smk_label; /* label */ | ||
92 | }; | ||
93 | |||
94 | /* | ||
83 | * This is the repository for labels seen so that it is | 95 | * This is the repository for labels seen so that it is |
84 | * not necessary to keep allocating tiny chuncks of memory | 96 | * not necessary to keep allocating tiny chuncks of memory |
85 | * and so that they can be shared. | 97 | * and so that they can be shared. |
@@ -127,6 +139,20 @@ struct smack_known { | |||
127 | #define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT | 139 | #define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT |
128 | 140 | ||
129 | /* | 141 | /* |
142 | * How communications on this socket are treated. | ||
143 | * Usually it's determined by the underlying netlabel code | ||
144 | * but there are certain cases, including single label hosts | ||
145 | * and potentially single label interfaces for which the | ||
146 | * treatment can not be known in advance. | ||
147 | * | ||
148 | * The possibility of additional labeling schemes being | ||
149 | * introduced in the future exists as well. | ||
150 | */ | ||
151 | #define SMACK_UNLABELED_SOCKET 0 | ||
152 | #define SMACK_CIPSO_SOCKET 1 | ||
153 | |||
154 | /* | ||
155 | * smackfs magic number | ||
130 | * smackfs macic number | 156 | * smackfs macic number |
131 | */ | 157 | */ |
132 | #define SMACK_MAGIC 0x43415d53 /* "SMAC" */ | 158 | #define SMACK_MAGIC 0x43415d53 /* "SMAC" */ |
@@ -141,6 +167,7 @@ struct smack_known { | |||
141 | * CIPSO defaults. | 167 | * CIPSO defaults. |
142 | */ | 168 | */ |
143 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ | 169 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ |
170 | #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ | ||
144 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ | 171 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ |
145 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ | 172 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ |
146 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ | 173 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ |
@@ -176,7 +203,6 @@ u32 smack_to_secid(const char *); | |||
176 | * Shared data. | 203 | * Shared data. |
177 | */ | 204 | */ |
178 | extern int smack_cipso_direct; | 205 | extern int smack_cipso_direct; |
179 | extern int smack_net_nltype; | ||
180 | extern char *smack_net_ambient; | 206 | extern char *smack_net_ambient; |
181 | extern char *smack_onlycap; | 207 | extern char *smack_onlycap; |
182 | 208 | ||
@@ -186,9 +212,10 @@ extern struct smack_known smack_known_hat; | |||
186 | extern struct smack_known smack_known_huh; | 212 | extern struct smack_known smack_known_huh; |
187 | extern struct smack_known smack_known_invalid; | 213 | extern struct smack_known smack_known_invalid; |
188 | extern struct smack_known smack_known_star; | 214 | extern struct smack_known smack_known_star; |
189 | extern struct smack_known smack_known_unset; | 215 | extern struct smack_known smack_known_web; |
190 | 216 | ||
191 | extern struct smk_list_entry *smack_list; | 217 | extern struct smk_list_entry *smack_list; |
218 | extern struct smk_netlbladdr *smack_netlbladdrs; | ||
192 | extern struct security_operations smack_ops; | 219 | extern struct security_operations smack_ops; |
193 | 220 | ||
194 | /* | 221 | /* |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 247cec3b5a4..2e0b83e77ff 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -15,15 +15,8 @@ | |||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include "smack.h" | 16 | #include "smack.h" |
17 | 17 | ||
18 | struct smack_known smack_known_unset = { | ||
19 | .smk_next = NULL, | ||
20 | .smk_known = "UNSET", | ||
21 | .smk_secid = 1, | ||
22 | .smk_cipso = NULL, | ||
23 | }; | ||
24 | |||
25 | struct smack_known smack_known_huh = { | 18 | struct smack_known smack_known_huh = { |
26 | .smk_next = &smack_known_unset, | 19 | .smk_next = NULL, |
27 | .smk_known = "?", | 20 | .smk_known = "?", |
28 | .smk_secid = 2, | 21 | .smk_secid = 2, |
29 | .smk_cipso = NULL, | 22 | .smk_cipso = NULL, |
@@ -57,7 +50,14 @@ struct smack_known smack_known_invalid = { | |||
57 | .smk_cipso = NULL, | 50 | .smk_cipso = NULL, |
58 | }; | 51 | }; |
59 | 52 | ||
60 | struct smack_known *smack_known = &smack_known_invalid; | 53 | struct smack_known smack_known_web = { |
54 | .smk_next = &smack_known_invalid, | ||
55 | .smk_known = "@", | ||
56 | .smk_secid = 7, | ||
57 | .smk_cipso = NULL, | ||
58 | }; | ||
59 | |||
60 | struct smack_known *smack_known = &smack_known_web; | ||
61 | 61 | ||
62 | /* | 62 | /* |
63 | * The initial value needs to be bigger than any of the | 63 | * The initial value needs to be bigger than any of the |
@@ -99,6 +99,16 @@ int smk_access(char *subject_label, char *object_label, int request) | |||
99 | strcmp(subject_label, smack_known_star.smk_known) == 0) | 99 | strcmp(subject_label, smack_known_star.smk_known) == 0) |
100 | return -EACCES; | 100 | return -EACCES; |
101 | /* | 101 | /* |
102 | * An internet object can be accessed by any subject. | ||
103 | * Tasks cannot be assigned the internet label. | ||
104 | * An internet subject can access any object. | ||
105 | */ | ||
106 | if (object_label == smack_known_web.smk_known || | ||
107 | subject_label == smack_known_web.smk_known || | ||
108 | strcmp(object_label, smack_known_web.smk_known) == 0 || | ||
109 | strcmp(subject_label, smack_known_web.smk_known) == 0) | ||
110 | return 0; | ||
111 | /* | ||
102 | * A star object can be accessed by any subject. | 112 | * A star object can be accessed by any subject. |
103 | */ | 113 | */ |
104 | if (object_label == smack_known_star.smk_known || | 114 | if (object_label == smack_known_star.smk_known || |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 848212fd484..0278bc08304 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -1277,6 +1277,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) | |||
1277 | 1277 | ||
1278 | ssp->smk_in = csp; | 1278 | ssp->smk_in = csp; |
1279 | ssp->smk_out = csp; | 1279 | ssp->smk_out = csp; |
1280 | ssp->smk_labeled = SMACK_CIPSO_SOCKET; | ||
1280 | ssp->smk_packet[0] = '\0'; | 1281 | ssp->smk_packet[0] = '\0'; |
1281 | 1282 | ||
1282 | sk->sk_security = ssp; | 1283 | sk->sk_security = ssp; |
@@ -1341,45 +1342,69 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) | |||
1341 | struct smack_cipso cipso; | 1342 | struct smack_cipso cipso; |
1342 | int rc; | 1343 | int rc; |
1343 | 1344 | ||
1344 | switch (smack_net_nltype) { | 1345 | nlsp->domain = smack; |
1345 | case NETLBL_NLTYPE_CIPSOV4: | 1346 | nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; |
1346 | nlsp->domain = smack; | ||
1347 | nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
1348 | 1347 | ||
1349 | rc = smack_to_cipso(smack, &cipso); | 1348 | rc = smack_to_cipso(smack, &cipso); |
1350 | if (rc == 0) { | 1349 | if (rc == 0) { |
1351 | nlsp->attr.mls.lvl = cipso.smk_level; | 1350 | nlsp->attr.mls.lvl = cipso.smk_level; |
1352 | smack_set_catset(cipso.smk_catset, nlsp); | 1351 | smack_set_catset(cipso.smk_catset, nlsp); |
1353 | } else { | 1352 | } else { |
1354 | nlsp->attr.mls.lvl = smack_cipso_direct; | 1353 | nlsp->attr.mls.lvl = smack_cipso_direct; |
1355 | smack_set_catset(smack, nlsp); | 1354 | smack_set_catset(smack, nlsp); |
1356 | } | ||
1357 | break; | ||
1358 | default: | ||
1359 | break; | ||
1360 | } | 1355 | } |
1361 | } | 1356 | } |
1362 | 1357 | ||
1363 | /** | 1358 | /** |
1364 | * smack_netlabel - Set the secattr on a socket | 1359 | * smack_netlabel - Set the secattr on a socket |
1365 | * @sk: the socket | 1360 | * @sk: the socket |
1361 | * @labeled: socket label scheme | ||
1366 | * | 1362 | * |
1367 | * Convert the outbound smack value (smk_out) to a | 1363 | * Convert the outbound smack value (smk_out) to a |
1368 | * secattr and attach it to the socket. | 1364 | * secattr and attach it to the socket. |
1369 | * | 1365 | * |
1370 | * Returns 0 on success or an error code | 1366 | * Returns 0 on success or an error code |
1371 | */ | 1367 | */ |
1372 | static int smack_netlabel(struct sock *sk) | 1368 | static int smack_netlabel(struct sock *sk, int labeled) |
1373 | { | 1369 | { |
1374 | struct socket_smack *ssp; | 1370 | struct socket_smack *ssp; |
1375 | struct netlbl_lsm_secattr secattr; | 1371 | struct netlbl_lsm_secattr secattr; |
1376 | int rc; | 1372 | int rc = 0; |
1377 | 1373 | ||
1378 | ssp = sk->sk_security; | 1374 | ssp = sk->sk_security; |
1379 | netlbl_secattr_init(&secattr); | 1375 | /* |
1380 | smack_to_secattr(ssp->smk_out, &secattr); | 1376 | * Usually the netlabel code will handle changing the |
1381 | rc = netlbl_sock_setattr(sk, &secattr); | 1377 | * packet labeling based on the label. |
1382 | netlbl_secattr_destroy(&secattr); | 1378 | * The case of a single label host is different, because |
1379 | * a single label host should never get a labeled packet | ||
1380 | * even though the label is usually associated with a packet | ||
1381 | * label. | ||
1382 | */ | ||
1383 | local_bh_disable(); | ||
1384 | bh_lock_sock_nested(sk); | ||
1385 | |||
1386 | if (ssp->smk_out == smack_net_ambient || | ||
1387 | labeled == SMACK_UNLABELED_SOCKET) | ||
1388 | netlbl_sock_delattr(sk); | ||
1389 | else { | ||
1390 | netlbl_secattr_init(&secattr); | ||
1391 | smack_to_secattr(ssp->smk_out, &secattr); | ||
1392 | rc = netlbl_sock_setattr(sk, &secattr); | ||
1393 | netlbl_secattr_destroy(&secattr); | ||
1394 | } | ||
1395 | |||
1396 | bh_unlock_sock(sk); | ||
1397 | local_bh_enable(); | ||
1398 | /* | ||
1399 | * Remember the label scheme used so that it is not | ||
1400 | * necessary to do the netlabel setting if it has not | ||
1401 | * changed the next time through. | ||
1402 | * | ||
1403 | * The -EDESTADDRREQ case is an indication that there's | ||
1404 | * a single level host involved. | ||
1405 | */ | ||
1406 | if (rc == 0) | ||
1407 | ssp->smk_labeled = labeled; | ||
1383 | 1408 | ||
1384 | return rc; | 1409 | return rc; |
1385 | } | 1410 | } |
@@ -1432,7 +1457,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
1432 | ssp->smk_in = sp; | 1457 | ssp->smk_in = sp; |
1433 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { | 1458 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { |
1434 | ssp->smk_out = sp; | 1459 | ssp->smk_out = sp; |
1435 | rc = smack_netlabel(sock->sk); | 1460 | rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); |
1436 | if (rc != 0) | 1461 | if (rc != 0) |
1437 | printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", | 1462 | printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", |
1438 | __func__, -rc); | 1463 | __func__, -rc); |
@@ -1462,7 +1487,108 @@ static int smack_socket_post_create(struct socket *sock, int family, | |||
1462 | /* | 1487 | /* |
1463 | * Set the outbound netlbl. | 1488 | * Set the outbound netlbl. |
1464 | */ | 1489 | */ |
1465 | return smack_netlabel(sock->sk); | 1490 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); |
1491 | } | ||
1492 | |||
1493 | |||
1494 | /** | ||
1495 | * smack_host_label - check host based restrictions | ||
1496 | * @sip: the object end | ||
1497 | * | ||
1498 | * looks for host based access restrictions | ||
1499 | * | ||
1500 | * This version will only be appropriate for really small | ||
1501 | * sets of single label hosts. Because of the masking | ||
1502 | * it cannot shortcut out on the first match. There are | ||
1503 | * numerious ways to address the problem, but none of them | ||
1504 | * have been applied here. | ||
1505 | * | ||
1506 | * Returns the label of the far end or NULL if it's not special. | ||
1507 | */ | ||
1508 | static char *smack_host_label(struct sockaddr_in *sip) | ||
1509 | { | ||
1510 | struct smk_netlbladdr *snp; | ||
1511 | char *bestlabel = NULL; | ||
1512 | struct in_addr *siap = &sip->sin_addr; | ||
1513 | struct in_addr *liap; | ||
1514 | struct in_addr *miap; | ||
1515 | struct in_addr bestmask; | ||
1516 | |||
1517 | if (siap->s_addr == 0) | ||
1518 | return NULL; | ||
1519 | |||
1520 | bestmask.s_addr = 0; | ||
1521 | |||
1522 | for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) { | ||
1523 | liap = &snp->smk_host.sin_addr; | ||
1524 | miap = &snp->smk_mask; | ||
1525 | /* | ||
1526 | * If the addresses match after applying the list entry mask | ||
1527 | * the entry matches the address. If it doesn't move along to | ||
1528 | * the next entry. | ||
1529 | */ | ||
1530 | if ((liap->s_addr & miap->s_addr) != | ||
1531 | (siap->s_addr & miap->s_addr)) | ||
1532 | continue; | ||
1533 | /* | ||
1534 | * If the list entry mask identifies a single address | ||
1535 | * it can't get any more specific. | ||
1536 | */ | ||
1537 | if (miap->s_addr == 0xffffffff) | ||
1538 | return snp->smk_label; | ||
1539 | /* | ||
1540 | * If the list entry mask is less specific than the best | ||
1541 | * already found this entry is uninteresting. | ||
1542 | */ | ||
1543 | if ((miap->s_addr | bestmask.s_addr) == bestmask.s_addr) | ||
1544 | continue; | ||
1545 | /* | ||
1546 | * This is better than any entry found so far. | ||
1547 | */ | ||
1548 | bestmask.s_addr = miap->s_addr; | ||
1549 | bestlabel = snp->smk_label; | ||
1550 | } | ||
1551 | |||
1552 | return bestlabel; | ||
1553 | } | ||
1554 | |||
1555 | /** | ||
1556 | * smack_socket_connect - connect access check | ||
1557 | * @sock: the socket | ||
1558 | * @sap: the other end | ||
1559 | * @addrlen: size of sap | ||
1560 | * | ||
1561 | * Verifies that a connection may be possible | ||
1562 | * | ||
1563 | * Returns 0 on success, and error code otherwise | ||
1564 | */ | ||
1565 | static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, | ||
1566 | int addrlen) | ||
1567 | { | ||
1568 | struct socket_smack *ssp = sock->sk->sk_security; | ||
1569 | char *hostsp; | ||
1570 | int rc; | ||
1571 | |||
1572 | if (sock->sk == NULL || sock->sk->sk_family != PF_INET) | ||
1573 | return 0; | ||
1574 | |||
1575 | if (addrlen < sizeof(struct sockaddr_in)) | ||
1576 | return -EINVAL; | ||
1577 | |||
1578 | hostsp = smack_host_label((struct sockaddr_in *)sap); | ||
1579 | if (hostsp == NULL) { | ||
1580 | if (ssp->smk_labeled != SMACK_CIPSO_SOCKET) | ||
1581 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); | ||
1582 | return 0; | ||
1583 | } | ||
1584 | |||
1585 | rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE); | ||
1586 | if (rc != 0) | ||
1587 | return rc; | ||
1588 | |||
1589 | if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET) | ||
1590 | return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET); | ||
1591 | return 0; | ||
1466 | } | 1592 | } |
1467 | 1593 | ||
1468 | /** | 1594 | /** |
@@ -2101,8 +2227,14 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2101 | if (newsmack == NULL) | 2227 | if (newsmack == NULL) |
2102 | return -EINVAL; | 2228 | return -EINVAL; |
2103 | 2229 | ||
2230 | /* | ||
2231 | * No process is ever allowed the web ("@") label. | ||
2232 | */ | ||
2233 | if (newsmack == smack_known_web.smk_known) | ||
2234 | return -EPERM; | ||
2235 | |||
2104 | new = prepare_creds(); | 2236 | new = prepare_creds(); |
2105 | if (!new) | 2237 | if (new == NULL) |
2106 | return -ENOMEM; | 2238 | return -ENOMEM; |
2107 | new->security = newsmack; | 2239 | new->security = newsmack; |
2108 | commit_creds(new); | 2240 | commit_creds(new); |
@@ -2144,6 +2276,49 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) | |||
2144 | } | 2276 | } |
2145 | 2277 | ||
2146 | /** | 2278 | /** |
2279 | * smack_socket_sendmsg - Smack check based on destination host | ||
2280 | * @sock: the socket | ||
2281 | * @msghdr: the message | ||
2282 | * @size: the size of the message | ||
2283 | * | ||
2284 | * Return 0 if the current subject can write to the destination | ||
2285 | * host. This is only a question if the destination is a single | ||
2286 | * label host. | ||
2287 | */ | ||
2288 | static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | ||
2289 | int size) | ||
2290 | { | ||
2291 | struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; | ||
2292 | struct socket_smack *ssp = sock->sk->sk_security; | ||
2293 | char *hostsp; | ||
2294 | int rc; | ||
2295 | |||
2296 | /* | ||
2297 | * Perfectly reasonable for this to be NULL | ||
2298 | */ | ||
2299 | if (sip == NULL || sip->sin_family != PF_INET) | ||
2300 | return 0; | ||
2301 | |||
2302 | hostsp = smack_host_label(sip); | ||
2303 | if (hostsp == NULL) { | ||
2304 | if (ssp->smk_labeled != SMACK_CIPSO_SOCKET) | ||
2305 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); | ||
2306 | return 0; | ||
2307 | } | ||
2308 | |||
2309 | rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE); | ||
2310 | if (rc != 0) | ||
2311 | return rc; | ||
2312 | |||
2313 | if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET) | ||
2314 | return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET); | ||
2315 | |||
2316 | return 0; | ||
2317 | |||
2318 | } | ||
2319 | |||
2320 | |||
2321 | /** | ||
2147 | * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat | 2322 | * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat |
2148 | * pair to smack | 2323 | * pair to smack |
2149 | * @sap: netlabel secattr | 2324 | * @sap: netlabel secattr |
@@ -2154,44 +2329,66 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) | |||
2154 | static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip) | 2329 | static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip) |
2155 | { | 2330 | { |
2156 | char smack[SMK_LABELLEN]; | 2331 | char smack[SMK_LABELLEN]; |
2332 | char *sp; | ||
2157 | int pcat; | 2333 | int pcat; |
2158 | 2334 | ||
2159 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) { | 2335 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { |
2160 | /* | 2336 | /* |
2337 | * Looks like a CIPSO packet. | ||
2161 | * If there are flags but no level netlabel isn't | 2338 | * If there are flags but no level netlabel isn't |
2162 | * behaving the way we expect it to. | 2339 | * behaving the way we expect it to. |
2163 | * | 2340 | * |
2341 | * Get the categories, if any | ||
2164 | * Without guidance regarding the smack value | 2342 | * Without guidance regarding the smack value |
2165 | * for the packet fall back on the network | 2343 | * for the packet fall back on the network |
2166 | * ambient value. | 2344 | * ambient value. |
2167 | */ | 2345 | */ |
2168 | strncpy(sip, smack_net_ambient, SMK_MAXLEN); | 2346 | memset(smack, '\0', SMK_LABELLEN); |
2347 | if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) | ||
2348 | for (pcat = -1;;) { | ||
2349 | pcat = netlbl_secattr_catmap_walk( | ||
2350 | sap->attr.mls.cat, pcat + 1); | ||
2351 | if (pcat < 0) | ||
2352 | break; | ||
2353 | smack_catset_bit(pcat, smack); | ||
2354 | } | ||
2355 | /* | ||
2356 | * If it is CIPSO using smack direct mapping | ||
2357 | * we are already done. WeeHee. | ||
2358 | */ | ||
2359 | if (sap->attr.mls.lvl == smack_cipso_direct) { | ||
2360 | memcpy(sip, smack, SMK_MAXLEN); | ||
2361 | return; | ||
2362 | } | ||
2363 | /* | ||
2364 | * Look it up in the supplied table if it is not | ||
2365 | * a direct mapping. | ||
2366 | */ | ||
2367 | smack_from_cipso(sap->attr.mls.lvl, smack, sip); | ||
2169 | return; | 2368 | return; |
2170 | } | 2369 | } |
2171 | /* | 2370 | if ((sap->flags & NETLBL_SECATTR_SECID) != 0) { |
2172 | * Get the categories, if any | 2371 | /* |
2173 | */ | 2372 | * Looks like a fallback, which gives us a secid. |
2174 | memset(smack, '\0', SMK_LABELLEN); | 2373 | */ |
2175 | if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) | 2374 | sp = smack_from_secid(sap->attr.secid); |
2176 | for (pcat = -1;;) { | 2375 | /* |
2177 | pcat = netlbl_secattr_catmap_walk(sap->attr.mls.cat, | 2376 | * This has got to be a bug because it is |
2178 | pcat + 1); | 2377 | * impossible to specify a fallback without |
2179 | if (pcat < 0) | 2378 | * specifying the label, which will ensure |
2180 | break; | 2379 | * it has a secid, and the only way to get a |
2181 | smack_catset_bit(pcat, smack); | 2380 | * secid is from a fallback. |
2182 | } | 2381 | */ |
2183 | /* | 2382 | BUG_ON(sp == NULL); |
2184 | * If it is CIPSO using smack direct mapping | 2383 | strncpy(sip, sp, SMK_MAXLEN); |
2185 | * we are already done. WeeHee. | ||
2186 | */ | ||
2187 | if (sap->attr.mls.lvl == smack_cipso_direct) { | ||
2188 | memcpy(sip, smack, SMK_MAXLEN); | ||
2189 | return; | 2384 | return; |
2190 | } | 2385 | } |
2191 | /* | 2386 | /* |
2192 | * Look it up in the supplied table if it is not a direct mapping. | 2387 | * Without guidance regarding the smack value |
2388 | * for the packet fall back on the network | ||
2389 | * ambient value. | ||
2193 | */ | 2390 | */ |
2194 | smack_from_cipso(sap->attr.mls.lvl, smack, sip); | 2391 | strncpy(sip, smack_net_ambient, SMK_MAXLEN); |
2195 | return; | 2392 | return; |
2196 | } | 2393 | } |
2197 | 2394 | ||
@@ -2207,6 +2404,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
2207 | struct netlbl_lsm_secattr secattr; | 2404 | struct netlbl_lsm_secattr secattr; |
2208 | struct socket_smack *ssp = sk->sk_security; | 2405 | struct socket_smack *ssp = sk->sk_security; |
2209 | char smack[SMK_LABELLEN]; | 2406 | char smack[SMK_LABELLEN]; |
2407 | char *csp; | ||
2210 | int rc; | 2408 | int rc; |
2211 | 2409 | ||
2212 | if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) | 2410 | if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) |
@@ -2215,21 +2413,24 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
2215 | /* | 2413 | /* |
2216 | * Translate what netlabel gave us. | 2414 | * Translate what netlabel gave us. |
2217 | */ | 2415 | */ |
2218 | memset(smack, '\0', SMK_LABELLEN); | ||
2219 | netlbl_secattr_init(&secattr); | 2416 | netlbl_secattr_init(&secattr); |
2417 | |||
2220 | rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); | 2418 | rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); |
2221 | if (rc == 0) | 2419 | if (rc == 0) { |
2222 | smack_from_secattr(&secattr, smack); | 2420 | smack_from_secattr(&secattr, smack); |
2223 | else | 2421 | csp = smack; |
2224 | strncpy(smack, smack_net_ambient, SMK_MAXLEN); | 2422 | } else |
2423 | csp = smack_net_ambient; | ||
2424 | |||
2225 | netlbl_secattr_destroy(&secattr); | 2425 | netlbl_secattr_destroy(&secattr); |
2426 | |||
2226 | /* | 2427 | /* |
2227 | * Receiving a packet requires that the other end | 2428 | * Receiving a packet requires that the other end |
2228 | * be able to write here. Read access is not required. | 2429 | * be able to write here. Read access is not required. |
2229 | * This is the simplist possible security model | 2430 | * This is the simplist possible security model |
2230 | * for networking. | 2431 | * for networking. |
2231 | */ | 2432 | */ |
2232 | rc = smk_access(smack, ssp->smk_in, MAY_WRITE); | 2433 | rc = smk_access(csp, ssp->smk_in, MAY_WRITE); |
2233 | if (rc != 0) | 2434 | if (rc != 0) |
2234 | netlbl_skbuff_err(skb, rc, 0); | 2435 | netlbl_skbuff_err(skb, rc, 0); |
2235 | return rc; | 2436 | return rc; |
@@ -2298,7 +2499,6 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, | |||
2298 | /* | 2499 | /* |
2299 | * Translate what netlabel gave us. | 2500 | * Translate what netlabel gave us. |
2300 | */ | 2501 | */ |
2301 | memset(smack, '\0', SMK_LABELLEN); | ||
2302 | netlbl_secattr_init(&secattr); | 2502 | netlbl_secattr_init(&secattr); |
2303 | rc = netlbl_skbuff_getattr(skb, family, &secattr); | 2503 | rc = netlbl_skbuff_getattr(skb, family, &secattr); |
2304 | if (rc == 0) | 2504 | if (rc == 0) |
@@ -2341,7 +2541,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent) | |||
2341 | ssp->smk_in = ssp->smk_out = current_security(); | 2541 | ssp->smk_in = ssp->smk_out = current_security(); |
2342 | ssp->smk_packet[0] = '\0'; | 2542 | ssp->smk_packet[0] = '\0'; |
2343 | 2543 | ||
2344 | rc = smack_netlabel(sk); | 2544 | rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET); |
2345 | if (rc != 0) | 2545 | if (rc != 0) |
2346 | printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", | 2546 | printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", |
2347 | __func__, -rc); | 2547 | __func__, -rc); |
@@ -2367,7 +2567,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
2367 | if (skb == NULL) | 2567 | if (skb == NULL) |
2368 | return -EACCES; | 2568 | return -EACCES; |
2369 | 2569 | ||
2370 | memset(smack, '\0', SMK_LABELLEN); | ||
2371 | netlbl_secattr_init(&skb_secattr); | 2570 | netlbl_secattr_init(&skb_secattr); |
2372 | rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr); | 2571 | rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr); |
2373 | if (rc == 0) | 2572 | if (rc == 0) |
@@ -2732,6 +2931,8 @@ struct security_operations smack_ops = { | |||
2732 | .unix_may_send = smack_unix_may_send, | 2931 | .unix_may_send = smack_unix_may_send, |
2733 | 2932 | ||
2734 | .socket_post_create = smack_socket_post_create, | 2933 | .socket_post_create = smack_socket_post_create, |
2934 | .socket_connect = smack_socket_connect, | ||
2935 | .socket_sendmsg = smack_socket_sendmsg, | ||
2735 | .socket_sock_rcv_skb = smack_socket_sock_rcv_skb, | 2936 | .socket_sock_rcv_skb = smack_socket_sock_rcv_skb, |
2736 | .socket_getpeersec_stream = smack_socket_getpeersec_stream, | 2937 | .socket_getpeersec_stream = smack_socket_getpeersec_stream, |
2737 | .socket_getpeersec_dgram = smack_socket_getpeersec_dgram, | 2938 | .socket_getpeersec_dgram = smack_socket_getpeersec_dgram, |
@@ -2783,7 +2984,6 @@ static __init int smack_init(void) | |||
2783 | /* | 2984 | /* |
2784 | * Initialize locks | 2985 | * Initialize locks |
2785 | */ | 2986 | */ |
2786 | spin_lock_init(&smack_known_unset.smk_cipsolock); | ||
2787 | spin_lock_init(&smack_known_huh.smk_cipsolock); | 2987 | spin_lock_init(&smack_known_huh.smk_cipsolock); |
2788 | spin_lock_init(&smack_known_hat.smk_cipsolock); | 2988 | spin_lock_init(&smack_known_hat.smk_cipsolock); |
2789 | spin_lock_init(&smack_known_star.smk_cipsolock); | 2989 | spin_lock_init(&smack_known_star.smk_cipsolock); |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 247dc9ebbc7..bf107a389ac 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
21 | #include <linux/security.h> | 21 | #include <linux/security.h> |
22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <net/net_namespace.h> | ||
23 | #include <net/netlabel.h> | 24 | #include <net/netlabel.h> |
24 | #include <net/cipso_ipv4.h> | 25 | #include <net/cipso_ipv4.h> |
25 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
@@ -38,7 +39,7 @@ enum smk_inos { | |||
38 | SMK_DOI = 5, /* CIPSO DOI */ | 39 | SMK_DOI = 5, /* CIPSO DOI */ |
39 | SMK_DIRECT = 6, /* CIPSO level indicating direct label */ | 40 | SMK_DIRECT = 6, /* CIPSO level indicating direct label */ |
40 | SMK_AMBIENT = 7, /* internet ambient label */ | 41 | SMK_AMBIENT = 7, /* internet ambient label */ |
41 | SMK_NLTYPE = 8, /* label scheme to use by default */ | 42 | SMK_NETLBLADDR = 8, /* single label hosts */ |
42 | SMK_ONLYCAP = 9, /* the only "capable" label */ | 43 | SMK_ONLYCAP = 9, /* the only "capable" label */ |
43 | }; | 44 | }; |
44 | 45 | ||
@@ -48,6 +49,7 @@ enum smk_inos { | |||
48 | static DEFINE_MUTEX(smack_list_lock); | 49 | static DEFINE_MUTEX(smack_list_lock); |
49 | static DEFINE_MUTEX(smack_cipso_lock); | 50 | static DEFINE_MUTEX(smack_cipso_lock); |
50 | static DEFINE_MUTEX(smack_ambient_lock); | 51 | static DEFINE_MUTEX(smack_ambient_lock); |
52 | static DEFINE_MUTEX(smk_netlbladdr_lock); | ||
51 | 53 | ||
52 | /* | 54 | /* |
53 | * This is the "ambient" label for network traffic. | 55 | * This is the "ambient" label for network traffic. |
@@ -57,12 +59,6 @@ static DEFINE_MUTEX(smack_ambient_lock); | |||
57 | char *smack_net_ambient = smack_known_floor.smk_known; | 59 | char *smack_net_ambient = smack_known_floor.smk_known; |
58 | 60 | ||
59 | /* | 61 | /* |
60 | * This is the default packet marking scheme for network traffic. | ||
61 | * It can be reset via smackfs/nltype | ||
62 | */ | ||
63 | int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4; | ||
64 | |||
65 | /* | ||
66 | * This is the level in a CIPSO header that indicates a | 62 | * This is the level in a CIPSO header that indicates a |
67 | * smack label is contained directly in the category set. | 63 | * smack label is contained directly in the category set. |
68 | * It can be reset via smackfs/direct | 64 | * It can be reset via smackfs/direct |
@@ -79,6 +75,13 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; | |||
79 | */ | 75 | */ |
80 | char *smack_onlycap; | 76 | char *smack_onlycap; |
81 | 77 | ||
78 | /* | ||
79 | * Certain IP addresses may be designated as single label hosts. | ||
80 | * Packets are sent there unlabeled, but only from tasks that | ||
81 | * can write to the specified label. | ||
82 | */ | ||
83 | struct smk_netlbladdr *smack_netlbladdrs; | ||
84 | |||
82 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; | 85 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; |
83 | struct smk_list_entry *smack_list; | 86 | struct smk_list_entry *smack_list; |
84 | 87 | ||
@@ -104,6 +107,24 @@ struct smk_list_entry *smack_list; | |||
104 | #define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1) | 107 | #define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1) |
105 | #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) | 108 | #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) |
106 | 109 | ||
110 | /** | ||
111 | * smk_netlabel_audit_set - fill a netlbl_audit struct | ||
112 | * @nap: structure to fill | ||
113 | */ | ||
114 | static void smk_netlabel_audit_set(struct netlbl_audit *nap) | ||
115 | { | ||
116 | nap->loginuid = audit_get_loginuid(current); | ||
117 | nap->sessionid = audit_get_sessionid(current); | ||
118 | nap->secid = smack_to_secid(current_security()); | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * Values for parsing single label host rules | ||
123 | * "1.2.3.4 X" | ||
124 | * "192.168.138.129/32 abcdefghijklmnopqrstuvw" | ||
125 | */ | ||
126 | #define SMK_NETLBLADDRMIN 9 | ||
127 | #define SMK_NETLBLADDRMAX 42 | ||
107 | 128 | ||
108 | /* | 129 | /* |
109 | * Seq_file read operations for /smack/load | 130 | * Seq_file read operations for /smack/load |
@@ -344,13 +365,11 @@ static void smk_cipso_doi(void) | |||
344 | { | 365 | { |
345 | int rc; | 366 | int rc; |
346 | struct cipso_v4_doi *doip; | 367 | struct cipso_v4_doi *doip; |
347 | struct netlbl_audit audit_info; | 368 | struct netlbl_audit nai; |
348 | 369 | ||
349 | audit_info.loginuid = audit_get_loginuid(current); | 370 | smk_netlabel_audit_set(&nai); |
350 | audit_info.sessionid = audit_get_sessionid(current); | ||
351 | audit_info.secid = smack_to_secid(current_security()); | ||
352 | 371 | ||
353 | rc = netlbl_cfg_map_del(NULL, &audit_info); | 372 | rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai); |
354 | if (rc != 0) | 373 | if (rc != 0) |
355 | printk(KERN_WARNING "%s:%d remove rc = %d\n", | 374 | printk(KERN_WARNING "%s:%d remove rc = %d\n", |
356 | __func__, __LINE__, rc); | 375 | __func__, __LINE__, rc); |
@@ -365,11 +384,19 @@ static void smk_cipso_doi(void) | |||
365 | for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) | 384 | for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++) |
366 | doip->tags[rc] = CIPSO_V4_TAG_INVALID; | 385 | doip->tags[rc] = CIPSO_V4_TAG_INVALID; |
367 | 386 | ||
368 | rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info); | 387 | rc = netlbl_cfg_cipsov4_add(doip, &nai); |
369 | if (rc != 0) { | 388 | if (rc != 0) { |
370 | printk(KERN_WARNING "%s:%d add rc = %d\n", | 389 | printk(KERN_WARNING "%s:%d cipso add rc = %d\n", |
371 | __func__, __LINE__, rc); | 390 | __func__, __LINE__, rc); |
372 | kfree(doip); | 391 | kfree(doip); |
392 | return; | ||
393 | } | ||
394 | rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai); | ||
395 | if (rc != 0) { | ||
396 | printk(KERN_WARNING "%s:%d map add rc = %d\n", | ||
397 | __func__, __LINE__, rc); | ||
398 | kfree(doip); | ||
399 | return; | ||
373 | } | 400 | } |
374 | } | 401 | } |
375 | 402 | ||
@@ -379,20 +406,19 @@ static void smk_cipso_doi(void) | |||
379 | static void smk_unlbl_ambient(char *oldambient) | 406 | static void smk_unlbl_ambient(char *oldambient) |
380 | { | 407 | { |
381 | int rc; | 408 | int rc; |
382 | struct netlbl_audit audit_info; | 409 | struct netlbl_audit nai; |
383 | 410 | ||
384 | audit_info.loginuid = audit_get_loginuid(current); | 411 | smk_netlabel_audit_set(&nai); |
385 | audit_info.sessionid = audit_get_sessionid(current); | ||
386 | audit_info.secid = smack_to_secid(current_security()); | ||
387 | 412 | ||
388 | if (oldambient != NULL) { | 413 | if (oldambient != NULL) { |
389 | rc = netlbl_cfg_map_del(oldambient, &audit_info); | 414 | rc = netlbl_cfg_map_del(oldambient, PF_INET, NULL, NULL, &nai); |
390 | if (rc != 0) | 415 | if (rc != 0) |
391 | printk(KERN_WARNING "%s:%d remove rc = %d\n", | 416 | printk(KERN_WARNING "%s:%d remove rc = %d\n", |
392 | __func__, __LINE__, rc); | 417 | __func__, __LINE__, rc); |
393 | } | 418 | } |
394 | 419 | ||
395 | rc = netlbl_cfg_unlbl_add_map(smack_net_ambient, &audit_info); | 420 | rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET, |
421 | NULL, NULL, &nai); | ||
396 | if (rc != 0) | 422 | if (rc != 0) |
397 | printk(KERN_WARNING "%s:%d add rc = %d\n", | 423 | printk(KERN_WARNING "%s:%d add rc = %d\n", |
398 | __func__, __LINE__, rc); | 424 | __func__, __LINE__, rc); |
@@ -603,6 +629,201 @@ static const struct file_operations smk_cipso_ops = { | |||
603 | .release = seq_release, | 629 | .release = seq_release, |
604 | }; | 630 | }; |
605 | 631 | ||
632 | /* | ||
633 | * Seq_file read operations for /smack/netlabel | ||
634 | */ | ||
635 | |||
636 | static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos) | ||
637 | { | ||
638 | if (*pos == SEQ_READ_FINISHED) | ||
639 | return NULL; | ||
640 | |||
641 | return smack_netlbladdrs; | ||
642 | } | ||
643 | |||
644 | static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
645 | { | ||
646 | struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next; | ||
647 | |||
648 | if (skp == NULL) | ||
649 | *pos = SEQ_READ_FINISHED; | ||
650 | |||
651 | return skp; | ||
652 | } | ||
653 | /* | ||
654 | #define BEMASK 0x80000000 | ||
655 | */ | ||
656 | #define BEMASK 0x00000001 | ||
657 | #define BEBITS (sizeof(__be32) * 8) | ||
658 | |||
659 | /* | ||
660 | * Print host/label pairs | ||
661 | */ | ||
662 | static int netlbladdr_seq_show(struct seq_file *s, void *v) | ||
663 | { | ||
664 | struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v; | ||
665 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; | ||
666 | __be32 bebits; | ||
667 | int maskn = 0; | ||
668 | |||
669 | for (bebits = BEMASK; bebits != 0; maskn++, bebits <<= 1) | ||
670 | if ((skp->smk_mask.s_addr & bebits) == 0) | ||
671 | break; | ||
672 | |||
673 | seq_printf(s, "%u.%u.%u.%u/%d %s\n", | ||
674 | hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static void netlbladdr_seq_stop(struct seq_file *s, void *v) | ||
680 | { | ||
681 | /* No-op */ | ||
682 | } | ||
683 | |||
684 | static struct seq_operations netlbladdr_seq_ops = { | ||
685 | .start = netlbladdr_seq_start, | ||
686 | .stop = netlbladdr_seq_stop, | ||
687 | .next = netlbladdr_seq_next, | ||
688 | .show = netlbladdr_seq_show, | ||
689 | }; | ||
690 | |||
691 | /** | ||
692 | * smk_open_netlbladdr - open() for /smack/netlabel | ||
693 | * @inode: inode structure representing file | ||
694 | * @file: "netlabel" file pointer | ||
695 | * | ||
696 | * Connect our netlbladdr_seq_* operations with /smack/netlabel | ||
697 | * file_operations | ||
698 | */ | ||
699 | static int smk_open_netlbladdr(struct inode *inode, struct file *file) | ||
700 | { | ||
701 | return seq_open(file, &netlbladdr_seq_ops); | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * smk_write_netlbladdr - write() for /smack/netlabel | ||
706 | * @filp: file pointer, not actually used | ||
707 | * @buf: where to get the data from | ||
708 | * @count: bytes sent | ||
709 | * @ppos: where to start | ||
710 | * | ||
711 | * Accepts only one netlbladdr per write call. | ||
712 | * Returns number of bytes written or error code, as appropriate | ||
713 | */ | ||
714 | static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | ||
715 | size_t count, loff_t *ppos) | ||
716 | { | ||
717 | struct smk_netlbladdr *skp; | ||
718 | struct sockaddr_in newname; | ||
719 | char smack[SMK_LABELLEN]; | ||
720 | char *sp; | ||
721 | char data[SMK_NETLBLADDRMAX]; | ||
722 | char *host = (char *)&newname.sin_addr.s_addr; | ||
723 | int rc; | ||
724 | struct netlbl_audit audit_info; | ||
725 | struct in_addr mask; | ||
726 | unsigned int m; | ||
727 | __be32 bebits = BEMASK; | ||
728 | __be32 nsa; | ||
729 | |||
730 | /* | ||
731 | * Must have privilege. | ||
732 | * No partial writes. | ||
733 | * Enough data must be present. | ||
734 | * "<addr/mask, as a.b.c.d/e><space><label>" | ||
735 | * "<addr, as a.b.c.d><space><label>" | ||
736 | */ | ||
737 | if (!capable(CAP_MAC_ADMIN)) | ||
738 | return -EPERM; | ||
739 | if (*ppos != 0) | ||
740 | return -EINVAL; | ||
741 | if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX) | ||
742 | return -EINVAL; | ||
743 | if (copy_from_user(data, buf, count) != 0) | ||
744 | return -EFAULT; | ||
745 | |||
746 | data[count] = '\0'; | ||
747 | |||
748 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%d %s", | ||
749 | &host[0], &host[1], &host[2], &host[3], &m, smack); | ||
750 | if (rc != 6) { | ||
751 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", | ||
752 | &host[0], &host[1], &host[2], &host[3], smack); | ||
753 | if (rc != 5) | ||
754 | return -EINVAL; | ||
755 | m = BEBITS; | ||
756 | } | ||
757 | if (m > BEBITS) | ||
758 | return -EINVAL; | ||
759 | |||
760 | sp = smk_import(smack, 0); | ||
761 | if (sp == NULL) | ||
762 | return -EINVAL; | ||
763 | |||
764 | for (mask.s_addr = 0; m > 0; m--) { | ||
765 | mask.s_addr |= bebits; | ||
766 | bebits <<= 1; | ||
767 | } | ||
768 | /* | ||
769 | * Only allow one writer at a time. Writes should be | ||
770 | * quite rare and small in any case. | ||
771 | */ | ||
772 | mutex_lock(&smk_netlbladdr_lock); | ||
773 | |||
774 | nsa = newname.sin_addr.s_addr; | ||
775 | for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next) | ||
776 | if (skp->smk_host.sin_addr.s_addr == nsa && | ||
777 | skp->smk_mask.s_addr == mask.s_addr) | ||
778 | break; | ||
779 | |||
780 | smk_netlabel_audit_set(&audit_info); | ||
781 | |||
782 | if (skp == NULL) { | ||
783 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); | ||
784 | if (skp == NULL) | ||
785 | rc = -ENOMEM; | ||
786 | else { | ||
787 | rc = 0; | ||
788 | skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; | ||
789 | skp->smk_mask.s_addr = mask.s_addr; | ||
790 | skp->smk_next = smack_netlbladdrs; | ||
791 | skp->smk_label = sp; | ||
792 | smack_netlbladdrs = skp; | ||
793 | } | ||
794 | } else { | ||
795 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, | ||
796 | &skp->smk_host.sin_addr, &skp->smk_mask, | ||
797 | PF_INET, &audit_info); | ||
798 | skp->smk_label = sp; | ||
799 | } | ||
800 | |||
801 | /* | ||
802 | * Now tell netlabel about the single label nature of | ||
803 | * this host so that incoming packets get labeled. | ||
804 | */ | ||
805 | |||
806 | if (rc == 0) | ||
807 | rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, | ||
808 | &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET, | ||
809 | smack_to_secid(skp->smk_label), &audit_info); | ||
810 | |||
811 | if (rc == 0) | ||
812 | rc = count; | ||
813 | |||
814 | mutex_unlock(&smk_netlbladdr_lock); | ||
815 | |||
816 | return rc; | ||
817 | } | ||
818 | |||
819 | static const struct file_operations smk_netlbladdr_ops = { | ||
820 | .open = smk_open_netlbladdr, | ||
821 | .read = seq_read, | ||
822 | .llseek = seq_lseek, | ||
823 | .write = smk_write_netlbladdr, | ||
824 | .release = seq_release, | ||
825 | }; | ||
826 | |||
606 | /** | 827 | /** |
607 | * smk_read_doi - read() for /smack/doi | 828 | * smk_read_doi - read() for /smack/doi |
608 | * @filp: file pointer, not actually used | 829 | * @filp: file pointer, not actually used |
@@ -891,110 +1112,6 @@ static const struct file_operations smk_onlycap_ops = { | |||
891 | .write = smk_write_onlycap, | 1112 | .write = smk_write_onlycap, |
892 | }; | 1113 | }; |
893 | 1114 | ||
894 | struct option_names { | ||
895 | int o_number; | ||
896 | char *o_name; | ||
897 | char *o_alias; | ||
898 | }; | ||
899 | |||
900 | static struct option_names netlbl_choices[] = { | ||
901 | { NETLBL_NLTYPE_RIPSO, | ||
902 | NETLBL_NLTYPE_RIPSO_NAME, "ripso" }, | ||
903 | { NETLBL_NLTYPE_CIPSOV4, | ||
904 | NETLBL_NLTYPE_CIPSOV4_NAME, "cipsov4" }, | ||
905 | { NETLBL_NLTYPE_CIPSOV4, | ||
906 | NETLBL_NLTYPE_CIPSOV4_NAME, "cipso" }, | ||
907 | { NETLBL_NLTYPE_CIPSOV6, | ||
908 | NETLBL_NLTYPE_CIPSOV6_NAME, "cipsov6" }, | ||
909 | { NETLBL_NLTYPE_UNLABELED, | ||
910 | NETLBL_NLTYPE_UNLABELED_NAME, "unlabeled" }, | ||
911 | }; | ||
912 | |||
913 | /** | ||
914 | * smk_read_nltype - read() for /smack/nltype | ||
915 | * @filp: file pointer, not actually used | ||
916 | * @buf: where to put the result | ||
917 | * @count: maximum to send along | ||
918 | * @ppos: where to start | ||
919 | * | ||
920 | * Returns number of bytes read or error code, as appropriate | ||
921 | */ | ||
922 | static ssize_t smk_read_nltype(struct file *filp, char __user *buf, | ||
923 | size_t count, loff_t *ppos) | ||
924 | { | ||
925 | char bound[40]; | ||
926 | ssize_t rc; | ||
927 | int i; | ||
928 | |||
929 | if (count < SMK_LABELLEN) | ||
930 | return -EINVAL; | ||
931 | |||
932 | if (*ppos != 0) | ||
933 | return 0; | ||
934 | |||
935 | sprintf(bound, "unknown"); | ||
936 | |||
937 | for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++) | ||
938 | if (smack_net_nltype == netlbl_choices[i].o_number) { | ||
939 | sprintf(bound, "%s", netlbl_choices[i].o_name); | ||
940 | break; | ||
941 | } | ||
942 | |||
943 | rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound)); | ||
944 | |||
945 | return rc; | ||
946 | } | ||
947 | |||
948 | /** | ||
949 | * smk_write_nltype - write() for /smack/nltype | ||
950 | * @filp: file pointer, not actually used | ||
951 | * @buf: where to get the data from | ||
952 | * @count: bytes sent | ||
953 | * @ppos: where to start | ||
954 | * | ||
955 | * Returns number of bytes written or error code, as appropriate | ||
956 | */ | ||
957 | static ssize_t smk_write_nltype(struct file *file, const char __user *buf, | ||
958 | size_t count, loff_t *ppos) | ||
959 | { | ||
960 | char bound[40]; | ||
961 | char *cp; | ||
962 | int i; | ||
963 | |||
964 | if (!capable(CAP_MAC_ADMIN)) | ||
965 | return -EPERM; | ||
966 | |||
967 | if (count >= 40) | ||
968 | return -EINVAL; | ||
969 | |||
970 | if (copy_from_user(bound, buf, count) != 0) | ||
971 | return -EFAULT; | ||
972 | |||
973 | bound[count] = '\0'; | ||
974 | cp = strchr(bound, ' '); | ||
975 | if (cp != NULL) | ||
976 | *cp = '\0'; | ||
977 | cp = strchr(bound, '\n'); | ||
978 | if (cp != NULL) | ||
979 | *cp = '\0'; | ||
980 | |||
981 | for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++) | ||
982 | if (strcmp(bound, netlbl_choices[i].o_name) == 0 || | ||
983 | strcmp(bound, netlbl_choices[i].o_alias) == 0) { | ||
984 | smack_net_nltype = netlbl_choices[i].o_number; | ||
985 | return count; | ||
986 | } | ||
987 | /* | ||
988 | * Not a valid choice. | ||
989 | */ | ||
990 | return -EINVAL; | ||
991 | } | ||
992 | |||
993 | static const struct file_operations smk_nltype_ops = { | ||
994 | .read = smk_read_nltype, | ||
995 | .write = smk_write_nltype, | ||
996 | }; | ||
997 | |||
998 | /** | 1115 | /** |
999 | * smk_fill_super - fill the /smackfs superblock | 1116 | * smk_fill_super - fill the /smackfs superblock |
1000 | * @sb: the empty superblock | 1117 | * @sb: the empty superblock |
@@ -1021,8 +1138,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
1021 | {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, | 1138 | {"direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, |
1022 | [SMK_AMBIENT] = | 1139 | [SMK_AMBIENT] = |
1023 | {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, | 1140 | {"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, |
1024 | [SMK_NLTYPE] = | 1141 | [SMK_NETLBLADDR] = |
1025 | {"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR}, | 1142 | {"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR}, |
1026 | [SMK_ONLYCAP] = | 1143 | [SMK_ONLYCAP] = |
1027 | {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, | 1144 | {"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, |
1028 | /* last one */ {""} | 1145 | /* last one */ {""} |