Commit graph

3419 commits

Author SHA1 Message Date
Christian Göttsche
8c59d614b3 libsepol: validate constraint expression operators and attributes
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:52:05 -05:00
Christian Göttsche
312eac1c18 libsepol: validate avtab and avrule types
Check for invalid avtab or avrule types.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:52:02 -05:00
Christian Göttsche
ba6d82255b libsepol: resolve log message mismatch
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:59 -05:00
Christian Göttsche
e39cf0a1f0 libsepol: validate permission count of classes
Check a common class or a class together with its common class parent
does not have more than the supported 32 permissions.

    ==28413==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f74ec3341a3 bp 0x7ffd0b7e5030 sp 0x7ffd0b7e47e8 T0)
    ==28413==The signal is caused by a READ memory access.
    ==28413==Hint: address points to the zero page.
        #0 0x7f74ec3341a3  string/../sysdeps/x86_64/multiarch/../strchr.S:32
        #1 0x4bfc78 in strchr (./out/binpolicy-fuzzer+0x4bfc78)
        #2 0x55b7f2 in class_constraint_rules_to_strs ./libsepol/src/kernel_to_conf.c:288:7
        #3 0x55b7f2 in constraint_rules_to_strs ./libsepol/src/kernel_to_conf.c:364:9
        #4 0x55ac80 in sepol_kernel_policydb_to_conf ./libsepol/src/kernel_to_conf.c:3071:7
        #5 0x55a34f in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:38:9
        #6 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #7 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #8 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #9 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #10 0x7f74ec2be7ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #11 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:57 -05:00
Christian Göttsche
fffb16093c libsepol: validate expanded user range and level
Check those contains valid values.

    ==57532==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000001178 at pc 0x000000564c04 bp 0x7ffed7a5ad90 sp 0x7ffed7a5ad88
    READ of size 8 at 0x603000001178 thread T0
        #0 0x564c03 in level_to_str ./libsepol/src/kernel_to_conf.c:1901:19
        #1 0x564c03 in range_to_str ./libsepol/src/kernel_to_conf.c:1926:9
        #2 0x564c03 in write_user_decl_rules_to_conf ./libsepol/src/kernel_to_conf.c:2367:12
        #3 0x55b137 in sepol_kernel_policydb_to_conf ./libsepol/src/kernel_to_conf.c:3184:7
        #4 0x55a34f in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:38:9
        #5 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #6 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #7 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #8 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #9 0x7f2c2e1a77ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #10 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:54 -05:00
Christian Göttsche
8fdb3eb272 libsepol: validate MLS levels
Validate the level map of the policy to ensure no level refers to a non
existent category.

READ of size 8 at 0x602000000c58 thread T0
    #0 0x568d2c in cats_ebitmap_len ./libsepol/src/kernel_to_conf.c:1003:14
    #1 0x568d2c in cats_ebitmap_to_str ./libsepol/src/kernel_to_conf.c:1038:19
    #2 0x55e371 in write_level_rules_to_conf ./libsepol/src/kernel_to_conf.c:1106:11
    #3 0x55e371 in write_mls_rules_to_conf ./libsepol/src/kernel_to_conf.c:1140:7
    #4 0x55adb1 in sepol_kernel_policydb_to_conf ./libsepol/src/kernel_to_conf.c:3103:7
    #5 0x55a34f in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:38:9
    #6 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
    #7 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
    #8 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
    #9 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
    #10 0x7f741d0d67ec in __libc_start_main csu/../csu/libc-start.c:332:16
    #11 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:52 -05:00
Christian Göttsche
e2e60d9b96 libsepol: split validation of datum array gaps and entries
Split the validation of array datums regarding their gaps and entries to
simplify further checking of common classes, booleans, levels and
categories.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:49 -05:00
Christian Göttsche
691e6aff4c libsepol: do not create a string list with initial size zero
Currently is it implementation defined, due to the size being passed to
calloc(3), whether the operations fails nor not.
Also strs_add() does not handle a size of zero, cause it just multiplies
the size by two.

