summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2015-07-10 17:19:56 -0400
committerPaul Moore <pmoore@redhat.com>2015-07-13 13:31:58 -0400
commitfa1aa143ac4a682c7f5fd52a3cf05f5a6fe44a0a (patch)
tree3f53aa6f35af83370aa7cd7bc25a2f6a2b6b8bbd /security
parent671a2781ff01abf4fdc8904881fc3abd3a8279af (diff)
selinux: extended permissions for ioctls
Add extended permissions logic to selinux. Extended permissions provides additional permissions in 256 bit increments. Extend the generic ioctl permission check to use the extended permissions for per-command filtering. Source/target/class sets including the ioctl permission may additionally include a set of commands. Example: allowxperm <source> <target>:<class> ioctl unpriv_app_socket_cmds auditallowxperm <source> <target>:<class> ioctl priv_gpu_cmds Where unpriv_app_socket_cmds and priv_gpu_cmds are macros representing commonly granted sets of ioctl commands. When ioctl commands are omitted only the permissions are checked. This feature is intended to provide finer granularity for the ioctl permission that may be too imprecise. For example, the same driver may use ioctls to provide important and benign functionality such as driver version or socket type as well as dangerous capabilities such as debugging features, read/write/execute to physical memory or access to sensitive data. Per-command filtering provides a mechanism to reduce the attack surface of the kernel, and limit applications to the subset of commands required. The format of the policy binary has been modified to include ioctl commands, and the policy version number has been incremented to POLICYDB_VERSION_XPERMS_IOCTL=30 to account for the format change. The extended permissions logic is deliberately generic to allow components to be reused e.g. netlink filters Signed-off-by: Jeff Vander Stoep <jeffv@google.com> Acked-by: Nick Kralevich <nnk@google.com> Signed-off-by: Paul Moore <pmoore@redhat.com>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/avc.c415
-rw-r--r--security/selinux/hooks.c42
-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
11 files changed, 834 insertions, 60 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 3c17dda9571d..2d5e1b04cd50 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{
@@ -170,7 +185,17 @@ void __init avc_init(void)
170 atomic_set(&avc_cache.lru_hint, 0); 185 atomic_set(&avc_cache.lru_hint, 0);
171 186
172 avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), 187 avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node),
173 0, SLAB_PANIC, NULL); 188 0, SLAB_PANIC, NULL);
189 avc_xperms_cachep = kmem_cache_create("avc_xperms_node",
190 sizeof(struct avc_xperms_node),
191 0, SLAB_PANIC, NULL);
192 avc_xperms_decision_cachep = kmem_cache_create(
193 "avc_xperms_decision_node",
194 sizeof(struct avc_xperms_decision_node),
195 0, SLAB_PANIC, NULL);
196 avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data",
197 sizeof(struct extended_perms_data),
198 0, SLAB_PANIC, NULL);
174 199
175 audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); 200 audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n");
176} 201}
@@ -205,9 +230,261 @@ int avc_get_hash_stats(char *page)
205 slots_used, AVC_CACHE_SLOTS, max_chain_len); 230 slots_used, AVC_CACHE_SLOTS, max_chain_len);
206} 231}
207 232
233/*
234 * using a linked list for extended_perms_decision lookup because the list is
235 * always small. i.e. less than 5, typically 1
236 */
237static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver,
238 struct avc_xperms_node *xp_node)
239{
240 struct avc_xperms_decision_node *xpd_node;
241
242 list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) {
243 if (xpd_node->xpd.driver == driver)
244 return &xpd_node->xpd;
245 }
246 return NULL;
247}
248
249static inline unsigned int
250avc_xperms_has_perm(struct extended_perms_decision *xpd,
251 u8 perm, u8 which)
252{
253 unsigned int rc = 0;
254
255 if ((which == XPERMS_ALLOWED) &&
256 (xpd->used & XPERMS_ALLOWED))
257 rc = security_xperm_test(xpd->allowed->p, perm);
258 else if ((which == XPERMS_AUDITALLOW) &&
259 (xpd->used & XPERMS_AUDITALLOW))
260 rc = security_xperm_test(xpd->auditallow->p, perm);
261 else if ((which == XPERMS_DONTAUDIT) &&
262 (xpd->used & XPERMS_DONTAUDIT))
263 rc = security_xperm_test(xpd->dontaudit->p, perm);
264 return rc;
265}
266
267static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node,
268 u8 driver, u8 perm)
269{
270 struct extended_perms_decision *xpd;
271 security_xperm_set(xp_node->xp.drivers.p, driver);
272 xpd = avc_xperms_decision_lookup(driver, xp_node);
273 if (xpd && xpd->allowed)
274 security_xperm_set(xpd->allowed->p, perm);
275}
276
277static void avc_xperms_decision_free(struct avc_xperms_decision_node *xpd_node)
278{
279 struct extended_perms_decision *xpd;
280
281 xpd = &xpd_node->xpd;
282 if (xpd->allowed)
283 kmem_cache_free(avc_xperms_data_cachep, xpd->allowed);
284 if (xpd->auditallow)
285 kmem_cache_free(avc_xperms_data_cachep, xpd->auditallow);
286 if (xpd->dontaudit)
287 kmem_cache_free(avc_xperms_data_cachep, xpd->dontaudit);
288 kmem_cache_free(avc_xperms_decision_cachep, xpd_node);
289}
290
291static void avc_xperms_free(struct avc_xperms_node *xp_node)
292{
293 struct avc_xperms_decision_node *xpd_node, *tmp;
294
295 if (!xp_node)
296 return;
297
298 list_for_each_entry_safe(xpd_node, tmp, &xp_node->xpd_head, xpd_list) {
299 list_del(&xpd_node->xpd_list);
300 avc_xperms_decision_free(xpd_node);
301 }
302 kmem_cache_free(avc_xperms_cachep, xp_node);
303}
304
305static void avc_copy_xperms_decision(struct extended_perms_decision *dest,
306 struct extended_perms_decision *src)
307{
308 dest->driver = src->driver;
309 dest->used = src->used;
310 if (dest->used & XPERMS_ALLOWED)
311 memcpy(dest->allowed->p, src->allowed->p,
312 sizeof(src->allowed->p));
313 if (dest->used & XPERMS_AUDITALLOW)
314 memcpy(dest->auditallow->p, src->auditallow->p,
315 sizeof(src->auditallow->p));
316 if (dest->used & XPERMS_DONTAUDIT)
317 memcpy(dest->dontaudit->p, src->dontaudit->p,
318 sizeof(src->dontaudit->p));
319}
320
321/*
322 * similar to avc_copy_xperms_decision, but only copy decision
323 * information relevant to this perm
324 */
325static inline void avc_quick_copy_xperms_decision(u8 perm,
326 struct extended_perms_decision *dest,
327 struct extended_perms_decision *src)
328{
329 /*
330 * compute index of the u32 of the 256 bits (8 u32s) that contain this
331 * command permission
332 */
333 u8 i = perm >> 5;
334
335 dest->used = src->used;
336 if (dest->used & XPERMS_ALLOWED)
337 dest->allowed->p[i] = src->allowed->p[i];
338 if (dest->used & XPERMS_AUDITALLOW)
339 dest->auditallow->p[i] = src->auditallow->p[i];
340 if (dest->used & XPERMS_DONTAUDIT)
341 dest->dontaudit->p[i] = src->dontaudit->p[i];
342}
343
344static struct avc_xperms_decision_node
345 *avc_xperms_decision_alloc(u8 which)
346{
347 struct avc_xperms_decision_node *xpd_node;
348 struct extended_perms_decision *xpd;
349
350 xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep,
351 GFP_ATOMIC | __GFP_NOMEMALLOC);
352 if (!xpd_node)
353 return NULL;
354
355 xpd = &xpd_node->xpd;
356 if (which & XPERMS_ALLOWED) {
357 xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep,
358 GFP_ATOMIC | __GFP_NOMEMALLOC);
359 if (!xpd->allowed)
360 goto error;
361 }
362 if (which & XPERMS_AUDITALLOW) {
363 xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep,
364 GFP_ATOMIC | __GFP_NOMEMALLOC);
365 if (!xpd->auditallow)
366 goto error;
367 }
368 if (which & XPERMS_DONTAUDIT) {
369 xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep,
370 GFP_ATOMIC | __GFP_NOMEMALLOC);
371 if (!xpd->dontaudit)
372 goto error;
373 }
374 return xpd_node;
375error:
376 avc_xperms_decision_free(xpd_node);
377 return NULL;
378}
379
380static int avc_add_xperms_decision(struct avc_node *node,
381 struct extended_perms_decision *src)
382{
383 struct avc_xperms_decision_node *dest_xpd;
384
385 node->ae.xp_node->xp.len++;
386 dest_xpd = avc_xperms_decision_alloc(src->used);
387 if (!dest_xpd)
388 return -ENOMEM;
389 avc_copy_xperms_decision(&dest_xpd->xpd, src);
390 list_add(&dest_xpd->xpd_list, &node->ae.xp_node->xpd_head);
391 return 0;
392}
393
394static struct avc_xperms_node *avc_xperms_alloc(void)
395{
396 struct avc_xperms_node *xp_node;
397
398 xp_node = kmem_cache_zalloc(avc_xperms_cachep,
399 GFP_ATOMIC|__GFP_NOMEMALLOC);
400 if (!xp_node)
401 return xp_node;
402 INIT_LIST_HEAD(&xp_node->xpd_head);
403 return xp_node;
404}
405
406static int avc_xperms_populate(struct avc_node *node,
407 struct avc_xperms_node *src)
408{
409 struct avc_xperms_node *dest;
410 struct avc_xperms_decision_node *dest_xpd;
411 struct avc_xperms_decision_node *src_xpd;
412
413 if (src->xp.len == 0)
414 return 0;
415 dest = avc_xperms_alloc();
416 if (!dest)
417 return -ENOMEM;
418
419 memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p));
420 dest->xp.len = src->xp.len;
421
422 /* for each source xpd allocate a destination xpd and copy */
423 list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) {
424 dest_xpd = avc_xperms_decision_alloc(src_xpd->xpd.used);
425 if (!dest_xpd)
426 goto error;
427 avc_copy_xperms_decision(&dest_xpd->xpd, &src_xpd->xpd);
428 list_add(&dest_xpd->xpd_list, &dest->xpd_head);
429 }
430 node->ae.xp_node = dest;
431 return 0;
432error:
433 avc_xperms_free(dest);
434 return -ENOMEM;
435
436}
437
438static inline u32 avc_xperms_audit_required(u32 requested,
439 struct av_decision *avd,
440 struct extended_perms_decision *xpd,
441 u8 perm,
442 int result,
443 u32 *deniedp)
444{
445 u32 denied, audited;
446
447 denied = requested & ~avd->allowed;
448 if (unlikely(denied)) {
449 audited = denied & avd->auditdeny;
450 if (audited && xpd) {
451 if (avc_xperms_has_perm(xpd, perm, XPERMS_DONTAUDIT))
452 audited &= ~requested;
453 }
454 } else if (result) {
455 audited = denied = requested;
456 } else {
457 audited = requested & avd->auditallow;
458 if (audited && xpd) {
459 if (!avc_xperms_has_perm(xpd, perm, XPERMS_AUDITALLOW))
460 audited &= ~requested;
461 }
462 }
463
464 *deniedp = denied;
465 return audited;
466}
467
468static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass,
469 u32 requested, struct av_decision *avd,
470 struct extended_perms_decision *xpd,
471 u8 perm, int result,
472 struct common_audit_data *ad)
473{
474 u32 audited, denied;
475
476 audited = avc_xperms_audit_required(
477 requested, avd, xpd, perm, result, &denied);
478 if (likely(!audited))
479 return 0;
480 return slow_avc_audit(ssid, tsid, tclass, requested,
481 audited, denied, result, ad, 0);
482}
483
208static void avc_node_free(struct rcu_head *rhead) 484static void avc_node_free(struct rcu_head *rhead)
209{ 485{
210 struct avc_node *node = container_of(rhead, struct avc_node, rhead); 486 struct avc_node *node = container_of(rhead, struct avc_node, rhead);
487 avc_xperms_free(node->ae.xp_node);
211 kmem_cache_free(avc_node_cachep, node); 488 kmem_cache_free(avc_node_cachep, node);
212 avc_cache_stats_incr(frees); 489 avc_cache_stats_incr(frees);
213} 490}
@@ -221,6 +498,7 @@ static void avc_node_delete(struct avc_node *node)
221 498
222static void avc_node_kill(struct avc_node *node) 499static void avc_node_kill(struct avc_node *node)
223{ 500{
501 avc_xperms_free(node->ae.xp_node);
224 kmem_cache_free(avc_node_cachep, node); 502 kmem_cache_free(avc_node_cachep, node);
225 avc_cache_stats_incr(frees); 503 avc_cache_stats_incr(frees);
226 atomic_dec(&avc_cache.active_nodes); 504 atomic_dec(&avc_cache.active_nodes);
@@ -367,6 +645,7 @@ static int avc_latest_notif_update(int seqno, int is_insert)
367 * @tsid: target security identifier 645 * @tsid: target security identifier
368 * @tclass: target security class 646 * @tclass: target security class
369 * @avd: resulting av decision 647 * @avd: resulting av decision
648 * @xp_node: resulting extended permissions
370 * 649 *
371 * Insert an AVC entry for the SID pair 650 * Insert an AVC entry for the SID pair
372 * (@ssid, @tsid) and class @tclass. 651 * (@ssid, @tsid) and class @tclass.
@@ -378,7 +657,9 @@ static int avc_latest_notif_update(int seqno, int is_insert)
378 * the access vectors into a cache entry, returns 657 * the access vectors into a cache entry, returns
379 * avc_node inserted. Otherwise, this function returns NULL. 658 * avc_node inserted. Otherwise, this function returns NULL.
380 */ 659 */
381static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) 660static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass,
661 struct av_decision *avd,
662 struct avc_xperms_node *xp_node)
382{ 663{
383 struct avc_node *pos, *node = NULL; 664 struct avc_node *pos, *node = NULL;
384 int hvalue; 665 int hvalue;
@@ -391,10 +672,15 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_dec
391 if (node) { 672 if (node) {
392 struct hlist_head *head; 673 struct hlist_head *head;
393 spinlock_t *lock; 674 spinlock_t *lock;
675 int rc = 0;
394 676
395 hvalue = avc_hash(ssid, tsid, tclass); 677 hvalue = avc_hash(ssid, tsid, tclass);
396 avc_node_populate(node, ssid, tsid, tclass, avd); 678 avc_node_populate(node, ssid, tsid, tclass, avd);
397 679 rc = avc_xperms_populate(node, xp_node);
680 if (rc) {
681 kmem_cache_free(avc_node_cachep, node);
682 return NULL;
683 }
398 head = &avc_cache.slots[hvalue]; 684 head = &avc_cache.slots[hvalue];
399 lock = &avc_cache.slots_lock[hvalue]; 685 lock = &avc_cache.slots_lock[hvalue];
400 686
@@ -523,14 +809,17 @@ out:
523 * @perms : Permission mask bits 809 * @perms : Permission mask bits
524 * @ssid,@tsid,@tclass : identifier of an AVC entry 810 * @ssid,@tsid,@tclass : identifier of an AVC entry
525 * @seqno : sequence number when decision was made 811 * @seqno : sequence number when decision was made
812 * @xpd: extended_perms_decision to be added to the node
526 * 813 *
527 * if a valid AVC entry doesn't exist,this function returns -ENOENT. 814 * if a valid AVC entry doesn't exist,this function returns -ENOENT.
528 * if kmalloc() called internal returns NULL, this function returns -ENOMEM. 815 * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
529 * otherwise, this function updates the AVC entry. The original AVC-entry object 816 * otherwise, this function updates the AVC entry. The original AVC-entry object
530 * will release later by RCU. 817 * will release later by RCU.
531 */ 818 */
532static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, 819static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
533 u32 seqno) 820 u32 tsid, u16 tclass, u32 seqno,
821 struct extended_perms_decision *xpd,
822 u32 flags)
534{ 823{
535 int hvalue, rc = 0; 824 int hvalue, rc = 0;
536 unsigned long flag; 825 unsigned long flag;
@@ -574,9 +863,19 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
574 863
575 avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); 864 avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd);
576 865
866 if (orig->ae.xp_node) {
867 rc = avc_xperms_populate(node, orig->ae.xp_node);
868 if (rc) {
869 kmem_cache_free(avc_node_cachep, node);
870 goto out_unlock;
871 }
872 }
873
577 switch (event) { 874 switch (event) {
578 case AVC_CALLBACK_GRANT: 875 case AVC_CALLBACK_GRANT:
579 node->ae.avd.allowed |= perms; 876 node->ae.avd.allowed |= perms;
877 if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS))
878 avc_xperms_allow_perm(node->ae.xp_node, driver, xperm);
580 break; 879 break;
581 case AVC_CALLBACK_TRY_REVOKE: 880 case AVC_CALLBACK_TRY_REVOKE:
582 case AVC_CALLBACK_REVOKE: 881 case AVC_CALLBACK_REVOKE:
@@ -594,6 +893,9 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
594 case AVC_CALLBACK_AUDITDENY_DISABLE: 893 case AVC_CALLBACK_AUDITDENY_DISABLE:
595 node->ae.avd.auditdeny &= ~perms; 894 node->ae.avd.auditdeny &= ~perms;
596 break; 895 break;
896 case AVC_CALLBACK_ADD_XPERMS:
897 avc_add_xperms_decision(node, xpd);
898 break;
597 } 899 }
598 avc_node_replace(node, orig); 900 avc_node_replace(node, orig);
599out_unlock: 901out_unlock:
@@ -665,18 +967,20 @@ int avc_ss_reset(u32 seqno)
665 * results in a bigger stack frame. 967 * results in a bigger stack frame.
666 */ 968 */
667static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, 969static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid,
668 u16 tclass, struct av_decision *avd) 970 u16 tclass, struct av_decision *avd,
971 struct avc_xperms_node *xp_node)
669{ 972{
670 rcu_read_unlock(); 973 rcu_read_unlock();
671 security_compute_av(ssid, tsid, tclass, avd); 974 INIT_LIST_HEAD(&xp_node->xpd_head);
975 security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp);
672 rcu_read_lock(); 976 rcu_read_lock();
673 return avc_insert(ssid, tsid, tclass, avd); 977 return avc_insert(ssid, tsid, tclass, avd, xp_node);
674} 978}
675 979
676static noinline int avc_denied(u32 ssid, u32 tsid, 980static noinline int avc_denied(u32 ssid, u32 tsid,
677 u16 tclass, u32 requested, 981 u16 tclass, u32 requested,
678 unsigned flags, 982 u8 driver, u8 xperm, unsigned flags,
679 struct av_decision *avd) 983 struct av_decision *avd)
680{ 984{
681 if (flags & AVC_STRICT) 985 if (flags & AVC_STRICT)
682 return -EACCES; 986 return -EACCES;
@@ -684,11 +988,91 @@ static noinline int avc_denied(u32 ssid, u32 tsid,
684 if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) 988 if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE))
685 return -EACCES; 989 return -EACCES;
686 990
687 avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, 991 avc_update_node(AVC_CALLBACK_GRANT, requested, driver, xperm, ssid,
688 tsid, tclass, avd->seqno); 992 tsid, tclass, avd->seqno, NULL, flags);
689 return 0; 993 return 0;
690} 994}
691 995
996/*
997 * The avc extended permissions logic adds an additional 256 bits of
998 * permissions to an avc node when extended permissions for that node are
999 * specified in the avtab. If the additional 256 permissions is not adequate,
1000 * as-is the case with ioctls, then multiple may be chained together and the
1001 * driver field is used to specify which set contains the permission.
1002 */
1003int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
1004 u8 driver, u8 xperm, struct common_audit_data *ad)
1005{
1006 struct avc_node *node;
1007 struct av_decision avd;
1008 u32 denied;
1009 struct extended_perms_decision local_xpd;
1010 struct extended_perms_decision *xpd = NULL;
1011 struct extended_perms_data allowed;
1012 struct extended_perms_data auditallow;
1013 struct extended_perms_data dontaudit;
1014 struct avc_xperms_node local_xp_node;
1015 struct avc_xperms_node *xp_node;
1016 int rc = 0, rc2;
1017
1018 xp_node = &local_xp_node;
1019 BUG_ON(!requested);
1020
1021 rcu_read_lock();
1022
1023 node = avc_lookup(ssid, tsid, tclass);
1024 if (unlikely(!node)) {
1025 node = avc_compute_av(ssid, tsid, tclass, &avd, xp_node);
1026 } else {
1027 memcpy(&avd, &node->ae.avd, sizeof(avd));
1028 xp_node = node->ae.xp_node;
1029 }
1030 /* if extended permissions are not defined, only consider av_decision */
1031 if (!xp_node || !xp_node->xp.len)
1032 goto decision;
1033
1034 local_xpd.allowed = &allowed;
1035 local_xpd.auditallow = &auditallow;
1036 local_xpd.dontaudit = &dontaudit;
1037
1038 xpd = avc_xperms_decision_lookup(driver, xp_node);
1039 if (unlikely(!xpd)) {
1040 /*
1041 * Compute the extended_perms_decision only if the driver
1042 * is flagged
1043 */
1044 if (!security_xperm_test(xp_node->xp.drivers.p, driver)) {
1045 avd.allowed &= ~requested;
1046 goto decision;
1047 }
1048 rcu_read_unlock();
1049 security_compute_xperms_decision(ssid, tsid, tclass, driver,
1050 &local_xpd);
1051 rcu_read_lock();
1052 avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver, xperm,
1053 ssid, tsid, tclass, avd.seqno, &local_xpd, 0);
1054 } else {
1055 avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd);
1056 }
1057 xpd = &local_xpd;
1058
1059 if (!avc_xperms_has_perm(xpd, xperm, XPERMS_ALLOWED))
1060 avd.allowed &= ~requested;
1061
1062decision:
1063 denied = requested & ~(avd.allowed);
1064 if (unlikely(denied))
1065 rc = avc_denied(ssid, tsid, tclass, requested, driver, xperm,
1066 AVC_EXTENDED_PERMS, &avd);
1067
1068 rcu_read_unlock();
1069
1070 rc2 = avc_xperms_audit(ssid, tsid, tclass, requested,
1071 &avd, xpd, xperm, rc, ad);
1072 if (rc2)
1073 return rc2;
1074 return rc;
1075}
692 1076
693/** 1077/**
694 * avc_has_perm_noaudit - Check permissions but perform no auditing. 1078 * avc_has_perm_noaudit - Check permissions but perform no auditing.
@@ -716,6 +1100,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
716 struct av_decision *avd) 1100 struct av_decision *avd)
717{ 1101{
718 struct avc_node *node; 1102 struct avc_node *node;
1103 struct avc_xperms_node xp_node;
719 int rc = 0; 1104 int rc = 0;
720 u32 denied; 1105 u32 denied;
721 1106
@@ -725,13 +1110,13 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
725 1110
726 node = avc_lookup(ssid, tsid, tclass); 1111 node = avc_lookup(ssid, tsid, tclass);
727 if (unlikely(!node)) 1112 if (unlikely(!node))
728 node = avc_compute_av(ssid, tsid, tclass, avd); 1113 node = avc_compute_av(ssid, tsid, tclass, avd, &xp_node);
729 else 1114 else
730 memcpy(avd, &node->ae.avd, sizeof(*avd)); 1115 memcpy(avd, &node->ae.avd, sizeof(*avd));
731 1116
732 denied = requested & ~(avd->allowed); 1117 denied = requested & ~(avd->allowed);
733 if (unlikely(denied)) 1118 if (unlikely(denied))
734 rc = avc_denied(ssid, tsid, tclass, requested, flags, avd); 1119 rc = avc_denied(ssid, tsid, tclass, requested, 0, 0, flags, avd);
735 1120
736 rcu_read_unlock(); 1121 rcu_read_unlock();
737 return rc; 1122 return rc;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 692e3cc8ce23..a049b7216270 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3216,6 +3216,46 @@ static void selinux_file_free_security(struct file *file)
3216 file_free_security(file); 3216 file_free_security(file);
3217} 3217}
3218 3218
3219/*
3220 * Check whether a task has the ioctl permission and cmd
3221 * operation to an inode.
3222 */
3223int ioctl_has_perm(const struct cred *cred, struct file *file,
3224 u32 requested, u16 cmd)
3225{
3226 struct common_audit_data ad;
3227 struct file_security_struct *fsec = file->f_security;
3228 struct inode *inode = file_inode(file);
3229 struct inode_security_struct *isec = inode->i_security;
3230 struct lsm_ioctlop_audit ioctl;
3231 u32 ssid = cred_sid(cred);
3232 int rc;
3233 u8 driver = cmd >> 8;
3234 u8 xperm = cmd & 0xff;
3235
3236 ad.type = LSM_AUDIT_DATA_IOCTL_OP;
3237 ad.u.op = &ioctl;
3238 ad.u.op->cmd = cmd;
3239 ad.u.op->path = file->f_path;
3240
3241 if (ssid != fsec->sid) {
3242 rc = avc_has_perm(ssid, fsec->sid,
3243 SECCLASS_FD,
3244 FD__USE,
3245 &ad);
3246 if (rc)
3247 goto out;
3248 }
3249
3250 if (unlikely(IS_PRIVATE(inode)))
3251 return 0;
3252
3253 rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,
3254 requested, driver, xperm, &ad);
3255out:
3256 return rc;
3257}
3258
3219static int selinux_file_ioctl(struct file *file, unsigned int cmd, 3259static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3220 unsigned long arg) 3260 unsigned long arg)
3221{ 3261{
@@ -3258,7 +3298,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
3258 * to the file's ioctl() function. 3298 * to the file's ioctl() function.
3259 */ 3299 */
3260 default: 3300 default:
3261 error = file_has_perm(cred, file, FILE__IOCTL); 3301 error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
3262 } 3302 }
3263 return error; 3303 return error;
3264} 3304}
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index ddf8eec03f21..db12ff14277b 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -142,6 +142,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
142} 142}
143 143
144#define AVC_STRICT 1 /* Ignore permissive mode. */ 144#define AVC_STRICT 1 /* Ignore permissive mode. */
145#define AVC_EXTENDED_PERMS 2 /* update extended permissions */
145int avc_has_perm_noaudit(u32 ssid, u32 tsid, 146int avc_has_perm_noaudit(u32 ssid, u32 tsid,
146 u16 tclass, u32 requested, 147 u16 tclass, u32 requested,
147 unsigned flags, 148 unsigned flags,
@@ -151,6 +152,10 @@ int avc_has_perm(u32 ssid, u32 tsid,
151 u16 tclass, u32 requested, 152 u16 tclass, u32 requested,
152 struct common_audit_data *auditdata); 153 struct common_audit_data *auditdata);
153 154
155int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
156 u8 driver, u8 perm, struct common_audit_data *ad);
157
158
154u32 avc_policy_seqno(void); 159u32 avc_policy_seqno(void);
155 160
156#define AVC_CALLBACK_GRANT 1 161#define AVC_CALLBACK_GRANT 1
@@ -161,6 +166,7 @@ u32 avc_policy_seqno(void);
161#define AVC_CALLBACK_AUDITALLOW_DISABLE 32 166#define AVC_CALLBACK_AUDITALLOW_DISABLE 32
162#define AVC_CALLBACK_AUDITDENY_ENABLE 64 167#define AVC_CALLBACK_AUDITDENY_ENABLE 64
163#define AVC_CALLBACK_AUDITDENY_DISABLE 128 168#define AVC_CALLBACK_AUDITDENY_DISABLE 128
169#define AVC_CALLBACK_ADD_XPERMS 256
164 170
165int avc_add_callback(int (*callback)(u32 event), u32 events); 171int avc_add_callback(int (*callback)(u32 event), u32 events);
166 172
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