aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPaul Moore <pmoore@redhat.com>2014-08-01 11:17:17 -0400
committerPaul Moore <pmoore@redhat.com>2014-08-01 11:17:17 -0400
commit4b8feff251da3d7058b5779e21b33a85c686b974 (patch)
tree600fb14c92a11abf730e9f26236d33ba5ae9c278 /net
parent41c3bd2039e0d7b3dc32313141773f20716ec524 (diff)
netlabel: fix the horribly broken catmap functions
The NetLabel secattr catmap functions, and the SELinux import/export glue routines, were broken in many horrible ways and the SELinux glue code fiddled with the NetLabel catmap structures in ways that we probably shouldn't allow. At some point this "worked", but that was likely due to a bit of dumb luck and sub-par testing (both inflicted by yours truly). This patch corrects these problems by basically gutting the code in favor of something less obtuse and restoring the NetLabel abstractions in the SELinux catmap glue code. Everything is working now, and if it decides to break itself in the future this code will be much easier to debug than the code it replaces. One noteworthy side effect of the changes is that it is no longer necessary to allocate a NetLabel catmap before calling one of the NetLabel APIs to set a bit in the catmap. NetLabel will automatically allocate the catmap nodes when needed, resulting in less allocations when the lowest bit is greater than 255 and less code in the LSMs. Cc: stable@vger.kernel.org Reported-by: Christian Evans <frodox@zoho.com> Signed-off-by: Paul Moore <pmoore@redhat.com> Tested-by: Casey Schaufler <casey@schaufler-ca.com>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/cipso_ipv4.c12
-rw-r--r--net/netlabel/netlabel_kapi.c216
2 files changed, 166 insertions, 62 deletions
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index dd433c943537..8a0c7bd6eff4 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -1335,10 +1335,6 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
1335 secattr->flags |= NETLBL_SECATTR_MLS_LVL; 1335 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1336 1336
1337 if (tag_len > 4) { 1337 if (tag_len > 4) {
1338 secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
1339 if (secattr->attr.mls.cat == NULL)
1340 return -ENOMEM;
1341
1342 ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, 1338 ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
1343 &tag[4], 1339 &tag[4],
1344 tag_len - 4, 1340 tag_len - 4,
@@ -1430,10 +1426,6 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def,
1430 secattr->flags |= NETLBL_SECATTR_MLS_LVL; 1426 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1431 1427
1432 if (tag_len > 4) { 1428 if (tag_len > 4) {
1433 secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
1434 if (secattr->attr.mls.cat == NULL)
1435 return -ENOMEM;
1436
1437 ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, 1429 ret_val = cipso_v4_map_cat_enum_ntoh(doi_def,
1438 &tag[4], 1430 &tag[4],
1439 tag_len - 4, 1431 tag_len - 4,
@@ -1524,10 +1516,6 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
1524 secattr->flags |= NETLBL_SECATTR_MLS_LVL; 1516 secattr->flags |= NETLBL_SECATTR_MLS_LVL;
1525 1517
1526 if (tag_len > 4) { 1518 if (tag_len > 4) {
1527 secattr->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
1528 if (secattr->attr.mls.cat == NULL)
1529 return -ENOMEM;
1530
1531 ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, 1519 ret_val = cipso_v4_map_cat_rng_ntoh(doi_def,
1532 &tag[4], 1520 &tag[4],
1533 tag_len - 4, 1521 tag_len - 4,
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 84e810bef39a..d9e10466b928 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -405,6 +405,63 @@ out_entry:
405 * Security Attribute Functions 405 * Security Attribute Functions
406 */ 406 */
407 407
408#define _CM_F_NONE 0x00000000
409#define _CM_F_ALLOC 0x00000001
410
411/**
412 * _netlbl_secattr_catmap_getnode - Get a individual node from a catmap
413 * @catmap: pointer to the category bitmap
414 * @offset: the requested offset
415 * @cm_flags: catmap flags, see _CM_F_*
416 * @gfp_flags: memory allocation flags
417 *
418 * Description:
419 * Iterate through the catmap looking for the node associated with @offset; if
420 * the _CM_F_ALLOC flag is set in @cm_flags and there is no associated node,
421 * one will be created and inserted into the catmap. Returns a pointer to the
422 * node on success, NULL on failure.
423 *
424 */
425static struct netlbl_lsm_secattr_catmap *_netlbl_secattr_catmap_getnode(
426 struct netlbl_lsm_secattr_catmap **catmap,
427 u32 offset,
428 unsigned int cm_flags,
429 gfp_t gfp_flags)
430{
431 struct netlbl_lsm_secattr_catmap *iter = *catmap;
432 struct netlbl_lsm_secattr_catmap *prev = NULL;
433
434 if (iter == NULL || offset < iter->startbit)
435 goto secattr_catmap_getnode_alloc;
436 while (iter && offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
437 prev = iter;
438 iter = iter->next;
439 }
440 if (iter == NULL || offset < iter->startbit)
441 goto secattr_catmap_getnode_alloc;
442
443 return iter;
444
445secattr_catmap_getnode_alloc:
446 if (!(cm_flags & _CM_F_ALLOC))
447 return NULL;
448
449 iter = netlbl_secattr_catmap_alloc(gfp_flags);
450 if (iter == NULL)
451 return NULL;
452 iter->startbit = offset & ~(NETLBL_CATMAP_SIZE - 1);
453
454 if (prev == NULL) {
455 iter->next = *catmap;
456 *catmap = iter;
457 } else {
458 iter->next = prev->next;
459 prev->next = iter;
460 }
461
462 return iter;
463}
464
408/** 465/**
409 * netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit 466 * netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit
410 * @catmap: the category bitmap 467 * @catmap: the category bitmap
@@ -521,6 +578,54 @@ int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
521} 578}
522 579
523/** 580/**
581 * netlbl_secattr_catmap_getlong - Export an unsigned long bitmap
582 * @catmap: pointer to the category bitmap
583 * @offset: pointer to the requested offset
584 * @bitmap: the exported bitmap
585 *
586 * Description:
587 * Export a bitmap with an offset greater than or equal to @offset and return
588 * it in @bitmap. The @offset must be aligned to an unsigned long and will be
589 * updated on return if different from what was requested; if the catmap is
590 * empty at the requested offset and beyond, the @offset is set to (u32)-1.
591 * Returns zero on sucess, negative values on failure.
592 *
593 */
594int netlbl_secattr_catmap_getlong(struct netlbl_lsm_secattr_catmap *catmap,
595 u32 *offset,
596 unsigned long *bitmap)
597{
598 struct netlbl_lsm_secattr_catmap *iter;
599 u32 off = *offset;
600 u32 idx;
601
602 /* only allow aligned offsets */
603 if ((off & (BITS_PER_LONG - 1)) != 0)
604 return -EINVAL;
605
606 if (off < catmap->startbit) {
607 off = catmap->startbit;
608 *offset = off;
609 }
610 iter = _netlbl_secattr_catmap_getnode(&catmap, off, _CM_F_NONE, 0);
611 if (iter == NULL) {
612 *offset = (u32)-1;
613 return 0;
614 }
615
616 if (off < iter->startbit) {
617 off = iter->startbit;
618 *offset = off;
619 } else
620 off -= iter->startbit;
621
622 idx = off / NETLBL_CATMAP_MAPSIZE;
623 *bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_SIZE);
624
625 return 0;
626}
627
628/**
524 * netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap 629 * netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap
525 * @catmap: pointer to the category bitmap 630 * @catmap: pointer to the category bitmap
526 * @bit: the bit to set 631 * @bit: the bit to set
@@ -535,32 +640,16 @@ int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap **catmap,
535 u32 bit, 640 u32 bit,
536 gfp_t flags) 641 gfp_t flags)
537{ 642{
538 struct netlbl_lsm_secattr_catmap *iter = *catmap; 643 struct netlbl_lsm_secattr_catmap *iter;
539 u32 node_bit; 644 u32 idx;
540 u32 node_idx;
541 645
542 while (iter->next != NULL && 646 iter = _netlbl_secattr_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags);
543 bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) 647 if (iter == NULL)
544 iter = iter->next; 648 return -ENOMEM;
545 if (bit < iter->startbit) {
546 iter = netlbl_secattr_catmap_alloc(flags);
547 if (iter == NULL)
548 return -ENOMEM;
549 iter->next = *catmap;
550 iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1);
551 *catmap = iter;
552 } else if (bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
553 iter->next = netlbl_secattr_catmap_alloc(flags);
554 if (iter->next == NULL)
555 return -ENOMEM;
556 iter = iter->next;
557 iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1);
558 }
559 649
560 /* gcc always rounds to zero when doing integer division */ 650 bit -= iter->startbit;
561 node_idx = (bit - iter->startbit) / NETLBL_CATMAP_MAPSIZE; 651 idx = bit / NETLBL_CATMAP_MAPSIZE;
562 node_bit = bit - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx); 652 iter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE);
563 iter->bitmap[node_idx] |= NETLBL_CATMAP_BIT << node_bit;
564 653
565 return 0; 654 return 0;
566} 655}
@@ -582,34 +671,61 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap **catmap,
582 u32 end, 671 u32 end,
583 gfp_t flags) 672 gfp_t flags)
584{ 673{
585 int ret_val = 0; 674 int rc = 0;
586 struct netlbl_lsm_secattr_catmap *iter = *catmap; 675 u32 spot = start;
587 u32 iter_max_spot; 676
588 u32 spot; 677 while (rc == 0 && spot <= end) {
589 u32 orig_spot = iter->startbit; 678 if (((spot & (BITS_PER_LONG - 1)) != 0) &&
590 679 ((end - spot) > BITS_PER_LONG)) {
591 /* XXX - This could probably be made a bit faster by combining writes 680 rc = netlbl_secattr_catmap_setlong(catmap,
592 * to the catmap instead of setting a single bit each time, but for 681 spot,
593 * right now skipping to the start of the range in the catmap should 682 (unsigned long)-1,
594 * be a nice improvement over calling the individual setbit function 683 flags);
595 * repeatedly from a loop. */ 684 spot += BITS_PER_LONG;
596 685 } else
597 while (iter->next != NULL && 686 rc = netlbl_secattr_catmap_setbit(catmap,
598 start >= (iter->startbit + NETLBL_CATMAP_SIZE)) 687 spot++,
599 iter = iter->next; 688 flags);
600 iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
601
602 for (spot = start; spot <= end && ret_val == 0; spot++) {
603 if (spot >= iter_max_spot && iter->next != NULL) {
604 iter = iter->next;
605 iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
606 }
607 ret_val = netlbl_secattr_catmap_setbit(&iter, spot, flags);
608 if (iter->startbit < orig_spot)
609 *catmap = iter;
610 } 689 }
611 690
612 return ret_val; 691 return rc;
692}
693
694/**
695 * netlbl_secattr_catmap_setlong - Import an unsigned long bitmap
696 * @catmap: pointer to the category bitmap
697 * @offset: offset to the start of the imported bitmap
698 * @bitmap: the bitmap to import
699 * @flags: memory allocation flags
700 *
701 * Description:
702 * Import the bitmap specified in @bitmap into @catmap, using the offset
703 * in @offset. The offset must be aligned to an unsigned long. Returns zero
704 * on success, negative values on failure.
705 *
706 */
707int netlbl_secattr_catmap_setlong(struct netlbl_lsm_secattr_catmap **catmap,
708 u32 offset,
709 unsigned long bitmap,
710 gfp_t flags)
711{
712 struct netlbl_lsm_secattr_catmap *iter;
713 u32 idx;
714
715 /* only allow aligned offsets */
716 if ((offset & (BITS_PER_LONG - 1)) != 0)
717 return -EINVAL;
718
719 iter = _netlbl_secattr_catmap_getnode(catmap,
720 offset, _CM_F_ALLOC, flags);
721 if (iter == NULL)
722 return -ENOMEM;
723
724 offset -= iter->startbit;
725 idx = offset / NETLBL_CATMAP_MAPSIZE;
726 iter->bitmap[idx] |= bitmap << (offset % NETLBL_CATMAP_MAPSIZE);
727
728 return 0;
613} 729}
614 730
615/* 731/*