Use a default size of 1 if 0 is passed and swap the calloc arguments for
consistency.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:47 -05:00
Christian Göttsche
35ef9b95e7 libsepol: use correct size for initial string list
Use the number of categories not levels, which might be zero, for the
string list initial size of categories.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:45 -05:00
Christian Göttsche
731540202a libsepol: do not crash on user gaps
Handle gaps in the user table while printing a policy configuration.

    ==24424==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x0000004bdc55 bp 0x7ffc8790b810 sp 0x7ffc8790afb0 T0)
    ==24424==The signal is caused by a READ memory access.
    ==24424==Hint: address points to the zero page.
        #0 0x4bdc55 in __interceptor_strcmp (./out/binpolicy-fuzzer+0x4bdc55)
        #1 0x5ebdf6 in strs_cmp ./libsepol/src/kernel_to_common.c:253:9
        #2 0x505669 in __interceptor_qsort (./out/binpolicy-fuzzer+0x505669)
        #3 0x5ebd84 in strs_sort ./libsepol/src/kernel_to_common.c:261:2
        #4 0x564550 in write_user_decl_rules_to_conf ./libsepol/src/kernel_to_conf.c:2333:2
        #5 0x55b137 in sepol_kernel_policydb_to_conf ./libsepol/src/kernel_to_conf.c:3190:7
        #6 0x55a34f in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:38:9
        #7 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #8 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #9 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #10 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #11 0x7f530128d7ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #12 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:42 -05:00
Christian Göttsche
b76eda527f libsepol: do not crash on class gaps
Handle gaps in the class table while printing a policy configuration.

    ==21763==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000028 (pc 0x00000055b696 bp 0x7ffe69e8ab50 sp 0x7ffe69e8aa60 T0)
    ==21763==The signal is caused by a READ memory access.
    ==21763==Hint: address points to the zero page.
        #0 0x55b696 in constraint_rules_to_strs ./libsepol/src/kernel_to_conf.c:361:14
        #1 0x55ac80 in sepol_kernel_policydb_to_conf ./libsepol/src/kernel_to_conf.c:3063:7
        #2 0x55a34f in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:38:9
        #3 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #4 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #5 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #6 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #7 0x7fc60d39e7ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #8 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:36 -05:00
Christian Göttsche
c12b7d907a libsepol: do not underflow on short format arguments
Handle format arguments that do not have a size of at least 2.

    kernel_to_common.c:69:20: runtime error: unsigned integer overflow: 1 - 2 cannot be represented in type 'unsigned long'
        #0 0x557b0b in create_str_helper ./libsepol/src/kernel_to_common.c:69:20
        #1 0x5577b8 in create_str ./libsepol/src/kernel_to_common.c:99:8
        #2 0x56448c in cond_expr_to_str ./libsepol/src/kernel_to_conf.c:82:15
        #3 0x56448c in write_cond_nodes_to_conf ./libsepol/src/kernel_to_conf.c:2103:10
        #4 0x55bd9b in sepol_kernel_policydb_to_conf ./libsepol/src/kernel_to_conf.c:3171:7
        #5 0x4f9d79 in main ./checkpolicy/checkpolicy.c:684:11
        #6 0x7fe2a342b7ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #7 0x41f3a9 in _start (./checkpolicy/checkpolicy+0x41f3a9)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:33 -05:00
Christian Göttsche
47c3d96e56 libsepol: use size_t for indexes in strs helpers
Use size_t, as the strs struct uses it for its size member.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:30 -05:00
Christian Göttsche
8565e2c5c8 libsepol: zero member before potential dereference
The `next` member might be checked against NULL and dereferenced before
it gets assigned, due to jumps from failure gotos to the cleanup
section.

    ==31017==ERROR: AddressSanitizer: SEGV on unknown address (pc 0x000000579654 bp 0x7ffd3a07d110 sp 0x7ffd3a07d000 T0)
    ==31017==The signal is caused by a READ memory access.
    ==31017==Hint: this fault was caused by a dereference of a high value address (see register values below).  Disassemble the provided pc to learn which register was used.
        #0 0x579654 in filename_trans_read_one ./libsepol/src/policydb.c:2874:55
        #1 0x579654 in filename_trans_read ./libsepol/src/policydb.c:2902:9
        #2 0x5771b7 in policydb_read ./libsepol/src/policydb.c:4509:7
        #3 0x55a1f5 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:24:6
        #4 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #5 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #6 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #7 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #8 0x7f2a4e7f97ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #9 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:27 -05:00
