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 <[email protected]>
diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
index ae3e1fe..c16c6fb 100644
--- a/libsepol/src/kernel_to_cil.c
+++ b/libsepol/src/kernel_to_cil.c
@@ -358,6 +358,7 @@
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->constraints) {
name = pdb->p_class_val_to_name[i];
rc = class_constraint_rules_to_strs(pdb, name, class, class->constraints, mls_strs, non_mls_strs);
@@ -383,6 +384,7 @@
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->validatetrans) {
name = pdb->p_class_val_to_name[i];
rc = class_validatetrans_rules_to_strs(pdb, name, class->validatetrans, mls_strs, non_mls_strs);
@@ -461,6 +463,7 @@
/* class */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
name = pdb->p_class_val_to_name[i];
perms = class_or_common_perms_to_str(&class->permissions);
if (perms) {
@@ -488,6 +491,7 @@
/* classcommon */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
name = pdb->p_class_val_to_name[i];
if (class->comkey != NULL) {
sepol_printf(out, "(classcommon %s %s)\n", name, class->comkey);
@@ -503,6 +507,7 @@
}
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
name = class->comkey;
if (name != NULL) {
common = hashtab_search(pdb->p_commons.table, name);
@@ -727,6 +732,7 @@
/* default_user */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_user != 0) {
rc = write_default_user_to_cil(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -738,6 +744,7 @@
/* default_role */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_role != 0) {
rc = write_default_role_to_cil(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -749,6 +756,7 @@
/* default_type */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_type != 0) {
rc = write_default_type_to_cil(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -764,6 +772,7 @@
/* default_range */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_range) {
rc = write_default_range_to_cil(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
index 9e4d676..8c923d9 100644
--- a/libsepol/src/kernel_to_conf.c
+++ b/libsepol/src/kernel_to_conf.c
@@ -362,7 +362,7 @@
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
- if (class->constraints) {
+ if (class && class->constraints) {
name = pdb->p_class_val_to_name[i];
rc = class_constraint_rules_to_strs(pdb, name, class, class->constraints, mls_strs, non_mls_strs);
if (rc != 0) {
@@ -387,7 +387,7 @@
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
- if (class->validatetrans) {
+ if (class && class->validatetrans) {
name = pdb->p_class_val_to_name[i];
rc = class_validatetrans_rules_to_strs(pdb, name, class->validatetrans, mls_strs, non_mls_strs);
if (rc != 0) {
@@ -555,6 +555,7 @@
}
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
name = class->comkey;
if (!name) continue;
common = hashtab_search(pdb->p_commons.table, name);
@@ -581,6 +582,7 @@
/* class */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
name = pdb->p_class_val_to_name[i];
sepol_printf(out, "class %s", name);
if (class->comkey) {
@@ -706,6 +708,7 @@
/* default_user */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_user != 0) {
rc = write_default_user_to_conf(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -717,6 +720,7 @@
/* default_role */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_role != 0) {
rc = write_default_role_to_conf(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -728,6 +732,7 @@
/* default_type */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_type != 0) {
rc = write_default_type_to_conf(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {
@@ -743,6 +748,7 @@
/* default_range */
for (i=0; i < pdb->p_classes.nprim; i++) {
class = pdb->class_val_to_struct[i];
+ if (!class) continue;
if (class->default_range != 0) {
rc = write_default_range_to_conf(out, pdb->p_class_val_to_name[i], class);
if (rc != 0) {