aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJames Morris <james.l.morris@oracle.com>2015-08-14 23:29:57 -0400
committerJames Morris <james.l.morris@oracle.com>2015-08-14 23:29:57 -0400
commit3e5f206c00f73f535c914eedc8b91f424c5a14ab (patch)
tree209f621fc8a9b84053bb4feda619185e17242982 /security
parent0e38c35815f50e5a347977d76fb5eb4c3bf020b5 (diff)
parentfda4d578ed0a7e1d116f56a15efea0e4ba78acad (diff)
Merge branch 'next' of git://git.infradead.org/users/pcmoore/selinux into next
Diffstat (limited to 'security')
-rw-r--r--security/lsm_audit.c15
-rw-r--r--security/selinux/avc.c418
-rw-r--r--security/selinux/hooks.c147
-rw-r--r--security/selinux/include/avc.h6
-rw-r--r--security/selinux/include/security.h32
-rw-r--r--security/selinux/ss/avtab.c104
-rw-r--r--security/selinux/ss/avtab.h33
-rw-r--r--security/selinux/ss/conditional.c32
-rw-r--r--security/selinux/ss/conditional.h6
-rw-r--r--security/selinux/ss/policydb.c5
-rw-r--r--security/selinux/ss/services.c213
-rw-r--r--security/selinux/ss/services.h6
12 files changed, 907 insertions, 110 deletions
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/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
53struct avc_node { 55struct avc_node {
@@ -56,6 +58,16 @@ struct avc_node {
56 struct rcu_head rhead; 58 struct rcu_head rhead;
57}; 59};
58 60
61struct avc_xperms_decision_node {
62 struct extended_perms_decision xpd;
63 struct list_head xpd_list; /* list of extended_perms_decision */
64};
65
66struct avc_xperms_node {
67 struct extended_perms xp;
68 struct list_head xpd_head; /* list head of extended_perms_decision */
69};
70
59struct avc_cache { 71struct 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 };
80static struct avc_cache avc_cache; 92static struct avc_cache avc_cache;
81static struct avc_callback_node *avc_callbacks; 93static struct avc_callback_node *avc_callbacks;
82static struct kmem_cache *avc_node_cachep; 94static struct kmem_cache *avc_node_cachep;
95static struct kmem_cache *avc_xperms_data_cachep;
96static struct kmem_cache *avc_xperms_decision_cachep;
97static struct kmem_cache *avc_xperms_cachep;
83 98
84static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) 99static 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 */
238static 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
250static inline unsigned int
251avc_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
268static 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
278static 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
292static 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
306static 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 */
326static 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
345static 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;
376error:
377 avc_xperms_decision_free(xpd_node);
378 return NULL;
379}
380
381static 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
395static 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
407static 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;
433error:
434 avc_xperms_free(dest);
435 return -ENOMEM;
436
437}
438
439static 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
469static 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
208static void avc_node_free(struct rcu_head *rhead) 485static 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
222static void avc_node_kill(struct avc_node *node) 500static 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 */
381static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) 661static 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 */
532static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, 820static 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);
599out_unlock: 902out_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 */
667static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, 970static 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
676static noinline int avc_denied(u32 ssid, u32 tsid, 981static 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 */
1004int 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
1063decision:
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 564079c5c49d..55285054aa73 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 */
1715static 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. */
1702static int may_create(struct inode *dir, 1739static 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 */
3241int 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);
3273out:
3274 return rc;
3275}
3276
3231static int selinux_file_ioctl(struct file *file, unsigned int cmd, 3277static 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 */
146int avc_has_perm_noaudit(u32 ssid, u32 tsid, 147int 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
160int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
161 u8 driver, u8 perm, struct common_audit_data *ad);
162
163
159u32 avc_policy_seqno(void); 164u32 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
170int avc_add_callback(int (*callback)(u32 event), u32 events); 176int 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)))
119struct extended_perms_data {
120 u32 p[8];
121};
122
123struct 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
131struct 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
115void security_compute_av(u32 ssid, u32 tsid, 139void 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
143void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass,
144 u8 driver, struct extended_perms_decision *xpermd);
117 145
118void security_compute_av_user(u32 ssid, u32 tsid, 146void 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
26static struct kmem_cache *avtab_node_cachep; 26static struct kmem_cache *avtab_node_cachep;
27static 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
365int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, 389int 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:
543int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) 600int 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
593void avtab_cache_destroy(void) 668void 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
28struct avtab_key { 29struct 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 */
57struct 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
45struct avtab_datum { 73struct 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
49struct avtab_node { 80struct 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
617void 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 */
618void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd) 636void 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);
73int cond_write_bool(void *key, void *datum, void *ptr); 73int cond_write_bool(void *key, void *datum, void *ptr);
74int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); 74int cond_write_list(struct policydb *p, struct cond_node *list, void *fp);
75 75
76void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); 76void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
77 77 struct av_decision *avd, struct extended_perms *xperms);
78void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
79 struct extended_perms_decision *xpermd);
78int evaluate_cond_node(struct policydb *p, struct cond_node *node); 80int 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
153static struct policydb_compat_info *policydb_lookup_compat(int version) 158static 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
95static void context_struct_compute_av(struct context *scontext, 95static 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
100struct selinux_mapping { 101struct 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 */
623void 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 */
619static void context_struct_compute_av(struct context *scontext, 648static 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
939void 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
993void 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 }
1065out:
1066 read_unlock(&policy_rwlock);
1067 return;
1068allow:
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)
913void security_compute_av(u32 ssid, 1084void 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);
952out: 1125out:
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
12extern struct policydb policydb; 12extern struct policydb policydb;
13 13
14void services_compute_xperms_drivers(struct extended_perms *xperms,
15 struct avtab_node *node);
16
17void 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