Christian Göttsche
1b4979c528 libsepol: reject invalid filetrans source type
Avoid integer underflow on invalid filetrans source types.

    policydb.c:2658:47: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'unsigned int'
        #0 0x4cf4cb in policydb_filetrans_insert ./libsepol/src/policydb.c:2658:47
        #1 0x4d221a in filename_trans_read_one_compat ./libsepol/src/policydb.c:2691:7
        #2 0x4d221a in filename_trans_read ./libsepol/src/policydb.c:2842:9
        #3 0x4d1370 in policydb_read ./libsepol/src/policydb.c:4447:7
        #4 0x4b1ee3 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:35:6
        #5 0x43f2f3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #6 0x42ae32 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #7 0x430d5b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #8 0x45a1f2 in main (./out/binpolicy-fuzzer+0x45a1f2)
        #9 0x7f8b8923a7ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #10 0x407aa9 in _start (./out/binpolicy-fuzzer+0x407aa9)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:24 -05:00
Christian Göttsche
8750fb68e6 libsepol: reject abnormal huge sid ids
Check if the sid value is saturated to guard dependent allocations.

    ==19967== ERROR: libFuzzer: out-of-memory (malloc(7784628224))
        #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
        #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
        #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
        #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
        #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
        #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
        #6 0x4aabe3 in __asan::Allocator::Reallocate(void*, unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aabe3)
        #7 0x4aaa32 in __asan::asan_reallocarray(void*, unsigned long, unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aaa32)
        #8 0x525f8e in __interceptor_reallocarray (./out/binpolicy-fuzzer+0x525f8e)
        #9 0x5ebad3 in strs_add_at_index ./libsepol/src/kernel_to_common.c:224:9
        #10 0x5680eb in write_sids_to_conf ./libsepol/src/kernel_to_conf.c:466:8
        #11 0x55c1c0 in write_sid_decl_rules_to_conf ./libsepol/src/kernel_to_conf.c:498:8
        #12 0x55ad36 in sepol_kernel_policydb_to_conf ./libsepol/src/kernel_to_conf.c:3083:7
        #13 0x55a34f in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:38:9
        #14 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #15 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #16 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #17 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #18 0x7f085ac657ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #19 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:21 -05:00
