Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'next' of git://git.infradead.org/users/pcmoore/selinux into next

+918 -113
+7
include/linux/lsm_audit.h
··· 40 40 } fam; 41 41 }; 42 42 43 + struct lsm_ioctlop_audit { 44 + struct path path; 45 + u16 cmd; 46 + }; 47 + 43 48 /* Auxiliary data to use in generating the audit record. */ 44 49 struct common_audit_data { 45 50 char type; ··· 58 53 #define LSM_AUDIT_DATA_KMOD 8 59 54 #define LSM_AUDIT_DATA_INODE 9 60 55 #define LSM_AUDIT_DATA_DENTRY 10 56 + #define LSM_AUDIT_DATA_IOCTL_OP 11 61 57 union { 62 58 struct path path; 63 59 struct dentry *dentry; ··· 74 68 } key_struct; 75 69 #endif 76 70 char *kmod_name; 71 + struct lsm_ioctlop_audit *op; 77 72 } u; 78 73 /* this union contains LSM specific data */ 79 74 union {
+1
scripts/selinux/mdp/mdp.c
··· 98 98 99 99 /* types, roles, and allows */ 100 100 fprintf(fout, "type base_t;\n"); 101 + fprintf(fout, "role base_r;\n"); 101 102 fprintf(fout, "role base_r types { base_t };\n"); 102 103 for (i = 0; secclass_map[i].name; i++) 103 104 fprintf(fout, "allow base_t base_t:%s *;\n",
+15
security/lsm_audit.c
··· 245 245 } 246 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 263 case LSM_AUDIT_DATA_DENTRY: { 249 264 struct inode *inode; 250 265
+402 -16
security/selinux/avc.c
··· 22 22 #include <linux/init.h> 23 23 #include <linux/skbuff.h> 24 24 #include <linux/percpu.h> 25 + #include <linux/list.h> 25 26 #include <net/sock.h> 26 27 #include <linux/un.h> 27 28 #include <net/af_unix.h> ··· 49 48 u32 tsid; 50 49 u16 tclass; 51 50 struct av_decision avd; 51 + struct avc_xperms_node *xp_node; 52 52 }; 53 53 54 54 struct avc_node { 55 55 struct avc_entry ae; 56 56 struct hlist_node list; /* anchored in avc_cache->slots[i] */ 57 57 struct rcu_head rhead; 58 + }; 59 + 60 + struct avc_xperms_decision_node { 61 + struct extended_perms_decision xpd; 62 + struct list_head xpd_list; /* list of extended_perms_decision */ 63 + }; 64 + 65 + struct avc_xperms_node { 66 + struct extended_perms xp; 67 + struct list_head xpd_head; /* list head of extended_perms_decision */ 58 68 }; 59 69 60 70 struct avc_cache { ··· 92 80 static struct avc_cache avc_cache; 93 81 static struct avc_callback_node *avc_callbacks; 94 82 static struct kmem_cache *avc_node_cachep; 83 + static struct kmem_cache *avc_xperms_data_cachep; 84 + static struct kmem_cache *avc_xperms_decision_cachep; 85 + static struct kmem_cache *avc_xperms_cachep; 95 86 96 87 static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) 97 88 { ··· 116 101 return; 117 102 } 118 103 104 + BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); 119 105 perms = secclass_map[tclass-1].perms; 120 106 121 107 audit_log_format(ab, " {"); ··· 165 149 kfree(scontext); 166 150 } 167 151 168 - BUG_ON(tclass >= ARRAY_SIZE(secclass_map)); 152 + BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); 169 153 audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name); 170 154 } 171 155 ··· 186 170 atomic_set(&avc_cache.lru_hint, 0); 187 171 188 172 avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), 189 - 0, SLAB_PANIC, NULL); 173 + 0, SLAB_PANIC, NULL); 174 + avc_xperms_cachep = kmem_cache_create("avc_xperms_node", 175 + sizeof(struct avc_xperms_node), 176 + 0, SLAB_PANIC, NULL); 177 + avc_xperms_decision_cachep = kmem_cache_create( 178 + "avc_xperms_decision_node", 179 + sizeof(struct avc_xperms_decision_node), 180 + 0, SLAB_PANIC, NULL); 181 + avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data", 182 + sizeof(struct extended_perms_data), 183 + 0, SLAB_PANIC, NULL); 190 184 191 185 audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); 192 186 } ··· 231 205 slots_used, AVC_CACHE_SLOTS, max_chain_len); 232 206 } 233 207 208 + /* 209 + * using a linked list for extended_perms_decision lookup because the list is 210 + * always small. i.e. less than 5, typically 1 211 + */ 212 + static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver, 213 + struct avc_xperms_node *xp_node) 214 + { 215 + struct avc_xperms_decision_node *xpd_node; 216 + 217 + list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) { 218 + if (xpd_node->xpd.driver == driver) 219 + return &xpd_node->xpd; 220 + } 221 + return NULL; 222 + } 223 + 224 + static inline unsigned int 225 + avc_xperms_has_perm(struct extended_perms_decision *xpd, 226 + u8 perm, u8 which) 227 + { 228 + unsigned int rc = 0; 229 + 230 + if ((which == XPERMS_ALLOWED) && 231 + (xpd->used & XPERMS_ALLOWED)) 232 + rc = security_xperm_test(xpd->allowed->p, perm); 233 + else if ((which == XPERMS_AUDITALLOW) && 234 + (xpd->used & XPERMS_AUDITALLOW)) 235 + rc = security_xperm_test(xpd->auditallow->p, perm); 236 + else if ((which == XPERMS_DONTAUDIT) && 237 + (xpd->used & XPERMS_DONTAUDIT)) 238 + rc = security_xperm_test(xpd->dontaudit->p, perm); 239 + return rc; 240 + } 241 + 242 + static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node, 243 + u8 driver, u8 perm) 244 + { 245 + struct extended_perms_decision *xpd; 246 + security_xperm_set(xp_node->xp.drivers.p, driver); 247 + xpd = avc_xperms_decision_lookup(driver, xp_node); 248 + if (xpd && xpd->allowed) 249 + security_xperm_set(xpd->allowed->p, perm); 250 + } 251 + 252 + static void avc_xperms_decision_free(struct avc_xperms_decision_node *xpd_node) 253 + { 254 + struct extended_perms_decision *xpd; 255 + 256 + xpd = &xpd_node->xpd; 257 + if (xpd->allowed) 258 + kmem_cache_free(avc_xperms_data_cachep, xpd->allowed); 259 + if (xpd->auditallow) 260 + kmem_cache_free(avc_xperms_data_cachep, xpd->auditallow); 261 + if (xpd->dontaudit) 262 + kmem_cache_free(avc_xperms_data_cachep, xpd->dontaudit); 263 + kmem_cache_free(avc_xperms_decision_cachep, xpd_node); 264 + } 265 + 266 + static void avc_xperms_free(struct avc_xperms_node *xp_node) 267 + { 268 + struct avc_xperms_decision_node *xpd_node, *tmp; 269 + 270 + if (!xp_node) 271 + return; 272 + 273 + list_for_each_entry_safe(xpd_node, tmp, &xp_node->xpd_head, xpd_list) { 274 + list_del(&xpd_node->xpd_list); 275 + avc_xperms_decision_free(xpd_node); 276 + } 277 + kmem_cache_free(avc_xperms_cachep, xp_node); 278 + } 279 + 280 + static void avc_copy_xperms_decision(struct extended_perms_decision *dest, 281 + struct extended_perms_decision *src) 282 + { 283 + dest->driver = src->driver; 284 + dest->used = src->used; 285 + if (dest->used & XPERMS_ALLOWED) 286 + memcpy(dest->allowed->p, src->allowed->p, 287 + sizeof(src->allowed->p)); 288 + if (dest->used & XPERMS_AUDITALLOW) 289 + memcpy(dest->auditallow->p, src->auditallow->p, 290 + sizeof(src->auditallow->p)); 291 + if (dest->used & XPERMS_DONTAUDIT) 292 + memcpy(dest->dontaudit->p, src->dontaudit->p, 293 + sizeof(src->dontaudit->p)); 294 + } 295 + 296 + /* 297 + * similar to avc_copy_xperms_decision, but only copy decision 298 + * information relevant to this perm 299 + */ 300 + static inline void avc_quick_copy_xperms_decision(u8 perm, 301 + struct extended_perms_decision *dest, 302 + struct extended_perms_decision *src) 303 + { 304 + /* 305 + * compute index of the u32 of the 256 bits (8 u32s) that contain this 306 + * command permission 307 + */ 308 + u8 i = perm >> 5; 309 + 310 + dest->used = src->used; 311 + if (dest->used & XPERMS_ALLOWED) 312 + dest->allowed->p[i] = src->allowed->p[i]; 313 + if (dest->used & XPERMS_AUDITALLOW) 314 + dest->auditallow->p[i] = src->auditallow->p[i]; 315 + if (dest->used & XPERMS_DONTAUDIT) 316 + dest->dontaudit->p[i] = src->dontaudit->p[i]; 317 + } 318 + 319 + static struct avc_xperms_decision_node 320 + *avc_xperms_decision_alloc(u8 which) 321 + { 322 + struct avc_xperms_decision_node *xpd_node; 323 + struct extended_perms_decision *xpd; 324 + 325 + xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, 326 + GFP_ATOMIC | __GFP_NOMEMALLOC); 327 + if (!xpd_node) 328 + return NULL; 329 + 330 + xpd = &xpd_node->xpd; 331 + if (which & XPERMS_ALLOWED) { 332 + xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep, 333 + GFP_ATOMIC | __GFP_NOMEMALLOC); 334 + if (!xpd->allowed) 335 + goto error; 336 + } 337 + if (which & XPERMS_AUDITALLOW) { 338 + xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep, 339 + GFP_ATOMIC | __GFP_NOMEMALLOC); 340 + if (!xpd->auditallow) 341 + goto error; 342 + } 343 + if (which & XPERMS_DONTAUDIT) { 344 + xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep, 345 + GFP_ATOMIC | __GFP_NOMEMALLOC); 346 + if (!xpd->dontaudit) 347 + goto error; 348 + } 349 + return xpd_node; 350 + error: 351 + avc_xperms_decision_free(xpd_node); 352 + return NULL; 353 + } 354 + 355 + static int avc_add_xperms_decision(struct avc_node *node, 356 + struct extended_perms_decision *src) 357 + { 358 + struct avc_xperms_decision_node *dest_xpd; 359 + 360 + node->ae.xp_node->xp.len++; 361 + dest_xpd = avc_xperms_decision_alloc(src->used); 362 + if (!dest_xpd) 363 + return -ENOMEM; 364 + avc_copy_xperms_decision(&dest_xpd->xpd, src); 365 + list_add(&dest_xpd->xpd_list, &node->ae.xp_node->xpd_head); 366 + return 0; 367 + } 368 + 369 + static struct avc_xperms_node *avc_xperms_alloc(void) 370 + { 371 + struct avc_xperms_node *xp_node; 372 + 373 + xp_node = kmem_cache_zalloc(avc_xperms_cachep, 374 + GFP_ATOMIC|__GFP_NOMEMALLOC); 375 + if (!xp_node) 376 + return xp_node; 377 + INIT_LIST_HEAD(&xp_node->xpd_head); 378 + return xp_node; 379 + } 380 + 381 + static int avc_xperms_populate(struct avc_node *node, 382 + struct avc_xperms_node *src) 383 + { 384 + struct avc_xperms_node *dest; 385 + struct avc_xperms_decision_node *dest_xpd; 386 + struct avc_xperms_decision_node *src_xpd; 387 + 388 + if (src->xp.len == 0) 389 + return 0; 390 + dest = avc_xperms_alloc(); 391 + if (!dest) 392 + return -ENOMEM; 393 + 394 + memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p)); 395 + dest->xp.len = src->xp.len; 396 + 397 + /* for each source xpd allocate a destination xpd and copy */ 398 + list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) { 399 + dest_xpd = avc_xperms_decision_alloc(src_xpd->xpd.used); 400 + if (!dest_xpd) 401 + goto error; 402 + avc_copy_xperms_decision(&dest_xpd->xpd, &src_xpd->xpd); 403 + list_add(&dest_xpd->xpd_list, &dest->xpd_head); 404 + } 405 + node->ae.xp_node = dest; 406 + return 0; 407 + error: 408 + avc_xperms_free(dest); 409 + return -ENOMEM; 410 + 411 + } 412 + 413 + static inline u32 avc_xperms_audit_required(u32 requested, 414 + struct av_decision *avd, 415 + struct extended_perms_decision *xpd, 416 + u8 perm, 417 + int result, 418 + u32 *deniedp) 419 + { 420 + u32 denied, audited; 421 + 422 + denied = requested & ~avd->allowed; 423 + if (unlikely(denied)) { 424 + audited = denied & avd->auditdeny; 425 + if (audited && xpd) { 426 + if (avc_xperms_has_perm(xpd, perm, XPERMS_DONTAUDIT)) 427 + audited &= ~requested; 428 + } 429 + } else if (result) { 430 + audited = denied = requested; 431 + } else { 432 + audited = requested & avd->auditallow; 433 + if (audited && xpd) { 434 + if (!avc_xperms_has_perm(xpd, perm, XPERMS_AUDITALLOW)) 435 + audited &= ~requested; 436 + } 437 + } 438 + 439 + *deniedp = denied; 440 + return audited; 441 + } 442 + 443 + static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, 444 + u32 requested, struct av_decision *avd, 445 + struct extended_perms_decision *xpd, 446 + u8 perm, int result, 447 + struct common_audit_data *ad) 448 + { 449 + u32 audited, denied; 450 + 451 + audited = avc_xperms_audit_required( 452 + requested, avd, xpd, perm, result, &denied); 453 + if (likely(!audited)) 454 + return 0; 455 + return slow_avc_audit(ssid, tsid, tclass, requested, 456 + audited, denied, result, ad, 0); 457 + } 458 + 234 459 static void avc_node_free(struct rcu_head *rhead) 235 460 { 236 461 struct avc_node *node = container_of(rhead, struct avc_node, rhead); 462 + avc_xperms_free(node->ae.xp_node); 237 463 kmem_cache_free(avc_node_cachep, node); 238 464 avc_cache_stats_incr(frees); 239 465 } ··· 499 221 500 222 static void avc_node_kill(struct avc_node *node) 501 223 { 224 + avc_xperms_free(node->ae.xp_node); 502 225 kmem_cache_free(avc_node_cachep, node); 503 226 avc_cache_stats_incr(frees); 504 227 atomic_dec(&avc_cache.active_nodes); ··· 646 367 * @tsid: target security identifier 647 368 * @tclass: target security class 648 369 * @avd: resulting av decision 370 + * @xp_node: resulting extended permissions 649 371 * 650 372 * Insert an AVC entry for the SID pair 651 373 * (@ssid, @tsid) and class @tclass. ··· 658 378 * the access vectors into a cache entry, returns 659 379 * avc_node inserted. Otherwise, this function returns NULL. 660 380 */ 661 - static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) 381 + static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, 382 + struct av_decision *avd, 383 + struct avc_xperms_node *xp_node) 662 384 { 663 385 struct avc_node *pos, *node = NULL; 664 386 int hvalue; ··· 673 391 if (node) { 674 392 struct hlist_head *head; 675 393 spinlock_t *lock; 394 + int rc = 0; 676 395 677 396 hvalue = avc_hash(ssid, tsid, tclass); 678 397 avc_node_populate(node, ssid, tsid, tclass, avd); 679 - 398 + rc = avc_xperms_populate(node, xp_node); 399 + if (rc) { 400 + kmem_cache_free(avc_node_cachep, node); 401 + return NULL; 402 + } 680 403 head = &avc_cache.slots[hvalue]; 681 404 lock = &avc_cache.slots_lock[hvalue]; 682 405 ··· 810 523 * @perms : Permission mask bits 811 524 * @ssid,@tsid,@tclass : identifier of an AVC entry 812 525 * @seqno : sequence number when decision was made 526 + * @xpd: extended_perms_decision to be added to the node 813 527 * 814 528 * if a valid AVC entry doesn't exist,this function returns -ENOENT. 815 529 * if kmalloc() called internal returns NULL, this function returns -ENOMEM. 816 530 * otherwise, this function updates the AVC entry. The original AVC-entry object 817 531 * will release later by RCU. 818 532 */ 819 - static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, 820 - u32 seqno) 533 + static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, 534 + u32 tsid, u16 tclass, u32 seqno, 535 + struct extended_perms_decision *xpd, 536 + u32 flags) 821 537 { 822 538 int hvalue, rc = 0; 823 539 unsigned long flag; ··· 864 574 865 575 avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); 866 576 577 + if (orig->ae.xp_node) { 578 + rc = avc_xperms_populate(node, orig->ae.xp_node); 579 + if (rc) { 580 + kmem_cache_free(avc_node_cachep, node); 581 + goto out_unlock; 582 + } 583 + } 584 + 867 585 switch (event) { 868 586 case AVC_CALLBACK_GRANT: 869 587 node->ae.avd.allowed |= perms; 588 + if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS)) 589 + avc_xperms_allow_perm(node->ae.xp_node, driver, xperm); 870 590 break; 871 591 case AVC_CALLBACK_TRY_REVOKE: 872 592 case AVC_CALLBACK_REVOKE: ··· 893 593 break; 894 594 case AVC_CALLBACK_AUDITDENY_DISABLE: 895 595 node->ae.avd.auditdeny &= ~perms; 596 + break; 597 + case AVC_CALLBACK_ADD_XPERMS: 598 + avc_add_xperms_decision(node, xpd); 896 599 break; 897 600 } 898 601 avc_node_replace(node, orig); ··· 968 665 * results in a bigger stack frame. 969 666 */ 970 667 static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, 971 - u16 tclass, struct av_decision *avd) 668 + u16 tclass, struct av_decision *avd, 669 + struct avc_xperms_node *xp_node) 972 670 { 973 671 rcu_read_unlock(); 974 - security_compute_av(ssid, tsid, tclass, avd); 672 + INIT_LIST_HEAD(&xp_node->xpd_head); 673 + security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp); 975 674 rcu_read_lock(); 976 - return avc_insert(ssid, tsid, tclass, avd); 675 + return avc_insert(ssid, tsid, tclass, avd, xp_node); 977 676 } 978 677 979 678 static noinline int avc_denied(u32 ssid, u32 tsid, 980 - u16 tclass, u32 requested, 981 - unsigned flags, 982 - struct av_decision *avd) 679 + u16 tclass, u32 requested, 680 + u8 driver, u8 xperm, unsigned flags, 681 + struct av_decision *avd) 983 682 { 984 683 if (flags & AVC_STRICT) 985 684 return -EACCES; ··· 989 684 if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) 990 685 return -EACCES; 991 686 992 - avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, 993 - tsid, tclass, avd->seqno); 687 + avc_update_node(AVC_CALLBACK_GRANT, requested, driver, xperm, ssid, 688 + tsid, tclass, avd->seqno, NULL, flags); 994 689 return 0; 995 690 } 996 691 692 + /* 693 + * The avc extended permissions logic adds an additional 256 bits of 694 + * permissions to an avc node when extended permissions for that node are 695 + * specified in the avtab. If the additional 256 permissions is not adequate, 696 + * as-is the case with ioctls, then multiple may be chained together and the 697 + * driver field is used to specify which set contains the permission. 698 + */ 699 + int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, 700 + u8 driver, u8 xperm, struct common_audit_data *ad) 701 + { 702 + struct avc_node *node; 703 + struct av_decision avd; 704 + u32 denied; 705 + struct extended_perms_decision local_xpd; 706 + struct extended_perms_decision *xpd = NULL; 707 + struct extended_perms_data allowed; 708 + struct extended_perms_data auditallow; 709 + struct extended_perms_data dontaudit; 710 + struct avc_xperms_node local_xp_node; 711 + struct avc_xperms_node *xp_node; 712 + int rc = 0, rc2; 713 + 714 + xp_node = &local_xp_node; 715 + BUG_ON(!requested); 716 + 717 + rcu_read_lock(); 718 + 719 + node = avc_lookup(ssid, tsid, tclass); 720 + if (unlikely(!node)) { 721 + node = avc_compute_av(ssid, tsid, tclass, &avd, xp_node); 722 + } else { 723 + memcpy(&avd, &node->ae.avd, sizeof(avd)); 724 + xp_node = node->ae.xp_node; 725 + } 726 + /* if extended permissions are not defined, only consider av_decision */ 727 + if (!xp_node || !xp_node->xp.len) 728 + goto decision; 729 + 730 + local_xpd.allowed = &allowed; 731 + local_xpd.auditallow = &auditallow; 732 + local_xpd.dontaudit = &dontaudit; 733 + 734 + xpd = avc_xperms_decision_lookup(driver, xp_node); 735 + if (unlikely(!xpd)) { 736 + /* 737 + * Compute the extended_perms_decision only if the driver 738 + * is flagged 739 + */ 740 + if (!security_xperm_test(xp_node->xp.drivers.p, driver)) { 741 + avd.allowed &= ~requested; 742 + goto decision; 743 + } 744 + rcu_read_unlock(); 745 + security_compute_xperms_decision(ssid, tsid, tclass, driver, 746 + &local_xpd); 747 + rcu_read_lock(); 748 + avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver, xperm, 749 + ssid, tsid, tclass, avd.seqno, &local_xpd, 0); 750 + } else { 751 + avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd); 752 + } 753 + xpd = &local_xpd; 754 + 755 + if (!avc_xperms_has_perm(xpd, xperm, XPERMS_ALLOWED)) 756 + avd.allowed &= ~requested; 757 + 758 + decision: 759 + denied = requested & ~(avd.allowed); 760 + if (unlikely(denied)) 761 + rc = avc_denied(ssid, tsid, tclass, requested, driver, xperm, 762 + AVC_EXTENDED_PERMS, &avd); 763 + 764 + rcu_read_unlock(); 765 + 766 + rc2 = avc_xperms_audit(ssid, tsid, tclass, requested, 767 + &avd, xpd, xperm, rc, ad); 768 + if (rc2) 769 + return rc2; 770 + return rc; 771 + } 997 772 998 773 /** 999 774 * avc_has_perm_noaudit - Check permissions but perform no auditing. ··· 1101 716 struct av_decision *avd) 1102 717 { 1103 718 struct avc_node *node; 719 + struct avc_xperms_node xp_node; 1104 720 int rc = 0; 1105 721 u32 denied; 1106 722 ··· 1111 725 1112 726 node = avc_lookup(ssid, tsid, tclass); 1113 727 if (unlikely(!node)) 1114 - node = avc_compute_av(ssid, tsid, tclass, avd); 728 + node = avc_compute_av(ssid, tsid, tclass, avd, &xp_node); 1115 729 else 1116 730 memcpy(avd, &node->ae.avd, sizeof(*avd)); 1117 731 1118 732 denied = requested & ~(avd->allowed); 1119 733 if (unlikely(denied)) 1120 - rc = avc_denied(ssid, tsid, tclass, requested, flags, avd); 734 + rc = avc_denied(ssid, tsid, tclass, requested, 0, 0, flags, avd); 1121 735 1122 736 rcu_read_unlock(); 1123 737 return rc;
+97 -50
security/selinux/hooks.c
··· 254 254 struct inode_security_struct *isec = inode->i_security; 255 255 struct superblock_security_struct *sbsec = inode->i_sb->s_security; 256 256 257 - spin_lock(&sbsec->isec_lock); 258 - if (!list_empty(&isec->list)) 257 + /* 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 269 list_del_init(&isec->list); 260 - spin_unlock(&sbsec->isec_lock); 270 + spin_unlock(&sbsec->isec_lock); 271 + } 261 272 262 273 /* 263 274 * The inode may still be referenced in a path walk and ··· 1709 1698 return rc; 1710 1699 } 1711 1700 1701 + /* 1702 + * Determine the label for an inode that might be unioned. 1703 + */ 1704 + static int selinux_determine_inode_label(const struct inode *dir, 1705 + const struct qstr *name, 1706 + u16 tclass, 1707 + u32 *_new_isid) 1708 + { 1709 + const struct superblock_security_struct *sbsec = dir->i_sb->s_security; 1710 + const struct inode_security_struct *dsec = dir->i_security; 1711 + const struct task_security_struct *tsec = current_security(); 1712 + 1713 + if ((sbsec->flags & SE_SBINITIALIZED) && 1714 + (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) { 1715 + *_new_isid = sbsec->mntpoint_sid; 1716 + } else if ((sbsec->flags & SBLABEL_MNT) && 1717 + tsec->create_sid) { 1718 + *_new_isid = tsec->create_sid; 1719 + } else { 1720 + return security_transition_sid(tsec->sid, dsec->sid, tclass, 1721 + name, _new_isid); 1722 + } 1723 + 1724 + return 0; 1725 + } 1726 + 1712 1727 /* Check whether a task can create a file. */ 1713 1728 static int may_create(struct inode *dir, 1714 1729 struct dentry *dentry, ··· 1751 1714 sbsec = dir->i_sb->s_security; 1752 1715 1753 1716 sid = tsec->sid; 1754 - newsid = tsec->create_sid; 1755 1717 1756 1718 ad.type = LSM_AUDIT_DATA_DENTRY; 1757 1719 ad.u.dentry = dentry; ··· 1761 1725 if (rc) 1762 1726 return rc; 1763 1727 1764 - if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { 1765 - rc = security_transition_sid(sid, dsec->sid, tclass, 1766 - &dentry->d_name, &newsid); 1767 - if (rc) 1768 - return rc; 1769 - } 1728 + rc = selinux_determine_inode_label(dir, &dentry->d_name, tclass, 1729 + &newsid); 1730 + if (rc) 1731 + return rc; 1770 1732 1771 1733 rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); 1772 1734 if (rc) ··· 2738 2704 struct qstr *name, void **ctx, 2739 2705 u32 *ctxlen) 2740 2706 { 2741 - const struct cred *cred = current_cred(); 2742 - struct task_security_struct *tsec; 2743 - struct inode_security_struct *dsec; 2744 - struct superblock_security_struct *sbsec; 2745 - struct inode *dir = d_backing_inode(dentry->d_parent); 2746 2707 u32 newsid; 2747 2708 int rc; 2748 2709 2749 - tsec = cred->security; 2750 - dsec = dir->i_security; 2751 - sbsec = dir->i_sb->s_security; 2752 - 2753 - if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { 2754 - newsid = tsec->create_sid; 2755 - } else { 2756 - rc = security_transition_sid(tsec->sid, dsec->sid, 2757 - inode_mode_to_security_class(mode), 2758 - name, 2759 - &newsid); 2760 - if (rc) { 2761 - printk(KERN_WARNING 2762 - "%s: security_transition_sid failed, rc=%d\n", 2763 - __func__, -rc); 2764 - return rc; 2765 - } 2766 - } 2710 + rc = selinux_determine_inode_label(d_inode(dentry->d_parent), name, 2711 + inode_mode_to_security_class(mode), 2712 + &newsid); 2713 + if (rc) 2714 + return rc; 2767 2715 2768 2716 return security_sid_to_context(newsid, (char **)ctx, ctxlen); 2769 2717 } ··· 2768 2752 sid = tsec->sid; 2769 2753 newsid = tsec->create_sid; 2770 2754 2771 - if ((sbsec->flags & SE_SBINITIALIZED) && 2772 - (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) 2773 - newsid = sbsec->mntpoint_sid; 2774 - else if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { 2775 - rc = security_transition_sid(sid, dsec->sid, 2776 - inode_mode_to_security_class(inode->i_mode), 2777 - qstr, &newsid); 2778 - if (rc) { 2779 - printk(KERN_WARNING "%s: " 2780 - "security_transition_sid failed, rc=%d (dev=%s " 2781 - "ino=%ld)\n", 2782 - __func__, 2783 - -rc, inode->i_sb->s_id, inode->i_ino); 2784 - return rc; 2785 - } 2786 - } 2755 + rc = selinux_determine_inode_label( 2756 + dir, qstr, 2757 + inode_mode_to_security_class(inode->i_mode), 2758 + &newsid); 2759 + if (rc) 2760 + return rc; 2787 2761 2788 2762 /* Possibly defer initialization to selinux_complete_init. */ 2789 2763 if (sbsec->flags & SE_SBINITIALIZED) { ··· 3234 3228 file_free_security(file); 3235 3229 } 3236 3230 3231 + /* 3232 + * Check whether a task has the ioctl permission and cmd 3233 + * operation to an inode. 3234 + */ 3235 + int ioctl_has_perm(const struct cred *cred, struct file *file, 3236 + u32 requested, u16 cmd) 3237 + { 3238 + struct common_audit_data ad; 3239 + struct file_security_struct *fsec = file->f_security; 3240 + struct inode *inode = file_inode(file); 3241 + struct inode_security_struct *isec = inode->i_security; 3242 + struct lsm_ioctlop_audit ioctl; 3243 + u32 ssid = cred_sid(cred); 3244 + int rc; 3245 + u8 driver = cmd >> 8; 3246 + u8 xperm = cmd & 0xff; 3247 + 3248 + ad.type = LSM_AUDIT_DATA_IOCTL_OP; 3249 + ad.u.op = &ioctl; 3250 + ad.u.op->cmd = cmd; 3251 + ad.u.op->path = file->f_path; 3252 + 3253 + if (ssid != fsec->sid) { 3254 + rc = avc_has_perm(ssid, fsec->sid, 3255 + SECCLASS_FD, 3256 + FD__USE, 3257 + &ad); 3258 + if (rc) 3259 + goto out; 3260 + } 3261 + 3262 + if (unlikely(IS_PRIVATE(inode))) 3263 + return 0; 3264 + 3265 + rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, 3266 + requested, driver, xperm, &ad); 3267 + out: 3268 + return rc; 3269 + } 3270 + 3237 3271 static int selinux_file_ioctl(struct file *file, unsigned int cmd, 3238 3272 unsigned long arg) 3239 3273 { ··· 3316 3270 * to the file's ioctl() function. 3317 3271 */ 3318 3272 default: 3319 - error = file_has_perm(cred, file, FILE__IOCTL); 3273 + error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); 3320 3274 } 3321 3275 return error; 3322 3276 } ··· 4566 4520 4567 4521 sksec->peer_sid = SECINITSID_UNLABELED; 4568 4522 sksec->sid = SECINITSID_UNLABELED; 4523 + sksec->sclass = SECCLASS_SOCKET; 4569 4524 selinux_netlbl_sk_security_reset(sksec); 4570 4525 sk->sk_security = sksec; 4571 4526
+6
security/selinux/include/avc.h
··· 143 143 } 144 144 145 145 #define AVC_STRICT 1 /* Ignore permissive mode. */ 146 + #define AVC_EXTENDED_PERMS 2 /* update extended permissions */ 146 147 int avc_has_perm_noaudit(u32 ssid, u32 tsid, 147 148 u16 tclass, u32 requested, 148 149 unsigned flags, ··· 157 156 struct common_audit_data *auditdata, 158 157 int flags); 159 158 159 + int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, 160 + u8 driver, u8 perm, struct common_audit_data *ad); 161 + 162 + 160 163 u32 avc_policy_seqno(void); 161 164 162 165 #define AVC_CALLBACK_GRANT 1 ··· 171 166 #define AVC_CALLBACK_AUDITALLOW_DISABLE 32 172 167 #define AVC_CALLBACK_AUDITDENY_ENABLE 64 173 168 #define AVC_CALLBACK_AUDITDENY_DISABLE 128 169 + #define AVC_CALLBACK_ADD_XPERMS 256 174 170 175 171 int avc_add_callback(int (*callback)(u32 event), u32 events); 176 172
+30 -2
security/selinux/include/security.h
··· 35 35 #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 36 36 #define POLICYDB_VERSION_DEFAULT_TYPE 28 37 37 #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 38 + #define POLICYDB_VERSION_XPERMS_IOCTL 30 38 39 39 40 /* Range of policy versions we understand*/ 40 41 #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE 41 42 #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX 42 43 #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE 43 44 #else 44 - #define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES 45 + #define POLICYDB_VERSION_MAX POLICYDB_VERSION_XPERMS_IOCTL 45 46 #endif 46 47 47 48 /* Mask for just the mount related flags */ ··· 110 109 u32 flags; 111 110 }; 112 111 112 + #define XPERMS_ALLOWED 1 113 + #define XPERMS_AUDITALLOW 2 114 + #define XPERMS_DONTAUDIT 4 115 + 116 + #define security_xperm_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f)) 117 + #define security_xperm_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f))) 118 + struct extended_perms_data { 119 + u32 p[8]; 120 + }; 121 + 122 + struct extended_perms_decision { 123 + u8 used; 124 + u8 driver; 125 + struct extended_perms_data *allowed; 126 + struct extended_perms_data *auditallow; 127 + struct extended_perms_data *dontaudit; 128 + }; 129 + 130 + struct extended_perms { 131 + u16 len; /* length associated decision chain */ 132 + struct extended_perms_data drivers; /* flag drivers that are used */ 133 + }; 134 + 113 135 /* definitions of av_decision.flags */ 114 136 #define AVD_FLAGS_PERMISSIVE 0x0001 115 137 116 138 void security_compute_av(u32 ssid, u32 tsid, 117 - u16 tclass, struct av_decision *avd); 139 + u16 tclass, struct av_decision *avd, 140 + struct extended_perms *xperms); 141 + 142 + void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, 143 + u8 driver, struct extended_perms_decision *xpermd); 118 144 119 145 void security_compute_av_user(u32 ssid, u32 tsid, 120 146 u16 tclass, struct av_decision *avd);
+90 -14
security/selinux/ss/avtab.c
··· 24 24 #include "policydb.h" 25 25 26 26 static struct kmem_cache *avtab_node_cachep; 27 + static struct kmem_cache *avtab_xperms_cachep; 27 28 28 29 /* Based on MurmurHash3, written by Austin Appleby and placed in the 29 30 * public domain. ··· 71 70 struct avtab_key *key, struct avtab_datum *datum) 72 71 { 73 72 struct avtab_node *newnode; 73 + struct avtab_extended_perms *xperms; 74 74 newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); 75 75 if (newnode == NULL) 76 76 return NULL; 77 77 newnode->key = *key; 78 - newnode->datum = *datum; 78 + 79 + if (key->specified & AVTAB_XPERMS) { 80 + xperms = kmem_cache_zalloc(avtab_xperms_cachep, GFP_KERNEL); 81 + if (xperms == NULL) { 82 + kmem_cache_free(avtab_node_cachep, newnode); 83 + return NULL; 84 + } 85 + *xperms = *(datum->u.xperms); 86 + newnode->datum.u.xperms = xperms; 87 + } else { 88 + newnode->datum.u.data = datum->u.data; 89 + } 90 + 79 91 if (prev) { 80 92 newnode->next = prev->next; 81 93 prev->next = newnode; ··· 121 107 if (key->source_type == cur->key.source_type && 122 108 key->target_type == cur->key.target_type && 123 109 key->target_class == cur->key.target_class && 124 - (specified & cur->key.specified)) 110 + (specified & cur->key.specified)) { 111 + /* extended perms may not be unique */ 112 + if (specified & AVTAB_XPERMS) 113 + break; 125 114 return -EEXIST; 115 + } 126 116 if (key->source_type < cur->key.source_type) 127 117 break; 128 118 if (key->source_type == cur->key.source_type && ··· 289 271 while (cur) { 290 272 temp = cur; 291 273 cur = cur->next; 274 + if (temp->key.specified & AVTAB_XPERMS) 275 + kmem_cache_free(avtab_xperms_cachep, 276 + temp->datum.u.xperms); 292 277 kmem_cache_free(avtab_node_cachep, temp); 293 278 } 294 279 } ··· 380 359 AVTAB_AUDITALLOW, 381 360 AVTAB_TRANSITION, 382 361 AVTAB_CHANGE, 383 - AVTAB_MEMBER 362 + AVTAB_MEMBER, 363 + AVTAB_XPERMS_ALLOWED, 364 + AVTAB_XPERMS_AUDITALLOW, 365 + AVTAB_XPERMS_DONTAUDIT 384 366 }; 385 367 386 368 int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, ··· 393 369 { 394 370 __le16 buf16[4]; 395 371 u16 enabled; 396 - __le32 buf32[7]; 397 372 u32 items, items2, val, vers = pol->policyvers; 398 373 struct avtab_key key; 399 374 struct avtab_datum datum; 375 + struct avtab_extended_perms xperms; 376 + __le32 buf32[ARRAY_SIZE(xperms.perms.p)]; 400 377 int i, rc; 401 378 unsigned set; 402 379 ··· 454 429 printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); 455 430 return -EINVAL; 456 431 } 432 + if (val & AVTAB_XPERMS) { 433 + printk(KERN_ERR "SELinux: avtab: entry has extended permissions\n"); 434 + return -EINVAL; 435 + } 457 436 458 437 for (i = 0; i < ARRAY_SIZE(spec_order); i++) { 459 438 if (val & spec_order[i]) { 460 439 key.specified = spec_order[i] | enabled; 461 - datum.data = le32_to_cpu(buf32[items++]); 440 + datum.u.data = le32_to_cpu(buf32[items++]); 462 441 rc = insertf(a, &key, &datum, p); 463 442 if (rc) 464 443 return rc; ··· 505 476 return -EINVAL; 506 477 } 507 478 508 - rc = next_entry(buf32, fp, sizeof(u32)); 509 - if (rc) { 510 - printk(KERN_ERR "SELinux: avtab: truncated entry\n"); 511 - return rc; 479 + if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) && 480 + (key.specified & AVTAB_XPERMS)) { 481 + printk(KERN_ERR "SELinux: avtab: policy version %u does not " 482 + "support extended permissions rules and one " 483 + "was specified\n", vers); 484 + return -EINVAL; 485 + } else if (key.specified & AVTAB_XPERMS) { 486 + memset(&xperms, 0, sizeof(struct avtab_extended_perms)); 487 + rc = next_entry(&xperms.specified, fp, sizeof(u8)); 488 + if (rc) { 489 + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); 490 + return rc; 491 + } 492 + rc = next_entry(&xperms.driver, fp, sizeof(u8)); 493 + if (rc) { 494 + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); 495 + return rc; 496 + } 497 + rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p)); 498 + if (rc) { 499 + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); 500 + return rc; 501 + } 502 + for (i = 0; i < ARRAY_SIZE(xperms.perms.p); i++) 503 + xperms.perms.p[i] = le32_to_cpu(buf32[i]); 504 + datum.u.xperms = &xperms; 505 + } else { 506 + rc = next_entry(buf32, fp, sizeof(u32)); 507 + if (rc) { 508 + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); 509 + return rc; 510 + } 511 + datum.u.data = le32_to_cpu(*buf32); 512 512 } 513 - datum.data = le32_to_cpu(*buf32); 514 513 if ((key.specified & AVTAB_TYPE) && 515 - !policydb_type_isvalid(pol, datum.data)) { 514 + !policydb_type_isvalid(pol, datum.u.data)) { 516 515 printk(KERN_ERR "SELinux: avtab: invalid type\n"); 517 516 return -EINVAL; 518 517 } ··· 600 543 int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) 601 544 { 602 545 __le16 buf16[4]; 603 - __le32 buf32[1]; 546 + __le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)]; 604 547 int rc; 548 + unsigned int i; 605 549 606 550 buf16[0] = cpu_to_le16(cur->key.source_type); 607 551 buf16[1] = cpu_to_le16(cur->key.target_type); ··· 611 553 rc = put_entry(buf16, sizeof(u16), 4, fp); 612 554 if (rc) 613 555 return rc; 614 - buf32[0] = cpu_to_le32(cur->datum.data); 615 - rc = put_entry(buf32, sizeof(u32), 1, fp); 556 + 557 + if (cur->key.specified & AVTAB_XPERMS) { 558 + rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp); 559 + if (rc) 560 + return rc; 561 + rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp); 562 + if (rc) 563 + return rc; 564 + for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++) 565 + buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]); 566 + rc = put_entry(buf32, sizeof(u32), 567 + ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp); 568 + } else { 569 + buf32[0] = cpu_to_le32(cur->datum.u.data); 570 + rc = put_entry(buf32, sizeof(u32), 1, fp); 571 + } 616 572 if (rc) 617 573 return rc; 618 574 return 0; ··· 660 588 avtab_node_cachep = kmem_cache_create("avtab_node", 661 589 sizeof(struct avtab_node), 662 590 0, SLAB_PANIC, NULL); 591 + avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms", 592 + sizeof(struct avtab_extended_perms), 593 + 0, SLAB_PANIC, NULL); 663 594 } 664 595 665 596 void avtab_cache_destroy(void) 666 597 { 667 598 kmem_cache_destroy(avtab_node_cachep); 599 + kmem_cache_destroy(avtab_xperms_cachep); 668 600 }
+32 -1
security/selinux/ss/avtab.h
··· 23 23 #ifndef _SS_AVTAB_H_ 24 24 #define _SS_AVTAB_H_ 25 25 26 + #include "security.h" 26 27 #include <linux/flex_array.h> 27 28 28 29 struct avtab_key { ··· 38 37 #define AVTAB_MEMBER 0x0020 39 38 #define AVTAB_CHANGE 0x0040 40 39 #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) 40 + /* extended permissions */ 41 + #define AVTAB_XPERMS_ALLOWED 0x0100 42 + #define AVTAB_XPERMS_AUDITALLOW 0x0200 43 + #define AVTAB_XPERMS_DONTAUDIT 0x0400 44 + #define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | \ 45 + AVTAB_XPERMS_AUDITALLOW | \ 46 + AVTAB_XPERMS_DONTAUDIT) 41 47 #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ 42 48 #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ 43 49 u16 specified; /* what field is specified */ 44 50 }; 45 51 52 + /* 53 + * For operations that require more than the 32 permissions provided by the avc 54 + * extended permissions may be used to provide 256 bits of permissions. 55 + */ 56 + struct avtab_extended_perms { 57 + /* These are not flags. All 256 values may be used */ 58 + #define AVTAB_XPERMS_IOCTLFUNCTION 0x01 59 + #define AVTAB_XPERMS_IOCTLDRIVER 0x02 60 + /* extension of the avtab_key specified */ 61 + u8 specified; /* ioctl, netfilter, ... */ 62 + /* 63 + * if 256 bits is not adequate as is often the case with ioctls, then 64 + * multiple extended perms may be used and the driver field 65 + * specifies which permissions are included. 66 + */ 67 + u8 driver; 68 + /* 256 bits of permissions */ 69 + struct extended_perms_data perms; 70 + }; 71 + 46 72 struct avtab_datum { 47 - u32 data; /* access vector or type value */ 73 + union { 74 + u32 data; /* access vector or type value */ 75 + struct avtab_extended_perms *xperms; 76 + } u; 48 77 }; 49 78 50 79 struct avtab_node {
+30 -8
security/selinux/ss/conditional.c
··· 15 15 16 16 #include "security.h" 17 17 #include "conditional.h" 18 + #include "services.h" 18 19 19 20 /* 20 21 * cond_evaluate_expr evaluates a conditional expr ··· 613 612 614 613 return 0; 615 614 } 616 - /* Determine whether additional permissions are granted by the conditional 617 - * av table, and if so, add them to the result 618 - */ 619 - void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd) 615 + 616 + void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, 617 + struct extended_perms_decision *xpermd) 620 618 { 621 619 struct avtab_node *node; 622 620 623 - if (!ctab || !key || !avd) 621 + if (!ctab || !key || !xpermd) 622 + return; 623 + 624 + for (node = avtab_search_node(ctab, key); node; 625 + node = avtab_search_node_next(node, key->specified)) { 626 + if (node->key.specified & AVTAB_ENABLED) 627 + services_compute_xperms_decision(xpermd, node); 628 + } 629 + return; 630 + 631 + } 632 + /* Determine whether additional permissions are granted by the conditional 633 + * av table, and if so, add them to the result 634 + */ 635 + void cond_compute_av(struct avtab *ctab, struct avtab_key *key, 636 + struct av_decision *avd, struct extended_perms *xperms) 637 + { 638 + struct avtab_node *node; 639 + 640 + if (!ctab || !key || !avd || !xperms) 624 641 return; 625 642 626 643 for (node = avtab_search_node(ctab, key); node; 627 644 node = avtab_search_node_next(node, key->specified)) { 628 645 if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == 629 646 (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) 630 - avd->allowed |= node->datum.data; 647 + avd->allowed |= node->datum.u.data; 631 648 if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == 632 649 (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) 633 650 /* Since a '0' in an auditdeny mask represents a ··· 653 634 * the '&' operand to ensure that all '0's in the mask 654 635 * are retained (much unlike the allow and auditallow cases). 655 636 */ 656 - avd->auditdeny &= node->datum.data; 637 + avd->auditdeny &= node->datum.u.data; 657 638 if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == 658 639 (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) 659 - avd->auditallow |= node->datum.data; 640 + avd->auditallow |= node->datum.u.data; 641 + if ((node->key.specified & AVTAB_ENABLED) && 642 + (node->key.specified & AVTAB_XPERMS)) 643 + services_compute_xperms_drivers(xperms, node); 660 644 } 661 645 return; 662 646 }
+4 -2
security/selinux/ss/conditional.h
··· 73 73 int cond_write_bool(void *key, void *datum, void *ptr); 74 74 int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); 75 75 76 - void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); 77 - 76 + void cond_compute_av(struct avtab *ctab, struct avtab_key *key, 77 + struct av_decision *avd, struct extended_perms *xperms); 78 + void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, 79 + struct extended_perms_decision *xpermd); 78 80 int evaluate_cond_node(struct policydb *p, struct cond_node *node); 79 81 80 82 #endif /* _CONDITIONAL_H_ */
+5
security/selinux/ss/policydb.c
··· 148 148 .sym_num = SYM_NUM, 149 149 .ocon_num = OCON_NUM, 150 150 }, 151 + { 152 + .version = POLICYDB_VERSION_XPERMS_IOCTL, 153 + .sym_num = SYM_NUM, 154 + .ocon_num = OCON_NUM, 155 + }, 151 156 }; 152 157 153 158 static struct policydb_compat_info *policydb_lookup_compat(int version)
+193 -20
security/selinux/ss/services.c
··· 93 93 u32 *scontext_len); 94 94 95 95 static void context_struct_compute_av(struct context *scontext, 96 - struct context *tcontext, 97 - u16 tclass, 98 - struct av_decision *avd); 96 + struct context *tcontext, 97 + u16 tclass, 98 + struct av_decision *avd, 99 + struct extended_perms *xperms); 99 100 100 101 struct selinux_mapping { 101 102 u16 value; /* policy value */ ··· 566 565 context_struct_compute_av(&lo_scontext, 567 566 tcontext, 568 567 tclass, 569 - &lo_avd); 568 + &lo_avd, 569 + NULL); 570 570 if ((lo_avd.allowed & avd->allowed) == avd->allowed) 571 571 return; /* no masked permission */ 572 572 masked = ~lo_avd.allowed & avd->allowed; ··· 582 580 context_struct_compute_av(scontext, 583 581 &lo_tcontext, 584 582 tclass, 585 - &lo_avd); 583 + &lo_avd, 584 + NULL); 586 585 if ((lo_avd.allowed & avd->allowed) == avd->allowed) 587 586 return; /* no masked permission */ 588 587 masked = ~lo_avd.allowed & avd->allowed; ··· 599 596 context_struct_compute_av(&lo_scontext, 600 597 &lo_tcontext, 601 598 tclass, 602 - &lo_avd); 599 + &lo_avd, 600 + NULL); 603 601 if ((lo_avd.allowed & avd->allowed) == avd->allowed) 604 602 return; /* no masked permission */ 605 603 masked = ~lo_avd.allowed & avd->allowed; ··· 617 613 } 618 614 619 615 /* 620 - * Compute access vectors based on a context structure pair for 621 - * the permissions in a particular class. 616 + * flag which drivers have permissions 617 + * only looking for ioctl based extended permssions 618 + */ 619 + void services_compute_xperms_drivers( 620 + struct extended_perms *xperms, 621 + struct avtab_node *node) 622 + { 623 + unsigned int i; 624 + 625 + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 626 + /* if one or more driver has all permissions allowed */ 627 + for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) 628 + xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; 629 + } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 630 + /* if allowing permissions within a driver */ 631 + security_xperm_set(xperms->drivers.p, 632 + node->datum.u.xperms->driver); 633 + } 634 + 635 + /* If no ioctl commands are allowed, ignore auditallow and auditdeny */ 636 + if (node->key.specified & AVTAB_XPERMS_ALLOWED) 637 + xperms->len = 1; 638 + } 639 + 640 + /* 641 + * Compute access vectors and extended permissions based on a context 642 + * structure pair for the permissions in a particular class. 622 643 */ 623 644 static void context_struct_compute_av(struct context *scontext, 624 - struct context *tcontext, 625 - u16 tclass, 626 - struct av_decision *avd) 645 + struct context *tcontext, 646 + u16 tclass, 647 + struct av_decision *avd, 648 + struct extended_perms *xperms) 627 649 { 628 650 struct constraint_node *constraint; 629 651 struct role_allow *ra; ··· 663 633 avd->allowed = 0; 664 634 avd->auditallow = 0; 665 635 avd->auditdeny = 0xffffffff; 636 + if (xperms) { 637 + memset(&xperms->drivers, 0, sizeof(xperms->drivers)); 638 + xperms->len = 0; 639 + } 666 640 667 641 if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { 668 642 if (printk_ratelimit()) ··· 681 647 * this permission check, then use it. 682 648 */ 683 649 avkey.target_class = tclass; 684 - avkey.specified = AVTAB_AV; 650 + avkey.specified = AVTAB_AV | AVTAB_XPERMS; 685 651 sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); 686 652 BUG_ON(!sattr); 687 653 tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); ··· 694 660 node; 695 661 node = avtab_search_node_next(node, avkey.specified)) { 696 662 if (node->key.specified == AVTAB_ALLOWED) 697 - avd->allowed |= node->datum.data; 663 + avd->allowed |= node->datum.u.data; 698 664 else if (node->key.specified == AVTAB_AUDITALLOW) 699 - avd->auditallow |= node->datum.data; 665 + avd->auditallow |= node->datum.u.data; 700 666 else if (node->key.specified == AVTAB_AUDITDENY) 701 - avd->auditdeny &= node->datum.data; 667 + avd->auditdeny &= node->datum.u.data; 668 + else if (xperms && (node->key.specified & AVTAB_XPERMS)) 669 + services_compute_xperms_drivers(xperms, node); 702 670 } 703 671 704 672 /* Check conditional av table for additional permissions */ 705 - cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); 673 + cond_compute_av(&policydb.te_cond_avtab, &avkey, 674 + avd, xperms); 706 675 707 676 } 708 677 } ··· 936 899 avd->flags = 0; 937 900 } 938 901 902 + void services_compute_xperms_decision(struct extended_perms_decision *xpermd, 903 + struct avtab_node *node) 904 + { 905 + unsigned int i; 906 + 907 + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 908 + if (xpermd->driver != node->datum.u.xperms->driver) 909 + return; 910 + } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 911 + if (!security_xperm_test(node->datum.u.xperms->perms.p, 912 + xpermd->driver)) 913 + return; 914 + } else { 915 + BUG(); 916 + } 917 + 918 + if (node->key.specified == AVTAB_XPERMS_ALLOWED) { 919 + xpermd->used |= XPERMS_ALLOWED; 920 + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 921 + memset(xpermd->allowed->p, 0xff, 922 + sizeof(xpermd->allowed->p)); 923 + } 924 + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 925 + for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) 926 + xpermd->allowed->p[i] |= 927 + node->datum.u.xperms->perms.p[i]; 928 + } 929 + } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { 930 + xpermd->used |= XPERMS_AUDITALLOW; 931 + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 932 + memset(xpermd->auditallow->p, 0xff, 933 + sizeof(xpermd->auditallow->p)); 934 + } 935 + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 936 + for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) 937 + xpermd->auditallow->p[i] |= 938 + node->datum.u.xperms->perms.p[i]; 939 + } 940 + } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { 941 + xpermd->used |= XPERMS_DONTAUDIT; 942 + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 943 + memset(xpermd->dontaudit->p, 0xff, 944 + sizeof(xpermd->dontaudit->p)); 945 + } 946 + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 947 + for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) 948 + xpermd->dontaudit->p[i] |= 949 + node->datum.u.xperms->perms.p[i]; 950 + } 951 + } else { 952 + BUG(); 953 + } 954 + } 955 + 956 + void security_compute_xperms_decision(u32 ssid, 957 + u32 tsid, 958 + u16 orig_tclass, 959 + u8 driver, 960 + struct extended_perms_decision *xpermd) 961 + { 962 + u16 tclass; 963 + struct context *scontext, *tcontext; 964 + struct avtab_key avkey; 965 + struct avtab_node *node; 966 + struct ebitmap *sattr, *tattr; 967 + struct ebitmap_node *snode, *tnode; 968 + unsigned int i, j; 969 + 970 + xpermd->driver = driver; 971 + xpermd->used = 0; 972 + memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p)); 973 + memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); 974 + memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); 975 + 976 + read_lock(&policy_rwlock); 977 + if (!ss_initialized) 978 + goto allow; 979 + 980 + scontext = sidtab_search(&sidtab, ssid); 981 + if (!scontext) { 982 + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 983 + __func__, ssid); 984 + goto out; 985 + } 986 + 987 + tcontext = sidtab_search(&sidtab, tsid); 988 + if (!tcontext) { 989 + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 990 + __func__, tsid); 991 + goto out; 992 + } 993 + 994 + tclass = unmap_class(orig_tclass); 995 + if (unlikely(orig_tclass && !tclass)) { 996 + if (policydb.allow_unknown) 997 + goto allow; 998 + goto out; 999 + } 1000 + 1001 + 1002 + if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { 1003 + pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass); 1004 + goto out; 1005 + } 1006 + 1007 + avkey.target_class = tclass; 1008 + avkey.specified = AVTAB_XPERMS; 1009 + sattr = flex_array_get(policydb.type_attr_map_array, 1010 + scontext->type - 1); 1011 + BUG_ON(!sattr); 1012 + tattr = flex_array_get(policydb.type_attr_map_array, 1013 + tcontext->type - 1); 1014 + BUG_ON(!tattr); 1015 + ebitmap_for_each_positive_bit(sattr, snode, i) { 1016 + ebitmap_for_each_positive_bit(tattr, tnode, j) { 1017 + avkey.source_type = i + 1; 1018 + avkey.target_type = j + 1; 1019 + for (node = avtab_search_node(&policydb.te_avtab, &avkey); 1020 + node; 1021 + node = avtab_search_node_next(node, avkey.specified)) 1022 + services_compute_xperms_decision(xpermd, node); 1023 + 1024 + cond_compute_xperms(&policydb.te_cond_avtab, 1025 + &avkey, xpermd); 1026 + } 1027 + } 1028 + out: 1029 + read_unlock(&policy_rwlock); 1030 + return; 1031 + allow: 1032 + memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); 1033 + goto out; 1034 + } 939 1035 940 1036 /** 941 1037 * security_compute_av - Compute access vector decisions. ··· 1076 906 * @tsid: target security identifier 1077 907 * @tclass: target security class 1078 908 * @avd: access vector decisions 909 + * @xperms: extended permissions 1079 910 * 1080 911 * Compute a set of access vector decisions based on the 1081 912 * SID pair (@ssid, @tsid) for the permissions in @tclass. ··· 1084 913 void security_compute_av(u32 ssid, 1085 914 u32 tsid, 1086 915 u16 orig_tclass, 1087 - struct av_decision *avd) 916 + struct av_decision *avd, 917 + struct extended_perms *xperms) 1088 918 { 1089 919 u16 tclass; 1090 920 struct context *scontext = NULL, *tcontext = NULL; 1091 921 1092 922 read_lock(&policy_rwlock); 1093 923 avd_init(avd); 924 + xperms->len = 0; 1094 925 if (!ss_initialized) 1095 926 goto allow; 1096 927 ··· 1120 947 goto allow; 1121 948 goto out; 1122 949 } 1123 - context_struct_compute_av(scontext, tcontext, tclass, avd); 950 + context_struct_compute_av(scontext, tcontext, tclass, avd, xperms); 1124 951 map_decision(orig_tclass, avd, policydb.allow_unknown); 1125 952 out: 1126 953 read_unlock(&policy_rwlock); ··· 1166 993 goto out; 1167 994 } 1168 995 1169 - context_struct_compute_av(scontext, tcontext, tclass, avd); 996 + context_struct_compute_av(scontext, tcontext, tclass, avd, NULL); 1170 997 out: 1171 998 read_unlock(&policy_rwlock); 1172 999 return; ··· 1688 1515 1689 1516 if (avdatum) { 1690 1517 /* Use the type from the type transition/member/change rule. */ 1691 - newcontext.type = avdatum->data; 1518 + newcontext.type = avdatum->u.data; 1692 1519 } 1693 1520 1694 1521 /* if we have a objname this is a file trans check so check those rules */
+6
security/selinux/ss/services.h
··· 11 11 12 12 extern struct policydb policydb; 13 13 14 + void services_compute_xperms_drivers(struct extended_perms *xperms, 15 + struct avtab_node *node); 16 + 17 + void services_compute_xperms_decision(struct extended_perms_decision *xpermd, 18 + struct avtab_node *node); 19 + 14 20 #endif /* _SS_SERVICES_H_ */ 15 21