diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-08 15:41:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-08 15:41:25 -0400 |
commit | b793c005ceabf6db0b17494b0ec67ade6796bb34 (patch) | |
tree | 080c884f04254403ec9564742f591a9fd9b7e95a /security | |
parent | 6f0a2fc1feb19bd142961a39dc118e7e55418b3f (diff) | |
parent | 07f081fb5057b2ea98baeca3a47bf0eb33e94aa1 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"Highlights:
- PKCS#7 support added to support signed kexec, also utilized for
module signing. See comments in 3f1e1bea.
** NOTE: this requires linking against the OpenSSL library, which
must be installed, e.g. the openssl-devel on Fedora **
- Smack
- add IPv6 host labeling; ignore labels on kernel threads
- support smack labeling mounts which use binary mount data
- SELinux:
- add ioctl whitelisting (see
http://kernsec.org/files/lss2015/vanderstoep.pdf)
- fix mprotect PROT_EXEC regression caused by mm change
- Seccomp:
- add ptrace options for suspend/resume"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (57 commits)
PKCS#7: Add OIDs for sha224, sha284 and sha512 hash algos and use them
Documentation/Changes: Now need OpenSSL devel packages for module signing
scripts: add extract-cert and sign-file to .gitignore
modsign: Handle signing key in source tree
modsign: Use if_changed rule for extracting cert from module signing key
Move certificate handling to its own directory
sign-file: Fix warning about BIO_reset() return value
PKCS#7: Add MODULE_LICENSE() to test module
Smack - Fix build error with bringup unconfigured
sign-file: Document dependency on OpenSSL devel libraries
PKCS#7: Appropriately restrict authenticated attributes and content type
KEYS: Add a name for PKEY_ID_PKCS7
PKCS#7: Improve and export the X.509 ASN.1 time object decoder
modsign: Use extract-cert to process CONFIG_SYSTEM_TRUSTED_KEYS
extract-cert: Cope with multiple X.509 certificates in a single file
sign-file: Generate CMS message as signature instead of PKCS#7
PKCS#7: Support CMS messages also [RFC5652]
X.509: Change recorded SKID & AKID to not include Subject or Issuer
PKCS#7: Check content type and versions
MAINTAINERS: The keyrings mailing list has moved
...
Diffstat (limited to 'security')
-rw-r--r-- | security/Kconfig | 5 | ||||
-rw-r--r-- | security/lsm_audit.c | 15 | ||||
-rw-r--r-- | security/security.c | 11 | ||||
-rw-r--r-- | security/selinux/avc.c | 418 | ||||
-rw-r--r-- | security/selinux/hooks.c | 147 | ||||
-rw-r--r-- | security/selinux/include/avc.h | 6 | ||||
-rw-r--r-- | security/selinux/include/security.h | 32 | ||||
-rw-r--r-- | security/selinux/ss/avtab.c | 104 | ||||
-rw-r--r-- | security/selinux/ss/avtab.h | 33 | ||||
-rw-r--r-- | security/selinux/ss/conditional.c | 32 | ||||
-rw-r--r-- | security/selinux/ss/conditional.h | 6 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 5 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 213 | ||||
-rw-r--r-- | security/selinux/ss/services.h | 6 | ||||
-rw-r--r-- | security/smack/smack.h | 66 | ||||
-rw-r--r-- | security/smack/smack_access.c | 6 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 511 | ||||
-rw-r--r-- | security/smack/smackfs.c | 436 | ||||
-rw-r--r-- | security/yama/Kconfig | 9 | ||||
-rw-r--r-- | security/yama/yama_lsm.c | 33 |
20 files changed, 1732 insertions, 362 deletions
diff --git a/security/Kconfig b/security/Kconfig index bf4ec46474b6..e45237897b43 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -132,7 +132,6 @@ choice | |||
132 | default DEFAULT_SECURITY_SMACK if SECURITY_SMACK | 132 | default DEFAULT_SECURITY_SMACK if SECURITY_SMACK |
133 | default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO | 133 | default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO |
134 | default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR | 134 | default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR |
135 | default DEFAULT_SECURITY_YAMA if SECURITY_YAMA | ||
136 | default DEFAULT_SECURITY_DAC | 135 | default DEFAULT_SECURITY_DAC |
137 | 136 | ||
138 | help | 137 | help |
@@ -151,9 +150,6 @@ choice | |||
151 | config DEFAULT_SECURITY_APPARMOR | 150 | config DEFAULT_SECURITY_APPARMOR |
152 | bool "AppArmor" if SECURITY_APPARMOR=y | 151 | bool "AppArmor" if SECURITY_APPARMOR=y |
153 | 152 | ||
154 | config DEFAULT_SECURITY_YAMA | ||
155 | bool "Yama" if SECURITY_YAMA=y | ||
156 | |||
157 | config DEFAULT_SECURITY_DAC | 153 | config DEFAULT_SECURITY_DAC |
158 | bool "Unix Discretionary Access Controls" | 154 | bool "Unix Discretionary Access Controls" |
159 | 155 | ||
@@ -165,7 +161,6 @@ config DEFAULT_SECURITY | |||
165 | default "smack" if DEFAULT_SECURITY_SMACK | 161 | default "smack" if DEFAULT_SECURITY_SMACK |
166 | default "tomoyo" if DEFAULT_SECURITY_TOMOYO | 162 | default "tomoyo" if DEFAULT_SECURITY_TOMOYO |
167 | default "apparmor" if DEFAULT_SECURITY_APPARMOR | 163 | default "apparmor" if DEFAULT_SECURITY_APPARMOR |
168 | default "yama" if DEFAULT_SECURITY_YAMA | ||
169 | default "" if DEFAULT_SECURITY_DAC | 164 | default "" if DEFAULT_SECURITY_DAC |
170 | 165 | ||
171 | endmenu | 166 | endmenu |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 4ed98107ace3..cccbf3068cdc 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c | |||
@@ -245,6 +245,21 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
245 | } | 245 | } |
246 | break; | 246 | break; |
247 | } | 247 | } |
248 | case LSM_AUDIT_DATA_IOCTL_OP: { | ||
249 | struct inode *inode; | ||
250 | |||
251 | audit_log_d_path(ab, " path=", &a->u.op->path); | ||
252 | |||
253 | inode = a->u.op->path.dentry->d_inode; | ||
254 | if (inode) { | ||
255 | audit_log_format(ab, " dev="); | ||
256 | audit_log_untrustedstring(ab, inode->i_sb->s_id); | ||
257 | audit_log_format(ab, " ino=%lu", inode->i_ino); | ||
258 | } | ||
259 | |||
260 | audit_log_format(ab, " ioctlcmd=%hx", a->u.op->cmd); | ||
261 | break; | ||
262 | } | ||
248 | case LSM_AUDIT_DATA_DENTRY: { | 263 | case LSM_AUDIT_DATA_DENTRY: { |
249 | struct inode *inode; | 264 | struct inode *inode; |
250 | 265 | ||
diff --git a/security/security.c b/security/security.c index 75b85fdc4e97..46f405ce6b0f 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -56,18 +56,13 @@ int __init security_init(void) | |||
56 | pr_info("Security Framework initialized\n"); | 56 | pr_info("Security Framework initialized\n"); |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Always load the capability module. | 59 | * Load minor LSMs, with the capability module always first. |
60 | */ | 60 | */ |
61 | capability_add_hooks(); | 61 | capability_add_hooks(); |
62 | #ifdef CONFIG_SECURITY_YAMA_STACKED | ||
63 | /* | ||
64 | * If Yama is configured for stacking load it next. | ||
65 | */ | ||
66 | yama_add_hooks(); | 62 | yama_add_hooks(); |
67 | #endif | 63 | |
68 | /* | 64 | /* |
69 | * Load the chosen module if there is one. | 65 | * Load all the remaining security modules. |
70 | * This will also find yama if it is stacking | ||
71 | */ | 66 | */ |
72 | do_security_initcalls(); | 67 | do_security_initcalls(); |
73 | 68 | ||
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 0b122b1421a9..e60c79de13e1 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/skbuff.h> | 23 | #include <linux/skbuff.h> |
24 | #include <linux/percpu.h> | 24 | #include <linux/percpu.h> |
25 | #include <linux/list.h> | ||
25 | #include <net/sock.h> | 26 | #include <net/sock.h> |
26 | #include <linux/un.h> | 27 | #include <linux/un.h> |
27 | #include <net/af_unix.h> | 28 | #include <net/af_unix.h> |
@@ -48,6 +49,7 @@ struct avc_entry { | |||
48 | u32 tsid; | 49 | u32 tsid; |
49 | u16 tclass; | 50 | u16 tclass; |
50 | struct av_decision avd; | 51 | struct av_decision avd; |
52 | struct avc_xperms_node *xp_node; | ||
51 | }; | 53 | }; |
52 | 54 | ||
53 | struct avc_node { | 55 | struct avc_node { |
@@ -56,6 +58,16 @@ struct avc_node { | |||
56 | struct rcu_head rhead; | 58 | struct rcu_head rhead; |
57 | }; | 59 | }; |
58 | 60 | ||
61 | struct avc_xperms_decision_node { | ||
62 | struct extended_perms_decision xpd; | ||
63 | struct list_head xpd_list; /* list of extended_perms_decision */ | ||
64 | }; | ||
65 | |||
66 | struct avc_xperms_node { | ||
67 | struct extended_perms xp; | ||
68 | struct list_head xpd_head; /* list head of extended_perms_decision */ | ||
69 | }; | ||
70 | |||
59 | struct avc_cache { | 71 | struct avc_cache { |
60 | struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ | 72 | struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ |
61 | spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ | 73 | spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ |
@@ -80,6 +92,9 @@ DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; | |||
80 | static struct avc_cache avc_cache; | 92 | static struct avc_cache avc_cache; |
81 | static struct avc_callback_node *avc_callbacks; | 93 | static struct avc_callback_node *avc_callbacks; |
82 | static struct kmem_cache *avc_node_cachep; | 94 | static struct kmem_cache *avc_node_cachep; |
95 | static struct kmem_cache *avc_xperms_data_cachep; | ||
96 | static struct kmem_cache *avc_xperms_decision_cachep; | ||
97 | static struct kmem_cache *avc_xperms_cachep; | ||
83 | 98 | ||
84 | static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) | 99 | static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) |
85 | { | 100 | { |
@@ -101,6 +116,7 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) | |||
101 | return; | 116 | return; |
102 | } | 117 | } |
103 | 118 | ||
119 | BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); | ||
104 | perms = secclass_map[tclass-1].perms; | 120 | perms = secclass_map[tclass-1].perms; |
105 | 121 | ||
106 | audit_log_format(ab, " {"); | 122 | audit_log_format(ab, " {"); |
@@ -149,7 +165,7 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla | |||
149 | kfree(scontext); | 165 | kfree(scontext); |
150 | } | 166 | } |
151 | 167 | ||
152 | BUG_ON(tclass >= ARRAY_SIZE(secclass_map)); | 168 | BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); |
153 | audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name); | 169 | audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name); |
154 | } | 170 | } |
155 | 171 | ||
@@ -170,7 +186,17 @@ void __init avc_init(void) | |||
170 | atomic_set(&avc_cache.lru_hint, 0); | 186 | atomic_set(&avc_cache.lru_hint, 0); |
171 | 187 | ||
172 | avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), | 188 | avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), |
173 | 0, SLAB_PANIC, NULL); | 189 | 0, SLAB_PANIC, NULL); |
190 | avc_xperms_cachep = kmem_cache_create("avc_xperms_node", | ||
191 | sizeof(struct avc_xperms_node), | ||
192 | 0, SLAB_PANIC, NULL); | ||
193 | avc_xperms_decision_cachep = kmem_cache_create( | ||
194 | "avc_xperms_decision_node", | ||
195 | sizeof(struct avc_xperms_decision_node), | ||
196 | 0, SLAB_PANIC, NULL); | ||
197 | avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data", | ||
198 | sizeof(struct extended_perms_data), | ||
199 | 0, SLAB_PANIC, NULL); | ||
174 | 200 | ||
175 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); | 201 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); |
176 | } | 202 | } |
@@ -205,9 +231,261 @@ int avc_get_hash_stats(char *page) | |||
205 | slots_used, AVC_CACHE_SLOTS, max_chain_len); | 231 | slots_used, AVC_CACHE_SLOTS, max_chain_len); |
206 | } | 232 | } |
207 | 233 | ||
234 | /* | ||
235 | * using a linked list for extended_perms_decision lookup because the list is | ||
236 | * always small. i.e. less than 5, typically 1 | ||
237 | */ | ||
238 | static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver, | ||
239 | struct avc_xperms_node *xp_node) | ||
240 | { | ||
241 | struct avc_xperms_decision_node *xpd_node; | ||
242 | |||
243 | list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) { | ||
244 | if (xpd_node->xpd.driver == driver) | ||
245 | return &xpd_node->xpd; | ||
246 | } | ||
247 | return NULL; | ||
248 | } | ||
249 | |||
250 | static inline unsigned int | ||
251 | avc_xperms_has_perm(struct extended_perms_decision *xpd, | ||
252 | u8 perm, u8 which) | ||
253 | { | ||
254 | unsigned int rc = 0; | ||
255 | |||
256 | if ((which == XPERMS_ALLOWED) && | ||
257 | (xpd->used & XPERMS_ALLOWED)) | ||
258 | rc = security_xperm_test(xpd->allowed->p, perm); | ||
259 | else if ((which == XPERMS_AUDITALLOW) && | ||
260 | (xpd->used & XPERMS_AUDITALLOW)) | ||
261 | rc = security_xperm_test(xpd->auditallow->p, perm); | ||
262 | else if ((which == XPERMS_DONTAUDIT) && | ||
263 | (xpd->used & XPERMS_DONTAUDIT)) | ||
264 | rc = security_xperm_test(xpd->dontaudit->p, perm); | ||
265 | return rc; | ||
266 | } | ||
267 | |||
268 | static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node, | ||
269 | u8 driver, u8 perm) | ||
270 | { | ||
271 | struct extended_perms_decision *xpd; | ||
272 | security_xperm_set(xp_node->xp.drivers.p, driver); | ||
273 | xpd = avc_xperms_decision_lookup(driver, xp_node); | ||
274 | if (xpd && xpd->allowed) | ||
275 | security_xperm_set(xpd->allowed->p, perm); | ||
276 | } | ||
277 | |||
278 | static void avc_xperms_decision_free(struct avc_xperms_decision_node *xpd_node) | ||
279 | { | ||
280 | struct extended_perms_decision *xpd; | ||
281 | |||
282 | xpd = &xpd_node->xpd; | ||
283 | if (xpd->allowed) | ||
284 | kmem_cache_free(avc_xperms_data_cachep, xpd->allowed); | ||
285 | if (xpd->auditallow) | ||
286 | kmem_cache_free(avc_xperms_data_cachep, xpd->auditallow); | ||
287 | if (xpd->dontaudit) | ||
288 | kmem_cache_free(avc_xperms_data_cachep, xpd->dontaudit); | ||
289 | kmem_cache_free(avc_xperms_decision_cachep, xpd_node); | ||
290 | } | ||
291 | |||
292 | static void avc_xperms_free(struct avc_xperms_node *xp_node) | ||
293 | { | ||
294 | struct avc_xperms_decision_node *xpd_node, *tmp; | ||
295 | |||
296 | if (!xp_node) | ||
297 | return; | ||
298 | |||
299 | list_for_each_entry_safe(xpd_node, tmp, &xp_node->xpd_head, xpd_list) { | ||
300 | list_del(&xpd_node->xpd_list); | ||
301 | avc_xperms_decision_free(xpd_node); | ||
302 | } | ||
303 | kmem_cache_free(avc_xperms_cachep, xp_node); | ||
304 | } | ||
305 | |||
306 | static void avc_copy_xperms_decision(struct extended_perms_decision *dest, | ||
307 | struct extended_perms_decision *src) | ||
308 | { | ||
309 | dest->driver = src->driver; | ||
310 | dest->used = src->used; | ||
311 | if (dest->used & XPERMS_ALLOWED) | ||
312 | memcpy(dest->allowed->p, src->allowed->p, | ||
313 | sizeof(src->allowed->p)); | ||
314 | if (dest->used & XPERMS_AUDITALLOW) | ||
315 | memcpy(dest->auditallow->p, src->auditallow->p, | ||
316 | sizeof(src->auditallow->p)); | ||
317 | if (dest->used & XPERMS_DONTAUDIT) | ||
318 | memcpy(dest->dontaudit->p, src->dontaudit->p, | ||
319 | sizeof(src->dontaudit->p)); | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * similar to avc_copy_xperms_decision, but only copy decision | ||
324 | * information relevant to this perm | ||
325 | */ | ||
326 | static inline void avc_quick_copy_xperms_decision(u8 perm, | ||
327 | struct extended_perms_decision *dest, | ||
328 | struct extended_perms_decision *src) | ||
329 | { | ||
330 | /* | ||
331 | * compute index of the u32 of the 256 bits (8 u32s) that contain this | ||
332 | * command permission | ||
333 | */ | ||
334 | u8 i = perm >> 5; | ||
335 | |||
336 | dest->used = src->used; | ||
337 | if (dest->used & XPERMS_ALLOWED) | ||
338 | dest->allowed->p[i] = src->allowed->p[i]; | ||
339 | if (dest->used & XPERMS_AUDITALLOW) | ||
340 | dest->auditallow->p[i] = src->auditallow->p[i]; | ||
341 | if (dest->used & XPERMS_DONTAUDIT) | ||
342 | dest->dontaudit->p[i] = src->dontaudit->p[i]; | ||
343 | } | ||
344 | |||
345 | static struct avc_xperms_decision_node | ||
346 | *avc_xperms_decision_alloc(u8 which) | ||
347 | { | ||
348 | struct avc_xperms_decision_node *xpd_node; | ||
349 | struct extended_perms_decision *xpd; | ||
350 | |||
351 | xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, | ||
352 | GFP_ATOMIC | __GFP_NOMEMALLOC); | ||
353 | if (!xpd_node) | ||
354 | return NULL; | ||
355 | |||
356 | xpd = &xpd_node->xpd; | ||
357 | if (which & XPERMS_ALLOWED) { | ||
358 | xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep, | ||
359 | GFP_ATOMIC | __GFP_NOMEMALLOC); | ||
360 | if (!xpd->allowed) | ||
361 | goto error; | ||
362 | } | ||
363 | if (which & XPERMS_AUDITALLOW) { | ||
364 | xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep, | ||
365 | GFP_ATOMIC | __GFP_NOMEMALLOC); | ||
366 | if (!xpd->auditallow) | ||
367 | goto error; | ||
368 | } | ||
369 | if (which & XPERMS_DONTAUDIT) { | ||
370 | xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep, | ||
371 | GFP_ATOMIC | __GFP_NOMEMALLOC); | ||
372 | if (!xpd->dontaudit) | ||
373 | goto error; | ||
374 | } | ||
375 | return xpd_node; | ||
376 | error: | ||
377 | avc_xperms_decision_free(xpd_node); | ||
378 | return NULL; | ||
379 | } | ||
380 | |||
381 | static int avc_add_xperms_decision(struct avc_node *node, | ||
382 | struct extended_perms_decision *src) | ||
383 | { | ||
384 | struct avc_xperms_decision_node *dest_xpd; | ||
385 | |||
386 | node->ae.xp_node->xp.len++; | ||
387 | dest_xpd = avc_xperms_decision_alloc(src->used); | ||
388 | if (!dest_xpd) | ||
389 | return -ENOMEM; | ||
390 | avc_copy_xperms_decision(&dest_xpd->xpd, src); | ||
391 | list_add(&dest_xpd->xpd_list, &node->ae.xp_node->xpd_head); | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static struct avc_xperms_node *avc_xperms_alloc(void) | ||
396 | { | ||
397 | struct avc_xperms_node *xp_node; | ||
398 | |||
399 | xp_node = kmem_cache_zalloc(avc_xperms_cachep, | ||
400 | GFP_ATOMIC|__GFP_NOMEMALLOC); | ||
401 | if (!xp_node) | ||
402 | return xp_node; | ||
403 | INIT_LIST_HEAD(&xp_node->xpd_head); | ||
404 | return xp_node; | ||
405 | } | ||
406 | |||
407 | static int avc_xperms_populate(struct avc_node *node, | ||
408 | struct avc_xperms_node *src) | ||
409 | { | ||
410 | struct avc_xperms_node *dest; | ||
411 | struct avc_xperms_decision_node *dest_xpd; | ||
412 | struct avc_xperms_decision_node *src_xpd; | ||
413 | |||
414 | if (src->xp.len == 0) | ||
415 | return 0; | ||
416 | dest = avc_xperms_alloc(); | ||
417 | if (!dest) | ||
418 | return -ENOMEM; | ||
419 | |||
420 | memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p)); | ||
421 | dest->xp.len = src->xp.len; | ||
422 | |||
423 | /* for each source xpd allocate a destination xpd and copy */ | ||
424 | list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) { | ||
425 | dest_xpd = avc_xperms_decision_alloc(src_xpd->xpd.used); | ||
426 | if (!dest_xpd) | ||
427 | goto error; | ||
428 | avc_copy_xperms_decision(&dest_xpd->xpd, &src_xpd->xpd); | ||
429 | list_add(&dest_xpd->xpd_list, &dest->xpd_head); | ||
430 | } | ||
431 | node->ae.xp_node = dest; | ||
432 | return 0; | ||
433 | error: | ||
434 | avc_xperms_free(dest); | ||
435 | return -ENOMEM; | ||
436 | |||
437 | } | ||
438 | |||
439 | static inline u32 avc_xperms_audit_required(u32 requested, | ||
440 | struct av_decision *avd, | ||
441 | struct extended_perms_decision *xpd, | ||
442 | u8 perm, | ||
443 | int result, | ||
444 | u32 *deniedp) | ||
445 | { | ||
446 | u32 denied, audited; | ||
447 | |||
448 | denied = requested & ~avd->allowed; | ||
449 | if (unlikely(denied)) { | ||
450 | audited = denied & avd->auditdeny; | ||
451 | if (audited && xpd) { | ||
452 | if (avc_xperms_has_perm(xpd, perm, XPERMS_DONTAUDIT)) | ||
453 | audited &= ~requested; | ||
454 | } | ||
455 | } else if (result) { | ||
456 | audited = denied = requested; | ||
457 | } else { | ||
458 | audited = requested & avd->auditallow; | ||
459 | if (audited && xpd) { | ||
460 | if (!avc_xperms_has_perm(xpd, perm, XPERMS_AUDITALLOW)) | ||
461 | audited &= ~requested; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | *deniedp = denied; | ||
466 | return audited; | ||
467 | } | ||
468 | |||
469 | static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, | ||
470 | u32 requested, struct av_decision *avd, | ||
471 | struct extended_perms_decision *xpd, | ||
472 | u8 perm, int result, | ||
473 | struct common_audit_data *ad) | ||
474 | { | ||
475 | u32 audited, denied; | ||
476 | |||
477 | audited = avc_xperms_audit_required( | ||
478 | requested, avd, xpd, perm, result, &denied); | ||
479 | if (likely(!audited)) | ||
480 | return 0; | ||
481 | return slow_avc_audit(ssid, tsid, tclass, requested, | ||
482 | audited, denied, result, ad, 0); | ||
483 | } | ||
484 | |||
208 | static void avc_node_free(struct rcu_head *rhead) | 485 | static void avc_node_free(struct rcu_head *rhead) |
209 | { | 486 | { |
210 | struct avc_node *node = container_of(rhead, struct avc_node, rhead); | 487 | struct avc_node *node = container_of(rhead, struct avc_node, rhead); |
488 | avc_xperms_free(node->ae.xp_node); | ||
211 | kmem_cache_free(avc_node_cachep, node); | 489 | kmem_cache_free(avc_node_cachep, node); |
212 | avc_cache_stats_incr(frees); | 490 | avc_cache_stats_incr(frees); |
213 | } | 491 | } |
@@ -221,6 +499,7 @@ static void avc_node_delete(struct avc_node *node) | |||
221 | 499 | ||
222 | static void avc_node_kill(struct avc_node *node) | 500 | static void avc_node_kill(struct avc_node *node) |
223 | { | 501 | { |
502 | avc_xperms_free(node->ae.xp_node); | ||
224 | kmem_cache_free(avc_node_cachep, node); | 503 | kmem_cache_free(avc_node_cachep, node); |
225 | avc_cache_stats_incr(frees); | 504 | avc_cache_stats_incr(frees); |
226 | atomic_dec(&avc_cache.active_nodes); | 505 | atomic_dec(&avc_cache.active_nodes); |
@@ -367,6 +646,7 @@ static int avc_latest_notif_update(int seqno, int is_insert) | |||
367 | * @tsid: target security identifier | 646 | * @tsid: target security identifier |
368 | * @tclass: target security class | 647 | * @tclass: target security class |
369 | * @avd: resulting av decision | 648 | * @avd: resulting av decision |
649 | * @xp_node: resulting extended permissions | ||
370 | * | 650 | * |
371 | * Insert an AVC entry for the SID pair | 651 | * Insert an AVC entry for the SID pair |
372 | * (@ssid, @tsid) and class @tclass. | 652 | * (@ssid, @tsid) and class @tclass. |
@@ -378,7 +658,9 @@ static int avc_latest_notif_update(int seqno, int is_insert) | |||
378 | * the access vectors into a cache entry, returns | 658 | * the access vectors into a cache entry, returns |
379 | * avc_node inserted. Otherwise, this function returns NULL. | 659 | * avc_node inserted. Otherwise, this function returns NULL. |
380 | */ | 660 | */ |
381 | static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) | 661 | static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, |
662 | struct av_decision *avd, | ||
663 | struct avc_xperms_node *xp_node) | ||
382 | { | 664 | { |
383 | struct avc_node *pos, *node = NULL; | 665 | struct avc_node *pos, *node = NULL; |
384 | int hvalue; | 666 | int hvalue; |
@@ -391,10 +673,15 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_dec | |||
391 | if (node) { | 673 | if (node) { |
392 | struct hlist_head *head; | 674 | struct hlist_head *head; |
393 | spinlock_t *lock; | 675 | spinlock_t *lock; |
676 | int rc = 0; | ||
394 | 677 | ||
395 | hvalue = avc_hash(ssid, tsid, tclass); | 678 | hvalue = avc_hash(ssid, tsid, tclass); |
396 | avc_node_populate(node, ssid, tsid, tclass, avd); | 679 | avc_node_populate(node, ssid, tsid, tclass, avd); |
397 | 680 | rc = avc_xperms_populate(node, xp_node); | |
681 | if (rc) { | ||
682 | kmem_cache_free(avc_node_cachep, node); | ||
683 | return NULL; | ||
684 | } | ||
398 | head = &avc_cache.slots[hvalue]; | 685 | head = &avc_cache.slots[hvalue]; |
399 | lock = &avc_cache.slots_lock[hvalue]; | 686 | lock = &avc_cache.slots_lock[hvalue]; |
400 | 687 | ||
@@ -523,14 +810,17 @@ out: | |||
523 | * @perms : Permission mask bits | 810 | * @perms : Permission mask bits |
524 | * @ssid,@tsid,@tclass : identifier of an AVC entry | 811 | * @ssid,@tsid,@tclass : identifier of an AVC entry |
525 | * @seqno : sequence number when decision was made | 812 | * @seqno : sequence number when decision was made |
813 | * @xpd: extended_perms_decision to be added to the node | ||
526 | * | 814 | * |
527 | * if a valid AVC entry doesn't exist,this function returns -ENOENT. | 815 | * if a valid AVC entry doesn't exist,this function returns -ENOENT. |
528 | * if kmalloc() called internal returns NULL, this function returns -ENOMEM. | 816 | * if kmalloc() called internal returns NULL, this function returns -ENOMEM. |
529 | * otherwise, this function updates the AVC entry. The original AVC-entry object | 817 | * otherwise, this function updates the AVC entry. The original AVC-entry object |
530 | * will release later by RCU. | 818 | * will release later by RCU. |
531 | */ | 819 | */ |
532 | static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, | 820 | static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, |
533 | u32 seqno) | 821 | u32 tsid, u16 tclass, u32 seqno, |
822 | struct extended_perms_decision *xpd, | ||
823 | u32 flags) | ||
534 | { | 824 | { |
535 | int hvalue, rc = 0; | 825 | int hvalue, rc = 0; |
536 | unsigned long flag; | 826 | unsigned long flag; |
@@ -574,9 +864,19 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, | |||
574 | 864 | ||
575 | avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); | 865 | avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); |
576 | 866 | ||
867 | if (orig->ae.xp_node) { | ||
868 | rc = avc_xperms_populate(node, orig->ae.xp_node); | ||
869 | if (rc) { | ||
870 | kmem_cache_free(avc_node_cachep, node); | ||
871 | goto out_unlock; | ||
872 | } | ||
873 | } | ||
874 | |||
577 | switch (event) { | 875 | switch (event) { |
578 | case AVC_CALLBACK_GRANT: | 876 | case AVC_CALLBACK_GRANT: |
579 | node->ae.avd.allowed |= perms; | 877 | node->ae.avd.allowed |= perms; |
878 | if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS)) | ||
879 | avc_xperms_allow_perm(node->ae.xp_node, driver, xperm); | ||
580 | break; | 880 | break; |
581 | case AVC_CALLBACK_TRY_REVOKE: | 881 | case AVC_CALLBACK_TRY_REVOKE: |
582 | case AVC_CALLBACK_REVOKE: | 882 | case AVC_CALLBACK_REVOKE: |
@@ -594,6 +894,9 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, | |||
594 | case AVC_CALLBACK_AUDITDENY_DISABLE: | 894 | case AVC_CALLBACK_AUDITDENY_DISABLE: |
595 | node->ae.avd.auditdeny &= ~perms; | 895 | node->ae.avd.auditdeny &= ~perms; |
596 | break; | 896 | break; |
897 | case AVC_CALLBACK_ADD_XPERMS: | ||
898 | avc_add_xperms_decision(node, xpd); | ||
899 | break; | ||
597 | } | 900 | } |
598 | avc_node_replace(node, orig); | 901 | avc_node_replace(node, orig); |
599 | out_unlock: | 902 | out_unlock: |
@@ -665,18 +968,20 @@ int avc_ss_reset(u32 seqno) | |||
665 | * results in a bigger stack frame. | 968 | * results in a bigger stack frame. |
666 | */ | 969 | */ |
667 | static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, | 970 | static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, |
668 | u16 tclass, struct av_decision *avd) | 971 | u16 tclass, struct av_decision *avd, |
972 | struct avc_xperms_node *xp_node) | ||
669 | { | 973 | { |
670 | rcu_read_unlock(); | 974 | rcu_read_unlock(); |
671 | security_compute_av(ssid, tsid, tclass, avd); | 975 | INIT_LIST_HEAD(&xp_node->xpd_head); |
976 | security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp); | ||
672 | rcu_read_lock(); | 977 | rcu_read_lock(); |
673 | return avc_insert(ssid, tsid, tclass, avd); | 978 | return avc_insert(ssid, tsid, tclass, avd, xp_node); |
674 | } | 979 | } |
675 | 980 | ||
676 | static noinline int avc_denied(u32 ssid, u32 tsid, | 981 | static noinline int avc_denied(u32 ssid, u32 tsid, |
677 | u16 tclass, u32 requested, | 982 | u16 tclass, u32 requested, |
678 | unsigned flags, | 983 | u8 driver, u8 xperm, unsigned flags, |
679 | struct av_decision *avd) | 984 | struct av_decision *avd) |
680 | { | 985 | { |
681 | if (flags & AVC_STRICT) | 986 | if (flags & AVC_STRICT) |
682 | return -EACCES; | 987 | return -EACCES; |
@@ -684,11 +989,91 @@ static noinline int avc_denied(u32 ssid, u32 tsid, | |||
684 | if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) | 989 | if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) |
685 | return -EACCES; | 990 | return -EACCES; |
686 | 991 | ||
687 | avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, | 992 | avc_update_node(AVC_CALLBACK_GRANT, requested, driver, xperm, ssid, |
688 | tsid, tclass, avd->seqno); | 993 | tsid, tclass, avd->seqno, NULL, flags); |
689 | return 0; | 994 | return 0; |
690 | } | 995 | } |
691 | 996 | ||
997 | /* | ||
998 | * The avc extended permissions logic adds an additional 256 bits of | ||
999 | * permissions to an avc node when extended permissions for that node are | ||
1000 | * specified in the avtab. If the additional 256 permissions is not adequate, | ||
1001 | * as-is the case with ioctls, then multiple may be chained together and the | ||
1002 | * driver field is used to specify which set contains the permission. | ||
1003 | */ | ||
1004 | int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, | ||
1005 | u8 driver, u8 xperm, struct common_audit_data *ad) | ||
1006 | { | ||
1007 | struct avc_node *node; | ||
1008 | struct av_decision avd; | ||
1009 | u32 denied; | ||
1010 | struct extended_perms_decision local_xpd; | ||
1011 | struct extended_perms_decision *xpd = NULL; | ||
1012 | struct extended_perms_data allowed; | ||
1013 | struct extended_perms_data auditallow; | ||
1014 | struct extended_perms_data dontaudit; | ||
1015 | struct avc_xperms_node local_xp_node; | ||
1016 | struct avc_xperms_node *xp_node; | ||
1017 | int rc = 0, rc2; | ||
1018 | |||
1019 | xp_node = &local_xp_node; | ||
1020 | BUG_ON(!requested); | ||
1021 | |||
1022 | rcu_read_lock(); | ||
1023 | |||
1024 | node = avc_lookup(ssid, tsid, tclass); | ||
1025 | if (unlikely(!node)) { | ||
1026 | node = avc_compute_av(ssid, tsid, tclass, &avd, xp_node); | ||
1027 | } else { | ||
1028 | memcpy(&avd, &node->ae.avd, sizeof(avd)); | ||
1029 | xp_node = node->ae.xp_node; | ||
1030 | } | ||
1031 | /* if extended permissions are not defined, only consider av_decision */ | ||
1032 | if (!xp_node || !xp_node->xp.len) | ||
1033 | goto decision; | ||
1034 | |||
1035 | local_xpd.allowed = &allowed; | ||
1036 | local_xpd.auditallow = &auditallow; | ||
1037 | local_xpd.dontaudit = &dontaudit; | ||
1038 | |||
1039 | xpd = avc_xperms_decision_lookup(driver, xp_node); | ||
1040 | if (unlikely(!xpd)) { | ||
1041 | /* | ||
1042 | * Compute the extended_perms_decision only if the driver | ||
1043 | * is flagged | ||
1044 | */ | ||
1045 | if (!security_xperm_test(xp_node->xp.drivers.p, driver)) { | ||
1046 | avd.allowed &= ~requested; | ||
1047 | goto decision; | ||
1048 | } | ||
1049 | rcu_read_unlock(); | ||
1050 | security_compute_xperms_decision(ssid, tsid, tclass, driver, | ||
1051 | &local_xpd); | ||
1052 | rcu_read_lock(); | ||
1053 | avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver, xperm, | ||
1054 | ssid, tsid, tclass, avd.seqno, &local_xpd, 0); | ||
1055 | } else { | ||
1056 | avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd); | ||
1057 | } | ||
1058 | xpd = &local_xpd; | ||
1059 | |||
1060 | if (!avc_xperms_has_perm(xpd, xperm, XPERMS_ALLOWED)) | ||
1061 | avd.allowed &= ~requested; | ||
1062 | |||
1063 | decision: | ||
1064 | denied = requested & ~(avd.allowed); | ||
1065 | if (unlikely(denied)) | ||
1066 | rc = avc_denied(ssid, tsid, tclass, requested, driver, xperm, | ||
1067 | AVC_EXTENDED_PERMS, &avd); | ||
1068 | |||
1069 | rcu_read_unlock(); | ||
1070 | |||
1071 | rc2 = avc_xperms_audit(ssid, tsid, tclass, requested, | ||
1072 | &avd, xpd, xperm, rc, ad); | ||
1073 | if (rc2) | ||
1074 | return rc2; | ||
1075 | return rc; | ||
1076 | } | ||
692 | 1077 | ||
693 | /** | 1078 | /** |
694 | * avc_has_perm_noaudit - Check permissions but perform no auditing. | 1079 | * avc_has_perm_noaudit - Check permissions but perform no auditing. |
@@ -716,6 +1101,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
716 | struct av_decision *avd) | 1101 | struct av_decision *avd) |
717 | { | 1102 | { |
718 | struct avc_node *node; | 1103 | struct avc_node *node; |
1104 | struct avc_xperms_node xp_node; | ||
719 | int rc = 0; | 1105 | int rc = 0; |
720 | u32 denied; | 1106 | u32 denied; |
721 | 1107 | ||
@@ -725,13 +1111,13 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
725 | 1111 | ||
726 | node = avc_lookup(ssid, tsid, tclass); | 1112 | node = avc_lookup(ssid, tsid, tclass); |
727 | if (unlikely(!node)) | 1113 | if (unlikely(!node)) |
728 | node = avc_compute_av(ssid, tsid, tclass, avd); | 1114 | node = avc_compute_av(ssid, tsid, tclass, avd, &xp_node); |
729 | else | 1115 | else |
730 | memcpy(avd, &node->ae.avd, sizeof(*avd)); | 1116 | memcpy(avd, &node->ae.avd, sizeof(*avd)); |
731 | 1117 | ||
732 | denied = requested & ~(avd->allowed); | 1118 | denied = requested & ~(avd->allowed); |
733 | if (unlikely(denied)) | 1119 | if (unlikely(denied)) |
734 | rc = avc_denied(ssid, tsid, tclass, requested, flags, avd); | 1120 | rc = avc_denied(ssid, tsid, tclass, requested, 0, 0, flags, avd); |
735 | 1121 | ||
736 | rcu_read_unlock(); | 1122 | rcu_read_unlock(); |
737 | return rc; | 1123 | return rc; |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index cdf4c589a391..e4369d86e588 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -254,10 +254,21 @@ static void inode_free_security(struct inode *inode) | |||
254 | struct inode_security_struct *isec = inode->i_security; | 254 | struct inode_security_struct *isec = inode->i_security; |
255 | struct superblock_security_struct *sbsec = inode->i_sb->s_security; | 255 | struct superblock_security_struct *sbsec = inode->i_sb->s_security; |
256 | 256 | ||
257 | spin_lock(&sbsec->isec_lock); | 257 | /* |
258 | if (!list_empty(&isec->list)) | 258 | * As not all inode security structures are in a list, we check for |
259 | * empty list outside of the lock to make sure that we won't waste | ||
260 | * time taking a lock doing nothing. | ||
261 | * | ||
262 | * The list_del_init() function can be safely called more than once. | ||
263 | * It should not be possible for this function to be called with | ||
264 | * concurrent list_add(), but for better safety against future changes | ||
265 | * in the code, we use list_empty_careful() here. | ||
266 | */ | ||
267 | if (!list_empty_careful(&isec->list)) { | ||
268 | spin_lock(&sbsec->isec_lock); | ||
259 | list_del_init(&isec->list); | 269 | list_del_init(&isec->list); |
260 | spin_unlock(&sbsec->isec_lock); | 270 | spin_unlock(&sbsec->isec_lock); |
271 | } | ||
261 | 272 | ||
262 | /* | 273 | /* |
263 | * The inode may still be referenced in a path walk and | 274 | * The inode may still be referenced in a path walk and |
@@ -1698,6 +1709,32 @@ out: | |||
1698 | return rc; | 1709 | return rc; |
1699 | } | 1710 | } |
1700 | 1711 | ||
1712 | /* | ||
1713 | * Determine the label for an inode that might be unioned. | ||
1714 | */ | ||
1715 | static int selinux_determine_inode_label(const struct inode *dir, | ||
1716 | const struct qstr *name, | ||
1717 | u16 tclass, | ||
1718 | u32 *_new_isid) | ||
1719 | { | ||
1720 | const struct superblock_security_struct *sbsec = dir->i_sb->s_security; | ||
1721 | const struct inode_security_struct *dsec = dir->i_security; | ||
1722 | const struct task_security_struct *tsec = current_security(); | ||
1723 | |||
1724 | if ((sbsec->flags & SE_SBINITIALIZED) && | ||
1725 | (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) { | ||
1726 | *_new_isid = sbsec->mntpoint_sid; | ||
1727 | } else if ((sbsec->flags & SBLABEL_MNT) && | ||
1728 | tsec->create_sid) { | ||
1729 | *_new_isid = tsec->create_sid; | ||
1730 | } else { | ||
1731 | return security_transition_sid(tsec->sid, dsec->sid, tclass, | ||
1732 | name, _new_isid); | ||
1733 | } | ||
1734 | |||
1735 | return 0; | ||
1736 | } | ||
1737 | |||
1701 | /* Check whether a task can create a file. */ | 1738 | /* Check whether a task can create a file. */ |
1702 | static int may_create(struct inode *dir, | 1739 | static int may_create(struct inode *dir, |
1703 | struct dentry *dentry, | 1740 | struct dentry *dentry, |
@@ -1714,7 +1751,6 @@ static int may_create(struct inode *dir, | |||
1714 | sbsec = dir->i_sb->s_security; | 1751 | sbsec = dir->i_sb->s_security; |
1715 | 1752 | ||
1716 | sid = tsec->sid; | 1753 | sid = tsec->sid; |
1717 | newsid = tsec->create_sid; | ||
1718 | 1754 | ||
1719 | ad.type = LSM_AUDIT_DATA_DENTRY; | 1755 | ad.type = LSM_AUDIT_DATA_DENTRY; |
1720 | ad.u.dentry = dentry; | 1756 | ad.u.dentry = dentry; |
@@ -1725,12 +1761,10 @@ static int may_create(struct inode *dir, | |||
1725 | if (rc) | 1761 | if (rc) |
1726 | return rc; | 1762 | return rc; |
1727 | 1763 | ||
1728 | if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { | 1764 | rc = selinux_determine_inode_label(dir, &dentry->d_name, tclass, |
1729 | rc = security_transition_sid(sid, dsec->sid, tclass, | 1765 | &newsid); |
1730 | &dentry->d_name, &newsid); | 1766 | if (rc) |
1731 | if (rc) | 1767 | return rc; |
1732 | return rc; | ||
1733 | } | ||
1734 | 1768 | ||
1735 | rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); | 1769 | rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); |
1736 | if (rc) | 1770 | if (rc) |
@@ -2704,32 +2738,14 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, | |||
2704 | struct qstr *name, void **ctx, | 2738 | struct qstr *name, void **ctx, |
2705 | u32 *ctxlen) | 2739 | u32 *ctxlen) |
2706 | { | 2740 | { |
2707 | const struct cred *cred = current_cred(); | ||
2708 | struct task_security_struct *tsec; | ||
2709 | struct inode_security_struct *dsec; | ||
2710 | struct superblock_security_struct *sbsec; | ||
2711 | struct inode *dir = d_backing_inode(dentry->d_parent); | ||
2712 | u32 newsid; | 2741 | u32 newsid; |
2713 | int rc; | 2742 | int rc; |
2714 | 2743 | ||
2715 | tsec = cred->security; | 2744 | rc = selinux_determine_inode_label(d_inode(dentry->d_parent), name, |
2716 | dsec = dir->i_security; | 2745 | inode_mode_to_security_class(mode), |
2717 | sbsec = dir->i_sb->s_security; | 2746 | &newsid); |
2718 | 2747 | if (rc) | |
2719 | if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { | 2748 | return rc; |
2720 | newsid = tsec->create_sid; | ||
2721 | } else { | ||
2722 | rc = security_transition_sid(tsec->sid, dsec->sid, | ||
2723 | inode_mode_to_security_class(mode), | ||
2724 | name, | ||
2725 | &newsid); | ||
2726 | if (rc) { | ||
2727 | printk(KERN_WARNING | ||
2728 | "%s: security_transition_sid failed, rc=%d\n", | ||
2729 | __func__, -rc); | ||
2730 | return rc; | ||
2731 | } | ||
2732 | } | ||
2733 | 2749 | ||
2734 | return security_sid_to_context(newsid, (char **)ctx, ctxlen); | 2750 | return security_sid_to_context(newsid, (char **)ctx, ctxlen); |
2735 | } | 2751 | } |
@@ -2752,22 +2768,12 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2752 | sid = tsec->sid; | 2768 | sid = tsec->sid; |
2753 | newsid = tsec->create_sid; | 2769 | newsid = tsec->create_sid; |
2754 | 2770 | ||
2755 | if ((sbsec->flags & SE_SBINITIALIZED) && | 2771 | rc = selinux_determine_inode_label( |
2756 | (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) | 2772 | dir, qstr, |
2757 | newsid = sbsec->mntpoint_sid; | 2773 | inode_mode_to_security_class(inode->i_mode), |
2758 | else if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { | 2774 | &newsid); |
2759 | rc = security_transition_sid(sid, dsec->sid, | 2775 | if (rc) |
2760 | inode_mode_to_security_class(inode->i_mode), | 2776 | return rc; |
2761 | qstr, &newsid); | ||
2762 | if (rc) { | ||
2763 | printk(KERN_WARNING "%s: " | ||
2764 | "security_transition_sid failed, rc=%d (dev=%s " | ||
2765 | "ino=%ld)\n", | ||
2766 | __func__, | ||
2767 | -rc, inode->i_sb->s_id, inode->i_ino); | ||
2768 | return rc; | ||
2769 | } | ||
2770 | } | ||
2771 | 2777 | ||
2772 | /* Possibly defer initialization to selinux_complete_init. */ | 2778 | /* Possibly defer initialization to selinux_complete_init. */ |
2773 | if (sbsec->flags & SE_SBINITIALIZED) { | 2779 | if (sbsec->flags & SE_SBINITIALIZED) { |
@@ -3228,6 +3234,46 @@ static void selinux_file_free_security(struct file *file) | |||
3228 | file_free_security(file); | 3234 | file_free_security(file); |
3229 | } | 3235 | } |
3230 | 3236 | ||
3237 | /* | ||
3238 | * Check whether a task has the ioctl permission and cmd | ||
3239 | * operation to an inode. | ||
3240 | */ | ||
3241 | int ioctl_has_perm(const struct cred *cred, struct file *file, | ||
3242 | u32 requested, u16 cmd) | ||
3243 | { | ||
3244 | struct common_audit_data ad; | ||
3245 | struct file_security_struct *fsec = file->f_security; | ||
3246 | struct inode *inode = file_inode(file); | ||
3247 | struct inode_security_struct *isec = inode->i_security; | ||
3248 | struct lsm_ioctlop_audit ioctl; | ||
3249 | u32 ssid = cred_sid(cred); | ||
3250 | int rc; | ||
3251 | u8 driver = cmd >> 8; | ||
3252 | u8 xperm = cmd & 0xff; | ||
3253 | |||
3254 | ad.type = LSM_AUDIT_DATA_IOCTL_OP; | ||
3255 | ad.u.op = &ioctl; | ||
3256 | ad.u.op->cmd = cmd; | ||
3257 | ad.u.op->path = file->f_path; | ||
3258 | |||
3259 | if (ssid != fsec->sid) { | ||
3260 | rc = avc_has_perm(ssid, fsec->sid, | ||
3261 | SECCLASS_FD, | ||
3262 | FD__USE, | ||
3263 | &ad); | ||
3264 | if (rc) | ||
3265 | goto out; | ||
3266 | } | ||
3267 | |||
3268 | if (unlikely(IS_PRIVATE(inode))) | ||
3269 | return 0; | ||
3270 | |||
3271 | rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, | ||
3272 | requested, driver, xperm, &ad); | ||
3273 | out: | ||
3274 | return rc; | ||
3275 | } | ||
3276 | |||
3231 | static int selinux_file_ioctl(struct file *file, unsigned int cmd, | 3277 | static int selinux_file_ioctl(struct file *file, unsigned int cmd, |
3232 | unsigned long arg) | 3278 | unsigned long arg) |
3233 | { | 3279 | { |
@@ -3270,7 +3316,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, | |||
3270 | * to the file's ioctl() function. | 3316 | * to the file's ioctl() function. |
3271 | */ | 3317 | */ |
3272 | default: | 3318 | default: |
3273 | error = file_has_perm(cred, file, FILE__IOCTL); | 3319 | error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); |
3274 | } | 3320 | } |
3275 | return error; | 3321 | return error; |
3276 | } | 3322 | } |
@@ -4520,6 +4566,7 @@ static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority | |||
4520 | 4566 | ||
4521 | sksec->peer_sid = SECINITSID_UNLABELED; | 4567 | sksec->peer_sid = SECINITSID_UNLABELED; |
4522 | sksec->sid = SECINITSID_UNLABELED; | 4568 | sksec->sid = SECINITSID_UNLABELED; |
4569 | sksec->sclass = SECCLASS_SOCKET; | ||
4523 | selinux_netlbl_sk_security_reset(sksec); | 4570 | selinux_netlbl_sk_security_reset(sksec); |
4524 | sk->sk_security = sksec; | 4571 | sk->sk_security = sksec; |
4525 | 4572 | ||
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 5973c327c54e..0999df03af8b 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
@@ -143,6 +143,7 @@ static inline int avc_audit(u32 ssid, u32 tsid, | |||
143 | } | 143 | } |
144 | 144 | ||
145 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | 145 | #define AVC_STRICT 1 /* Ignore permissive mode. */ |
146 | #define AVC_EXTENDED_PERMS 2 /* update extended permissions */ | ||
146 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 147 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
147 | u16 tclass, u32 requested, | 148 | u16 tclass, u32 requested, |
148 | unsigned flags, | 149 | unsigned flags, |
@@ -156,6 +157,10 @@ int avc_has_perm_flags(u32 ssid, u32 tsid, | |||
156 | struct common_audit_data *auditdata, | 157 | struct common_audit_data *auditdata, |
157 | int flags); | 158 | int flags); |
158 | 159 | ||
160 | int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, | ||
161 | u8 driver, u8 perm, struct common_audit_data *ad); | ||
162 | |||
163 | |||
159 | u32 avc_policy_seqno(void); | 164 | u32 avc_policy_seqno(void); |
160 | 165 | ||
161 | #define AVC_CALLBACK_GRANT 1 | 166 | #define AVC_CALLBACK_GRANT 1 |
@@ -166,6 +171,7 @@ u32 avc_policy_seqno(void); | |||
166 | #define AVC_CALLBACK_AUDITALLOW_DISABLE 32 | 171 | #define AVC_CALLBACK_AUDITALLOW_DISABLE 32 |
167 | #define AVC_CALLBACK_AUDITDENY_ENABLE 64 | 172 | #define AVC_CALLBACK_AUDITDENY_ENABLE 64 |
168 | #define AVC_CALLBACK_AUDITDENY_DISABLE 128 | 173 | #define AVC_CALLBACK_AUDITDENY_DISABLE 128 |
174 | #define AVC_CALLBACK_ADD_XPERMS 256 | ||
169 | 175 | ||
170 | int avc_add_callback(int (*callback)(u32 event), u32 events); | 176 | int avc_add_callback(int (*callback)(u32 event), u32 events); |
171 | 177 | ||
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 36993ad1c067..6a681d26bf20 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -35,13 +35,14 @@ | |||
35 | #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 | 35 | #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 |
36 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 | 36 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 |
37 | #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 | 37 | #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 |
38 | #define POLICYDB_VERSION_XPERMS_IOCTL 30 | ||
38 | 39 | ||
39 | /* Range of policy versions we understand*/ | 40 | /* Range of policy versions we understand*/ |
40 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 41 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
41 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX | 42 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
42 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE | 43 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
43 | #else | 44 | #else |
44 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES | 45 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_XPERMS_IOCTL |
45 | #endif | 46 | #endif |
46 | 47 | ||
47 | /* Mask for just the mount related flags */ | 48 | /* Mask for just the mount related flags */ |
@@ -109,11 +110,38 @@ struct av_decision { | |||
109 | u32 flags; | 110 | u32 flags; |
110 | }; | 111 | }; |
111 | 112 | ||
113 | #define XPERMS_ALLOWED 1 | ||
114 | #define XPERMS_AUDITALLOW 2 | ||
115 | #define XPERMS_DONTAUDIT 4 | ||
116 | |||
117 | #define security_xperm_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f)) | ||
118 | #define security_xperm_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f))) | ||
119 | struct extended_perms_data { | ||
120 | u32 p[8]; | ||
121 | }; | ||
122 | |||
123 | struct extended_perms_decision { | ||
124 | u8 used; | ||
125 | u8 driver; | ||
126 | struct extended_perms_data *allowed; | ||
127 | struct extended_perms_data *auditallow; | ||
128 | struct extended_perms_data *dontaudit; | ||
129 | }; | ||
130 | |||
131 | struct extended_perms { | ||
132 | u16 len; /* length associated decision chain */ | ||
133 | struct extended_perms_data drivers; /* flag drivers that are used */ | ||
134 | }; | ||
135 | |||
112 | /* definitions of av_decision.flags */ | 136 | /* definitions of av_decision.flags */ |
113 | #define AVD_FLAGS_PERMISSIVE 0x0001 | 137 | #define AVD_FLAGS_PERMISSIVE 0x0001 |
114 | 138 | ||
115 | void security_compute_av(u32 ssid, u32 tsid, | 139 | void security_compute_av(u32 ssid, u32 tsid, |
116 | u16 tclass, struct av_decision *avd); | 140 | u16 tclass, struct av_decision *avd, |
141 | struct extended_perms *xperms); | ||
142 | |||
143 | void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, | ||
144 | u8 driver, struct extended_perms_decision *xpermd); | ||
117 | 145 | ||
118 | void security_compute_av_user(u32 ssid, u32 tsid, | 146 | void security_compute_av_user(u32 ssid, u32 tsid, |
119 | u16 tclass, struct av_decision *avd); | 147 | u16 tclass, struct av_decision *avd); |
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index b64f2772b030..3628d3a868b6 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "policydb.h" | 24 | #include "policydb.h" |
25 | 25 | ||
26 | static struct kmem_cache *avtab_node_cachep; | 26 | static struct kmem_cache *avtab_node_cachep; |
27 | static struct kmem_cache *avtab_xperms_cachep; | ||
27 | 28 | ||
28 | /* Based on MurmurHash3, written by Austin Appleby and placed in the | 29 | /* Based on MurmurHash3, written by Austin Appleby and placed in the |
29 | * public domain. | 30 | * public domain. |
@@ -70,11 +71,24 @@ avtab_insert_node(struct avtab *h, int hvalue, | |||
70 | struct avtab_key *key, struct avtab_datum *datum) | 71 | struct avtab_key *key, struct avtab_datum *datum) |
71 | { | 72 | { |
72 | struct avtab_node *newnode; | 73 | struct avtab_node *newnode; |
74 | struct avtab_extended_perms *xperms; | ||
73 | newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); | 75 | newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); |
74 | if (newnode == NULL) | 76 | if (newnode == NULL) |
75 | return NULL; | 77 | return NULL; |
76 | newnode->key = *key; | 78 | newnode->key = *key; |
77 | newnode->datum = *datum; | 79 | |
80 | if (key->specified & AVTAB_XPERMS) { | ||
81 | xperms = kmem_cache_zalloc(avtab_xperms_cachep, GFP_KERNEL); | ||
82 | if (xperms == NULL) { | ||
83 | kmem_cache_free(avtab_node_cachep, newnode); | ||
84 | return NULL; | ||
85 | } | ||
86 | *xperms = *(datum->u.xperms); | ||
87 | newnode->datum.u.xperms = xperms; | ||
88 | } else { | ||
89 | newnode->datum.u.data = datum->u.data; | ||
90 | } | ||
91 | |||
78 | if (prev) { | 92 | if (prev) { |
79 | newnode->next = prev->next; | 93 | newnode->next = prev->next; |
80 | prev->next = newnode; | 94 | prev->next = newnode; |
@@ -107,8 +121,12 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat | |||
107 | if (key->source_type == cur->key.source_type && | 121 | if (key->source_type == cur->key.source_type && |
108 | key->target_type == cur->key.target_type && | 122 | key->target_type == cur->key.target_type && |
109 | key->target_class == cur->key.target_class && | 123 | key->target_class == cur->key.target_class && |
110 | (specified & cur->key.specified)) | 124 | (specified & cur->key.specified)) { |
125 | /* extended perms may not be unique */ | ||
126 | if (specified & AVTAB_XPERMS) | ||
127 | break; | ||
111 | return -EEXIST; | 128 | return -EEXIST; |
129 | } | ||
112 | if (key->source_type < cur->key.source_type) | 130 | if (key->source_type < cur->key.source_type) |
113 | break; | 131 | break; |
114 | if (key->source_type == cur->key.source_type && | 132 | if (key->source_type == cur->key.source_type && |
@@ -271,6 +289,9 @@ void avtab_destroy(struct avtab *h) | |||
271 | while (cur) { | 289 | while (cur) { |
272 | temp = cur; | 290 | temp = cur; |
273 | cur = cur->next; | 291 | cur = cur->next; |
292 | if (temp->key.specified & AVTAB_XPERMS) | ||
293 | kmem_cache_free(avtab_xperms_cachep, | ||
294 | temp->datum.u.xperms); | ||
274 | kmem_cache_free(avtab_node_cachep, temp); | 295 | kmem_cache_free(avtab_node_cachep, temp); |
275 | } | 296 | } |
276 | } | 297 | } |
@@ -359,7 +380,10 @@ static uint16_t spec_order[] = { | |||
359 | AVTAB_AUDITALLOW, | 380 | AVTAB_AUDITALLOW, |
360 | AVTAB_TRANSITION, | 381 | AVTAB_TRANSITION, |
361 | AVTAB_CHANGE, | 382 | AVTAB_CHANGE, |
362 | AVTAB_MEMBER | 383 | AVTAB_MEMBER, |
384 | AVTAB_XPERMS_ALLOWED, | ||
385 | AVTAB_XPERMS_AUDITALLOW, | ||
386 | AVTAB_XPERMS_DONTAUDIT | ||
363 | }; | 387 | }; |
364 | 388 | ||
365 | int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | 389 | int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, |
@@ -369,10 +393,11 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
369 | { | 393 | { |
370 | __le16 buf16[4]; | 394 | __le16 buf16[4]; |
371 | u16 enabled; | 395 | u16 enabled; |
372 | __le32 buf32[7]; | ||
373 | u32 items, items2, val, vers = pol->policyvers; | 396 | u32 items, items2, val, vers = pol->policyvers; |
374 | struct avtab_key key; | 397 | struct avtab_key key; |
375 | struct avtab_datum datum; | 398 | struct avtab_datum datum; |
399 | struct avtab_extended_perms xperms; | ||
400 | __le32 buf32[ARRAY_SIZE(xperms.perms.p)]; | ||
376 | int i, rc; | 401 | int i, rc; |
377 | unsigned set; | 402 | unsigned set; |
378 | 403 | ||
@@ -429,11 +454,15 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
429 | printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); | 454 | printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); |
430 | return -EINVAL; | 455 | return -EINVAL; |
431 | } | 456 | } |
457 | if (val & AVTAB_XPERMS) { | ||
458 | printk(KERN_ERR "SELinux: avtab: entry has extended permissions\n"); | ||
459 | return -EINVAL; | ||
460 | } | ||
432 | 461 | ||
433 | for (i = 0; i < ARRAY_SIZE(spec_order); i++) { | 462 | for (i = 0; i < ARRAY_SIZE(spec_order); i++) { |
434 | if (val & spec_order[i]) { | 463 | if (val & spec_order[i]) { |
435 | key.specified = spec_order[i] | enabled; | 464 | key.specified = spec_order[i] | enabled; |
436 | datum.data = le32_to_cpu(buf32[items++]); | 465 | datum.u.data = le32_to_cpu(buf32[items++]); |
437 | rc = insertf(a, &key, &datum, p); | 466 | rc = insertf(a, &key, &datum, p); |
438 | if (rc) | 467 | if (rc) |
439 | return rc; | 468 | return rc; |
@@ -476,14 +505,42 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
476 | return -EINVAL; | 505 | return -EINVAL; |
477 | } | 506 | } |
478 | 507 | ||
479 | rc = next_entry(buf32, fp, sizeof(u32)); | 508 | if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) && |
480 | if (rc) { | 509 | (key.specified & AVTAB_XPERMS)) { |
481 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | 510 | printk(KERN_ERR "SELinux: avtab: policy version %u does not " |
482 | return rc; | 511 | "support extended permissions rules and one " |
512 | "was specified\n", vers); | ||
513 | return -EINVAL; | ||
514 | } else if (key.specified & AVTAB_XPERMS) { | ||
515 | memset(&xperms, 0, sizeof(struct avtab_extended_perms)); | ||
516 | rc = next_entry(&xperms.specified, fp, sizeof(u8)); | ||
517 | if (rc) { | ||
518 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
519 | return rc; | ||
520 | } | ||
521 | rc = next_entry(&xperms.driver, fp, sizeof(u8)); | ||
522 | if (rc) { | ||
523 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
524 | return rc; | ||
525 | } | ||
526 | rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p)); | ||
527 | if (rc) { | ||
528 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
529 | return rc; | ||
530 | } | ||
531 | for (i = 0; i < ARRAY_SIZE(xperms.perms.p); i++) | ||
532 | xperms.perms.p[i] = le32_to_cpu(buf32[i]); | ||
533 | datum.u.xperms = &xperms; | ||
534 | } else { | ||
535 | rc = next_entry(buf32, fp, sizeof(u32)); | ||
536 | if (rc) { | ||
537 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
538 | return rc; | ||
539 | } | ||
540 | datum.u.data = le32_to_cpu(*buf32); | ||
483 | } | 541 | } |
484 | datum.data = le32_to_cpu(*buf32); | ||
485 | if ((key.specified & AVTAB_TYPE) && | 542 | if ((key.specified & AVTAB_TYPE) && |
486 | !policydb_type_isvalid(pol, datum.data)) { | 543 | !policydb_type_isvalid(pol, datum.u.data)) { |
487 | printk(KERN_ERR "SELinux: avtab: invalid type\n"); | 544 | printk(KERN_ERR "SELinux: avtab: invalid type\n"); |
488 | return -EINVAL; | 545 | return -EINVAL; |
489 | } | 546 | } |
@@ -543,8 +600,9 @@ bad: | |||
543 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) | 600 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) |
544 | { | 601 | { |
545 | __le16 buf16[4]; | 602 | __le16 buf16[4]; |
546 | __le32 buf32[1]; | 603 | __le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)]; |
547 | int rc; | 604 | int rc; |
605 | unsigned int i; | ||
548 | 606 | ||
549 | buf16[0] = cpu_to_le16(cur->key.source_type); | 607 | buf16[0] = cpu_to_le16(cur->key.source_type); |
550 | buf16[1] = cpu_to_le16(cur->key.target_type); | 608 | buf16[1] = cpu_to_le16(cur->key.target_type); |
@@ -553,8 +611,22 @@ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) | |||
553 | rc = put_entry(buf16, sizeof(u16), 4, fp); | 611 | rc = put_entry(buf16, sizeof(u16), 4, fp); |
554 | if (rc) | 612 | if (rc) |
555 | return rc; | 613 | return rc; |
556 | buf32[0] = cpu_to_le32(cur->datum.data); | 614 | |
557 | rc = put_entry(buf32, sizeof(u32), 1, fp); | 615 | if (cur->key.specified & AVTAB_XPERMS) { |
616 | rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp); | ||
617 | if (rc) | ||
618 | return rc; | ||
619 | rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp); | ||
620 | if (rc) | ||
621 | return rc; | ||
622 | for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++) | ||
623 | buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]); | ||
624 | rc = put_entry(buf32, sizeof(u32), | ||
625 | ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp); | ||
626 | } else { | ||
627 | buf32[0] = cpu_to_le32(cur->datum.u.data); | ||
628 | rc = put_entry(buf32, sizeof(u32), 1, fp); | ||
629 | } | ||
558 | if (rc) | 630 | if (rc) |
559 | return rc; | 631 | return rc; |
560 | return 0; | 632 | return 0; |
@@ -588,9 +660,13 @@ void avtab_cache_init(void) | |||
588 | avtab_node_cachep = kmem_cache_create("avtab_node", | 660 | avtab_node_cachep = kmem_cache_create("avtab_node", |
589 | sizeof(struct avtab_node), | 661 | sizeof(struct avtab_node), |
590 | 0, SLAB_PANIC, NULL); | 662 | 0, SLAB_PANIC, NULL); |
663 | avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms", | ||
664 | sizeof(struct avtab_extended_perms), | ||
665 | 0, SLAB_PANIC, NULL); | ||
591 | } | 666 | } |
592 | 667 | ||
593 | void avtab_cache_destroy(void) | 668 | void avtab_cache_destroy(void) |
594 | { | 669 | { |
595 | kmem_cache_destroy(avtab_node_cachep); | 670 | kmem_cache_destroy(avtab_node_cachep); |
671 | kmem_cache_destroy(avtab_xperms_cachep); | ||
596 | } | 672 | } |
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index adb451cd44f9..d946c9dc3c9c 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #ifndef _SS_AVTAB_H_ | 23 | #ifndef _SS_AVTAB_H_ |
24 | #define _SS_AVTAB_H_ | 24 | #define _SS_AVTAB_H_ |
25 | 25 | ||
26 | #include "security.h" | ||
26 | #include <linux/flex_array.h> | 27 | #include <linux/flex_array.h> |
27 | 28 | ||
28 | struct avtab_key { | 29 | struct avtab_key { |
@@ -37,13 +38,43 @@ struct avtab_key { | |||
37 | #define AVTAB_MEMBER 0x0020 | 38 | #define AVTAB_MEMBER 0x0020 |
38 | #define AVTAB_CHANGE 0x0040 | 39 | #define AVTAB_CHANGE 0x0040 |
39 | #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) | 40 | #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) |
41 | /* extended permissions */ | ||
42 | #define AVTAB_XPERMS_ALLOWED 0x0100 | ||
43 | #define AVTAB_XPERMS_AUDITALLOW 0x0200 | ||
44 | #define AVTAB_XPERMS_DONTAUDIT 0x0400 | ||
45 | #define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | \ | ||
46 | AVTAB_XPERMS_AUDITALLOW | \ | ||
47 | AVTAB_XPERMS_DONTAUDIT) | ||
40 | #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ | 48 | #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ |
41 | #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ | 49 | #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ |
42 | u16 specified; /* what field is specified */ | 50 | u16 specified; /* what field is specified */ |
43 | }; | 51 | }; |
44 | 52 | ||
53 | /* | ||
54 | * For operations that require more than the 32 permissions provided by the avc | ||
55 | * extended permissions may be used to provide 256 bits of permissions. | ||
56 | */ | ||
57 | struct avtab_extended_perms { | ||
58 | /* These are not flags. All 256 values may be used */ | ||
59 | #define AVTAB_XPERMS_IOCTLFUNCTION 0x01 | ||
60 | #define AVTAB_XPERMS_IOCTLDRIVER 0x02 | ||
61 | /* extension of the avtab_key specified */ | ||
62 | u8 specified; /* ioctl, netfilter, ... */ | ||
63 | /* | ||
64 | * if 256 bits is not adequate as is often the case with ioctls, then | ||
65 | * multiple extended perms may be used and the driver field | ||
66 | * specifies which permissions are included. | ||
67 | */ | ||
68 | u8 driver; | ||
69 | /* 256 bits of permissions */ | ||
70 | struct extended_perms_data perms; | ||
71 | }; | ||
72 | |||
45 | struct avtab_datum { | 73 | struct avtab_datum { |
46 | u32 data; /* access vector or type value */ | 74 | union { |
75 | u32 data; /* access vector or type value */ | ||
76 | struct avtab_extended_perms *xperms; | ||
77 | } u; | ||
47 | }; | 78 | }; |
48 | 79 | ||
49 | struct avtab_node { | 80 | struct avtab_node { |
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 62c6773be0b7..18643bf9894d 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include "security.h" | 16 | #include "security.h" |
17 | #include "conditional.h" | 17 | #include "conditional.h" |
18 | #include "services.h" | ||
18 | 19 | ||
19 | /* | 20 | /* |
20 | * cond_evaluate_expr evaluates a conditional expr | 21 | * cond_evaluate_expr evaluates a conditional expr |
@@ -612,21 +613,39 @@ int cond_write_list(struct policydb *p, struct cond_node *list, void *fp) | |||
612 | 613 | ||
613 | return 0; | 614 | return 0; |
614 | } | 615 | } |
616 | |||
617 | void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, | ||
618 | struct extended_perms_decision *xpermd) | ||
619 | { | ||
620 | struct avtab_node *node; | ||
621 | |||
622 | if (!ctab || !key || !xpermd) | ||
623 | return; | ||
624 | |||
625 | for (node = avtab_search_node(ctab, key); node; | ||
626 | node = avtab_search_node_next(node, key->specified)) { | ||
627 | if (node->key.specified & AVTAB_ENABLED) | ||
628 | services_compute_xperms_decision(xpermd, node); | ||
629 | } | ||
630 | return; | ||
631 | |||
632 | } | ||
615 | /* Determine whether additional permissions are granted by the conditional | 633 | /* Determine whether additional permissions are granted by the conditional |
616 | * av table, and if so, add them to the result | 634 | * av table, and if so, add them to the result |
617 | */ | 635 | */ |
618 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd) | 636 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, |
637 | struct av_decision *avd, struct extended_perms *xperms) | ||
619 | { | 638 | { |
620 | struct avtab_node *node; | 639 | struct avtab_node *node; |
621 | 640 | ||
622 | if (!ctab || !key || !avd) | 641 | if (!ctab || !key || !avd || !xperms) |
623 | return; | 642 | return; |
624 | 643 | ||
625 | for (node = avtab_search_node(ctab, key); node; | 644 | for (node = avtab_search_node(ctab, key); node; |
626 | node = avtab_search_node_next(node, key->specified)) { | 645 | node = avtab_search_node_next(node, key->specified)) { |
627 | if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == | 646 | if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == |
628 | (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) | 647 | (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) |
629 | avd->allowed |= node->datum.data; | 648 | avd->allowed |= node->datum.u.data; |
630 | if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == | 649 | if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == |
631 | (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) | 650 | (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) |
632 | /* Since a '0' in an auditdeny mask represents a | 651 | /* Since a '0' in an auditdeny mask represents a |
@@ -634,10 +653,13 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi | |||
634 | * the '&' operand to ensure that all '0's in the mask | 653 | * the '&' operand to ensure that all '0's in the mask |
635 | * are retained (much unlike the allow and auditallow cases). | 654 | * are retained (much unlike the allow and auditallow cases). |
636 | */ | 655 | */ |
637 | avd->auditdeny &= node->datum.data; | 656 | avd->auditdeny &= node->datum.u.data; |
638 | if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == | 657 | if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == |
639 | (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) | 658 | (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) |
640 | avd->auditallow |= node->datum.data; | 659 | avd->auditallow |= node->datum.u.data; |
660 | if ((node->key.specified & AVTAB_ENABLED) && | ||
661 | (node->key.specified & AVTAB_XPERMS)) | ||
662 | services_compute_xperms_drivers(xperms, node); | ||
641 | } | 663 | } |
642 | return; | 664 | return; |
643 | } | 665 | } |
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 4d1f87466508..ddb43e7e1c75 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h | |||
@@ -73,8 +73,10 @@ int cond_read_list(struct policydb *p, void *fp); | |||
73 | int cond_write_bool(void *key, void *datum, void *ptr); | 73 | int cond_write_bool(void *key, void *datum, void *ptr); |
74 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); | 74 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); |
75 | 75 | ||
76 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); | 76 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, |
77 | 77 | struct av_decision *avd, struct extended_perms *xperms); | |
78 | void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, | ||
79 | struct extended_perms_decision *xpermd); | ||
78 | int evaluate_cond_node(struct policydb *p, struct cond_node *node); | 80 | int evaluate_cond_node(struct policydb *p, struct cond_node *node); |
79 | 81 | ||
80 | #endif /* _CONDITIONAL_H_ */ | 82 | #endif /* _CONDITIONAL_H_ */ |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 74aa224267c1..992a31530825 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -148,6 +148,11 @@ static struct policydb_compat_info policydb_compat[] = { | |||
148 | .sym_num = SYM_NUM, | 148 | .sym_num = SYM_NUM, |
149 | .ocon_num = OCON_NUM, | 149 | .ocon_num = OCON_NUM, |
150 | }, | 150 | }, |
151 | { | ||
152 | .version = POLICYDB_VERSION_XPERMS_IOCTL, | ||
153 | .sym_num = SYM_NUM, | ||
154 | .ocon_num = OCON_NUM, | ||
155 | }, | ||
151 | }; | 156 | }; |
152 | 157 | ||
153 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 158 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 9e2d82070915..b7df12ba61d8 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -93,9 +93,10 @@ static int context_struct_to_string(struct context *context, char **scontext, | |||
93 | u32 *scontext_len); | 93 | u32 *scontext_len); |
94 | 94 | ||
95 | static void context_struct_compute_av(struct context *scontext, | 95 | static void context_struct_compute_av(struct context *scontext, |
96 | struct context *tcontext, | 96 | struct context *tcontext, |
97 | u16 tclass, | 97 | u16 tclass, |
98 | struct av_decision *avd); | 98 | struct av_decision *avd, |
99 | struct extended_perms *xperms); | ||
99 | 100 | ||
100 | struct selinux_mapping { | 101 | struct selinux_mapping { |
101 | u16 value; /* policy value */ | 102 | u16 value; /* policy value */ |
@@ -565,7 +566,8 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
565 | context_struct_compute_av(&lo_scontext, | 566 | context_struct_compute_av(&lo_scontext, |
566 | tcontext, | 567 | tcontext, |
567 | tclass, | 568 | tclass, |
568 | &lo_avd); | 569 | &lo_avd, |
570 | NULL); | ||
569 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 571 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
570 | return; /* no masked permission */ | 572 | return; /* no masked permission */ |
571 | masked = ~lo_avd.allowed & avd->allowed; | 573 | masked = ~lo_avd.allowed & avd->allowed; |
@@ -580,7 +582,8 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
580 | context_struct_compute_av(scontext, | 582 | context_struct_compute_av(scontext, |
581 | &lo_tcontext, | 583 | &lo_tcontext, |
582 | tclass, | 584 | tclass, |
583 | &lo_avd); | 585 | &lo_avd, |
586 | NULL); | ||
584 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 587 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
585 | return; /* no masked permission */ | 588 | return; /* no masked permission */ |
586 | masked = ~lo_avd.allowed & avd->allowed; | 589 | masked = ~lo_avd.allowed & avd->allowed; |
@@ -596,7 +599,8 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
596 | context_struct_compute_av(&lo_scontext, | 599 | context_struct_compute_av(&lo_scontext, |
597 | &lo_tcontext, | 600 | &lo_tcontext, |
598 | tclass, | 601 | tclass, |
599 | &lo_avd); | 602 | &lo_avd, |
603 | NULL); | ||
600 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 604 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
601 | return; /* no masked permission */ | 605 | return; /* no masked permission */ |
602 | masked = ~lo_avd.allowed & avd->allowed; | 606 | masked = ~lo_avd.allowed & avd->allowed; |
@@ -613,13 +617,39 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
613 | } | 617 | } |
614 | 618 | ||
615 | /* | 619 | /* |
616 | * Compute access vectors based on a context structure pair for | 620 | * flag which drivers have permissions |
617 | * the permissions in a particular class. | 621 | * only looking for ioctl based extended permssions |
622 | */ | ||
623 | void services_compute_xperms_drivers( | ||
624 | struct extended_perms *xperms, | ||
625 | struct avtab_node *node) | ||
626 | { | ||
627 | unsigned int i; | ||
628 | |||
629 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
630 | /* if one or more driver has all permissions allowed */ | ||
631 | for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) | ||
632 | xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; | ||
633 | } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
634 | /* if allowing permissions within a driver */ | ||
635 | security_xperm_set(xperms->drivers.p, | ||
636 | node->datum.u.xperms->driver); | ||
637 | } | ||
638 | |||
639 | /* If no ioctl commands are allowed, ignore auditallow and auditdeny */ | ||
640 | if (node->key.specified & AVTAB_XPERMS_ALLOWED) | ||
641 | xperms->len = 1; | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * Compute access vectors and extended permissions based on a context | ||
646 | * structure pair for the permissions in a particular class. | ||
618 | */ | 647 | */ |
619 | static void context_struct_compute_av(struct context *scontext, | 648 | static void context_struct_compute_av(struct context *scontext, |
620 | struct context *tcontext, | 649 | struct context *tcontext, |
621 | u16 tclass, | 650 | u16 tclass, |
622 | struct av_decision *avd) | 651 | struct av_decision *avd, |
652 | struct extended_perms *xperms) | ||
623 | { | 653 | { |
624 | struct constraint_node *constraint; | 654 | struct constraint_node *constraint; |
625 | struct role_allow *ra; | 655 | struct role_allow *ra; |
@@ -633,6 +663,10 @@ static void context_struct_compute_av(struct context *scontext, | |||
633 | avd->allowed = 0; | 663 | avd->allowed = 0; |
634 | avd->auditallow = 0; | 664 | avd->auditallow = 0; |
635 | avd->auditdeny = 0xffffffff; | 665 | avd->auditdeny = 0xffffffff; |
666 | if (xperms) { | ||
667 | memset(&xperms->drivers, 0, sizeof(xperms->drivers)); | ||
668 | xperms->len = 0; | ||
669 | } | ||
636 | 670 | ||
637 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { | 671 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { |
638 | if (printk_ratelimit()) | 672 | if (printk_ratelimit()) |
@@ -647,7 +681,7 @@ static void context_struct_compute_av(struct context *scontext, | |||
647 | * this permission check, then use it. | 681 | * this permission check, then use it. |
648 | */ | 682 | */ |
649 | avkey.target_class = tclass; | 683 | avkey.target_class = tclass; |
650 | avkey.specified = AVTAB_AV; | 684 | avkey.specified = AVTAB_AV | AVTAB_XPERMS; |
651 | sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); | 685 | sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); |
652 | BUG_ON(!sattr); | 686 | BUG_ON(!sattr); |
653 | tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); | 687 | tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); |
@@ -660,15 +694,18 @@ static void context_struct_compute_av(struct context *scontext, | |||
660 | node; | 694 | node; |
661 | node = avtab_search_node_next(node, avkey.specified)) { | 695 | node = avtab_search_node_next(node, avkey.specified)) { |
662 | if (node->key.specified == AVTAB_ALLOWED) | 696 | if (node->key.specified == AVTAB_ALLOWED) |
663 | avd->allowed |= node->datum.data; | 697 | avd->allowed |= node->datum.u.data; |
664 | else if (node->key.specified == AVTAB_AUDITALLOW) | 698 | else if (node->key.specified == AVTAB_AUDITALLOW) |
665 | avd->auditallow |= node->datum.data; | 699 | avd->auditallow |= node->datum.u.data; |
666 | else if (node->key.specified == AVTAB_AUDITDENY) | 700 | else if (node->key.specified == AVTAB_AUDITDENY) |
667 | avd->auditdeny &= node->datum.data; | 701 | avd->auditdeny &= node->datum.u.data; |
702 | else if (xperms && (node->key.specified & AVTAB_XPERMS)) | ||
703 | services_compute_xperms_drivers(xperms, node); | ||
668 | } | 704 | } |
669 | 705 | ||
670 | /* Check conditional av table for additional permissions */ | 706 | /* Check conditional av table for additional permissions */ |
671 | cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); | 707 | cond_compute_av(&policydb.te_cond_avtab, &avkey, |
708 | avd, xperms); | ||
672 | 709 | ||
673 | } | 710 | } |
674 | } | 711 | } |
@@ -899,6 +936,139 @@ static void avd_init(struct av_decision *avd) | |||
899 | avd->flags = 0; | 936 | avd->flags = 0; |
900 | } | 937 | } |
901 | 938 | ||
939 | void services_compute_xperms_decision(struct extended_perms_decision *xpermd, | ||
940 | struct avtab_node *node) | ||
941 | { | ||
942 | unsigned int i; | ||
943 | |||
944 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
945 | if (xpermd->driver != node->datum.u.xperms->driver) | ||
946 | return; | ||
947 | } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
948 | if (!security_xperm_test(node->datum.u.xperms->perms.p, | ||
949 | xpermd->driver)) | ||
950 | return; | ||
951 | } else { | ||
952 | BUG(); | ||
953 | } | ||
954 | |||
955 | if (node->key.specified == AVTAB_XPERMS_ALLOWED) { | ||
956 | xpermd->used |= XPERMS_ALLOWED; | ||
957 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
958 | memset(xpermd->allowed->p, 0xff, | ||
959 | sizeof(xpermd->allowed->p)); | ||
960 | } | ||
961 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
962 | for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) | ||
963 | xpermd->allowed->p[i] |= | ||
964 | node->datum.u.xperms->perms.p[i]; | ||
965 | } | ||
966 | } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { | ||
967 | xpermd->used |= XPERMS_AUDITALLOW; | ||
968 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
969 | memset(xpermd->auditallow->p, 0xff, | ||
970 | sizeof(xpermd->auditallow->p)); | ||
971 | } | ||
972 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
973 | for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) | ||
974 | xpermd->auditallow->p[i] |= | ||
975 | node->datum.u.xperms->perms.p[i]; | ||
976 | } | ||
977 | } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { | ||
978 | xpermd->used |= XPERMS_DONTAUDIT; | ||
979 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
980 | memset(xpermd->dontaudit->p, 0xff, | ||
981 | sizeof(xpermd->dontaudit->p)); | ||
982 | } | ||
983 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
984 | for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) | ||
985 | xpermd->dontaudit->p[i] |= | ||
986 | node->datum.u.xperms->perms.p[i]; | ||
987 | } | ||
988 | } else { | ||
989 | BUG(); | ||
990 | } | ||
991 | } | ||
992 | |||
993 | void security_compute_xperms_decision(u32 ssid, | ||
994 | u32 tsid, | ||
995 | u16 orig_tclass, | ||
996 | u8 driver, | ||
997 | struct extended_perms_decision *xpermd) | ||
998 | { | ||
999 | u16 tclass; | ||
1000 | struct context *scontext, *tcontext; | ||
1001 | struct avtab_key avkey; | ||
1002 | struct avtab_node *node; | ||
1003 | struct ebitmap *sattr, *tattr; | ||
1004 | struct ebitmap_node *snode, *tnode; | ||
1005 | unsigned int i, j; | ||
1006 | |||
1007 | xpermd->driver = driver; | ||
1008 | xpermd->used = 0; | ||
1009 | memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p)); | ||
1010 | memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); | ||
1011 | memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); | ||
1012 | |||
1013 | read_lock(&policy_rwlock); | ||
1014 | if (!ss_initialized) | ||
1015 | goto allow; | ||
1016 | |||
1017 | scontext = sidtab_search(&sidtab, ssid); | ||
1018 | if (!scontext) { | ||
1019 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
1020 | __func__, ssid); | ||
1021 | goto out; | ||
1022 | } | ||
1023 | |||
1024 | tcontext = sidtab_search(&sidtab, tsid); | ||
1025 | if (!tcontext) { | ||
1026 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
1027 | __func__, tsid); | ||
1028 | goto out; | ||
1029 | } | ||
1030 | |||
1031 | tclass = unmap_class(orig_tclass); | ||
1032 | if (unlikely(orig_tclass && !tclass)) { | ||
1033 | if (policydb.allow_unknown) | ||
1034 | goto allow; | ||
1035 | goto out; | ||
1036 | } | ||
1037 | |||
1038 | |||
1039 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { | ||
1040 | pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass); | ||
1041 | goto out; | ||
1042 | } | ||
1043 | |||
1044 | avkey.target_class = tclass; | ||
1045 | avkey.specified = AVTAB_XPERMS; | ||
1046 | sattr = flex_array_get(policydb.type_attr_map_array, | ||
1047 | scontext->type - 1); | ||
1048 | BUG_ON(!sattr); | ||
1049 | tattr = flex_array_get(policydb.type_attr_map_array, | ||
1050 | tcontext->type - 1); | ||
1051 | BUG_ON(!tattr); | ||
1052 | ebitmap_for_each_positive_bit(sattr, snode, i) { | ||
1053 | ebitmap_for_each_positive_bit(tattr, tnode, j) { | ||
1054 | avkey.source_type = i + 1; | ||
1055 | avkey.target_type = j + 1; | ||
1056 | for (node = avtab_search_node(&policydb.te_avtab, &avkey); | ||
1057 | node; | ||
1058 | node = avtab_search_node_next(node, avkey.specified)) | ||
1059 | services_compute_xperms_decision(xpermd, node); | ||
1060 | |||
1061 | cond_compute_xperms(&policydb.te_cond_avtab, | ||
1062 | &avkey, xpermd); | ||
1063 | } | ||
1064 | } | ||
1065 | out: | ||
1066 | read_unlock(&policy_rwlock); | ||
1067 | return; | ||
1068 | allow: | ||
1069 | memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); | ||
1070 | goto out; | ||
1071 | } | ||
902 | 1072 | ||
903 | /** | 1073 | /** |
904 | * security_compute_av - Compute access vector decisions. | 1074 | * security_compute_av - Compute access vector decisions. |
@@ -906,6 +1076,7 @@ static void avd_init(struct av_decision *avd) | |||
906 | * @tsid: target security identifier | 1076 | * @tsid: target security identifier |
907 | * @tclass: target security class | 1077 | * @tclass: target security class |
908 | * @avd: access vector decisions | 1078 | * @avd: access vector decisions |
1079 | * @xperms: extended permissions | ||
909 | * | 1080 | * |
910 | * Compute a set of access vector decisions based on the | 1081 | * Compute a set of access vector decisions based on the |
911 | * SID pair (@ssid, @tsid) for the permissions in @tclass. | 1082 | * SID pair (@ssid, @tsid) for the permissions in @tclass. |
@@ -913,13 +1084,15 @@ static void avd_init(struct av_decision *avd) | |||
913 | void security_compute_av(u32 ssid, | 1084 | void security_compute_av(u32 ssid, |
914 | u32 tsid, | 1085 | u32 tsid, |
915 | u16 orig_tclass, | 1086 | u16 orig_tclass, |
916 | struct av_decision *avd) | 1087 | struct av_decision *avd, |
1088 | struct extended_perms *xperms) | ||
917 | { | 1089 | { |
918 | u16 tclass; | 1090 | u16 tclass; |
919 | struct context *scontext = NULL, *tcontext = NULL; | 1091 | struct context *scontext = NULL, *tcontext = NULL; |
920 | 1092 | ||
921 | read_lock(&policy_rwlock); | 1093 | read_lock(&policy_rwlock); |
922 | avd_init(avd); | 1094 | avd_init(avd); |
1095 | xperms->len = 0; | ||
923 | if (!ss_initialized) | 1096 | if (!ss_initialized) |
924 | goto allow; | 1097 | goto allow; |
925 | 1098 | ||
@@ -947,7 +1120,7 @@ void security_compute_av(u32 ssid, | |||
947 | goto allow; | 1120 | goto allow; |
948 | goto out; | 1121 | goto out; |
949 | } | 1122 | } |
950 | context_struct_compute_av(scontext, tcontext, tclass, avd); | 1123 | context_struct_compute_av(scontext, tcontext, tclass, avd, xperms); |
951 | map_decision(orig_tclass, avd, policydb.allow_unknown); | 1124 | map_decision(orig_tclass, avd, policydb.allow_unknown); |
952 | out: | 1125 | out: |
953 | read_unlock(&policy_rwlock); | 1126 | read_unlock(&policy_rwlock); |
@@ -993,7 +1166,7 @@ void security_compute_av_user(u32 ssid, | |||
993 | goto out; | 1166 | goto out; |
994 | } | 1167 | } |
995 | 1168 | ||
996 | context_struct_compute_av(scontext, tcontext, tclass, avd); | 1169 | context_struct_compute_av(scontext, tcontext, tclass, avd, NULL); |
997 | out: | 1170 | out: |
998 | read_unlock(&policy_rwlock); | 1171 | read_unlock(&policy_rwlock); |
999 | return; | 1172 | return; |
@@ -1515,7 +1688,7 @@ static int security_compute_sid(u32 ssid, | |||
1515 | 1688 | ||
1516 | if (avdatum) { | 1689 | if (avdatum) { |
1517 | /* Use the type from the type transition/member/change rule. */ | 1690 | /* Use the type from the type transition/member/change rule. */ |
1518 | newcontext.type = avdatum->data; | 1691 | newcontext.type = avdatum->u.data; |
1519 | } | 1692 | } |
1520 | 1693 | ||
1521 | /* if we have a objname this is a file trans check so check those rules */ | 1694 | /* if we have a objname this is a file trans check so check those rules */ |
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h index e8d907e903cd..6abcd8729ec3 100644 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h | |||
@@ -11,5 +11,11 @@ | |||
11 | 11 | ||
12 | extern struct policydb policydb; | 12 | extern struct policydb policydb; |
13 | 13 | ||
14 | void services_compute_xperms_drivers(struct extended_perms *xperms, | ||
15 | struct avtab_node *node); | ||
16 | |||
17 | void services_compute_xperms_decision(struct extended_perms_decision *xpermd, | ||
18 | struct avtab_node *node); | ||
19 | |||
14 | #endif /* _SS_SERVICES_H_ */ | 20 | #endif /* _SS_SERVICES_H_ */ |
15 | 21 | ||
diff --git a/security/smack/smack.h b/security/smack/smack.h index 244e035e5a99..fff0c612bbb7 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -17,12 +17,27 @@ | |||
17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
18 | #include <linux/lsm_hooks.h> | 18 | #include <linux/lsm_hooks.h> |
19 | #include <linux/in.h> | 19 | #include <linux/in.h> |
20 | #if IS_ENABLED(CONFIG_IPV6) | ||
21 | #include <linux/in6.h> | ||
22 | #endif /* CONFIG_IPV6 */ | ||
20 | #include <net/netlabel.h> | 23 | #include <net/netlabel.h> |
21 | #include <linux/list.h> | 24 | #include <linux/list.h> |
22 | #include <linux/rculist.h> | 25 | #include <linux/rculist.h> |
23 | #include <linux/lsm_audit.h> | 26 | #include <linux/lsm_audit.h> |
24 | 27 | ||
25 | /* | 28 | /* |
29 | * Use IPv6 port labeling if IPv6 is enabled and secmarks | ||
30 | * are not being used. | ||
31 | */ | ||
32 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | ||
33 | #define SMACK_IPV6_PORT_LABELING 1 | ||
34 | #endif | ||
35 | |||
36 | #if IS_ENABLED(CONFIG_IPV6) && defined(CONFIG_SECURITY_SMACK_NETFILTER) | ||
37 | #define SMACK_IPV6_SECMARK_LABELING 1 | ||
38 | #endif | ||
39 | |||
40 | /* | ||
26 | * Smack labels were limited to 23 characters for a long time. | 41 | * Smack labels were limited to 23 characters for a long time. |
27 | */ | 42 | */ |
28 | #define SMK_LABELLEN 24 | 43 | #define SMK_LABELLEN 24 |
@@ -118,15 +133,30 @@ struct smack_rule { | |||
118 | }; | 133 | }; |
119 | 134 | ||
120 | /* | 135 | /* |
121 | * An entry in the table identifying hosts. | 136 | * An entry in the table identifying IPv4 hosts. |
122 | */ | 137 | */ |
123 | struct smk_netlbladdr { | 138 | struct smk_net4addr { |
124 | struct list_head list; | 139 | struct list_head list; |
125 | struct sockaddr_in smk_host; /* network address */ | 140 | struct in_addr smk_host; /* network address */ |
126 | struct in_addr smk_mask; /* network mask */ | 141 | struct in_addr smk_mask; /* network mask */ |
142 | int smk_masks; /* mask size */ | ||
143 | struct smack_known *smk_label; /* label */ | ||
144 | }; | ||
145 | |||
146 | #if IS_ENABLED(CONFIG_IPV6) | ||
147 | /* | ||
148 | * An entry in the table identifying IPv6 hosts. | ||
149 | */ | ||
150 | struct smk_net6addr { | ||
151 | struct list_head list; | ||
152 | struct in6_addr smk_host; /* network address */ | ||
153 | struct in6_addr smk_mask; /* network mask */ | ||
154 | int smk_masks; /* mask size */ | ||
127 | struct smack_known *smk_label; /* label */ | 155 | struct smack_known *smk_label; /* label */ |
128 | }; | 156 | }; |
157 | #endif /* CONFIG_IPV6 */ | ||
129 | 158 | ||
159 | #ifdef SMACK_IPV6_PORT_LABELING | ||
130 | /* | 160 | /* |
131 | * An entry in the table identifying ports. | 161 | * An entry in the table identifying ports. |
132 | */ | 162 | */ |
@@ -137,12 +167,31 @@ struct smk_port_label { | |||
137 | struct smack_known *smk_in; /* inbound label */ | 167 | struct smack_known *smk_in; /* inbound label */ |
138 | struct smack_known *smk_out; /* outgoing label */ | 168 | struct smack_known *smk_out; /* outgoing label */ |
139 | }; | 169 | }; |
170 | #endif /* SMACK_IPV6_PORT_LABELING */ | ||
140 | 171 | ||
141 | struct smack_onlycap { | 172 | struct smack_onlycap { |
142 | struct list_head list; | 173 | struct list_head list; |
143 | struct smack_known *smk_label; | 174 | struct smack_known *smk_label; |
144 | }; | 175 | }; |
145 | 176 | ||
177 | /* Super block security struct flags for mount options */ | ||
178 | #define FSDEFAULT_MNT 0x01 | ||
179 | #define FSFLOOR_MNT 0x02 | ||
180 | #define FSHAT_MNT 0x04 | ||
181 | #define FSROOT_MNT 0x08 | ||
182 | #define FSTRANS_MNT 0x10 | ||
183 | |||
184 | #define NUM_SMK_MNT_OPTS 5 | ||
185 | |||
186 | enum { | ||
187 | Opt_error = -1, | ||
188 | Opt_fsdefault = 1, | ||
189 | Opt_fsfloor = 2, | ||
190 | Opt_fshat = 3, | ||
191 | Opt_fsroot = 4, | ||
192 | Opt_fstransmute = 5, | ||
193 | }; | ||
194 | |||
146 | /* | 195 | /* |
147 | * Mount options | 196 | * Mount options |
148 | */ | 197 | */ |
@@ -152,6 +201,7 @@ struct smack_onlycap { | |||
152 | #define SMK_FSROOT "smackfsroot=" | 201 | #define SMK_FSROOT "smackfsroot=" |
153 | #define SMK_FSTRANS "smackfstransmute=" | 202 | #define SMK_FSTRANS "smackfstransmute=" |
154 | 203 | ||
204 | #define SMACK_DELETE_OPTION "-DELETE" | ||
155 | #define SMACK_CIPSO_OPTION "-CIPSO" | 205 | #define SMACK_CIPSO_OPTION "-CIPSO" |
156 | 206 | ||
157 | /* | 207 | /* |
@@ -234,10 +284,6 @@ struct smk_audit_info { | |||
234 | struct smack_audit_data sad; | 284 | struct smack_audit_data sad; |
235 | #endif | 285 | #endif |
236 | }; | 286 | }; |
237 | /* | ||
238 | * These functions are in smack_lsm.c | ||
239 | */ | ||
240 | struct inode_smack *new_inode_smack(struct smack_known *); | ||
241 | 287 | ||
242 | /* | 288 | /* |
243 | * These functions are in smack_access.c | 289 | * These functions are in smack_access.c |
@@ -267,7 +313,6 @@ extern struct smack_known *smack_syslog_label; | |||
267 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 313 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
268 | extern struct smack_known *smack_unconfined; | 314 | extern struct smack_known *smack_unconfined; |
269 | #endif | 315 | #endif |
270 | extern struct smack_known smack_cipso_option; | ||
271 | extern int smack_ptrace_rule; | 316 | extern int smack_ptrace_rule; |
272 | 317 | ||
273 | extern struct smack_known smack_known_floor; | 318 | extern struct smack_known smack_known_floor; |
@@ -279,7 +324,10 @@ extern struct smack_known smack_known_web; | |||
279 | 324 | ||
280 | extern struct mutex smack_known_lock; | 325 | extern struct mutex smack_known_lock; |
281 | extern struct list_head smack_known_list; | 326 | extern struct list_head smack_known_list; |
282 | extern struct list_head smk_netlbladdr_list; | 327 | extern struct list_head smk_net4addr_list; |
328 | #if IS_ENABLED(CONFIG_IPV6) | ||
329 | extern struct list_head smk_net6addr_list; | ||
330 | #endif /* CONFIG_IPV6 */ | ||
283 | 331 | ||
284 | extern struct mutex smack_onlycap_lock; | 332 | extern struct mutex smack_onlycap_lock; |
285 | extern struct list_head smack_onlycap_list; | 333 | extern struct list_head smack_onlycap_list; |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 00f6b38bffbd..bc1053fb5d1d 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -639,6 +639,12 @@ int smack_privileged(int cap) | |||
639 | struct smack_known *skp = smk_of_current(); | 639 | struct smack_known *skp = smk_of_current(); |
640 | struct smack_onlycap *sop; | 640 | struct smack_onlycap *sop; |
641 | 641 | ||
642 | /* | ||
643 | * All kernel tasks are privileged | ||
644 | */ | ||
645 | if (unlikely(current->flags & PF_KTHREAD)) | ||
646 | return 1; | ||
647 | |||
642 | if (!capable(cap)) | 648 | if (!capable(cap)) |
643 | return 0; | 649 | return 0; |
644 | 650 | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index a143328f75eb..996c88956438 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/msg.h> | 41 | #include <linux/msg.h> |
42 | #include <linux/shm.h> | 42 | #include <linux/shm.h> |
43 | #include <linux/binfmts.h> | 43 | #include <linux/binfmts.h> |
44 | #include <linux/parser.h> | ||
44 | #include "smack.h" | 45 | #include "smack.h" |
45 | 46 | ||
46 | #define TRANS_TRUE "TRUE" | 47 | #define TRANS_TRUE "TRUE" |
@@ -50,12 +51,21 @@ | |||
50 | #define SMK_RECEIVING 1 | 51 | #define SMK_RECEIVING 1 |
51 | #define SMK_SENDING 2 | 52 | #define SMK_SENDING 2 |
52 | 53 | ||
53 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 54 | #ifdef SMACK_IPV6_PORT_LABELING |
54 | LIST_HEAD(smk_ipv6_port_list); | 55 | LIST_HEAD(smk_ipv6_port_list); |
55 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 56 | #endif |
56 | static struct kmem_cache *smack_inode_cache; | 57 | static struct kmem_cache *smack_inode_cache; |
57 | int smack_enabled; | 58 | int smack_enabled; |
58 | 59 | ||
60 | static const match_table_t smk_mount_tokens = { | ||
61 | {Opt_fsdefault, SMK_FSDEFAULT "%s"}, | ||
62 | {Opt_fsfloor, SMK_FSFLOOR "%s"}, | ||
63 | {Opt_fshat, SMK_FSHAT "%s"}, | ||
64 | {Opt_fsroot, SMK_FSROOT "%s"}, | ||
65 | {Opt_fstransmute, SMK_FSTRANS "%s"}, | ||
66 | {Opt_error, NULL}, | ||
67 | }; | ||
68 | |||
59 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 69 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
60 | static char *smk_bu_mess[] = { | 70 | static char *smk_bu_mess[] = { |
61 | "Bringup Error", /* Unused */ | 71 | "Bringup Error", /* Unused */ |
@@ -281,7 +291,7 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip, | |||
281 | * | 291 | * |
282 | * Returns the new blob or NULL if there's no memory available | 292 | * Returns the new blob or NULL if there's no memory available |
283 | */ | 293 | */ |
284 | struct inode_smack *new_inode_smack(struct smack_known *skp) | 294 | static struct inode_smack *new_inode_smack(struct smack_known *skp) |
285 | { | 295 | { |
286 | struct inode_smack *isp; | 296 | struct inode_smack *isp; |
287 | 297 | ||
@@ -577,76 +587,197 @@ static int smack_sb_copy_data(char *orig, char *smackopts) | |||
577 | } | 587 | } |
578 | 588 | ||
579 | /** | 589 | /** |
580 | * smack_sb_kern_mount - Smack specific mount processing | 590 | * smack_parse_opts_str - parse Smack specific mount options |
591 | * @options: mount options string | ||
592 | * @opts: where to store converted mount opts | ||
593 | * | ||
594 | * Returns 0 on success or -ENOMEM on error. | ||
595 | * | ||
596 | * converts Smack specific mount options to generic security option format | ||
597 | */ | ||
598 | static int smack_parse_opts_str(char *options, | ||
599 | struct security_mnt_opts *opts) | ||
600 | { | ||
601 | char *p; | ||
602 | char *fsdefault = NULL; | ||
603 | char *fsfloor = NULL; | ||
604 | char *fshat = NULL; | ||
605 | char *fsroot = NULL; | ||
606 | char *fstransmute = NULL; | ||
607 | int rc = -ENOMEM; | ||
608 | int num_mnt_opts = 0; | ||
609 | int token; | ||
610 | |||
611 | opts->num_mnt_opts = 0; | ||
612 | |||
613 | if (!options) | ||
614 | return 0; | ||
615 | |||
616 | while ((p = strsep(&options, ",")) != NULL) { | ||
617 | substring_t args[MAX_OPT_ARGS]; | ||
618 | |||
619 | if (!*p) | ||
620 | continue; | ||
621 | |||
622 | token = match_token(p, smk_mount_tokens, args); | ||
623 | |||
624 | switch (token) { | ||
625 | case Opt_fsdefault: | ||
626 | if (fsdefault) | ||
627 | goto out_opt_err; | ||
628 | fsdefault = match_strdup(&args[0]); | ||
629 | if (!fsdefault) | ||
630 | goto out_err; | ||
631 | break; | ||
632 | case Opt_fsfloor: | ||
633 | if (fsfloor) | ||
634 | goto out_opt_err; | ||
635 | fsfloor = match_strdup(&args[0]); | ||
636 | if (!fsfloor) | ||
637 | goto out_err; | ||
638 | break; | ||
639 | case Opt_fshat: | ||
640 | if (fshat) | ||
641 | goto out_opt_err; | ||
642 | fshat = match_strdup(&args[0]); | ||
643 | if (!fshat) | ||
644 | goto out_err; | ||
645 | break; | ||
646 | case Opt_fsroot: | ||
647 | if (fsroot) | ||
648 | goto out_opt_err; | ||
649 | fsroot = match_strdup(&args[0]); | ||
650 | if (!fsroot) | ||
651 | goto out_err; | ||
652 | break; | ||
653 | case Opt_fstransmute: | ||
654 | if (fstransmute) | ||
655 | goto out_opt_err; | ||
656 | fstransmute = match_strdup(&args[0]); | ||
657 | if (!fstransmute) | ||
658 | goto out_err; | ||
659 | break; | ||
660 | default: | ||
661 | rc = -EINVAL; | ||
662 | pr_warn("Smack: unknown mount option\n"); | ||
663 | goto out_err; | ||
664 | } | ||
665 | } | ||
666 | |||
667 | opts->mnt_opts = kcalloc(NUM_SMK_MNT_OPTS, sizeof(char *), GFP_ATOMIC); | ||
668 | if (!opts->mnt_opts) | ||
669 | goto out_err; | ||
670 | |||
671 | opts->mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS, sizeof(int), | ||
672 | GFP_ATOMIC); | ||
673 | if (!opts->mnt_opts_flags) { | ||
674 | kfree(opts->mnt_opts); | ||
675 | goto out_err; | ||
676 | } | ||
677 | |||
678 | if (fsdefault) { | ||
679 | opts->mnt_opts[num_mnt_opts] = fsdefault; | ||
680 | opts->mnt_opts_flags[num_mnt_opts++] = FSDEFAULT_MNT; | ||
681 | } | ||
682 | if (fsfloor) { | ||
683 | opts->mnt_opts[num_mnt_opts] = fsfloor; | ||
684 | opts->mnt_opts_flags[num_mnt_opts++] = FSFLOOR_MNT; | ||
685 | } | ||
686 | if (fshat) { | ||
687 | opts->mnt_opts[num_mnt_opts] = fshat; | ||
688 | opts->mnt_opts_flags[num_mnt_opts++] = FSHAT_MNT; | ||
689 | } | ||
690 | if (fsroot) { | ||
691 | opts->mnt_opts[num_mnt_opts] = fsroot; | ||
692 | opts->mnt_opts_flags[num_mnt_opts++] = FSROOT_MNT; | ||
693 | } | ||
694 | if (fstransmute) { | ||
695 | opts->mnt_opts[num_mnt_opts] = fstransmute; | ||
696 | opts->mnt_opts_flags[num_mnt_opts++] = FSTRANS_MNT; | ||
697 | } | ||
698 | |||
699 | opts->num_mnt_opts = num_mnt_opts; | ||
700 | return 0; | ||
701 | |||
702 | out_opt_err: | ||
703 | rc = -EINVAL; | ||
704 | pr_warn("Smack: duplicate mount options\n"); | ||
705 | |||
706 | out_err: | ||
707 | kfree(fsdefault); | ||
708 | kfree(fsfloor); | ||
709 | kfree(fshat); | ||
710 | kfree(fsroot); | ||
711 | kfree(fstransmute); | ||
712 | return rc; | ||
713 | } | ||
714 | |||
715 | /** | ||
716 | * smack_set_mnt_opts - set Smack specific mount options | ||
581 | * @sb: the file system superblock | 717 | * @sb: the file system superblock |
582 | * @flags: the mount flags | 718 | * @opts: Smack mount options |
583 | * @data: the smack mount options | 719 | * @kern_flags: mount option from kernel space or user space |
720 | * @set_kern_flags: where to store converted mount opts | ||
584 | * | 721 | * |
585 | * Returns 0 on success, an error code on failure | 722 | * Returns 0 on success, an error code on failure |
723 | * | ||
724 | * Allow filesystems with binary mount data to explicitly set Smack mount | ||
725 | * labels. | ||
586 | */ | 726 | */ |
587 | static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | 727 | static int smack_set_mnt_opts(struct super_block *sb, |
728 | struct security_mnt_opts *opts, | ||
729 | unsigned long kern_flags, | ||
730 | unsigned long *set_kern_flags) | ||
588 | { | 731 | { |
589 | struct dentry *root = sb->s_root; | 732 | struct dentry *root = sb->s_root; |
590 | struct inode *inode = d_backing_inode(root); | 733 | struct inode *inode = d_backing_inode(root); |
591 | struct superblock_smack *sp = sb->s_security; | 734 | struct superblock_smack *sp = sb->s_security; |
592 | struct inode_smack *isp; | 735 | struct inode_smack *isp; |
593 | struct smack_known *skp; | 736 | struct smack_known *skp; |
594 | char *op; | 737 | int i; |
595 | char *commap; | 738 | int num_opts = opts->num_mnt_opts; |
596 | int transmute = 0; | 739 | int transmute = 0; |
597 | int specified = 0; | ||
598 | 740 | ||
599 | if (sp->smk_initialized) | 741 | if (sp->smk_initialized) |
600 | return 0; | 742 | return 0; |
601 | 743 | ||
602 | sp->smk_initialized = 1; | 744 | sp->smk_initialized = 1; |
603 | 745 | ||
604 | for (op = data; op != NULL; op = commap) { | 746 | for (i = 0; i < num_opts; i++) { |
605 | commap = strchr(op, ','); | 747 | switch (opts->mnt_opts_flags[i]) { |
606 | if (commap != NULL) | 748 | case FSDEFAULT_MNT: |
607 | *commap++ = '\0'; | 749 | skp = smk_import_entry(opts->mnt_opts[i], 0); |
608 | |||
609 | if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { | ||
610 | op += strlen(SMK_FSHAT); | ||
611 | skp = smk_import_entry(op, 0); | ||
612 | if (IS_ERR(skp)) | 750 | if (IS_ERR(skp)) |
613 | return PTR_ERR(skp); | 751 | return PTR_ERR(skp); |
614 | sp->smk_hat = skp; | 752 | sp->smk_default = skp; |
615 | specified = 1; | 753 | break; |
616 | 754 | case FSFLOOR_MNT: | |
617 | } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { | 755 | skp = smk_import_entry(opts->mnt_opts[i], 0); |
618 | op += strlen(SMK_FSFLOOR); | ||
619 | skp = smk_import_entry(op, 0); | ||
620 | if (IS_ERR(skp)) | 756 | if (IS_ERR(skp)) |
621 | return PTR_ERR(skp); | 757 | return PTR_ERR(skp); |
622 | sp->smk_floor = skp; | 758 | sp->smk_floor = skp; |
623 | specified = 1; | 759 | break; |
624 | 760 | case FSHAT_MNT: | |
625 | } else if (strncmp(op, SMK_FSDEFAULT, | 761 | skp = smk_import_entry(opts->mnt_opts[i], 0); |
626 | strlen(SMK_FSDEFAULT)) == 0) { | ||
627 | op += strlen(SMK_FSDEFAULT); | ||
628 | skp = smk_import_entry(op, 0); | ||
629 | if (IS_ERR(skp)) | 762 | if (IS_ERR(skp)) |
630 | return PTR_ERR(skp); | 763 | return PTR_ERR(skp); |
631 | sp->smk_default = skp; | 764 | sp->smk_hat = skp; |
632 | specified = 1; | 765 | break; |
633 | 766 | case FSROOT_MNT: | |
634 | } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { | 767 | skp = smk_import_entry(opts->mnt_opts[i], 0); |
635 | op += strlen(SMK_FSROOT); | ||
636 | skp = smk_import_entry(op, 0); | ||
637 | if (IS_ERR(skp)) | 768 | if (IS_ERR(skp)) |
638 | return PTR_ERR(skp); | 769 | return PTR_ERR(skp); |
639 | sp->smk_root = skp; | 770 | sp->smk_root = skp; |
640 | specified = 1; | 771 | break; |
641 | 772 | case FSTRANS_MNT: | |
642 | } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { | 773 | skp = smk_import_entry(opts->mnt_opts[i], 0); |
643 | op += strlen(SMK_FSTRANS); | ||
644 | skp = smk_import_entry(op, 0); | ||
645 | if (IS_ERR(skp)) | 774 | if (IS_ERR(skp)) |
646 | return PTR_ERR(skp); | 775 | return PTR_ERR(skp); |
647 | sp->smk_root = skp; | 776 | sp->smk_root = skp; |
648 | transmute = 1; | 777 | transmute = 1; |
649 | specified = 1; | 778 | break; |
779 | default: | ||
780 | break; | ||
650 | } | 781 | } |
651 | } | 782 | } |
652 | 783 | ||
@@ -654,7 +785,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
654 | /* | 785 | /* |
655 | * Unprivileged mounts don't get to specify Smack values. | 786 | * Unprivileged mounts don't get to specify Smack values. |
656 | */ | 787 | */ |
657 | if (specified) | 788 | if (num_opts) |
658 | return -EPERM; | 789 | return -EPERM; |
659 | /* | 790 | /* |
660 | * Unprivileged mounts get root and default from the caller. | 791 | * Unprivileged mounts get root and default from the caller. |
@@ -663,6 +794,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
663 | sp->smk_root = skp; | 794 | sp->smk_root = skp; |
664 | sp->smk_default = skp; | 795 | sp->smk_default = skp; |
665 | } | 796 | } |
797 | |||
666 | /* | 798 | /* |
667 | * Initialize the root inode. | 799 | * Initialize the root inode. |
668 | */ | 800 | */ |
@@ -682,6 +814,37 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
682 | } | 814 | } |
683 | 815 | ||
684 | /** | 816 | /** |
817 | * smack_sb_kern_mount - Smack specific mount processing | ||
818 | * @sb: the file system superblock | ||
819 | * @flags: the mount flags | ||
820 | * @data: the smack mount options | ||
821 | * | ||
822 | * Returns 0 on success, an error code on failure | ||
823 | */ | ||
824 | static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | ||
825 | { | ||
826 | int rc = 0; | ||
827 | char *options = data; | ||
828 | struct security_mnt_opts opts; | ||
829 | |||
830 | security_init_mnt_opts(&opts); | ||
831 | |||
832 | if (!options) | ||
833 | goto out; | ||
834 | |||
835 | rc = smack_parse_opts_str(options, &opts); | ||
836 | if (rc) | ||
837 | goto out_err; | ||
838 | |||
839 | out: | ||
840 | rc = smack_set_mnt_opts(sb, &opts, 0, NULL); | ||
841 | |||
842 | out_err: | ||
843 | security_free_mnt_opts(&opts); | ||
844 | return rc; | ||
845 | } | ||
846 | |||
847 | /** | ||
685 | * smack_sb_statfs - Smack check on statfs | 848 | * smack_sb_statfs - Smack check on statfs |
686 | * @dentry: identifies the file system in question | 849 | * @dentry: identifies the file system in question |
687 | * | 850 | * |
@@ -2113,7 +2276,7 @@ static void smack_sk_free_security(struct sock *sk) | |||
2113 | } | 2276 | } |
2114 | 2277 | ||
2115 | /** | 2278 | /** |
2116 | * smack_host_label - check host based restrictions | 2279 | * smack_ipv4host_label - check host based restrictions |
2117 | * @sip: the object end | 2280 | * @sip: the object end |
2118 | * | 2281 | * |
2119 | * looks for host based access restrictions | 2282 | * looks for host based access restrictions |
@@ -2124,30 +2287,96 @@ static void smack_sk_free_security(struct sock *sk) | |||
2124 | * | 2287 | * |
2125 | * Returns the label of the far end or NULL if it's not special. | 2288 | * Returns the label of the far end or NULL if it's not special. |
2126 | */ | 2289 | */ |
2127 | static struct smack_known *smack_host_label(struct sockaddr_in *sip) | 2290 | static struct smack_known *smack_ipv4host_label(struct sockaddr_in *sip) |
2128 | { | 2291 | { |
2129 | struct smk_netlbladdr *snp; | 2292 | struct smk_net4addr *snp; |
2130 | struct in_addr *siap = &sip->sin_addr; | 2293 | struct in_addr *siap = &sip->sin_addr; |
2131 | 2294 | ||
2132 | if (siap->s_addr == 0) | 2295 | if (siap->s_addr == 0) |
2133 | return NULL; | 2296 | return NULL; |
2134 | 2297 | ||
2135 | list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) | 2298 | list_for_each_entry_rcu(snp, &smk_net4addr_list, list) |
2299 | /* | ||
2300 | * we break after finding the first match because | ||
2301 | * the list is sorted from longest to shortest mask | ||
2302 | * so we have found the most specific match | ||
2303 | */ | ||
2304 | if (snp->smk_host.s_addr == | ||
2305 | (siap->s_addr & snp->smk_mask.s_addr)) | ||
2306 | return snp->smk_label; | ||
2307 | |||
2308 | return NULL; | ||
2309 | } | ||
2310 | |||
2311 | #if IS_ENABLED(CONFIG_IPV6) | ||
2312 | /* | ||
2313 | * smk_ipv6_localhost - Check for local ipv6 host address | ||
2314 | * @sip: the address | ||
2315 | * | ||
2316 | * Returns boolean true if this is the localhost address | ||
2317 | */ | ||
2318 | static bool smk_ipv6_localhost(struct sockaddr_in6 *sip) | ||
2319 | { | ||
2320 | __be16 *be16p = (__be16 *)&sip->sin6_addr; | ||
2321 | __be32 *be32p = (__be32 *)&sip->sin6_addr; | ||
2322 | |||
2323 | if (be32p[0] == 0 && be32p[1] == 0 && be32p[2] == 0 && be16p[6] == 0 && | ||
2324 | ntohs(be16p[7]) == 1) | ||
2325 | return true; | ||
2326 | return false; | ||
2327 | } | ||
2328 | |||
2329 | /** | ||
2330 | * smack_ipv6host_label - check host based restrictions | ||
2331 | * @sip: the object end | ||
2332 | * | ||
2333 | * looks for host based access restrictions | ||
2334 | * | ||
2335 | * This version will only be appropriate for really small sets of single label | ||
2336 | * hosts. The caller is responsible for ensuring that the RCU read lock is | ||
2337 | * taken before calling this function. | ||
2338 | * | ||
2339 | * Returns the label of the far end or NULL if it's not special. | ||
2340 | */ | ||
2341 | static struct smack_known *smack_ipv6host_label(struct sockaddr_in6 *sip) | ||
2342 | { | ||
2343 | struct smk_net6addr *snp; | ||
2344 | struct in6_addr *sap = &sip->sin6_addr; | ||
2345 | int i; | ||
2346 | int found = 0; | ||
2347 | |||
2348 | /* | ||
2349 | * It's local. Don't look for a host label. | ||
2350 | */ | ||
2351 | if (smk_ipv6_localhost(sip)) | ||
2352 | return NULL; | ||
2353 | |||
2354 | list_for_each_entry_rcu(snp, &smk_net6addr_list, list) { | ||
2136 | /* | 2355 | /* |
2137 | * we break after finding the first match because | 2356 | * we break after finding the first match because |
2138 | * the list is sorted from longest to shortest mask | 2357 | * the list is sorted from longest to shortest mask |
2139 | * so we have found the most specific match | 2358 | * so we have found the most specific match |
2140 | */ | 2359 | */ |
2141 | if ((&snp->smk_host.sin_addr)->s_addr == | 2360 | for (found = 1, i = 0; i < 8; i++) { |
2142 | (siap->s_addr & (&snp->smk_mask)->s_addr)) { | 2361 | /* |
2143 | /* we have found the special CIPSO option */ | 2362 | * If the label is NULL the entry has |
2144 | if (snp->smk_label == &smack_cipso_option) | 2363 | * been renounced. Ignore it. |
2145 | return NULL; | 2364 | */ |
2146 | return snp->smk_label; | 2365 | if (snp->smk_label == NULL) |
2366 | continue; | ||
2367 | if ((sap->s6_addr16[i] & snp->smk_mask.s6_addr16[i]) != | ||
2368 | snp->smk_host.s6_addr16[i]) { | ||
2369 | found = 0; | ||
2370 | break; | ||
2371 | } | ||
2147 | } | 2372 | } |
2373 | if (found) | ||
2374 | return snp->smk_label; | ||
2375 | } | ||
2148 | 2376 | ||
2149 | return NULL; | 2377 | return NULL; |
2150 | } | 2378 | } |
2379 | #endif /* CONFIG_IPV6 */ | ||
2151 | 2380 | ||
2152 | /** | 2381 | /** |
2153 | * smack_netlabel - Set the secattr on a socket | 2382 | * smack_netlabel - Set the secattr on a socket |
@@ -2211,7 +2440,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) | |||
2211 | struct smk_audit_info ad; | 2440 | struct smk_audit_info ad; |
2212 | 2441 | ||
2213 | rcu_read_lock(); | 2442 | rcu_read_lock(); |
2214 | hkp = smack_host_label(sap); | 2443 | hkp = smack_ipv4host_label(sap); |
2215 | if (hkp != NULL) { | 2444 | if (hkp != NULL) { |
2216 | #ifdef CONFIG_AUDIT | 2445 | #ifdef CONFIG_AUDIT |
2217 | struct lsm_network_audit net; | 2446 | struct lsm_network_audit net; |
@@ -2236,7 +2465,42 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) | |||
2236 | return smack_netlabel(sk, sk_lbl); | 2465 | return smack_netlabel(sk, sk_lbl); |
2237 | } | 2466 | } |
2238 | 2467 | ||
2239 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 2468 | #if IS_ENABLED(CONFIG_IPV6) |
2469 | /** | ||
2470 | * smk_ipv6_check - check Smack access | ||
2471 | * @subject: subject Smack label | ||
2472 | * @object: object Smack label | ||
2473 | * @address: address | ||
2474 | * @act: the action being taken | ||
2475 | * | ||
2476 | * Check an IPv6 access | ||
2477 | */ | ||
2478 | static int smk_ipv6_check(struct smack_known *subject, | ||
2479 | struct smack_known *object, | ||
2480 | struct sockaddr_in6 *address, int act) | ||
2481 | { | ||
2482 | #ifdef CONFIG_AUDIT | ||
2483 | struct lsm_network_audit net; | ||
2484 | #endif | ||
2485 | struct smk_audit_info ad; | ||
2486 | int rc; | ||
2487 | |||
2488 | #ifdef CONFIG_AUDIT | ||
2489 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); | ||
2490 | ad.a.u.net->family = PF_INET6; | ||
2491 | ad.a.u.net->dport = ntohs(address->sin6_port); | ||
2492 | if (act == SMK_RECEIVING) | ||
2493 | ad.a.u.net->v6info.saddr = address->sin6_addr; | ||
2494 | else | ||
2495 | ad.a.u.net->v6info.daddr = address->sin6_addr; | ||
2496 | #endif | ||
2497 | rc = smk_access(subject, object, MAY_WRITE, &ad); | ||
2498 | rc = smk_bu_note("IPv6 check", subject, object, MAY_WRITE, rc); | ||
2499 | return rc; | ||
2500 | } | ||
2501 | #endif /* CONFIG_IPV6 */ | ||
2502 | |||
2503 | #ifdef SMACK_IPV6_PORT_LABELING | ||
2240 | /** | 2504 | /** |
2241 | * smk_ipv6_port_label - Smack port access table management | 2505 | * smk_ipv6_port_label - Smack port access table management |
2242 | * @sock: socket | 2506 | * @sock: socket |
@@ -2320,48 +2584,43 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) | |||
2320 | static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, | 2584 | static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, |
2321 | int act) | 2585 | int act) |
2322 | { | 2586 | { |
2323 | __be16 *bep; | ||
2324 | __be32 *be32p; | ||
2325 | struct smk_port_label *spp; | 2587 | struct smk_port_label *spp; |
2326 | struct socket_smack *ssp = sk->sk_security; | 2588 | struct socket_smack *ssp = sk->sk_security; |
2327 | struct smack_known *skp; | 2589 | struct smack_known *skp = NULL; |
2328 | unsigned short port = 0; | 2590 | unsigned short port; |
2329 | struct smack_known *object; | 2591 | struct smack_known *object; |
2330 | struct smk_audit_info ad; | ||
2331 | int rc; | ||
2332 | #ifdef CONFIG_AUDIT | ||
2333 | struct lsm_network_audit net; | ||
2334 | #endif | ||
2335 | 2592 | ||
2336 | if (act == SMK_RECEIVING) { | 2593 | if (act == SMK_RECEIVING) { |
2337 | skp = smack_net_ambient; | 2594 | skp = smack_ipv6host_label(address); |
2338 | object = ssp->smk_in; | 2595 | object = ssp->smk_in; |
2339 | } else { | 2596 | } else { |
2340 | skp = ssp->smk_out; | 2597 | skp = ssp->smk_out; |
2341 | object = smack_net_ambient; | 2598 | object = smack_ipv6host_label(address); |
2342 | } | 2599 | } |
2343 | 2600 | ||
2344 | /* | 2601 | /* |
2345 | * Get the IP address and port from the address. | 2602 | * The other end is a single label host. |
2346 | */ | 2603 | */ |
2347 | port = ntohs(address->sin6_port); | 2604 | if (skp != NULL && object != NULL) |
2348 | bep = (__be16 *)(&address->sin6_addr); | 2605 | return smk_ipv6_check(skp, object, address, act); |
2349 | be32p = (__be32 *)(&address->sin6_addr); | 2606 | if (skp == NULL) |
2607 | skp = smack_net_ambient; | ||
2608 | if (object == NULL) | ||
2609 | object = smack_net_ambient; | ||
2350 | 2610 | ||
2351 | /* | 2611 | /* |
2352 | * It's remote, so port lookup does no good. | 2612 | * It's remote, so port lookup does no good. |
2353 | */ | 2613 | */ |
2354 | if (be32p[0] || be32p[1] || be32p[2] || bep[6] || ntohs(bep[7]) != 1) | 2614 | if (!smk_ipv6_localhost(address)) |
2355 | goto auditout; | 2615 | return smk_ipv6_check(skp, object, address, act); |
2356 | 2616 | ||
2357 | /* | 2617 | /* |
2358 | * It's local so the send check has to have passed. | 2618 | * It's local so the send check has to have passed. |
2359 | */ | 2619 | */ |
2360 | if (act == SMK_RECEIVING) { | 2620 | if (act == SMK_RECEIVING) |
2361 | skp = &smack_known_web; | 2621 | return 0; |
2362 | goto auditout; | ||
2363 | } | ||
2364 | 2622 | ||
2623 | port = ntohs(address->sin6_port); | ||
2365 | list_for_each_entry(spp, &smk_ipv6_port_list, list) { | 2624 | list_for_each_entry(spp, &smk_ipv6_port_list, list) { |
2366 | if (spp->smk_port != port) | 2625 | if (spp->smk_port != port) |
2367 | continue; | 2626 | continue; |
@@ -2371,22 +2630,9 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, | |||
2371 | break; | 2630 | break; |
2372 | } | 2631 | } |
2373 | 2632 | ||
2374 | auditout: | 2633 | return smk_ipv6_check(skp, object, address, act); |
2375 | |||
2376 | #ifdef CONFIG_AUDIT | ||
2377 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); | ||
2378 | ad.a.u.net->family = sk->sk_family; | ||
2379 | ad.a.u.net->dport = port; | ||
2380 | if (act == SMK_RECEIVING) | ||
2381 | ad.a.u.net->v6info.saddr = address->sin6_addr; | ||
2382 | else | ||
2383 | ad.a.u.net->v6info.daddr = address->sin6_addr; | ||
2384 | #endif | ||
2385 | rc = smk_access(skp, object, MAY_WRITE, &ad); | ||
2386 | rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc); | ||
2387 | return rc; | ||
2388 | } | 2634 | } |
2389 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 2635 | #endif /* SMACK_IPV6_PORT_LABELING */ |
2390 | 2636 | ||
2391 | /** | 2637 | /** |
2392 | * smack_inode_setsecurity - set smack xattrs | 2638 | * smack_inode_setsecurity - set smack xattrs |
@@ -2447,10 +2693,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
2447 | } else | 2693 | } else |
2448 | return -EOPNOTSUPP; | 2694 | return -EOPNOTSUPP; |
2449 | 2695 | ||
2450 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 2696 | #ifdef SMACK_IPV6_PORT_LABELING |
2451 | if (sock->sk->sk_family == PF_INET6) | 2697 | if (sock->sk->sk_family == PF_INET6) |
2452 | smk_ipv6_port_label(sock, NULL); | 2698 | smk_ipv6_port_label(sock, NULL); |
2453 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 2699 | #endif |
2454 | 2700 | ||
2455 | return 0; | 2701 | return 0; |
2456 | } | 2702 | } |
@@ -2492,7 +2738,7 @@ static int smack_socket_post_create(struct socket *sock, int family, | |||
2492 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); | 2738 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); |
2493 | } | 2739 | } |
2494 | 2740 | ||
2495 | #ifndef CONFIG_SECURITY_SMACK_NETFILTER | 2741 | #ifdef SMACK_IPV6_PORT_LABELING |
2496 | /** | 2742 | /** |
2497 | * smack_socket_bind - record port binding information. | 2743 | * smack_socket_bind - record port binding information. |
2498 | * @sock: the socket | 2744 | * @sock: the socket |
@@ -2506,14 +2752,11 @@ static int smack_socket_post_create(struct socket *sock, int family, | |||
2506 | static int smack_socket_bind(struct socket *sock, struct sockaddr *address, | 2752 | static int smack_socket_bind(struct socket *sock, struct sockaddr *address, |
2507 | int addrlen) | 2753 | int addrlen) |
2508 | { | 2754 | { |
2509 | #if IS_ENABLED(CONFIG_IPV6) | ||
2510 | if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) | 2755 | if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) |
2511 | smk_ipv6_port_label(sock, address); | 2756 | smk_ipv6_port_label(sock, address); |
2512 | #endif | ||
2513 | |||
2514 | return 0; | 2757 | return 0; |
2515 | } | 2758 | } |
2516 | #endif /* !CONFIG_SECURITY_SMACK_NETFILTER */ | 2759 | #endif /* SMACK_IPV6_PORT_LABELING */ |
2517 | 2760 | ||
2518 | /** | 2761 | /** |
2519 | * smack_socket_connect - connect access check | 2762 | * smack_socket_connect - connect access check |
@@ -2529,6 +2772,13 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, | |||
2529 | int addrlen) | 2772 | int addrlen) |
2530 | { | 2773 | { |
2531 | int rc = 0; | 2774 | int rc = 0; |
2775 | #if IS_ENABLED(CONFIG_IPV6) | ||
2776 | struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap; | ||
2777 | #endif | ||
2778 | #ifdef SMACK_IPV6_SECMARK_LABELING | ||
2779 | struct smack_known *rsp; | ||
2780 | struct socket_smack *ssp = sock->sk->sk_security; | ||
2781 | #endif | ||
2532 | 2782 | ||
2533 | if (sock->sk == NULL) | 2783 | if (sock->sk == NULL) |
2534 | return 0; | 2784 | return 0; |
@@ -2542,10 +2792,15 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, | |||
2542 | case PF_INET6: | 2792 | case PF_INET6: |
2543 | if (addrlen < sizeof(struct sockaddr_in6)) | 2793 | if (addrlen < sizeof(struct sockaddr_in6)) |
2544 | return -EINVAL; | 2794 | return -EINVAL; |
2545 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 2795 | #ifdef SMACK_IPV6_SECMARK_LABELING |
2546 | rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap, | 2796 | rsp = smack_ipv6host_label(sip); |
2797 | if (rsp != NULL) | ||
2798 | rc = smk_ipv6_check(ssp->smk_out, rsp, sip, | ||
2547 | SMK_CONNECTING); | 2799 | SMK_CONNECTING); |
2548 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 2800 | #endif |
2801 | #ifdef SMACK_IPV6_PORT_LABELING | ||
2802 | rc = smk_ipv6_port_check(sock->sk, sip, SMK_CONNECTING); | ||
2803 | #endif | ||
2549 | break; | 2804 | break; |
2550 | } | 2805 | } |
2551 | return rc; | 2806 | return rc; |
@@ -3431,9 +3686,13 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
3431 | int size) | 3686 | int size) |
3432 | { | 3687 | { |
3433 | struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; | 3688 | struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; |
3434 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 3689 | #if IS_ENABLED(CONFIG_IPV6) |
3435 | struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; | 3690 | struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; |
3436 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 3691 | #endif |
3692 | #ifdef SMACK_IPV6_SECMARK_LABELING | ||
3693 | struct socket_smack *ssp = sock->sk->sk_security; | ||
3694 | struct smack_known *rsp; | ||
3695 | #endif | ||
3437 | int rc = 0; | 3696 | int rc = 0; |
3438 | 3697 | ||
3439 | /* | 3698 | /* |
@@ -3447,9 +3706,15 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
3447 | rc = smack_netlabel_send(sock->sk, sip); | 3706 | rc = smack_netlabel_send(sock->sk, sip); |
3448 | break; | 3707 | break; |
3449 | case AF_INET6: | 3708 | case AF_INET6: |
3450 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 3709 | #ifdef SMACK_IPV6_SECMARK_LABELING |
3710 | rsp = smack_ipv6host_label(sap); | ||
3711 | if (rsp != NULL) | ||
3712 | rc = smk_ipv6_check(ssp->smk_out, rsp, sap, | ||
3713 | SMK_CONNECTING); | ||
3714 | #endif | ||
3715 | #ifdef SMACK_IPV6_PORT_LABELING | ||
3451 | rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); | 3716 | rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); |
3452 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 3717 | #endif |
3453 | break; | 3718 | break; |
3454 | } | 3719 | } |
3455 | return rc; | 3720 | return rc; |
@@ -3663,10 +3928,12 @@ access_check: | |||
3663 | proto = smk_skb_to_addr_ipv6(skb, &sadd); | 3928 | proto = smk_skb_to_addr_ipv6(skb, &sadd); |
3664 | if (proto != IPPROTO_UDP && proto != IPPROTO_TCP) | 3929 | if (proto != IPPROTO_UDP && proto != IPPROTO_TCP) |
3665 | break; | 3930 | break; |
3666 | #ifdef CONFIG_SECURITY_SMACK_NETFILTER | 3931 | #ifdef SMACK_IPV6_SECMARK_LABELING |
3667 | if (skb && skb->secmark != 0) | 3932 | if (skb && skb->secmark != 0) |
3668 | skp = smack_from_secid(skb->secmark); | 3933 | skp = smack_from_secid(skb->secmark); |
3669 | else | 3934 | else |
3935 | skp = smack_ipv6host_label(&sadd); | ||
3936 | if (skp == NULL) | ||
3670 | skp = smack_net_ambient; | 3937 | skp = smack_net_ambient; |
3671 | #ifdef CONFIG_AUDIT | 3938 | #ifdef CONFIG_AUDIT |
3672 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); | 3939 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); |
@@ -3677,9 +3944,10 @@ access_check: | |||
3677 | rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); | 3944 | rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); |
3678 | rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in, | 3945 | rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in, |
3679 | MAY_WRITE, rc); | 3946 | MAY_WRITE, rc); |
3680 | #else /* CONFIG_SECURITY_SMACK_NETFILTER */ | 3947 | #endif /* SMACK_IPV6_SECMARK_LABELING */ |
3948 | #ifdef SMACK_IPV6_PORT_LABELING | ||
3681 | rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); | 3949 | rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); |
3682 | #endif /* CONFIG_SECURITY_SMACK_NETFILTER */ | 3950 | #endif /* SMACK_IPV6_PORT_LABELING */ |
3683 | break; | 3951 | break; |
3684 | #endif /* CONFIG_IPV6 */ | 3952 | #endif /* CONFIG_IPV6 */ |
3685 | } | 3953 | } |
@@ -3777,13 +4045,11 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, | |||
3777 | } | 4045 | } |
3778 | netlbl_secattr_destroy(&secattr); | 4046 | netlbl_secattr_destroy(&secattr); |
3779 | break; | 4047 | break; |
3780 | #if IS_ENABLED(CONFIG_IPV6) | ||
3781 | case PF_INET6: | 4048 | case PF_INET6: |
3782 | #ifdef CONFIG_SECURITY_SMACK_NETFILTER | 4049 | #ifdef SMACK_IPV6_SECMARK_LABELING |
3783 | s = skb->secmark; | 4050 | s = skb->secmark; |
3784 | #endif /* CONFIG_SECURITY_SMACK_NETFILTER */ | 4051 | #endif |
3785 | break; | 4052 | break; |
3786 | #endif /* CONFIG_IPV6 */ | ||
3787 | } | 4053 | } |
3788 | *secid = s; | 4054 | *secid = s; |
3789 | if (s == 0) | 4055 | if (s == 0) |
@@ -3906,7 +4172,7 @@ access_check: | |||
3906 | hdr = ip_hdr(skb); | 4172 | hdr = ip_hdr(skb); |
3907 | addr.sin_addr.s_addr = hdr->saddr; | 4173 | addr.sin_addr.s_addr = hdr->saddr; |
3908 | rcu_read_lock(); | 4174 | rcu_read_lock(); |
3909 | hskp = smack_host_label(&addr); | 4175 | hskp = smack_ipv4host_label(&addr); |
3910 | rcu_read_unlock(); | 4176 | rcu_read_unlock(); |
3911 | 4177 | ||
3912 | if (hskp == NULL) | 4178 | if (hskp == NULL) |
@@ -4254,7 +4520,7 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | |||
4254 | return 0; | 4520 | return 0; |
4255 | } | 4521 | } |
4256 | 4522 | ||
4257 | struct security_hook_list smack_hooks[] = { | 4523 | static struct security_hook_list smack_hooks[] = { |
4258 | LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), | 4524 | LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), |
4259 | LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), | 4525 | LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), |
4260 | LSM_HOOK_INIT(syslog, smack_syslog), | 4526 | LSM_HOOK_INIT(syslog, smack_syslog), |
@@ -4264,6 +4530,8 @@ struct security_hook_list smack_hooks[] = { | |||
4264 | LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data), | 4530 | LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data), |
4265 | LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount), | 4531 | LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount), |
4266 | LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), | 4532 | LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), |
4533 | LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts), | ||
4534 | LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str), | ||
4267 | 4535 | ||
4268 | LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), | 4536 | LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), |
4269 | LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds), | 4537 | LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds), |
@@ -4356,9 +4624,9 @@ struct security_hook_list smack_hooks[] = { | |||
4356 | LSM_HOOK_INIT(unix_may_send, smack_unix_may_send), | 4624 | LSM_HOOK_INIT(unix_may_send, smack_unix_may_send), |
4357 | 4625 | ||
4358 | LSM_HOOK_INIT(socket_post_create, smack_socket_post_create), | 4626 | LSM_HOOK_INIT(socket_post_create, smack_socket_post_create), |
4359 | #ifndef CONFIG_SECURITY_SMACK_NETFILTER | 4627 | #ifdef SMACK_IPV6_PORT_LABELING |
4360 | LSM_HOOK_INIT(socket_bind, smack_socket_bind), | 4628 | LSM_HOOK_INIT(socket_bind, smack_socket_bind), |
4361 | #endif /* CONFIG_SECURITY_SMACK_NETFILTER */ | 4629 | #endif |
4362 | LSM_HOOK_INIT(socket_connect, smack_socket_connect), | 4630 | LSM_HOOK_INIT(socket_connect, smack_socket_connect), |
4363 | LSM_HOOK_INIT(socket_sendmsg, smack_socket_sendmsg), | 4631 | LSM_HOOK_INIT(socket_sendmsg, smack_socket_sendmsg), |
4364 | LSM_HOOK_INIT(socket_sock_rcv_skb, smack_socket_sock_rcv_skb), | 4632 | LSM_HOOK_INIT(socket_sock_rcv_skb, smack_socket_sock_rcv_skb), |
@@ -4453,7 +4721,16 @@ static __init int smack_init(void) | |||
4453 | return -ENOMEM; | 4721 | return -ENOMEM; |
4454 | } | 4722 | } |
4455 | 4723 | ||
4456 | printk(KERN_INFO "Smack: Initializing.\n"); | 4724 | pr_info("Smack: Initializing.\n"); |
4725 | #ifdef CONFIG_SECURITY_SMACK_NETFILTER | ||
4726 | pr_info("Smack: Netfilter enabled.\n"); | ||
4727 | #endif | ||
4728 | #ifdef SMACK_IPV6_PORT_LABELING | ||
4729 | pr_info("Smack: IPv6 port labeling enabled.\n"); | ||
4730 | #endif | ||
4731 | #ifdef SMACK_IPV6_SECMARK_LABELING | ||
4732 | pr_info("Smack: IPv6 Netfilter enabled.\n"); | ||
4733 | #endif | ||
4457 | 4734 | ||
4458 | /* | 4735 | /* |
4459 | * Set the security state for the initial task. | 4736 | * Set the security state for the initial task. |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 2716d02119f3..c20b154a33f2 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/magic.h> | 29 | #include <linux/magic.h> |
30 | #include "smack.h" | 30 | #include "smack.h" |
31 | 31 | ||
32 | #define BEBITS (sizeof(__be32) * 8) | ||
32 | /* | 33 | /* |
33 | * smackfs pseudo filesystem. | 34 | * smackfs pseudo filesystem. |
34 | */ | 35 | */ |
@@ -40,7 +41,7 @@ enum smk_inos { | |||
40 | SMK_DOI = 5, /* CIPSO DOI */ | 41 | SMK_DOI = 5, /* CIPSO DOI */ |
41 | SMK_DIRECT = 6, /* CIPSO level indicating direct label */ | 42 | SMK_DIRECT = 6, /* CIPSO level indicating direct label */ |
42 | SMK_AMBIENT = 7, /* internet ambient label */ | 43 | SMK_AMBIENT = 7, /* internet ambient label */ |
43 | SMK_NETLBLADDR = 8, /* single label hosts */ | 44 | SMK_NET4ADDR = 8, /* single label hosts */ |
44 | SMK_ONLYCAP = 9, /* the only "capable" label */ | 45 | SMK_ONLYCAP = 9, /* the only "capable" label */ |
45 | SMK_LOGGING = 10, /* logging */ | 46 | SMK_LOGGING = 10, /* logging */ |
46 | SMK_LOAD_SELF = 11, /* task specific rules */ | 47 | SMK_LOAD_SELF = 11, /* task specific rules */ |
@@ -57,6 +58,9 @@ enum smk_inos { | |||
57 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 58 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
58 | SMK_UNCONFINED = 22, /* define an unconfined label */ | 59 | SMK_UNCONFINED = 22, /* define an unconfined label */ |
59 | #endif | 60 | #endif |
61 | #if IS_ENABLED(CONFIG_IPV6) | ||
62 | SMK_NET6ADDR = 23, /* single label IPv6 hosts */ | ||
63 | #endif /* CONFIG_IPV6 */ | ||
60 | }; | 64 | }; |
61 | 65 | ||
62 | /* | 66 | /* |
@@ -64,7 +68,10 @@ enum smk_inos { | |||
64 | */ | 68 | */ |
65 | static DEFINE_MUTEX(smack_cipso_lock); | 69 | static DEFINE_MUTEX(smack_cipso_lock); |
66 | static DEFINE_MUTEX(smack_ambient_lock); | 70 | static DEFINE_MUTEX(smack_ambient_lock); |
67 | static DEFINE_MUTEX(smk_netlbladdr_lock); | 71 | static DEFINE_MUTEX(smk_net4addr_lock); |
72 | #if IS_ENABLED(CONFIG_IPV6) | ||
73 | static DEFINE_MUTEX(smk_net6addr_lock); | ||
74 | #endif /* CONFIG_IPV6 */ | ||
68 | 75 | ||
69 | /* | 76 | /* |
70 | * This is the "ambient" label for network traffic. | 77 | * This is the "ambient" label for network traffic. |
@@ -118,7 +125,10 @@ int smack_ptrace_rule = SMACK_PTRACE_DEFAULT; | |||
118 | * can write to the specified label. | 125 | * can write to the specified label. |
119 | */ | 126 | */ |
120 | 127 | ||
121 | LIST_HEAD(smk_netlbladdr_list); | 128 | LIST_HEAD(smk_net4addr_list); |
129 | #if IS_ENABLED(CONFIG_IPV6) | ||
130 | LIST_HEAD(smk_net6addr_list); | ||
131 | #endif /* CONFIG_IPV6 */ | ||
122 | 132 | ||
123 | /* | 133 | /* |
124 | * Rule lists are maintained for each label. | 134 | * Rule lists are maintained for each label. |
@@ -129,7 +139,7 @@ struct smack_master_list { | |||
129 | struct smack_rule *smk_rule; | 139 | struct smack_rule *smk_rule; |
130 | }; | 140 | }; |
131 | 141 | ||
132 | LIST_HEAD(smack_rule_list); | 142 | static LIST_HEAD(smack_rule_list); |
133 | 143 | ||
134 | struct smack_parsed_rule { | 144 | struct smack_parsed_rule { |
135 | struct smack_known *smk_subject; | 145 | struct smack_known *smk_subject; |
@@ -140,11 +150,6 @@ struct smack_parsed_rule { | |||
140 | 150 | ||
141 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; | 151 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; |
142 | 152 | ||
143 | struct smack_known smack_cipso_option = { | ||
144 | .smk_known = SMACK_CIPSO_OPTION, | ||
145 | .smk_secid = 0, | ||
146 | }; | ||
147 | |||
148 | /* | 153 | /* |
149 | * Values for parsing cipso rules | 154 | * Values for parsing cipso rules |
150 | * SMK_DIGITLEN: Length of a digit field in a rule. | 155 | * SMK_DIGITLEN: Length of a digit field in a rule. |
@@ -1047,92 +1052,90 @@ static const struct file_operations smk_cipso2_ops = { | |||
1047 | * Seq_file read operations for /smack/netlabel | 1052 | * Seq_file read operations for /smack/netlabel |
1048 | */ | 1053 | */ |
1049 | 1054 | ||
1050 | static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos) | 1055 | static void *net4addr_seq_start(struct seq_file *s, loff_t *pos) |
1051 | { | 1056 | { |
1052 | return smk_seq_start(s, pos, &smk_netlbladdr_list); | 1057 | return smk_seq_start(s, pos, &smk_net4addr_list); |
1053 | } | 1058 | } |
1054 | 1059 | ||
1055 | static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) | 1060 | static void *net4addr_seq_next(struct seq_file *s, void *v, loff_t *pos) |
1056 | { | 1061 | { |
1057 | return smk_seq_next(s, v, pos, &smk_netlbladdr_list); | 1062 | return smk_seq_next(s, v, pos, &smk_net4addr_list); |
1058 | } | 1063 | } |
1059 | #define BEBITS (sizeof(__be32) * 8) | ||
1060 | 1064 | ||
1061 | /* | 1065 | /* |
1062 | * Print host/label pairs | 1066 | * Print host/label pairs |
1063 | */ | 1067 | */ |
1064 | static int netlbladdr_seq_show(struct seq_file *s, void *v) | 1068 | static int net4addr_seq_show(struct seq_file *s, void *v) |
1065 | { | 1069 | { |
1066 | struct list_head *list = v; | 1070 | struct list_head *list = v; |
1067 | struct smk_netlbladdr *skp = | 1071 | struct smk_net4addr *skp = |
1068 | list_entry_rcu(list, struct smk_netlbladdr, list); | 1072 | list_entry_rcu(list, struct smk_net4addr, list); |
1069 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; | 1073 | char *kp = SMACK_CIPSO_OPTION; |
1070 | int maskn; | ||
1071 | u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); | ||
1072 | |||
1073 | for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++); | ||
1074 | 1074 | ||
1075 | seq_printf(s, "%u.%u.%u.%u/%d %s\n", | 1075 | if (skp->smk_label != NULL) |
1076 | hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label->smk_known); | 1076 | kp = skp->smk_label->smk_known; |
1077 | seq_printf(s, "%pI4/%d %s\n", &skp->smk_host.s_addr, | ||
1078 | skp->smk_masks, kp); | ||
1077 | 1079 | ||
1078 | return 0; | 1080 | return 0; |
1079 | } | 1081 | } |
1080 | 1082 | ||
1081 | static const struct seq_operations netlbladdr_seq_ops = { | 1083 | static const struct seq_operations net4addr_seq_ops = { |
1082 | .start = netlbladdr_seq_start, | 1084 | .start = net4addr_seq_start, |
1083 | .next = netlbladdr_seq_next, | 1085 | .next = net4addr_seq_next, |
1084 | .show = netlbladdr_seq_show, | 1086 | .show = net4addr_seq_show, |
1085 | .stop = smk_seq_stop, | 1087 | .stop = smk_seq_stop, |
1086 | }; | 1088 | }; |
1087 | 1089 | ||
1088 | /** | 1090 | /** |
1089 | * smk_open_netlbladdr - open() for /smack/netlabel | 1091 | * smk_open_net4addr - open() for /smack/netlabel |
1090 | * @inode: inode structure representing file | 1092 | * @inode: inode structure representing file |
1091 | * @file: "netlabel" file pointer | 1093 | * @file: "netlabel" file pointer |
1092 | * | 1094 | * |
1093 | * Connect our netlbladdr_seq_* operations with /smack/netlabel | 1095 | * Connect our net4addr_seq_* operations with /smack/netlabel |
1094 | * file_operations | 1096 | * file_operations |
1095 | */ | 1097 | */ |
1096 | static int smk_open_netlbladdr(struct inode *inode, struct file *file) | 1098 | static int smk_open_net4addr(struct inode *inode, struct file *file) |
1097 | { | 1099 | { |
1098 | return seq_open(file, &netlbladdr_seq_ops); | 1100 | return seq_open(file, &net4addr_seq_ops); |
1099 | } | 1101 | } |
1100 | 1102 | ||
1101 | /** | 1103 | /** |
1102 | * smk_netlbladdr_insert | 1104 | * smk_net4addr_insert |
1103 | * @new : netlabel to insert | 1105 | * @new : netlabel to insert |
1104 | * | 1106 | * |
1105 | * This helper insert netlabel in the smack_netlbladdrs list | 1107 | * This helper insert netlabel in the smack_net4addrs list |
1106 | * sorted by netmask length (longest to smallest) | 1108 | * sorted by netmask length (longest to smallest) |
1107 | * locked by &smk_netlbladdr_lock in smk_write_netlbladdr | 1109 | * locked by &smk_net4addr_lock in smk_write_net4addr |
1108 | * | 1110 | * |
1109 | */ | 1111 | */ |
1110 | static void smk_netlbladdr_insert(struct smk_netlbladdr *new) | 1112 | static void smk_net4addr_insert(struct smk_net4addr *new) |
1111 | { | 1113 | { |
1112 | struct smk_netlbladdr *m, *m_next; | 1114 | struct smk_net4addr *m; |
1115 | struct smk_net4addr *m_next; | ||
1113 | 1116 | ||
1114 | if (list_empty(&smk_netlbladdr_list)) { | 1117 | if (list_empty(&smk_net4addr_list)) { |
1115 | list_add_rcu(&new->list, &smk_netlbladdr_list); | 1118 | list_add_rcu(&new->list, &smk_net4addr_list); |
1116 | return; | 1119 | return; |
1117 | } | 1120 | } |
1118 | 1121 | ||
1119 | m = list_entry_rcu(smk_netlbladdr_list.next, | 1122 | m = list_entry_rcu(smk_net4addr_list.next, |
1120 | struct smk_netlbladdr, list); | 1123 | struct smk_net4addr, list); |
1121 | 1124 | ||
1122 | /* the comparison '>' is a bit hacky, but works */ | 1125 | /* the comparison '>' is a bit hacky, but works */ |
1123 | if (new->smk_mask.s_addr > m->smk_mask.s_addr) { | 1126 | if (new->smk_masks > m->smk_masks) { |
1124 | list_add_rcu(&new->list, &smk_netlbladdr_list); | 1127 | list_add_rcu(&new->list, &smk_net4addr_list); |
1125 | return; | 1128 | return; |
1126 | } | 1129 | } |
1127 | 1130 | ||
1128 | list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) { | 1131 | list_for_each_entry_rcu(m, &smk_net4addr_list, list) { |
1129 | if (list_is_last(&m->list, &smk_netlbladdr_list)) { | 1132 | if (list_is_last(&m->list, &smk_net4addr_list)) { |
1130 | list_add_rcu(&new->list, &m->list); | 1133 | list_add_rcu(&new->list, &m->list); |
1131 | return; | 1134 | return; |
1132 | } | 1135 | } |
1133 | m_next = list_entry_rcu(m->list.next, | 1136 | m_next = list_entry_rcu(m->list.next, |
1134 | struct smk_netlbladdr, list); | 1137 | struct smk_net4addr, list); |
1135 | if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) { | 1138 | if (new->smk_masks > m_next->smk_masks) { |
1136 | list_add_rcu(&new->list, &m->list); | 1139 | list_add_rcu(&new->list, &m->list); |
1137 | return; | 1140 | return; |
1138 | } | 1141 | } |
@@ -1141,28 +1144,29 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new) | |||
1141 | 1144 | ||
1142 | 1145 | ||
1143 | /** | 1146 | /** |
1144 | * smk_write_netlbladdr - write() for /smack/netlabel | 1147 | * smk_write_net4addr - write() for /smack/netlabel |
1145 | * @file: file pointer, not actually used | 1148 | * @file: file pointer, not actually used |
1146 | * @buf: where to get the data from | 1149 | * @buf: where to get the data from |
1147 | * @count: bytes sent | 1150 | * @count: bytes sent |
1148 | * @ppos: where to start | 1151 | * @ppos: where to start |
1149 | * | 1152 | * |
1150 | * Accepts only one netlbladdr per write call. | 1153 | * Accepts only one net4addr per write call. |
1151 | * Returns number of bytes written or error code, as appropriate | 1154 | * Returns number of bytes written or error code, as appropriate |
1152 | */ | 1155 | */ |
1153 | static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | 1156 | static ssize_t smk_write_net4addr(struct file *file, const char __user *buf, |
1154 | size_t count, loff_t *ppos) | 1157 | size_t count, loff_t *ppos) |
1155 | { | 1158 | { |
1156 | struct smk_netlbladdr *snp; | 1159 | struct smk_net4addr *snp; |
1157 | struct sockaddr_in newname; | 1160 | struct sockaddr_in newname; |
1158 | char *smack; | 1161 | char *smack; |
1159 | struct smack_known *skp; | 1162 | struct smack_known *skp = NULL; |
1160 | char *data; | 1163 | char *data; |
1161 | char *host = (char *)&newname.sin_addr.s_addr; | 1164 | char *host = (char *)&newname.sin_addr.s_addr; |
1162 | int rc; | 1165 | int rc; |
1163 | struct netlbl_audit audit_info; | 1166 | struct netlbl_audit audit_info; |
1164 | struct in_addr mask; | 1167 | struct in_addr mask; |
1165 | unsigned int m; | 1168 | unsigned int m; |
1169 | unsigned int masks; | ||
1166 | int found; | 1170 | int found; |
1167 | u32 mask_bits = (1<<31); | 1171 | u32 mask_bits = (1<<31); |
1168 | __be32 nsa; | 1172 | __be32 nsa; |
@@ -1200,7 +1204,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1200 | data[count] = '\0'; | 1204 | data[count] = '\0'; |
1201 | 1205 | ||
1202 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%u %s", | 1206 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%u %s", |
1203 | &host[0], &host[1], &host[2], &host[3], &m, smack); | 1207 | &host[0], &host[1], &host[2], &host[3], &masks, smack); |
1204 | if (rc != 6) { | 1208 | if (rc != 6) { |
1205 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", | 1209 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", |
1206 | &host[0], &host[1], &host[2], &host[3], smack); | 1210 | &host[0], &host[1], &host[2], &host[3], smack); |
@@ -1209,8 +1213,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1209 | goto free_out; | 1213 | goto free_out; |
1210 | } | 1214 | } |
1211 | m = BEBITS; | 1215 | m = BEBITS; |
1216 | masks = 32; | ||
1212 | } | 1217 | } |
1213 | if (m > BEBITS) { | 1218 | if (masks > BEBITS) { |
1214 | rc = -EINVAL; | 1219 | rc = -EINVAL; |
1215 | goto free_out; | 1220 | goto free_out; |
1216 | } | 1221 | } |
@@ -1225,16 +1230,16 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1225 | goto free_out; | 1230 | goto free_out; |
1226 | } | 1231 | } |
1227 | } else { | 1232 | } else { |
1228 | /* check known options */ | 1233 | /* |
1229 | if (strcmp(smack, smack_cipso_option.smk_known) == 0) | 1234 | * Only the -CIPSO option is supported for IPv4 |
1230 | skp = &smack_cipso_option; | 1235 | */ |
1231 | else { | 1236 | if (strcmp(smack, SMACK_CIPSO_OPTION) != 0) { |
1232 | rc = -EINVAL; | 1237 | rc = -EINVAL; |
1233 | goto free_out; | 1238 | goto free_out; |
1234 | } | 1239 | } |
1235 | } | 1240 | } |
1236 | 1241 | ||
1237 | for (temp_mask = 0; m > 0; m--) { | 1242 | for (m = masks, temp_mask = 0; m > 0; m--) { |
1238 | temp_mask |= mask_bits; | 1243 | temp_mask |= mask_bits; |
1239 | mask_bits >>= 1; | 1244 | mask_bits >>= 1; |
1240 | } | 1245 | } |
@@ -1245,14 +1250,13 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1245 | * Only allow one writer at a time. Writes should be | 1250 | * Only allow one writer at a time. Writes should be |
1246 | * quite rare and small in any case. | 1251 | * quite rare and small in any case. |
1247 | */ | 1252 | */ |
1248 | mutex_lock(&smk_netlbladdr_lock); | 1253 | mutex_lock(&smk_net4addr_lock); |
1249 | 1254 | ||
1250 | nsa = newname.sin_addr.s_addr; | 1255 | nsa = newname.sin_addr.s_addr; |
1251 | /* try to find if the prefix is already in the list */ | 1256 | /* try to find if the prefix is already in the list */ |
1252 | found = 0; | 1257 | found = 0; |
1253 | list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) { | 1258 | list_for_each_entry_rcu(snp, &smk_net4addr_list, list) { |
1254 | if (snp->smk_host.sin_addr.s_addr == nsa && | 1259 | if (snp->smk_host.s_addr == nsa && snp->smk_masks == masks) { |
1255 | snp->smk_mask.s_addr == mask.s_addr) { | ||
1256 | found = 1; | 1260 | found = 1; |
1257 | break; | 1261 | break; |
1258 | } | 1262 | } |
@@ -1265,17 +1269,20 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1265 | rc = -ENOMEM; | 1269 | rc = -ENOMEM; |
1266 | else { | 1270 | else { |
1267 | rc = 0; | 1271 | rc = 0; |
1268 | snp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; | 1272 | snp->smk_host.s_addr = newname.sin_addr.s_addr; |
1269 | snp->smk_mask.s_addr = mask.s_addr; | 1273 | snp->smk_mask.s_addr = mask.s_addr; |
1270 | snp->smk_label = skp; | 1274 | snp->smk_label = skp; |
1271 | smk_netlbladdr_insert(snp); | 1275 | snp->smk_masks = masks; |
1276 | smk_net4addr_insert(snp); | ||
1272 | } | 1277 | } |
1273 | } else { | 1278 | } else { |
1274 | /* we delete the unlabeled entry, only if the previous label | 1279 | /* |
1275 | * wasn't the special CIPSO option */ | 1280 | * Delete the unlabeled entry, only if the previous label |
1276 | if (snp->smk_label != &smack_cipso_option) | 1281 | * wasn't the special CIPSO option |
1282 | */ | ||
1283 | if (snp->smk_label != NULL) | ||
1277 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, | 1284 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, |
1278 | &snp->smk_host.sin_addr, &snp->smk_mask, | 1285 | &snp->smk_host, &snp->smk_mask, |
1279 | PF_INET, &audit_info); | 1286 | PF_INET, &audit_info); |
1280 | else | 1287 | else |
1281 | rc = 0; | 1288 | rc = 0; |
@@ -1287,15 +1294,15 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1287 | * this host so that incoming packets get labeled. | 1294 | * this host so that incoming packets get labeled. |
1288 | * but only if we didn't get the special CIPSO option | 1295 | * but only if we didn't get the special CIPSO option |
1289 | */ | 1296 | */ |
1290 | if (rc == 0 && skp != &smack_cipso_option) | 1297 | if (rc == 0 && skp != NULL) |
1291 | rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, | 1298 | rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, |
1292 | &snp->smk_host.sin_addr, &snp->smk_mask, PF_INET, | 1299 | &snp->smk_host, &snp->smk_mask, PF_INET, |
1293 | snp->smk_label->smk_secid, &audit_info); | 1300 | snp->smk_label->smk_secid, &audit_info); |
1294 | 1301 | ||
1295 | if (rc == 0) | 1302 | if (rc == 0) |
1296 | rc = count; | 1303 | rc = count; |
1297 | 1304 | ||
1298 | mutex_unlock(&smk_netlbladdr_lock); | 1305 | mutex_unlock(&smk_net4addr_lock); |
1299 | 1306 | ||
1300 | free_out: | 1307 | free_out: |
1301 | kfree(smack); | 1308 | kfree(smack); |
@@ -1305,14 +1312,279 @@ free_data_out: | |||
1305 | return rc; | 1312 | return rc; |
1306 | } | 1313 | } |
1307 | 1314 | ||
1308 | static const struct file_operations smk_netlbladdr_ops = { | 1315 | static const struct file_operations smk_net4addr_ops = { |
1309 | .open = smk_open_netlbladdr, | 1316 | .open = smk_open_net4addr, |
1310 | .read = seq_read, | 1317 | .read = seq_read, |
1311 | .llseek = seq_lseek, | 1318 | .llseek = seq_lseek, |
1312 | .write = smk_write_netlbladdr, | 1319 | .write = smk_write_net4addr, |
1313 | .release = seq_release, | 1320 | .release = seq_release, |
1314 | }; | 1321 | }; |
1315 | 1322 | ||
1323 | #if IS_ENABLED(CONFIG_IPV6) | ||
1324 | /* | ||
1325 | * Seq_file read operations for /smack/netlabel6 | ||
1326 | */ | ||
1327 | |||
1328 | static void *net6addr_seq_start(struct seq_file *s, loff_t *pos) | ||
1329 | { | ||
1330 | return smk_seq_start(s, pos, &smk_net6addr_list); | ||
1331 | } | ||
1332 | |||
1333 | static void *net6addr_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
1334 | { | ||
1335 | return smk_seq_next(s, v, pos, &smk_net6addr_list); | ||
1336 | } | ||
1337 | |||
1338 | /* | ||
1339 | * Print host/label pairs | ||
1340 | */ | ||
1341 | static int net6addr_seq_show(struct seq_file *s, void *v) | ||
1342 | { | ||
1343 | struct list_head *list = v; | ||
1344 | struct smk_net6addr *skp = | ||
1345 | list_entry(list, struct smk_net6addr, list); | ||
1346 | |||
1347 | if (skp->smk_label != NULL) | ||
1348 | seq_printf(s, "%pI6/%d %s\n", &skp->smk_host, skp->smk_masks, | ||
1349 | skp->smk_label->smk_known); | ||
1350 | |||
1351 | return 0; | ||
1352 | } | ||
1353 | |||
1354 | static const struct seq_operations net6addr_seq_ops = { | ||
1355 | .start = net6addr_seq_start, | ||
1356 | .next = net6addr_seq_next, | ||
1357 | .show = net6addr_seq_show, | ||
1358 | .stop = smk_seq_stop, | ||
1359 | }; | ||
1360 | |||
1361 | /** | ||
1362 | * smk_open_net6addr - open() for /smack/netlabel | ||
1363 | * @inode: inode structure representing file | ||
1364 | * @file: "netlabel" file pointer | ||
1365 | * | ||
1366 | * Connect our net6addr_seq_* operations with /smack/netlabel | ||
1367 | * file_operations | ||
1368 | */ | ||
1369 | static int smk_open_net6addr(struct inode *inode, struct file *file) | ||
1370 | { | ||
1371 | return seq_open(file, &net6addr_seq_ops); | ||
1372 | } | ||
1373 | |||
1374 | /** | ||
1375 | * smk_net6addr_insert | ||
1376 | * @new : entry to insert | ||
1377 | * | ||
1378 | * This inserts an entry in the smack_net6addrs list | ||
1379 | * sorted by netmask length (longest to smallest) | ||
1380 | * locked by &smk_net6addr_lock in smk_write_net6addr | ||
1381 | * | ||
1382 | */ | ||
1383 | static void smk_net6addr_insert(struct smk_net6addr *new) | ||
1384 | { | ||
1385 | struct smk_net6addr *m_next; | ||
1386 | struct smk_net6addr *m; | ||
1387 | |||
1388 | if (list_empty(&smk_net6addr_list)) { | ||
1389 | list_add_rcu(&new->list, &smk_net6addr_list); | ||
1390 | return; | ||
1391 | } | ||
1392 | |||
1393 | m = list_entry_rcu(smk_net6addr_list.next, | ||
1394 | struct smk_net6addr, list); | ||
1395 | |||
1396 | if (new->smk_masks > m->smk_masks) { | ||
1397 | list_add_rcu(&new->list, &smk_net6addr_list); | ||
1398 | return; | ||
1399 | } | ||
1400 | |||
1401 | list_for_each_entry_rcu(m, &smk_net6addr_list, list) { | ||
1402 | if (list_is_last(&m->list, &smk_net6addr_list)) { | ||
1403 | list_add_rcu(&new->list, &m->list); | ||
1404 | return; | ||
1405 | } | ||
1406 | m_next = list_entry_rcu(m->list.next, | ||
1407 | struct smk_net6addr, list); | ||
1408 | if (new->smk_masks > m_next->smk_masks) { | ||
1409 | list_add_rcu(&new->list, &m->list); | ||
1410 | return; | ||
1411 | } | ||
1412 | } | ||
1413 | } | ||
1414 | |||
1415 | |||
1416 | /** | ||
1417 | * smk_write_net6addr - write() for /smack/netlabel | ||
1418 | * @file: file pointer, not actually used | ||
1419 | * @buf: where to get the data from | ||
1420 | * @count: bytes sent | ||
1421 | * @ppos: where to start | ||
1422 | * | ||
1423 | * Accepts only one net6addr per write call. | ||
1424 | * Returns number of bytes written or error code, as appropriate | ||
1425 | */ | ||
1426 | static ssize_t smk_write_net6addr(struct file *file, const char __user *buf, | ||
1427 | size_t count, loff_t *ppos) | ||
1428 | { | ||
1429 | struct smk_net6addr *snp; | ||
1430 | struct in6_addr newname; | ||
1431 | struct in6_addr fullmask; | ||
1432 | struct smack_known *skp = NULL; | ||
1433 | char *smack; | ||
1434 | char *data; | ||
1435 | int rc = 0; | ||
1436 | int found = 0; | ||
1437 | int i; | ||
1438 | unsigned int scanned[8]; | ||
1439 | unsigned int m; | ||
1440 | unsigned int mask = 128; | ||
1441 | |||
1442 | /* | ||
1443 | * Must have privilege. | ||
1444 | * No partial writes. | ||
1445 | * Enough data must be present. | ||
1446 | * "<addr/mask, as a:b:c:d:e:f:g:h/e><space><label>" | ||
1447 | * "<addr, as a:b:c:d:e:f:g:h><space><label>" | ||
1448 | */ | ||
1449 | if (!smack_privileged(CAP_MAC_ADMIN)) | ||
1450 | return -EPERM; | ||
1451 | if (*ppos != 0) | ||
1452 | return -EINVAL; | ||
1453 | if (count < SMK_NETLBLADDRMIN) | ||
1454 | return -EINVAL; | ||
1455 | |||
1456 | data = kzalloc(count + 1, GFP_KERNEL); | ||
1457 | if (data == NULL) | ||
1458 | return -ENOMEM; | ||
1459 | |||
1460 | if (copy_from_user(data, buf, count) != 0) { | ||
1461 | rc = -EFAULT; | ||
1462 | goto free_data_out; | ||
1463 | } | ||
1464 | |||
1465 | smack = kzalloc(count + 1, GFP_KERNEL); | ||
1466 | if (smack == NULL) { | ||
1467 | rc = -ENOMEM; | ||
1468 | goto free_data_out; | ||
1469 | } | ||
1470 | |||
1471 | data[count] = '\0'; | ||
1472 | |||
1473 | i = sscanf(data, "%x:%x:%x:%x:%x:%x:%x:%x/%u %s", | ||
1474 | &scanned[0], &scanned[1], &scanned[2], &scanned[3], | ||
1475 | &scanned[4], &scanned[5], &scanned[6], &scanned[7], | ||
1476 | &mask, smack); | ||
1477 | if (i != 10) { | ||
1478 | i = sscanf(data, "%x:%x:%x:%x:%x:%x:%x:%x %s", | ||
1479 | &scanned[0], &scanned[1], &scanned[2], | ||
1480 | &scanned[3], &scanned[4], &scanned[5], | ||
1481 | &scanned[6], &scanned[7], smack); | ||
1482 | if (i != 9) { | ||
1483 | rc = -EINVAL; | ||
1484 | goto free_out; | ||
1485 | } | ||
1486 | } | ||
1487 | if (mask > 128) { | ||
1488 | rc = -EINVAL; | ||
1489 | goto free_out; | ||
1490 | } | ||
1491 | for (i = 0; i < 8; i++) { | ||
1492 | if (scanned[i] > 0xffff) { | ||
1493 | rc = -EINVAL; | ||
1494 | goto free_out; | ||
1495 | } | ||
1496 | newname.s6_addr16[i] = htons(scanned[i]); | ||
1497 | } | ||
1498 | |||
1499 | /* | ||
1500 | * If smack begins with '-', it is an option, don't import it | ||
1501 | */ | ||
1502 | if (smack[0] != '-') { | ||
1503 | skp = smk_import_entry(smack, 0); | ||
1504 | if (skp == NULL) { | ||
1505 | rc = -EINVAL; | ||
1506 | goto free_out; | ||
1507 | } | ||
1508 | } else { | ||
1509 | /* | ||
1510 | * Only -DELETE is supported for IPv6 | ||
1511 | */ | ||
1512 | if (strcmp(smack, SMACK_DELETE_OPTION) != 0) { | ||
1513 | rc = -EINVAL; | ||
1514 | goto free_out; | ||
1515 | } | ||
1516 | } | ||
1517 | |||
1518 | for (i = 0, m = mask; i < 8; i++) { | ||
1519 | if (m >= 16) { | ||
1520 | fullmask.s6_addr16[i] = 0xffff; | ||
1521 | m -= 16; | ||
1522 | } else if (m > 0) { | ||
1523 | fullmask.s6_addr16[i] = (1 << m) - 1; | ||
1524 | m = 0; | ||
1525 | } else | ||
1526 | fullmask.s6_addr16[i] = 0; | ||
1527 | newname.s6_addr16[i] &= fullmask.s6_addr16[i]; | ||
1528 | } | ||
1529 | |||
1530 | /* | ||
1531 | * Only allow one writer at a time. Writes should be | ||
1532 | * quite rare and small in any case. | ||
1533 | */ | ||
1534 | mutex_lock(&smk_net6addr_lock); | ||
1535 | /* | ||
1536 | * Try to find the prefix in the list | ||
1537 | */ | ||
1538 | list_for_each_entry_rcu(snp, &smk_net6addr_list, list) { | ||
1539 | if (mask != snp->smk_masks) | ||
1540 | continue; | ||
1541 | for (found = 1, i = 0; i < 8; i++) { | ||
1542 | if (newname.s6_addr16[i] != | ||
1543 | snp->smk_host.s6_addr16[i]) { | ||
1544 | found = 0; | ||
1545 | break; | ||
1546 | } | ||
1547 | } | ||
1548 | if (found == 1) | ||
1549 | break; | ||
1550 | } | ||
1551 | if (found == 0) { | ||
1552 | snp = kzalloc(sizeof(*snp), GFP_KERNEL); | ||
1553 | if (snp == NULL) | ||
1554 | rc = -ENOMEM; | ||
1555 | else { | ||
1556 | snp->smk_host = newname; | ||
1557 | snp->smk_mask = fullmask; | ||
1558 | snp->smk_masks = mask; | ||
1559 | snp->smk_label = skp; | ||
1560 | smk_net6addr_insert(snp); | ||
1561 | } | ||
1562 | } else { | ||
1563 | snp->smk_label = skp; | ||
1564 | } | ||
1565 | |||
1566 | if (rc == 0) | ||
1567 | rc = count; | ||
1568 | |||
1569 | mutex_unlock(&smk_net6addr_lock); | ||
1570 | |||
1571 | free_out: | ||
1572 | kfree(smack); | ||
1573 | free_data_out: | ||
1574 | kfree(data); | ||
1575 | |||
1576 | return rc; | ||
1577 | } | ||
1578 | |||
1579 | static const struct file_operations smk_net6addr_ops = { | ||
1580 | .open = smk_open_net6addr, | ||
1581 | .read = seq_read, | ||
1582 | .llseek = seq_lseek, | ||
1583 | .write = smk_write_net6addr, | ||
1584 | .release = seq_release, | ||
1585 | }; | ||
1586 | #endif /* CONFIG_IPV6 */ | ||
1587 | |||
1316 | /** | 1588 | /** |
1317 | * smk_read_doi - read() for /smack/doi | 1589 | * smk_read_doi - read() for /smack/doi |
1318 | * @filp: file pointer, not actually used | 1590 | * @filp: file pointer, not actually used |
@@ -2320,11 +2592,7 @@ static const struct file_operations smk_revoke_subj_ops = { | |||
2320 | */ | 2592 | */ |
2321 | static int smk_init_sysfs(void) | 2593 | static int smk_init_sysfs(void) |
2322 | { | 2594 | { |
2323 | int err; | 2595 | return sysfs_create_mount_point(fs_kobj, "smackfs"); |
2324 | err = sysfs_create_mount_point(fs_kobj, "smackfs"); | ||
2325 | if (err) | ||
2326 | return err; | ||
2327 | return 0; | ||
2328 | } | 2596 | } |
2329 | 2597 | ||
2330 | /** | 2598 | /** |
@@ -2519,8 +2787,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
2519 | "direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, | 2787 | "direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, |
2520 | [SMK_AMBIENT] = { | 2788 | [SMK_AMBIENT] = { |
2521 | "ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, | 2789 | "ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, |
2522 | [SMK_NETLBLADDR] = { | 2790 | [SMK_NET4ADDR] = { |
2523 | "netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR}, | 2791 | "netlabel", &smk_net4addr_ops, S_IRUGO|S_IWUSR}, |
2524 | [SMK_ONLYCAP] = { | 2792 | [SMK_ONLYCAP] = { |
2525 | "onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, | 2793 | "onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, |
2526 | [SMK_LOGGING] = { | 2794 | [SMK_LOGGING] = { |
@@ -2552,6 +2820,10 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
2552 | [SMK_UNCONFINED] = { | 2820 | [SMK_UNCONFINED] = { |
2553 | "unconfined", &smk_unconfined_ops, S_IRUGO|S_IWUSR}, | 2821 | "unconfined", &smk_unconfined_ops, S_IRUGO|S_IWUSR}, |
2554 | #endif | 2822 | #endif |
2823 | #if IS_ENABLED(CONFIG_IPV6) | ||
2824 | [SMK_NET6ADDR] = { | ||
2825 | "ipv6host", &smk_net6addr_ops, S_IRUGO|S_IWUSR}, | ||
2826 | #endif /* CONFIG_IPV6 */ | ||
2555 | /* last one */ | 2827 | /* last one */ |
2556 | {""} | 2828 | {""} |
2557 | }; | 2829 | }; |
diff --git a/security/yama/Kconfig b/security/yama/Kconfig index 3123e1da2fed..90c605eea892 100644 --- a/security/yama/Kconfig +++ b/security/yama/Kconfig | |||
@@ -6,14 +6,7 @@ config SECURITY_YAMA | |||
6 | This selects Yama, which extends DAC support with additional | 6 | This selects Yama, which extends DAC support with additional |
7 | system-wide security settings beyond regular Linux discretionary | 7 | system-wide security settings beyond regular Linux discretionary |
8 | access controls. Currently available is ptrace scope restriction. | 8 | access controls. Currently available is ptrace scope restriction. |
9 | Like capabilities, this security module stacks with other LSMs. | ||
9 | Further information can be found in Documentation/security/Yama.txt. | 10 | Further information can be found in Documentation/security/Yama.txt. |
10 | 11 | ||
11 | If you are unsure how to answer this question, answer N. | 12 | If you are unsure how to answer this question, answer N. |
12 | |||
13 | config SECURITY_YAMA_STACKED | ||
14 | bool "Yama stacked with other LSMs" | ||
15 | depends on SECURITY_YAMA | ||
16 | default n | ||
17 | help | ||
18 | When Yama is built into the kernel, force it to stack with the | ||
19 | selected primary LSM. | ||
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 5ebb89687936..d3c19c970a06 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
@@ -353,11 +353,6 @@ static struct security_hook_list yama_hooks[] = { | |||
353 | LSM_HOOK_INIT(task_free, yama_task_free), | 353 | LSM_HOOK_INIT(task_free, yama_task_free), |
354 | }; | 354 | }; |
355 | 355 | ||
356 | void __init yama_add_hooks(void) | ||
357 | { | ||
358 | security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks)); | ||
359 | } | ||
360 | |||
361 | #ifdef CONFIG_SYSCTL | 356 | #ifdef CONFIG_SYSCTL |
362 | static int yama_dointvec_minmax(struct ctl_table *table, int write, | 357 | static int yama_dointvec_minmax(struct ctl_table *table, int write, |
363 | void __user *buffer, size_t *lenp, loff_t *ppos) | 358 | void __user *buffer, size_t *lenp, loff_t *ppos) |
@@ -396,26 +391,18 @@ static struct ctl_table yama_sysctl_table[] = { | |||
396 | }, | 391 | }, |
397 | { } | 392 | { } |
398 | }; | 393 | }; |
399 | #endif /* CONFIG_SYSCTL */ | 394 | static void __init yama_init_sysctl(void) |
400 | |||
401 | static __init int yama_init(void) | ||
402 | { | 395 | { |
403 | #ifndef CONFIG_SECURITY_YAMA_STACKED | ||
404 | /* | ||
405 | * If yama is being stacked this is already taken care of. | ||
406 | */ | ||
407 | if (!security_module_enable("yama")) | ||
408 | return 0; | ||
409 | yama_add_hooks(); | ||
410 | #endif | ||
411 | pr_info("Yama: becoming mindful.\n"); | ||
412 | |||
413 | #ifdef CONFIG_SYSCTL | ||
414 | if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) | 396 | if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) |
415 | panic("Yama: sysctl registration failed.\n"); | 397 | panic("Yama: sysctl registration failed.\n"); |
416 | #endif | ||
417 | |||
418 | return 0; | ||
419 | } | 398 | } |
399 | #else | ||
400 | static inline void yama_init_sysctl(void) { } | ||
401 | #endif /* CONFIG_SYSCTL */ | ||
420 | 402 | ||
421 | security_initcall(yama_init); | 403 | void __init yama_add_hooks(void) |
404 | { | ||
405 | pr_info("Yama: becoming mindful.\n"); | ||
406 | security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks)); | ||
407 | yama_init_sysctl(); | ||
408 | } | ||