Christian Göttsche
f571438ac0 libsepol: clean memory on conditional insertion failure
Free the local access vector list on failure as it does not get moved
into the policy structure.
Drop the now redundant, but non-exhaustive, resource cleanup in
cond_insertf().

    Direct leak of 16 byte(s) in 1 object(s) allocated from:
        #0 0x52596d in malloc (./out/binpolicy-fuzzer+0x52596d)
        #1 0x5b30d2 in cond_insertf ./libsepol/src/conditional.c:682:9
        #2 0x5ac218 in avtab_read_item ./libsepol/src/avtab.c:583:10
        #3 0x5b21f4 in cond_read_av_list ./libsepol/src/conditional.c:725:8
        #4 0x5b21f4 in cond_read_node ./libsepol/src/conditional.c:798:7
        #5 0x5b21f4 in cond_read_list ./libsepol/src/conditional.c:847:7
        #6 0x576b6e in policydb_read ./libsepol/src/policydb.c:4436:8
        #7 0x55a1fe in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:24:6
        #8 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #9 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #10 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #11 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #12 0x7f47abeb87ec in __libc_start_main csu/../csu/libc-start.c:332:16

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:19 -05:00
Christian Göttsche
2331dcaf8e libsepol: enforce avtab item limit
Check the current item count does not exceed the maximum allowed to
avoid stack overflows.

    ==33660==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fa64b8fc070 at pc 0x0000005acba0 bp 0x7ffc1f0b2870 sp 0x7ffc1f0b2868
    READ of size 4 at 0x7fa64b8fc070 thread T0
        #0 0x5acb9f in avtab_read_item ./libsepol/src/avtab.c:507:18
        #1 0x5acec4 in avtab_read ./libsepol/src/avtab.c:611:8
        #2 0x576ae3 in policydb_read ./libsepol/src/policydb.c:4433:7
        #3 0x55a1fe in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:24:6
        #4 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #5 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #6 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #7 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #8 0x7fa64cc867ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #9 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

    Address 0x7fa64b8fc070 is located in stack of thread T0 at offset 112 in frame
        #0 0x5aabdf in avtab_read_item ./libsepol/src/avtab.c:437

      This frame has 6 object(s):
        [32, 33) 'buf8' (line 438)
        [48, 56) 'buf16' (line 439)
        [80, 112) 'buf32' (line 440) <== Memory access at offset 112 overflows this variable
        [144, 152) 'key' (line 441)
        [176, 192) 'datum' (line 442)
        [208, 244) 'xperms' (line 443)
    HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
          (longjmp and C++ exceptions *are* supported)
    SUMMARY: AddressSanitizer: stack-buffer-overflow ./libsepol/src/avtab.c:507:18 in avtab_read_item
    Shadow bytes around the buggy address:
      0x0ff5497177b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ff5497177c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ff5497177d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ff5497177e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ff5497177f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    =>0x0ff549717800: f1 f1 f1 f1 01 f2 00 f2 f2 f2 00 00 00 00[f2]f2
      0x0ff549717810: f2 f2 00 f2 f2 f2 00 00 f2 f2 00 00 00 00 04 f3
      0x0ff549717820: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ff549717830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ff549717840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
      0x0ff549717850: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    Shadow byte legend (one shadow byte represents 8 application bytes):
      Addressable:           00
      Partially addressable: 01 02 03 04 05 06 07
      Heap left redzone:       fa
      Freed heap region:       fd
      Stack left redzone:      f1
      Stack mid redzone:       f2
      Stack right redzone:     f3
      Stack after return:      f5
      Stack use after scope:   f8
      Global redzone:          f9
      Global init order:       f6
      Poisoned by user:        f7
      Container overflow:      fc
      Array cookie:            ac
      Intra object redzone:    bb
      ASan internal:           fe
      Left alloca redzone:     ca
      Right alloca redzone:    cb
    ==33660==ABORTING

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:51:10 -05:00
Christian Göttsche
97af65f696 libsepol: add checks for read sizes
Add checks for invalid read sizes from a binary policy to guard
allocations.

The common and class permission counts needs to be limited more strict
otherwise a too high count of common or class permissions can lead to
permission values with a too high value, which can lead to overflows
in shift operations.

In the fuzzer build the value will also be bounded to avoid oom reports.

    ==29857== ERROR: libFuzzer: out-of-memory (malloc(17179868160))
       To change the out-of-memory limit use -rss_limit_mb=<N>

        #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
        #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
        #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
        #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
        #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
        #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
        #6 0x4aa143 in __asan::asan_malloc(unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa143)
        #7 0x5259cb in malloc (./out/binpolicy-fuzzer+0x5259cb)
        #8 0x580b5d in mallocarray ./libsepol/src/./private.h:93:9
        #9 0x57c2ed in scope_read ./libsepol/src/policydb.c:4120:7
        #10 0x576b0d in policydb_read ./libsepol/src/policydb.c:4462:9
        #11 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
        #12 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #13 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #14 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #15 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #16 0x7ffad6e107ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #17 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

    ==19462== ERROR: libFuzzer: out-of-memory (malloc(18253611008))
       To change the out-of-memory limit use -rss_limit_mb=<N>

        #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
        #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
        #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
        #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
        #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
        #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
        #6 0x4aa999 in __asan::asan_calloc(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa999)
        #7 0x525b63 in __interceptor_calloc (./out/binpolicy-fuzzer+0x525b63)
        #8 0x570938 in policydb_index_others ./libsepol/src/policydb.c:1245:6
        #9 0x5771f3 in policydb_read ./src/policydb.c:4481:6
        #10 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
        #11 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #12 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #13 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #14 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #15 0x7f4d933157ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #16 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:48:45 -05:00
