Skip to content

Commit 4b8feff

Browse files
committed
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: [email protected] Reported-by: Christian Evans <[email protected]> Signed-off-by: Paul Moore <[email protected]> Tested-by: Casey Schaufler <[email protected]>
1 parent 41c3bd2 commit 4b8feff

File tree

5 files changed

+240
-146
lines changed

5 files changed

+240
-146
lines changed

include/net/netlabel.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,11 @@ static inline void netlbl_secattr_catmap_free(
285285
{
286286
struct netlbl_lsm_secattr_catmap *iter;
287287

288-
do {
288+
while (catmap) {
289289
iter = catmap;
290290
catmap = catmap->next;
291291
kfree(iter);
292-
} while (catmap);
292+
}
293293
}
294294

295295
/**
@@ -394,13 +394,20 @@ int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
394394
u32 offset);
395395
int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
396396
u32 offset);
397+
int netlbl_secattr_catmap_getlong(struct netlbl_lsm_secattr_catmap *catmap,
398+
u32 *offset,
399+
unsigned long *bitmap);
397400
int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap **catmap,
398401
u32 bit,
399402
gfp_t flags);
400403
int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap **catmap,
401404
u32 start,
402405
u32 end,
403406
gfp_t flags);
407+
int netlbl_secattr_catmap_setlong(struct netlbl_lsm_secattr_catmap **catmap,
408+
u32 offset,
409+
unsigned long bitmap,
410+
gfp_t flags);
404411

405412
/*
406413
* LSM protocol operations (NetLabel LSM/kernel API)
@@ -504,6 +511,13 @@ static inline int netlbl_secattr_catmap_walk_rng(
504511
{
505512
return -ENOENT;
506513
}
514+
static inline int netlbl_secattr_catmap_getlong(
515+
struct netlbl_lsm_secattr_catmap *catmap,
516+
u32 *offset,
517+
unsigned long *bitmap)
518+
{
519+
return 0;
520+
}
507521
static inline int netlbl_secattr_catmap_setbit(
508522
struct netlbl_lsm_secattr_catmap **catmap,
509523
u32 bit,
@@ -519,6 +533,14 @@ static inline int netlbl_secattr_catmap_setrng(
519533
{
520534
return 0;
521535
}
536+
static int netlbl_secattr_catmap_setlong(
537+
struct netlbl_lsm_secattr_catmap **catmap,
538+
u32 offset,
539+
unsigned long bitmap,
540+
gfp_t flags)
541+
{
542+
return 0;
543+
}
522544
static inline int netlbl_enabled(void)
523545
{
524546
return 0;

net/ipv4/cipso_ipv4.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,10 +1335,6 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
13351335
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
13361336

13371337
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-
13421338
ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
13431339
&tag[4],
13441340
tag_len - 4,
@@ -1430,10 +1426,6 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def,
14301426
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
14311427

14321428
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-
14371429
ret_val = cipso_v4_map_cat_enum_ntoh(doi_def,
14381430
&tag[4],
14391431
tag_len - 4,
@@ -1524,10 +1516,6 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
15241516
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
15251517

15261518
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-
15311519
ret_val = cipso_v4_map_cat_rng_ntoh(doi_def,
15321520
&tag[4],
15331521
tag_len - 4,

net/netlabel/netlabel_kapi.c

Lines changed: 166 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,63 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
405405
* Security Attribute Functions
406406
*/
407407

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+
*/
425+
static 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+
445+
secattr_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+
408465
/**
409466
* netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit
410467
* @catmap: the category bitmap
@@ -520,6 +577,54 @@ int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
520577
return -ENOENT;
521578
}
522579

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+
*/
594+
int 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+
523628
/**
524629
* netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap
525630
* @catmap: pointer to the category bitmap
@@ -535,32 +640,16 @@ int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap **catmap,
535640
u32 bit,
536641
gfp_t flags)
537642
{
538-
struct netlbl_lsm_secattr_catmap *iter = *catmap;
539-
u32 node_bit;
540-
u32 node_idx;
643+
struct netlbl_lsm_secattr_catmap *iter;
644+
u32 idx;
541645

542-
while (iter->next != NULL &&
543-
bit >= (iter->startbit + NETLBL_CATMAP_SIZE))
544-
iter = iter->next;
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-
}
646+
iter = _netlbl_secattr_catmap_getnode(catmap, bit, _CM_F_ALLOC, flags);
647+
if (iter == NULL)
648+
return -ENOMEM;
559649

560-
/* gcc always rounds to zero when doing integer division */
561-
node_idx = (bit - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
562-
node_bit = bit - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx);
563-
iter->bitmap[node_idx] |= NETLBL_CATMAP_BIT << node_bit;
650+
bit -= iter->startbit;
651+
idx = bit / NETLBL_CATMAP_MAPSIZE;
652+
iter->bitmap[idx] |= NETLBL_CATMAP_BIT << (bit % NETLBL_CATMAP_MAPSIZE);
564653

565654
return 0;
566655
}
@@ -582,34 +671,61 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap **catmap,
582671
u32 end,
583672
gfp_t flags)
584673
{
585-
int ret_val = 0;
586-
struct netlbl_lsm_secattr_catmap *iter = *catmap;
587-
u32 iter_max_spot;
588-
u32 spot;
589-
u32 orig_spot = iter->startbit;
590-
591-
/* XXX - This could probably be made a bit faster by combining writes
592-
* to the catmap instead of setting a single bit each time, but for
593-
* right now skipping to the start of the range in the catmap should
594-
* be a nice improvement over calling the individual setbit function
595-
* repeatedly from a loop. */
596-
597-
while (iter->next != NULL &&
598-
start >= (iter->startbit + NETLBL_CATMAP_SIZE))
599-
iter = iter->next;
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;
674+
int rc = 0;
675+
u32 spot = start;
676+
677+
while (rc == 0 && spot <= end) {
678+
if (((spot & (BITS_PER_LONG - 1)) != 0) &&
679+
((end - spot) > BITS_PER_LONG)) {
680+
rc = netlbl_secattr_catmap_setlong(catmap,
681+
spot,
682+
(unsigned long)-1,
683+
flags);
684+
spot += BITS_PER_LONG;
685+
} else
686+
rc = netlbl_secattr_catmap_setbit(catmap,
687+
spot++,
688+
flags);
610689
}
611690

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+
*/
707+
int 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;
613729
}
614730

615731
/*

0 commit comments

Comments
 (0)