Christian Göttsche
f0a5f6e330 libsepol: use reallocarray wrapper to avoid overflows
Use a wrapper to guard `realloc(p, a * b)` type allocations, to detect
multiplication overflows, which result in too few memory being
allocated.

Use a custom implementation if the used C library does not offer one.

Also use temporary variables for realloc(3) results in add_i_to_a() and
fp_to_buffer().

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:48:41 -05:00
Christian Göttsche
18303c85fb libsepol: use mallocarray wrapper to avoid overflows
Use a wrapper to guard `malloc(a * b)` type allocations, to detect
multiplication overflows, which result in too few memory being
allocated.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:48:39 -05:00
Christian Göttsche
852f14d43d libsepol: use logging framework in ebitmap.c
Use the internal logging framework instead of directly writing to
stdout as it might be undesired to do so within a library.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:48:36 -05:00
Christian Göttsche
5c178f9f55 libsepol: use logging framework in conditional.c
Use the internal logging framework instead of directly writing to
stdout as it might be undesired to do so within a library.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:48:33 -05:00
Christian Göttsche
5139433056 libsepol/fuzz: limit element sizes for fuzzing
Limit the maximum length of read sizes, like string length of module
version and name or keys and number of symtab entries.  This avoids the
fuzzer to report oom events for huge allocations (it also improves the
number of executions per seconds of the fuzzer).

This change only affects the fuzzer build.

    ==15211== ERROR: libFuzzer: out-of-memory (malloc(3115956666))
       To change the out-of-memory limit use -rss_limit_mb=<N>

        #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
        #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
        #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
        #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
        #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
        #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
        #6 0x4aa143 in __asan::asan_malloc(unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa143)
        #7 0x5259cb in malloc (./out/binpolicy-fuzzer+0x5259cb)
        #8 0x59d307 in str_read ./libsepol/src/services.c:1746:8
        #9 0x585b97 in perm_read ./libsepol/src/policydb.c:2063:5
        #10 0x581f8a in common_read ./libsepol/src/policydb.c:2119:7
        #11 0x576681 in policydb_read ./libsepol/src/policydb.c:4417:8
        #12 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
        #13 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #14 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #15 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #16 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #17 0x7fe1ec88a7ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #18 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

    ==12683== ERROR: libFuzzer: out-of-memory (malloc(2526451450))
       To change the out-of-memory limit use -rss_limit_mb=<N>

        #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
        #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
        #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
        #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
        #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
        #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
        #6 0x4aa143 in __asan::asan_malloc(unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa143)
        #7 0x5259cb in malloc (./out/binpolicy-fuzzer+0x5259cb)
        #8 0x575f8a in policydb_read ./libsepol/src/policydb.c:4356:18
        #9 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
        #10 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #11 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #12 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #13 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #14 0x7fa737b377ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #15 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:48:31 -05:00
Christian Göttsche
82438341f7 libsepol: add libfuzz based fuzzer for reading binary policies
Introduce a libfuzz[1] based fuzzer testing the parsing of a binary
policy.

Build the fuzzer in the oss-fuzz script.

[1]: https://llvm.org/docs/LibFuzzer.html

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:48:28 -05:00
Christian Göttsche
e0ba116803 libsepol/fuzz: silence secilc-fuzzer
Do not output CIL log messages while fuzzing, since their amount are
huge, e.g. for neverallow or typebounds violations.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:48:25 -05:00
Christian Göttsche
bf5ff1a8df cifuzz: use the default runtime of 600 seconds
The default runtime for CIFuzz[1] is 600 seconds; use it.

Since GitHub pull-requests are not the main contribution workflow the
number of runs should be manageable.

[1]: https://google.github.io/oss-fuzz/getting-started/continuous-integration/

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:48:23 -05:00
Christian Göttsche
01ce79182b cifuzz: enable report-unreproducible-crashes
Fail and report unreproducible fuzzing crashes and leaks. Such failures
are probably related to some global state not properly reset in the
fuzzer and can cause OSS-Fuzz to report flaky issues.

Suggested-by: Evgeny Vereshchagin
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:48:19 -05:00
Christian Göttsche
01b88ac323 checkpolicy: warn on bogus IP address or netmask in nodecon statement
Warn if the netmask is not contiguous or the address has host bits set,
e.g.:

    127.0.0.0 255.255.245.0
    127.0.0.1 255.255.255.0

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:47:22 -05:00
Christian Göttsche
413518a637 libsepol/cil: support IPv4/IPv6 address embedding
Accept IPv4 addresses embedded in IPv6, like `::ffff:127.0.0.1`.
This allows using those in nodecon statements leading to fine grained
access control:

    type=AVC msg=audit(11/29/21 20:27:44.437:419) : avc:  granted  { node_bind } for  pid=27500 comm=intercept saddr=::ffff:127.0.0.1 src=46293 scontext=xuser_u:xuser_r:xuser_t:s0 tcontext=system_u:object_r:lo_node_t:s0 tclass=tcp_socket

This does effect policies in the traditional language due to CIL usage
in semodule(8).

Also print on conversion failures the address in question.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-15 12:47:17 -05:00
Christian Göttsche
4ffe2dfc78 Replace PCRE with PCRE2 build dependencies
Now that libselinux defaults to PCRE2 and mcstrans has been ported,
update all documentation and scripts.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-09 11:07:10 -05:00
Christian Göttsche
e0da140d82 libselinux: use PCRE2 by default
Quoting pcre.org:

    There are two major versions of the PCRE library. The current
    version, PCRE2, released in 2015, is now at version 10.39.

    The older, but still widely deployed PCRE library, originally
    released in 1997, is at version 8.45. This version of PCRE is now at
    end of life, and is no longer being actively maintained. Version
    8.45 is expected to be the final release of the older PCRE library,
    and new projects should use PCRE2 instead.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
2021-12-09 11:07:00 -05:00
Christian Göttsche
647909cb90 mcstrans: port to new PCRE2 from end-of-life PCRE
Quoting pcre.org:

    There are two major versions of the PCRE library. The current
    version, PCRE2, released in 2015, is now at version 10.39.

    The older, but still widely deployed PCRE library, originally
    released in 1997, is at version 8.45. This version of PCRE is now at
    end of life, and is no longer being actively maintained. Version
    8.45 is expected to be the final release of the older PCRE library,
    and new projects should use PCRE2 instead.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>

Acked-by: Petr Lautrbach <plautrba@redhat.com>
2021-12-09 11:06:41 -05:00
James Carter
a46ade3f8f libsepol: Write out genfscon file type when writing out CIL policy
With an optional file type being added to CIL genfscon rules, it
should be used when writing out a kernel policy or module to CIL
when a genfscon rule should only apply to a single security class.

Signed-off-by: James Carter <jwcart2@gmail.com>
2021-12-09 10:46:30 -05:00
James Carter
03b1dcac2d secilc/docs: Document the optional file type for genfscon rules
Update the CIL documentation to include the optional file type for
genfscon rules.

Signed-off-by: James Carter <jwcart2@gmail.com>
2021-12-09 10:46:26 -05:00
James Carter
3677af8f27 libsepol/cil: Allow optional file type in genfscon rules
The optional specification of a file type for a genfscon rule to
make it apply only to a specific security class is allowed by
checkpolicy and checkmodule and should be allowed for CIL policies
as well.

Allow an optional file type to be specified for a genfscon rule.
The new syntax:
  (genfscon FSNAME PATH [FILE_TYPE] CONTEXT)

  FSNAME    - The name of the supported filesystem
  PATH      - If FSNAME is proc then this is the partial path,
              othewise this must be "/".
  FILE_TYPE - A single keyword representing the file type.
              file type  security class
                any        Same as not specifying a file type
                file       file
                dir        dir
                char       chr_file
                block      blk_file
                socket     sock_file
                pipe       fifo_file
                symlink    lnk_file
  CONTEXT    - Either a previously declared security context identifier
               or an anonymous security context.

Signed-off-by: James Carter <jwcart2@gmail.com>
2021-12-09 10:46:23 -05:00
James Carter
c9ed552129 libsepol/cil: Refactor filecon file type handling
Prepare for the addition of an optional file type in genfscon rules
by refactoring filecon file type handling.

Make the "any" file type be the first value in enum cil_filecon_types
because it will be the most common file type.

Signed-off-by: James Carter <jwcart2@gmail.com>
2021-12-09 10:46:20 -05:00
James Carter
55e674894b libsepol: Add support for file types in writing out policy.conf
Although rarely used, genfscon rules support the specification of a
file type just like the rules in a file context file. The file type
is used to make the genfscon rule apply only for a specific security
class. Currently, when writing out a policy.conf file from a kernel
policy, it is assumed that every genfscon rule applies to all security
classes and no file type will be added to the genfscon rule.

Write out the appropriate file type if the genfscon rule is only for
a specific security class (file, dir, blk_file, chr_file, fifo_file,
lnk_file, or sock_file).

Signed-off-by: James Carter <jwcart2@gmail.com>
2021-12-09 10:46:17 -05:00
Cutright Jacob
1cbce56115 Modified Russian and English man pages to fix typo; REQUIREUSERS -> REQUIRESEUSERS
Signed-off-by: Jacob M Cutright <cutrightjm@stl.sh>
Acked-by: Petr Lautrbach <plautrba@redhat.com>
2021-11-29 18:51:19 +01:00
Petr Lautrbach
4bafb8eb7a libselinux: Fix selinux_restorecon_parallel symbol version
selinux_restorecon_parallel was originally proposed before 3.3, but it
was merged after release so it will be introduced in version 3.4.

Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
Acked-by: Ondrej Mosnacek <omosnace@redhat.com>
2021-11-29 18:50:52 +01:00
Petr Lautrbach
c28763c4c9 semodule: Don't forget to munmap() data
semanage_module_extract() mmap()'s the module raw data but it leaves on
the caller to munmap() them.

Reported-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
Acked-by: James Carter <jwcart2@gmail.com>
2021-11-29 18:50:01 +01:00
Petr Lautrbach
f37b3e94d3 semodule: Fix lang_ext column index
lang_ext is 3. column - index number 2.

Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
Acked-by: James Carter <jwcart2@gmail.com>
2021-11-23 10:42:15 +01:00
Petr Lautrbach
ed4813be61 semodule: add -m | --checksum option
Since cil doesn't store module name and module version in module itself,
there's no simple way how to compare that installed module is the same
version as the module which is supposed to be installed. Even though the
version was not used by semodule itself, it was apparently used by some
team.

With `semodule -l --checksum` users get SHA256 hashes of modules and
could compare them with their files which is faster than installing
modules again and again.

E.g.

    # time (
    semodule -l --checksum | grep localmodule
    /usr/libexec/selinux/hll/pp localmodule.pp | sha256sum
    )
    localmodule db002f64ddfa3983257b42b54da7b182c9b2e476f47880ae3494f9099e1a42bd
    db002f64ddfa3983257b42b54da7b182c9b2e476f47880ae3494f9099e1a42bd  -

    real    0m0.876s
    user    0m0.849s
    sys     0m0.028s

vs

    # time semodule -i localmodule.pp

    real    0m6.147s
    user    0m5.800s
    sys     0m0.231s

Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
Acked-by: James Carter <jwcart2@gmail.com>
2021-11-23 10:42:05 +01:00
Ondrej Mosnacek
93902fc834 setfiles/restorecon: support parallel relabeling
Use the newly introduced selinux_restorecon_parallel(3) in
setfiles/restorecon and a -T option to both to allow enabling parallel
relabeling. The default behavior without specifying the -T option is to
use 1 thread; parallel relabeling must be requested explicitly by
passing -T 0 (which will use as many threads as there are available CPU
cores) or -T <N>, which will use <N> threads.

=== Benchmarks ===
As measured on a 32-core cloud VM with Fedora 34. Not a fully
representative environment, but still the scaling is quite good.

WITHOUT PATCHES:
$ time restorecon -rn /usr

real    0m21.689s
user    0m21.070s
sys     0m0.494s

WITH PATCHES:
$ time restorecon -rn /usr

real    0m23.940s
user    0m23.127s
sys     0m0.653s
$ time restorecon -rn -T 2 /usr

real    0m13.145s
user    0m25.306s
sys     0m0.695s
$ time restorecon -rn -T 4 /usr

real    0m7.559s
user    0m28.470s
sys     0m1.099s
$ time restorecon -rn -T 8 /usr

real    0m5.186s
user    0m37.450s
sys     0m2.094s
$ time restorecon -rn -T 16 /usr

real    0m3.831s
user    0m51.220s
sys     0m4.895s
$ time restorecon -rn -T 32 /usr

real    0m2.650s
user    1m5.136s
sys     0m6.614s

Note that the benchmarks were performed in read-only mode (-n), so the
labels were only read and looked up in the database, not written. When
fixing labels on a heavily mislabeled system, the scaling would likely
be event better, since a larger % of work could be done in parallel.

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
2021-11-23 10:03:18 +01:00
Ondrej Mosnacek
02f302fc5b selinux_restorecon: introduce selinux_restorecon_parallel(3)
Refactor selinux_restorecon(3) to allow for distributing the relabeling
to multiple threads and add a new function
selinux_restorecon_parallel(3), which allows specifying the number of
threads to use. The existing selinux_restorecon(3) function maintains
the same interface and maintains the same behavior (i.e. relabeling is
done on a single thread).

The parallel implementation takes a simple approach of performing all
the directory tree traversal in a critical section and only letting the
relabeling of individual objects run in parallel. Thankfully, this
approach turns out to be efficient enough in practice, as shown by
restorecon benchmarks (detailed in a subsequent patch that switches
setfiles & restorecon to use selinux_restorecon_parallel(3)).

Note that to be able to use the parallelism, the calling application/
library must be explicitly linked to the libpthread library (statically
or dynamically). This is necessary to mantain the requirement that
libselinux shouldn't explicitly link with libpthread. (I don't know what
exactly was the reason behind this requirement as the commit logs are
fuzzy, but special care has been taken in the past to maintain it, so I
didn't want to break it...)

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
2021-11-23 10:03:18 +01:00
Ondrej Mosnacek
a578d1cecd selinux_restorecon: add a global mutex to synchronize progress output
Another small incremental change to pave the way for a parallel
selinux_restorecon() function.

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
2021-11-23 10:03:17 +01:00
Ondrej Mosnacek
78bdce9c2a libselinux: make is_context_customizable() thread-safe
Use the __selinux_once() macro to ensure that threads don't race to
initialize the list of customizable types.

Reported-by: Christian Göttsche <cgzones@googlemail.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Tested-by: Christian Göttsche <cgzones@googlemail.com>
2021-11-23 10:03:16 +01:00
Ondrej Mosnacek
a3516ec647 libselinux: make selinux_log() thread-safe
Ensure that selinux_log() is thread-safe by guarding the call to the
underlying callback with a mutex.

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
2021-11-23 10:03:16 +01:00
Ondrej Mosnacek
46427054f8 selinux_restorecon: protect file_spec list with a mutex
Not very useful on its own, but will allow to implement a parallel
version of selinux_restorecon() in subsequent patches.

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
2021-11-23 10:03:15 +01:00
Ondrej Mosnacek
43dc50fc5c selinux_restorecon: simplify fl_head allocation by using calloc()
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
2021-11-23 10:03:15 +01:00