* [PATCH] libsepol: handle type gaps when optimizing
@ 2021-12-23 18:50 Christian Göttsche
2022-01-03 18:10 ` James Carter
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Christian Göttsche @ 2021-12-23 18:50 UTC (permalink / raw)
To: selinux
For policy versions between 20 and 23 the type_val_to_struct array might
contain gaps. Skip those gaps to avoid NULL pointer dereferences:
==1250==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00000058560b bp 0x7ffdca60c110 sp 0x7ffdca60bfc0 T0)
==1250==The signal is caused by a READ memory access.
==1250==Hint: address points to the zero page.
#0 0x58560b in build_type_map selinux/libsepol/src/optimize.c:107:33
#1 0x58560b in policydb_optimize selinux/libsepol/src/optimize.c:441:13
#2 0x55e63e in LLVMFuzzerTestOneInput selinux/libsepol/fuzz/binpolicy-fuzzer.c:42:10
#3 0x455283 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp:0
#4 0x440ec2 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
#5 0x44671c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp:0
#6 0x46f522 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#7 0x7f9c160d00b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/libc-start.c:308:16
#8 0x41f67d in _start
Found by oss-fuzz (#42697)
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
libsepol/src/optimize.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
index 8a048702..678d22bd 100644
--- a/libsepol/src/optimize.c
+++ b/libsepol/src/optimize.c
@@ -104,6 +104,10 @@ static struct type_vec *build_type_map(const policydb_t *p)
if (type_vec_init(&map[i]))
goto err;
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!p->type_val_to_struct[i])
+ continue;
+
if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
ebitmap_for_each_positive_bit(&p->type_attr_map[i],
n, k) {
@@ -114,11 +118,17 @@ static struct type_vec *build_type_map(const policydb_t *p)
ebitmap_t *types_i = &p->attr_type_map[i];
for (k = 0; k < p->p_types.nprim; k++) {
- ebitmap_t *types_k = &p->attr_type_map[k];
+ ebitmap_t *types_k;
+
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!p->type_val_to_struct[k])
+ continue;
if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
continue;
+ types_k = &p->attr_type_map[k];
+
if (ebitmap_contains(types_k, types_i)) {
if (type_vec_append(&map[i], k))
goto err;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] libsepol: handle type gaps when optimizing
2021-12-23 18:50 [PATCH] libsepol: handle type gaps when optimizing Christian Göttsche
@ 2022-01-03 18:10 ` James Carter
2022-01-06 20:42 ` [PATCH v2] libsepol: handle type gaps Christian Göttsche
2022-01-25 13:30 ` [PATCH v3] " Christian Göttsche
2 siblings, 0 replies; 9+ messages in thread
From: James Carter @ 2022-01-03 18:10 UTC (permalink / raw)
To: Christian Göttsche; +Cc: SElinux list
On Fri, Dec 24, 2021 at 8:10 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> For policy versions between 20 and 23 the type_val_to_struct array might
> contain gaps. Skip those gaps to avoid NULL pointer dereferences:
>
> ==1250==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00000058560b bp 0x7ffdca60c110 sp 0x7ffdca60bfc0 T0)
> ==1250==The signal is caused by a READ memory access.
> ==1250==Hint: address points to the zero page.
> #0 0x58560b in build_type_map selinux/libsepol/src/optimize.c:107:33
> #1 0x58560b in policydb_optimize selinux/libsepol/src/optimize.c:441:13
> #2 0x55e63e in LLVMFuzzerTestOneInput selinux/libsepol/fuzz/binpolicy-fuzzer.c:42:10
> #3 0x455283 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp:0
> #4 0x440ec2 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
> #5 0x44671c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp:0
> #6 0x46f522 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
> #7 0x7f9c160d00b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/libc-start.c:308:16
> #8 0x41f67d in _start
>
> Found by oss-fuzz (#42697)
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> ---
> libsepol/src/optimize.c | 12 +++++++++++-
> 1 file changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
> index 8a048702..678d22bd 100644
> --- a/libsepol/src/optimize.c
> +++ b/libsepol/src/optimize.c
> @@ -104,6 +104,10 @@ static struct type_vec *build_type_map(const policydb_t *p)
> if (type_vec_init(&map[i]))
> goto err;
>
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!p->type_val_to_struct[i])
> + continue;
> +
> if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
> ebitmap_for_each_positive_bit(&p->type_attr_map[i],
> n, k) {
> @@ -114,11 +118,17 @@ static struct type_vec *build_type_map(const policydb_t *p)
> ebitmap_t *types_i = &p->attr_type_map[i];
>
> for (k = 0; k < p->p_types.nprim; k++) {
> - ebitmap_t *types_k = &p->attr_type_map[k];
> + ebitmap_t *types_k;
> +
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!p->type_val_to_struct[k])
> + continue;
>
> if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
> continue;
>
> + types_k = &p->attr_type_map[k];
> +
> if (ebitmap_contains(types_k, types_i)) {
> if (type_vec_append(&map[i], k))
> goto err;
> --
> 2.34.1
>
Before policy version 20, there are no attributes, so I think that a
check should be made in policydb_optimize() for a version less than 24
and just exit with an error there with an error message.
Policy version 23 has not been the latest for more than 10 years.
Thanks,
Jim
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2] libsepol: handle type gaps
2021-12-23 18:50 [PATCH] libsepol: handle type gaps when optimizing Christian Göttsche
2022-01-03 18:10 ` James Carter
@ 2022-01-06 20:42 ` Christian Göttsche
2022-01-12 15:55 ` James Carter
2022-01-25 13:30 ` [PATCH v3] " Christian Göttsche
2 siblings, 1 reply; 9+ messages in thread
From: Christian Göttsche @ 2022-01-06 20:42 UTC (permalink / raw)
To: selinux
For policy versions between 20 and 23 the type_val_to_struct array might
contain gaps. Skip those gaps to avoid NULL pointer dereferences:
==1250==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00000058560b bp 0x7ffdca60c110 sp 0x7ffdca60bfc0 T0)
==1250==The signal is caused by a READ memory access.
==1250==Hint: address points to the zero page.
#0 0x58560b in build_type_map selinux/libsepol/src/optimize.c:107:33
#1 0x58560b in policydb_optimize selinux/libsepol/src/optimize.c:441:13
#2 0x55e63e in LLVMFuzzerTestOneInput selinux/libsepol/fuzz/binpolicy-fuzzer.c:42:10
#3 0x455283 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp:0
#4 0x440ec2 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
#5 0x44671c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp:0
#6 0x46f522 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#7 0x7f9c160d00b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/libc-start.c:308:16
#8 0x41f67d in _start
Found by oss-fuzz (#42697)
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
@Jim:
I hope I have interpreted and implemented your feedback correctly, but I
am not sure I have seen through the whole gaps logic yet.
---
libsepol/src/kernel_to_cil.c | 40 +++++++++++++++++++++++++++++++++++
libsepol/src/kernel_to_conf.c | 32 ++++++++++++++++++++++++++++
libsepol/src/optimize.c | 18 +++++++++++++++-
3 files changed, 89 insertions(+), 1 deletion(-)
diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
index 18294a9a..1353e77f 100644
--- a/libsepol/src/kernel_to_cil.c
+++ b/libsepol/src/kernel_to_cil.c
@@ -1227,6 +1227,14 @@ static int write_type_attributes_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!type) {
+ if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ rc = -1;
+ goto exit;
+ }
+ continue;
+ }
if (type->flavor == TYPE_ATTRIB) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
@@ -1357,6 +1365,14 @@ static int write_type_decl_rules_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!type) {
+ if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ rc = -1;
+ goto exit;
+ }
+ continue;
+ }
if (type->flavor == TYPE_TYPE && type->primary) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
@@ -1486,6 +1502,14 @@ static int write_type_bounds_rules_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!type) {
+ if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ rc = -1;
+ goto exit;
+ }
+ continue;
+ }
if (type->flavor == TYPE_TYPE) {
if (type->bounds > 0) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
@@ -1540,6 +1564,14 @@ static int write_type_attribute_sets_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
attr = pdb->type_val_to_struct[i];
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!attr) {
+ if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ rc = -1;
+ goto exit;
+ }
+ continue;
+ }
if (attr->flavor != TYPE_ATTRIB) continue;
name = pdb->p_type_val_to_name[i];
typemap = &pdb->attr_type_map[i];
@@ -2273,6 +2305,14 @@ static int write_role_decl_rules_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type_datum = pdb->type_val_to_struct[i];
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!type_datum) {
+ if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ rc = -1;
+ goto exit;
+ }
+ continue;
+ }
if (type_datum->flavor == TYPE_TYPE && type_datum->primary) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
index a92ba9fd..235b4556 100644
--- a/libsepol/src/kernel_to_conf.c
+++ b/libsepol/src/kernel_to_conf.c
@@ -1210,6 +1210,14 @@ static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!type) {
+ if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ rc = -1;
+ goto exit;
+ }
+ continue;
+ }
if (type->flavor == TYPE_ATTRIB) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
@@ -1340,6 +1348,14 @@ static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!type) {
+ if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ rc = -1;
+ goto exit;
+ }
+ continue;
+ }
if (type->flavor == TYPE_TYPE && type->primary) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
@@ -1460,6 +1476,14 @@ static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!type) {
+ if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ rc = -1;
+ goto exit;
+ }
+ continue;
+ }
if (type->flavor == TYPE_TYPE) {
if (type->bounds > 0) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
@@ -1583,6 +1607,14 @@ static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!type) {
+ if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ rc = -1;
+ goto exit;
+ }
+ continue;
+ }
if (type->flavor != TYPE_TYPE || !type->primary) continue;
if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
index 8a048702..f8c28313 100644
--- a/libsepol/src/optimize.c
+++ b/libsepol/src/optimize.c
@@ -104,6 +104,13 @@ static struct type_vec *build_type_map(const policydb_t *p)
if (type_vec_init(&map[i]))
goto err;
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!p->type_val_to_struct[i]) {
+ if (p->policyvers <= POLICYDB_VERSION_PERMISSIVE)
+ goto err;
+ continue;
+ }
+
if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
ebitmap_for_each_positive_bit(&p->type_attr_map[i],
n, k) {
@@ -114,11 +121,20 @@ static struct type_vec *build_type_map(const policydb_t *p)
ebitmap_t *types_i = &p->attr_type_map[i];
for (k = 0; k < p->p_types.nprim; k++) {
- ebitmap_t *types_k = &p->attr_type_map[k];
+ ebitmap_t *types_k;
+
+ /* Gap in types for policy versions between 20 and 23 */
+ if (!p->type_val_to_struct[k]) {
+ if (p->policyvers <= POLICYDB_VERSION_PERMISSIVE)
+ goto err;
+ continue;
+ }
if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
continue;
+ types_k = &p->attr_type_map[k];
+
if (ebitmap_contains(types_k, types_i)) {
if (type_vec_append(&map[i], k))
goto err;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2] libsepol: handle type gaps
2022-01-06 20:42 ` [PATCH v2] libsepol: handle type gaps Christian Göttsche
@ 2022-01-12 15:55 ` James Carter
2022-01-19 15:43 ` Christian Göttsche
0 siblings, 1 reply; 9+ messages in thread
From: James Carter @ 2022-01-12 15:55 UTC (permalink / raw)
To: Christian Göttsche; +Cc: SElinux list
On Fri, Jan 7, 2022 at 1:57 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> For policy versions between 20 and 23 the type_val_to_struct array might
> contain gaps. Skip those gaps to avoid NULL pointer dereferences:
>
> ==1250==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00000058560b bp 0x7ffdca60c110 sp 0x7ffdca60bfc0 T0)
> ==1250==The signal is caused by a READ memory access.
> ==1250==Hint: address points to the zero page.
> #0 0x58560b in build_type_map selinux/libsepol/src/optimize.c:107:33
> #1 0x58560b in policydb_optimize selinux/libsepol/src/optimize.c:441:13
> #2 0x55e63e in LLVMFuzzerTestOneInput selinux/libsepol/fuzz/binpolicy-fuzzer.c:42:10
> #3 0x455283 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp:0
> #4 0x440ec2 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
> #5 0x44671c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp:0
> #6 0x46f522 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
> #7 0x7f9c160d00b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/libc-start.c:308:16
> #8 0x41f67d in _start
>
> Found by oss-fuzz (#42697)
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> ---
> @Jim:
> I hope I have interpreted and implemented your feedback correctly, but I
> am not sure I have seen through the whole gaps logic yet.
> ---
> libsepol/src/kernel_to_cil.c | 40 +++++++++++++++++++++++++++++++++++
> libsepol/src/kernel_to_conf.c | 32 ++++++++++++++++++++++++++++
> libsepol/src/optimize.c | 18 +++++++++++++++-
> 3 files changed, 89 insertions(+), 1 deletion(-)
>
> diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
> index 18294a9a..1353e77f 100644
> --- a/libsepol/src/kernel_to_cil.c
> +++ b/libsepol/src/kernel_to_cil.c
> @@ -1227,6 +1227,14 @@ static int write_type_attributes_to_cil(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!type) {
> + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> + rc = -1;
> + goto exit;
> + }
> + continue;
> + }
There is already a check in sepol_kernel_policydb_to_cil() and an
error is returned if the policy version is between 20 and 23.
While no policy that is written by libsepol will have gaps in this
array, the validate_policydb() only checks that gaps are not referred
to by any rules, so there does need to be a check for a NULL here.
I would make the line below to be "if (type && type->flavor ..."
> if (type->flavor == TYPE_ATTRIB) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> @@ -1357,6 +1365,14 @@ static int write_type_decl_rules_to_cil(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!type) {
> + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> + rc = -1;
> + goto exit;
> + }
> + continue;
> + }
Same here.
> if (type->flavor == TYPE_TYPE && type->primary) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> @@ -1486,6 +1502,14 @@ static int write_type_bounds_rules_to_cil(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!type) {
> + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> + rc = -1;
> + goto exit;
> + }
> + continue;
> + }
And here.
> if (type->flavor == TYPE_TYPE) {
> if (type->bounds > 0) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> @@ -1540,6 +1564,14 @@ static int write_type_attribute_sets_to_cil(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> attr = pdb->type_val_to_struct[i];
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!attr) {
> + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> + rc = -1;
> + goto exit;
> + }
> + continue;
> + }
And here.
> if (attr->flavor != TYPE_ATTRIB) continue;
> name = pdb->p_type_val_to_name[i];
> typemap = &pdb->attr_type_map[i];
> @@ -2273,6 +2305,14 @@ static int write_role_decl_rules_to_cil(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type_datum = pdb->type_val_to_struct[i];
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!type_datum) {
> + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> + rc = -1;
> + goto exit;
> + }
> + continue;
> + }
And here.
> if (type_datum->flavor == TYPE_TYPE && type_datum->primary) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
> index a92ba9fd..235b4556 100644
> --- a/libsepol/src/kernel_to_conf.c
> +++ b/libsepol/src/kernel_to_conf.c
> @@ -1210,6 +1210,14 @@ static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!type) {
> + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> + rc = -1;
> + goto exit;
> + }
> + continue;
> + }
Same thing here. sepol_kernel_policydb_to_conf() already does a check
and returns an error if the policy version is between 20 and 23. All
the same comments above apply here.
> if (type->flavor == TYPE_ATTRIB) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> @@ -1340,6 +1348,14 @@ static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!type) {
> + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> + rc = -1;
> + goto exit;
> + }
> + continue;
> + }
> if (type->flavor == TYPE_TYPE && type->primary) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> @@ -1460,6 +1476,14 @@ static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!type) {
> + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> + rc = -1;
> + goto exit;
> + }
> + continue;
> + }
> if (type->flavor == TYPE_TYPE) {
> if (type->bounds > 0) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> @@ -1583,6 +1607,14 @@ static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!type) {
> + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> + rc = -1;
> + goto exit;
> + }
> + continue;
> + }
> if (type->flavor != TYPE_TYPE || !type->primary) continue;
> if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
>
> diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
> index 8a048702..f8c28313 100644
> --- a/libsepol/src/optimize.c
> +++ b/libsepol/src/optimize.c
> @@ -104,6 +104,13 @@ static struct type_vec *build_type_map(const policydb_t *p)
> if (type_vec_init(&map[i]))
> goto err;
>
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!p->type_val_to_struct[i]) {
> + if (p->policyvers <= POLICYDB_VERSION_PERMISSIVE)
> + goto err;
> + continue;
> + }
> +
I want the same sort of check for the policy version done in
policydb_optimize(), not throughout the code.
Can still check for NULL.
> if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
> ebitmap_for_each_positive_bit(&p->type_attr_map[i],
> n, k) {
> @@ -114,11 +121,20 @@ static struct type_vec *build_type_map(const policydb_t *p)
> ebitmap_t *types_i = &p->attr_type_map[i];
>
> for (k = 0; k < p->p_types.nprim; k++) {
> - ebitmap_t *types_k = &p->attr_type_map[k];
> + ebitmap_t *types_k;
> +
> + /* Gap in types for policy versions between 20 and 23 */
> + if (!p->type_val_to_struct[k]) {
> + if (p->policyvers <= POLICYDB_VERSION_PERMISSIVE)
> + goto err;
> + continue;
> + }
Same here.
Thanks,
Jim
>
> if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
> continue;
>
> + types_k = &p->attr_type_map[k];
> +
> if (ebitmap_contains(types_k, types_i)) {
> if (type_vec_append(&map[i], k))
> goto err;
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2] libsepol: handle type gaps
2022-01-12 15:55 ` James Carter
@ 2022-01-19 15:43 ` Christian Göttsche
2022-01-19 18:11 ` James Carter
0 siblings, 1 reply; 9+ messages in thread
From: Christian Göttsche @ 2022-01-19 15:43 UTC (permalink / raw)
To: James Carter; +Cc: SElinux list
On Wed, 12 Jan 2022 at 16:55, James Carter <jwcart2@gmail.com> wrote:
>
> On Fri, Jan 7, 2022 at 1:57 PM Christian Göttsche
> <cgzones@googlemail.com> wrote:
> >
> > For policy versions between 20 and 23 the type_val_to_struct array might
> > contain gaps. Skip those gaps to avoid NULL pointer dereferences:
> >
> > ==1250==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00000058560b bp 0x7ffdca60c110 sp 0x7ffdca60bfc0 T0)
> > ==1250==The signal is caused by a READ memory access.
> > ==1250==Hint: address points to the zero page.
> > #0 0x58560b in build_type_map selinux/libsepol/src/optimize.c:107:33
> > #1 0x58560b in policydb_optimize selinux/libsepol/src/optimize.c:441:13
> > #2 0x55e63e in LLVMFuzzerTestOneInput selinux/libsepol/fuzz/binpolicy-fuzzer.c:42:10
> > #3 0x455283 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp:0
> > #4 0x440ec2 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
> > #5 0x44671c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp:0
> > #6 0x46f522 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
> > #7 0x7f9c160d00b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/libc-start.c:308:16
> > #8 0x41f67d in _start
> >
> > Found by oss-fuzz (#42697)
> >
> > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> > ---
> > @Jim:
> > I hope I have interpreted and implemented your feedback correctly, but I
> > am not sure I have seen through the whole gaps logic yet.
> > ---
> > libsepol/src/kernel_to_cil.c | 40 +++++++++++++++++++++++++++++++++++
> > libsepol/src/kernel_to_conf.c | 32 ++++++++++++++++++++++++++++
> > libsepol/src/optimize.c | 18 +++++++++++++++-
> > 3 files changed, 89 insertions(+), 1 deletion(-)
> >
> > diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
> > index 18294a9a..1353e77f 100644
> > --- a/libsepol/src/kernel_to_cil.c
> > +++ b/libsepol/src/kernel_to_cil.c
> > @@ -1227,6 +1227,14 @@ static int write_type_attributes_to_cil(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!type) {
> > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > + rc = -1;
> > + goto exit;
> > + }
> > + continue;
> > + }
>
> There is already a check in sepol_kernel_policydb_to_cil() and an
> error is returned if the policy version is between 20 and 23.
> While no policy that is written by libsepol will have gaps in this
> array, the validate_policydb() only checks that gaps are not referred
> to by any rules, so there does need to be a check for a NULL here.
>
> I would make the line below to be "if (type && type->flavor ..."
>
> > if (type->flavor == TYPE_ATTRIB) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > @@ -1357,6 +1365,14 @@ static int write_type_decl_rules_to_cil(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!type) {
> > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > + rc = -1;
> > + goto exit;
> > + }
> > + continue;
> > + }
>
> Same here.
>
> > if (type->flavor == TYPE_TYPE && type->primary) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > @@ -1486,6 +1502,14 @@ static int write_type_bounds_rules_to_cil(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!type) {
> > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > + rc = -1;
> > + goto exit;
> > + }
> > + continue;
> > + }
>
> And here.
>
> > if (type->flavor == TYPE_TYPE) {
> > if (type->bounds > 0) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > @@ -1540,6 +1564,14 @@ static int write_type_attribute_sets_to_cil(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > attr = pdb->type_val_to_struct[i];
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!attr) {
> > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > + rc = -1;
> > + goto exit;
> > + }
> > + continue;
> > + }
>
> And here.
>
> > if (attr->flavor != TYPE_ATTRIB) continue;
> > name = pdb->p_type_val_to_name[i];
> > typemap = &pdb->attr_type_map[i];
> > @@ -2273,6 +2305,14 @@ static int write_role_decl_rules_to_cil(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type_datum = pdb->type_val_to_struct[i];
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!type_datum) {
> > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > + rc = -1;
> > + goto exit;
> > + }
> > + continue;
> > + }
>
> And here.
>
> > if (type_datum->flavor == TYPE_TYPE && type_datum->primary) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
> > index a92ba9fd..235b4556 100644
> > --- a/libsepol/src/kernel_to_conf.c
> > +++ b/libsepol/src/kernel_to_conf.c
> > @@ -1210,6 +1210,14 @@ static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!type) {
> > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > + rc = -1;
> > + goto exit;
> > + }
> > + continue;
> > + }
>
> Same thing here. sepol_kernel_policydb_to_conf() already does a check
> and returns an error if the policy version is between 20 and 23. All
> the same comments above apply here.
>
> > if (type->flavor == TYPE_ATTRIB) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > @@ -1340,6 +1348,14 @@ static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!type) {
> > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > + rc = -1;
> > + goto exit;
> > + }
> > + continue;
> > + }
> > if (type->flavor == TYPE_TYPE && type->primary) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > @@ -1460,6 +1476,14 @@ static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!type) {
> > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > + rc = -1;
> > + goto exit;
> > + }
> > + continue;
> > + }
> > if (type->flavor == TYPE_TYPE) {
> > if (type->bounds > 0) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > @@ -1583,6 +1607,14 @@ static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!type) {
> > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > + rc = -1;
> > + goto exit;
> > + }
> > + continue;
> > + }
> > if (type->flavor != TYPE_TYPE || !type->primary) continue;
> > if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
> >
> > diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
> > index 8a048702..f8c28313 100644
> > --- a/libsepol/src/optimize.c
> > +++ b/libsepol/src/optimize.c
> > @@ -104,6 +104,13 @@ static struct type_vec *build_type_map(const policydb_t *p)
> > if (type_vec_init(&map[i]))
> > goto err;
> >
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!p->type_val_to_struct[i]) {
> > + if (p->policyvers <= POLICYDB_VERSION_PERMISSIVE)
> > + goto err;
> > + continue;
> > + }
> > +
>
> I want the same sort of check for the policy version done in
> policydb_optimize(), not throughout the code.
Something like
diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
index 8a048702..059c61f2 100644
--- a/libsepol/src/optimize.c
+++ b/libsepol/src/optimize.c
@@ -438,6 +443,15 @@ int policydb_optimize(policydb_t *p)
if (p->policy_type != POLICY_KERN)
return -1;
+ if (p->policyvers >= POLICYDB_VERSION_AVTAB &&
p->policyvers <= POLICYDB_VERSION_PERMISSIVE)
+ /*
+ * For policy versions between 20 and 23,
attributes exist in the policy,
+ * but only in the type_attr_map. This means that
there are gaps in both
+ * the type_val_to_struct and p_type_val_to_name
arrays and policy rules
+ * can refer to those gaps.
+ */
+ return FIXME;
+
type_map = build_type_map(p);
if (!type_map)
return -1;
?
Should it return 0 and silently not optimize or fail with -1?
In case of a failure should there be a message, e.g.
ERR(NULL, "Optimizing policy versions between 20 and 23 is not supported");
?
> Can still check for NULL.
>
> > if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
> > ebitmap_for_each_positive_bit(&p->type_attr_map[i],
> > n, k) {
> > @@ -114,11 +121,20 @@ static struct type_vec *build_type_map(const policydb_t *p)
> > ebitmap_t *types_i = &p->attr_type_map[i];
> >
> > for (k = 0; k < p->p_types.nprim; k++) {
> > - ebitmap_t *types_k = &p->attr_type_map[k];
> > + ebitmap_t *types_k;
> > +
> > + /* Gap in types for policy versions between 20 and 23 */
> > + if (!p->type_val_to_struct[k]) {
> > + if (p->policyvers <= POLICYDB_VERSION_PERMISSIVE)
> > + goto err;
> > + continue;
> > + }
>
> Same here.
>
> Thanks,
> Jim
>
> >
> > if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
> > continue;
> >
> > + types_k = &p->attr_type_map[k];
> > +
> > if (ebitmap_contains(types_k, types_i)) {
> > if (type_vec_append(&map[i], k))
> > goto err;
> > --
> > 2.34.1
> >
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2] libsepol: handle type gaps
2022-01-19 15:43 ` Christian Göttsche
@ 2022-01-19 18:11 ` James Carter
0 siblings, 0 replies; 9+ messages in thread
From: James Carter @ 2022-01-19 18:11 UTC (permalink / raw)
To: Christian Göttsche; +Cc: SElinux list
On Wed, Jan 19, 2022 at 10:43 AM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> On Wed, 12 Jan 2022 at 16:55, James Carter <jwcart2@gmail.com> wrote:
> >
> > On Fri, Jan 7, 2022 at 1:57 PM Christian Göttsche
> > <cgzones@googlemail.com> wrote:
> > >
> > > For policy versions between 20 and 23 the type_val_to_struct array might
> > > contain gaps. Skip those gaps to avoid NULL pointer dereferences:
> > >
> > > ==1250==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00000058560b bp 0x7ffdca60c110 sp 0x7ffdca60bfc0 T0)
> > > ==1250==The signal is caused by a READ memory access.
> > > ==1250==Hint: address points to the zero page.
> > > #0 0x58560b in build_type_map selinux/libsepol/src/optimize.c:107:33
> > > #1 0x58560b in policydb_optimize selinux/libsepol/src/optimize.c:441:13
> > > #2 0x55e63e in LLVMFuzzerTestOneInput selinux/libsepol/fuzz/binpolicy-fuzzer.c:42:10
> > > #3 0x455283 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp:0
> > > #4 0x440ec2 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
> > > #5 0x44671c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp:0
> > > #6 0x46f522 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
> > > #7 0x7f9c160d00b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/libc-start.c:308:16
> > > #8 0x41f67d in _start
> > >
> > > Found by oss-fuzz (#42697)
> > >
> > > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> > > ---
> > > @Jim:
> > > I hope I have interpreted and implemented your feedback correctly, but I
> > > am not sure I have seen through the whole gaps logic yet.
> > > ---
> > > libsepol/src/kernel_to_cil.c | 40 +++++++++++++++++++++++++++++++++++
> > > libsepol/src/kernel_to_conf.c | 32 ++++++++++++++++++++++++++++
> > > libsepol/src/optimize.c | 18 +++++++++++++++-
> > > 3 files changed, 89 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
> > > index 18294a9a..1353e77f 100644
> > > --- a/libsepol/src/kernel_to_cil.c
> > > +++ b/libsepol/src/kernel_to_cil.c
> > > @@ -1227,6 +1227,14 @@ static int write_type_attributes_to_cil(FILE *out, struct policydb *pdb)
> > >
> > > for (i=0; i < pdb->p_types.nprim; i++) {
> > > type = pdb->type_val_to_struct[i];
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!type) {
> > > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > > + rc = -1;
> > > + goto exit;
> > > + }
> > > + continue;
> > > + }
> >
> > There is already a check in sepol_kernel_policydb_to_cil() and an
> > error is returned if the policy version is between 20 and 23.
> > While no policy that is written by libsepol will have gaps in this
> > array, the validate_policydb() only checks that gaps are not referred
> > to by any rules, so there does need to be a check for a NULL here.
> >
> > I would make the line below to be "if (type && type->flavor ..."
> >
> > > if (type->flavor == TYPE_ATTRIB) {
> > > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > > if (rc != 0) {
> > > @@ -1357,6 +1365,14 @@ static int write_type_decl_rules_to_cil(FILE *out, struct policydb *pdb)
> > >
> > > for (i=0; i < pdb->p_types.nprim; i++) {
> > > type = pdb->type_val_to_struct[i];
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!type) {
> > > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > > + rc = -1;
> > > + goto exit;
> > > + }
> > > + continue;
> > > + }
> >
> > Same here.
> >
> > > if (type->flavor == TYPE_TYPE && type->primary) {
> > > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > > if (rc != 0) {
> > > @@ -1486,6 +1502,14 @@ static int write_type_bounds_rules_to_cil(FILE *out, struct policydb *pdb)
> > >
> > > for (i=0; i < pdb->p_types.nprim; i++) {
> > > type = pdb->type_val_to_struct[i];
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!type) {
> > > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > > + rc = -1;
> > > + goto exit;
> > > + }
> > > + continue;
> > > + }
> >
> > And here.
> >
> > > if (type->flavor == TYPE_TYPE) {
> > > if (type->bounds > 0) {
> > > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > > @@ -1540,6 +1564,14 @@ static int write_type_attribute_sets_to_cil(FILE *out, struct policydb *pdb)
> > >
> > > for (i=0; i < pdb->p_types.nprim; i++) {
> > > attr = pdb->type_val_to_struct[i];
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!attr) {
> > > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > > + rc = -1;
> > > + goto exit;
> > > + }
> > > + continue;
> > > + }
> >
> > And here.
> >
> > > if (attr->flavor != TYPE_ATTRIB) continue;
> > > name = pdb->p_type_val_to_name[i];
> > > typemap = &pdb->attr_type_map[i];
> > > @@ -2273,6 +2305,14 @@ static int write_role_decl_rules_to_cil(FILE *out, struct policydb *pdb)
> > >
> > > for (i=0; i < pdb->p_types.nprim; i++) {
> > > type_datum = pdb->type_val_to_struct[i];
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!type_datum) {
> > > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > > + rc = -1;
> > > + goto exit;
> > > + }
> > > + continue;
> > > + }
> >
> > And here.
> >
> > > if (type_datum->flavor == TYPE_TYPE && type_datum->primary) {
> > > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > > if (rc != 0) {
> > > diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
> > > index a92ba9fd..235b4556 100644
> > > --- a/libsepol/src/kernel_to_conf.c
> > > +++ b/libsepol/src/kernel_to_conf.c
> > > @@ -1210,6 +1210,14 @@ static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
> > >
> > > for (i=0; i < pdb->p_types.nprim; i++) {
> > > type = pdb->type_val_to_struct[i];
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!type) {
> > > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > > + rc = -1;
> > > + goto exit;
> > > + }
> > > + continue;
> > > + }
> >
> > Same thing here. sepol_kernel_policydb_to_conf() already does a check
> > and returns an error if the policy version is between 20 and 23. All
> > the same comments above apply here.
> >
> > > if (type->flavor == TYPE_ATTRIB) {
> > > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > > if (rc != 0) {
> > > @@ -1340,6 +1348,14 @@ static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
> > >
> > > for (i=0; i < pdb->p_types.nprim; i++) {
> > > type = pdb->type_val_to_struct[i];
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!type) {
> > > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > > + rc = -1;
> > > + goto exit;
> > > + }
> > > + continue;
> > > + }
> > > if (type->flavor == TYPE_TYPE && type->primary) {
> > > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > > if (rc != 0) {
> > > @@ -1460,6 +1476,14 @@ static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
> > >
> > > for (i=0; i < pdb->p_types.nprim; i++) {
> > > type = pdb->type_val_to_struct[i];
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!type) {
> > > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > > + rc = -1;
> > > + goto exit;
> > > + }
> > > + continue;
> > > + }
> > > if (type->flavor == TYPE_TYPE) {
> > > if (type->bounds > 0) {
> > > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > > @@ -1583,6 +1607,14 @@ static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
> > >
> > > for (i=0; i < pdb->p_types.nprim; i++) {
> > > type = pdb->type_val_to_struct[i];
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!type) {
> > > + if (pdb->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > > + rc = -1;
> > > + goto exit;
> > > + }
> > > + continue;
> > > + }
> > > if (type->flavor != TYPE_TYPE || !type->primary) continue;
> > > if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
> > >
> > > diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
> > > index 8a048702..f8c28313 100644
> > > --- a/libsepol/src/optimize.c
> > > +++ b/libsepol/src/optimize.c
> > > @@ -104,6 +104,13 @@ static struct type_vec *build_type_map(const policydb_t *p)
> > > if (type_vec_init(&map[i]))
> > > goto err;
> > >
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!p->type_val_to_struct[i]) {
> > > + if (p->policyvers <= POLICYDB_VERSION_PERMISSIVE)
> > > + goto err;
> > > + continue;
> > > + }
> > > +
> >
> > I want the same sort of check for the policy version done in
> > policydb_optimize(), not throughout the code.
>
> Something like
>
> diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
> index 8a048702..059c61f2 100644
> --- a/libsepol/src/optimize.c
> +++ b/libsepol/src/optimize.c
> @@ -438,6 +443,15 @@ int policydb_optimize(policydb_t *p)
> if (p->policy_type != POLICY_KERN)
> return -1;
>
> + if (p->policyvers >= POLICYDB_VERSION_AVTAB &&
> p->policyvers <= POLICYDB_VERSION_PERMISSIVE)
> + /*
> + * For policy versions between 20 and 23,
> attributes exist in the policy,
> + * but only in the type_attr_map. This means that
> there are gaps in both
> + * the type_val_to_struct and p_type_val_to_name
> arrays and policy rules
> + * can refer to those gaps.
> + */
> + return FIXME;
> +
> type_map = build_type_map(p);
> if (!type_map)
> return -1;
>
Yes.
> ?
> Should it return 0 and silently not optimize or fail with -1?
> In case of a failure should there be a message, e.g.
>
> ERR(NULL, "Optimizing policy versions between 20 and 23 is not supported");
>
> ?
>
Fail with -1 and the error message you have there.
Thanks,
Jim
> > Can still check for NULL.
> >
> > > if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
> > > ebitmap_for_each_positive_bit(&p->type_attr_map[i],
> > > n, k) {
> > > @@ -114,11 +121,20 @@ static struct type_vec *build_type_map(const policydb_t *p)
> > > ebitmap_t *types_i = &p->attr_type_map[i];
> > >
> > > for (k = 0; k < p->p_types.nprim; k++) {
> > > - ebitmap_t *types_k = &p->attr_type_map[k];
> > > + ebitmap_t *types_k;
> > > +
> > > + /* Gap in types for policy versions between 20 and 23 */
> > > + if (!p->type_val_to_struct[k]) {
> > > + if (p->policyvers <= POLICYDB_VERSION_PERMISSIVE)
> > > + goto err;
> > > + continue;
> > > + }
> >
> > Same here.
> >
> > Thanks,
> > Jim
> >
> > >
> > > if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
> > > continue;
> > >
> > > + types_k = &p->attr_type_map[k];
> > > +
> > > if (ebitmap_contains(types_k, types_i)) {
> > > if (type_vec_append(&map[i], k))
> > > goto err;
> > > --
> > > 2.34.1
> > >
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3] libsepol: handle type gaps
2021-12-23 18:50 [PATCH] libsepol: handle type gaps when optimizing Christian Göttsche
2022-01-03 18:10 ` James Carter
2022-01-06 20:42 ` [PATCH v2] libsepol: handle type gaps Christian Göttsche
@ 2022-01-25 13:30 ` Christian Göttsche
2022-01-25 21:17 ` James Carter
2 siblings, 1 reply; 9+ messages in thread
From: Christian Göttsche @ 2022-01-25 13:30 UTC (permalink / raw)
To: selinux
For policy versions between 20 and 23 the type_val_to_struct array might
contain gaps. Skip those gaps to avoid NULL pointer dereferences:
==1250==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00000058560b bp 0x7ffdca60c110 sp 0x7ffdca60bfc0 T0)
==1250==The signal is caused by a READ memory access.
==1250==Hint: address points to the zero page.
#0 0x58560b in build_type_map selinux/libsepol/src/optimize.c:107:33
#1 0x58560b in policydb_optimize selinux/libsepol/src/optimize.c:441:13
#2 0x55e63e in LLVMFuzzerTestOneInput selinux/libsepol/fuzz/binpolicy-fuzzer.c:42:10
#3 0x455283 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp:0
#4 0x440ec2 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
#5 0x44671c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp:0
#6 0x46f522 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#7 0x7f9c160d00b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/libc-start.c:308:16
#8 0x41f67d in _start
Found by oss-fuzz (#42697)
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
v3:
- drop extra error blocks in kernel_to_(cil|conf).c in favor of a
simple non-NULL check, as writing policies between version 20 and
23 is not supported and previously checked
- refuse to optimize policies between version 20 and 23 altogether
and simplify NULL checks
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
libsepol/src/kernel_to_cil.c | 10 +++++-----
libsepol/src/kernel_to_conf.c | 8 ++++----
libsepol/src/optimize.c | 21 +++++++++++++++++++--
3 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
index 18294a9a..693206d2 100644
--- a/libsepol/src/kernel_to_cil.c
+++ b/libsepol/src/kernel_to_cil.c
@@ -1227,7 +1227,7 @@ static int write_type_attributes_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_ATTRIB) {
+ if (type && type->flavor == TYPE_ATTRIB) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -1357,7 +1357,7 @@ static int write_type_decl_rules_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_TYPE && type->primary) {
+ if (type && type->flavor == TYPE_TYPE && type->primary) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -1486,7 +1486,7 @@ static int write_type_bounds_rules_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_TYPE) {
+ if (type && type->flavor == TYPE_TYPE) {
if (type->bounds > 0) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
@@ -1540,7 +1540,7 @@ static int write_type_attribute_sets_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
attr = pdb->type_val_to_struct[i];
- if (attr->flavor != TYPE_ATTRIB) continue;
+ if (!attr || attr->flavor != TYPE_ATTRIB) continue;
name = pdb->p_type_val_to_name[i];
typemap = &pdb->attr_type_map[i];
if (ebitmap_is_empty(typemap)) continue;
@@ -2273,7 +2273,7 @@ static int write_role_decl_rules_to_cil(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type_datum = pdb->type_val_to_struct[i];
- if (type_datum->flavor == TYPE_TYPE && type_datum->primary) {
+ if (type_datum && type_datum->flavor == TYPE_TYPE && type_datum->primary) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
goto exit;
diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
index a92ba9fd..52b6c60f 100644
--- a/libsepol/src/kernel_to_conf.c
+++ b/libsepol/src/kernel_to_conf.c
@@ -1210,7 +1210,7 @@ static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_ATTRIB) {
+ if (type && type->flavor == TYPE_ATTRIB) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -1340,7 +1340,7 @@ static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_TYPE && type->primary) {
+ if (type && type->flavor == TYPE_TYPE && type->primary) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
goto exit;
@@ -1460,7 +1460,7 @@ static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor == TYPE_TYPE) {
+ if (type && type->flavor == TYPE_TYPE) {
if (type->bounds > 0) {
rc = strs_add(strs, pdb->p_type_val_to_name[i]);
if (rc != 0) {
@@ -1583,7 +1583,7 @@ static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
for (i=0; i < pdb->p_types.nprim; i++) {
type = pdb->type_val_to_struct[i];
- if (type->flavor != TYPE_TYPE || !type->primary) continue;
+ if (!type || type->flavor != TYPE_TYPE || !type->primary) continue;
if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
rc = ebitmap_cpy(&attrmap, &pdb->type_attr_map[i]);
diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
index 8a048702..93ff2116 100644
--- a/libsepol/src/optimize.c
+++ b/libsepol/src/optimize.c
@@ -31,6 +31,7 @@
#include <sepol/policydb/policydb.h>
#include <sepol/policydb/conditional.h>
+#include "debug.h"
#include "private.h"
#define TYPE_VEC_INIT_SIZE 16
@@ -104,6 +105,9 @@ static struct type_vec *build_type_map(const policydb_t *p)
if (type_vec_init(&map[i]))
goto err;
+ if (!p->type_val_to_struct[i])
+ continue;
+
if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
ebitmap_for_each_positive_bit(&p->type_attr_map[i],
n, k) {
@@ -114,11 +118,13 @@ static struct type_vec *build_type_map(const policydb_t *p)
ebitmap_t *types_i = &p->attr_type_map[i];
for (k = 0; k < p->p_types.nprim; k++) {
- ebitmap_t *types_k = &p->attr_type_map[k];
+ const ebitmap_t *types_k;
- if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
+ if (!p->type_val_to_struct[k] || p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
continue;
+ types_k = &p->attr_type_map[k];
+
if (ebitmap_contains(types_k, types_i)) {
if (type_vec_append(&map[i], k))
goto err;
@@ -438,6 +444,17 @@ int policydb_optimize(policydb_t *p)
if (p->policy_type != POLICY_KERN)
return -1;
+ if (p->policyvers >= POLICYDB_VERSION_AVTAB && p->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
+ /*
+ * For policy versions between 20 and 23, attributes exist in the policy,
+ * but only in the type_attr_map. This means that there are gaps in both
+ * the type_val_to_struct and p_type_val_to_name arrays and policy rules
+ * can refer to those gaps.
+ */
+ ERR(NULL, "Optimizing policy versions between 20 and 23 is not supported");
+ return -1;
+ }
+
type_map = build_type_map(p);
if (!type_map)
return -1;
--
2.34.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3] libsepol: handle type gaps
2022-01-25 13:30 ` [PATCH v3] " Christian Göttsche
@ 2022-01-25 21:17 ` James Carter
2022-01-27 15:31 ` James Carter
0 siblings, 1 reply; 9+ messages in thread
From: James Carter @ 2022-01-25 21:17 UTC (permalink / raw)
To: Christian Göttsche; +Cc: SElinux list
On Tue, Jan 25, 2022 at 2:43 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> For policy versions between 20 and 23 the type_val_to_struct array might
> contain gaps. Skip those gaps to avoid NULL pointer dereferences:
>
> ==1250==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00000058560b bp 0x7ffdca60c110 sp 0x7ffdca60bfc0 T0)
> ==1250==The signal is caused by a READ memory access.
> ==1250==Hint: address points to the zero page.
> #0 0x58560b in build_type_map selinux/libsepol/src/optimize.c:107:33
> #1 0x58560b in policydb_optimize selinux/libsepol/src/optimize.c:441:13
> #2 0x55e63e in LLVMFuzzerTestOneInput selinux/libsepol/fuzz/binpolicy-fuzzer.c:42:10
> #3 0x455283 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp:0
> #4 0x440ec2 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
> #5 0x44671c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp:0
> #6 0x46f522 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
> #7 0x7f9c160d00b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/libc-start.c:308:16
> #8 0x41f67d in _start
>
> Found by oss-fuzz (#42697)
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
>
Acked-by: James Carter <jwcart2@gmail.com>
> ---
> v3:
> - drop extra error blocks in kernel_to_(cil|conf).c in favor of a
> simple non-NULL check, as writing policies between version 20 and
> 23 is not supported and previously checked
> - refuse to optimize policies between version 20 and 23 altogether
> and simplify NULL checks
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> ---
> libsepol/src/kernel_to_cil.c | 10 +++++-----
> libsepol/src/kernel_to_conf.c | 8 ++++----
> libsepol/src/optimize.c | 21 +++++++++++++++++++--
> 3 files changed, 28 insertions(+), 11 deletions(-)
>
> diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
> index 18294a9a..693206d2 100644
> --- a/libsepol/src/kernel_to_cil.c
> +++ b/libsepol/src/kernel_to_cil.c
> @@ -1227,7 +1227,7 @@ static int write_type_attributes_to_cil(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> - if (type->flavor == TYPE_ATTRIB) {
> + if (type && type->flavor == TYPE_ATTRIB) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> goto exit;
> @@ -1357,7 +1357,7 @@ static int write_type_decl_rules_to_cil(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> - if (type->flavor == TYPE_TYPE && type->primary) {
> + if (type && type->flavor == TYPE_TYPE && type->primary) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> goto exit;
> @@ -1486,7 +1486,7 @@ static int write_type_bounds_rules_to_cil(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> - if (type->flavor == TYPE_TYPE) {
> + if (type && type->flavor == TYPE_TYPE) {
> if (type->bounds > 0) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> @@ -1540,7 +1540,7 @@ static int write_type_attribute_sets_to_cil(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> attr = pdb->type_val_to_struct[i];
> - if (attr->flavor != TYPE_ATTRIB) continue;
> + if (!attr || attr->flavor != TYPE_ATTRIB) continue;
> name = pdb->p_type_val_to_name[i];
> typemap = &pdb->attr_type_map[i];
> if (ebitmap_is_empty(typemap)) continue;
> @@ -2273,7 +2273,7 @@ static int write_role_decl_rules_to_cil(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type_datum = pdb->type_val_to_struct[i];
> - if (type_datum->flavor == TYPE_TYPE && type_datum->primary) {
> + if (type_datum && type_datum->flavor == TYPE_TYPE && type_datum->primary) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> goto exit;
> diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
> index a92ba9fd..52b6c60f 100644
> --- a/libsepol/src/kernel_to_conf.c
> +++ b/libsepol/src/kernel_to_conf.c
> @@ -1210,7 +1210,7 @@ static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> - if (type->flavor == TYPE_ATTRIB) {
> + if (type && type->flavor == TYPE_ATTRIB) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> goto exit;
> @@ -1340,7 +1340,7 @@ static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> - if (type->flavor == TYPE_TYPE && type->primary) {
> + if (type && type->flavor == TYPE_TYPE && type->primary) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> goto exit;
> @@ -1460,7 +1460,7 @@ static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> - if (type->flavor == TYPE_TYPE) {
> + if (type && type->flavor == TYPE_TYPE) {
> if (type->bounds > 0) {
> rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> if (rc != 0) {
> @@ -1583,7 +1583,7 @@ static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
>
> for (i=0; i < pdb->p_types.nprim; i++) {
> type = pdb->type_val_to_struct[i];
> - if (type->flavor != TYPE_TYPE || !type->primary) continue;
> + if (!type || type->flavor != TYPE_TYPE || !type->primary) continue;
> if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
>
> rc = ebitmap_cpy(&attrmap, &pdb->type_attr_map[i]);
> diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
> index 8a048702..93ff2116 100644
> --- a/libsepol/src/optimize.c
> +++ b/libsepol/src/optimize.c
> @@ -31,6 +31,7 @@
> #include <sepol/policydb/policydb.h>
> #include <sepol/policydb/conditional.h>
>
> +#include "debug.h"
> #include "private.h"
>
> #define TYPE_VEC_INIT_SIZE 16
> @@ -104,6 +105,9 @@ static struct type_vec *build_type_map(const policydb_t *p)
> if (type_vec_init(&map[i]))
> goto err;
>
> + if (!p->type_val_to_struct[i])
> + continue;
> +
> if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
> ebitmap_for_each_positive_bit(&p->type_attr_map[i],
> n, k) {
> @@ -114,11 +118,13 @@ static struct type_vec *build_type_map(const policydb_t *p)
> ebitmap_t *types_i = &p->attr_type_map[i];
>
> for (k = 0; k < p->p_types.nprim; k++) {
> - ebitmap_t *types_k = &p->attr_type_map[k];
> + const ebitmap_t *types_k;
>
> - if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
> + if (!p->type_val_to_struct[k] || p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
> continue;
>
> + types_k = &p->attr_type_map[k];
> +
> if (ebitmap_contains(types_k, types_i)) {
> if (type_vec_append(&map[i], k))
> goto err;
> @@ -438,6 +444,17 @@ int policydb_optimize(policydb_t *p)
> if (p->policy_type != POLICY_KERN)
> return -1;
>
> + if (p->policyvers >= POLICYDB_VERSION_AVTAB && p->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> + /*
> + * For policy versions between 20 and 23, attributes exist in the policy,
> + * but only in the type_attr_map. This means that there are gaps in both
> + * the type_val_to_struct and p_type_val_to_name arrays and policy rules
> + * can refer to those gaps.
> + */
> + ERR(NULL, "Optimizing policy versions between 20 and 23 is not supported");
> + return -1;
> + }
> +
> type_map = build_type_map(p);
> if (!type_map)
> return -1;
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3] libsepol: handle type gaps
2022-01-25 21:17 ` James Carter
@ 2022-01-27 15:31 ` James Carter
0 siblings, 0 replies; 9+ messages in thread
From: James Carter @ 2022-01-27 15:31 UTC (permalink / raw)
To: Christian Göttsche; +Cc: SElinux list
On Tue, Jan 25, 2022 at 4:17 PM James Carter <jwcart2@gmail.com> wrote:
>
> On Tue, Jan 25, 2022 at 2:43 PM Christian Göttsche
> <cgzones@googlemail.com> wrote:
> >
> > For policy versions between 20 and 23 the type_val_to_struct array might
> > contain gaps. Skip those gaps to avoid NULL pointer dereferences:
> >
> > ==1250==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00000058560b bp 0x7ffdca60c110 sp 0x7ffdca60bfc0 T0)
> > ==1250==The signal is caused by a READ memory access.
> > ==1250==Hint: address points to the zero page.
> > #0 0x58560b in build_type_map selinux/libsepol/src/optimize.c:107:33
> > #1 0x58560b in policydb_optimize selinux/libsepol/src/optimize.c:441:13
> > #2 0x55e63e in LLVMFuzzerTestOneInput selinux/libsepol/fuzz/binpolicy-fuzzer.c:42:10
> > #3 0x455283 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) cxa_noexception.cpp:0
> > #4 0x440ec2 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:324:6
> > #5 0x44671c in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) cxa_noexception.cpp:0
> > #6 0x46f522 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
> > #7 0x7f9c160d00b2 in __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/libc-start.c:308:16
> > #8 0x41f67d in _start
> >
> > Found by oss-fuzz (#42697)
> >
> > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> >
>
> Acked-by: James Carter <jwcart2@gmail.com>
>
Merged.
Thanks,
Jim
> > ---
> > v3:
> > - drop extra error blocks in kernel_to_(cil|conf).c in favor of a
> > simple non-NULL check, as writing policies between version 20 and
> > 23 is not supported and previously checked
> > - refuse to optimize policies between version 20 and 23 altogether
> > and simplify NULL checks
> >
> > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> > ---
> > libsepol/src/kernel_to_cil.c | 10 +++++-----
> > libsepol/src/kernel_to_conf.c | 8 ++++----
> > libsepol/src/optimize.c | 21 +++++++++++++++++++--
> > 3 files changed, 28 insertions(+), 11 deletions(-)
> >
> > diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
> > index 18294a9a..693206d2 100644
> > --- a/libsepol/src/kernel_to_cil.c
> > +++ b/libsepol/src/kernel_to_cil.c
> > @@ -1227,7 +1227,7 @@ static int write_type_attributes_to_cil(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > - if (type->flavor == TYPE_ATTRIB) {
> > + if (type && type->flavor == TYPE_ATTRIB) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > goto exit;
> > @@ -1357,7 +1357,7 @@ static int write_type_decl_rules_to_cil(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > - if (type->flavor == TYPE_TYPE && type->primary) {
> > + if (type && type->flavor == TYPE_TYPE && type->primary) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > goto exit;
> > @@ -1486,7 +1486,7 @@ static int write_type_bounds_rules_to_cil(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > - if (type->flavor == TYPE_TYPE) {
> > + if (type && type->flavor == TYPE_TYPE) {
> > if (type->bounds > 0) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > @@ -1540,7 +1540,7 @@ static int write_type_attribute_sets_to_cil(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > attr = pdb->type_val_to_struct[i];
> > - if (attr->flavor != TYPE_ATTRIB) continue;
> > + if (!attr || attr->flavor != TYPE_ATTRIB) continue;
> > name = pdb->p_type_val_to_name[i];
> > typemap = &pdb->attr_type_map[i];
> > if (ebitmap_is_empty(typemap)) continue;
> > @@ -2273,7 +2273,7 @@ static int write_role_decl_rules_to_cil(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type_datum = pdb->type_val_to_struct[i];
> > - if (type_datum->flavor == TYPE_TYPE && type_datum->primary) {
> > + if (type_datum && type_datum->flavor == TYPE_TYPE && type_datum->primary) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > goto exit;
> > diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
> > index a92ba9fd..52b6c60f 100644
> > --- a/libsepol/src/kernel_to_conf.c
> > +++ b/libsepol/src/kernel_to_conf.c
> > @@ -1210,7 +1210,7 @@ static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > - if (type->flavor == TYPE_ATTRIB) {
> > + if (type && type->flavor == TYPE_ATTRIB) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > goto exit;
> > @@ -1340,7 +1340,7 @@ static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > - if (type->flavor == TYPE_TYPE && type->primary) {
> > + if (type && type->flavor == TYPE_TYPE && type->primary) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > goto exit;
> > @@ -1460,7 +1460,7 @@ static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > - if (type->flavor == TYPE_TYPE) {
> > + if (type && type->flavor == TYPE_TYPE) {
> > if (type->bounds > 0) {
> > rc = strs_add(strs, pdb->p_type_val_to_name[i]);
> > if (rc != 0) {
> > @@ -1583,7 +1583,7 @@ static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
> >
> > for (i=0; i < pdb->p_types.nprim; i++) {
> > type = pdb->type_val_to_struct[i];
> > - if (type->flavor != TYPE_TYPE || !type->primary) continue;
> > + if (!type || type->flavor != TYPE_TYPE || !type->primary) continue;
> > if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
> >
> > rc = ebitmap_cpy(&attrmap, &pdb->type_attr_map[i]);
> > diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c
> > index 8a048702..93ff2116 100644
> > --- a/libsepol/src/optimize.c
> > +++ b/libsepol/src/optimize.c
> > @@ -31,6 +31,7 @@
> > #include <sepol/policydb/policydb.h>
> > #include <sepol/policydb/conditional.h>
> >
> > +#include "debug.h"
> > #include "private.h"
> >
> > #define TYPE_VEC_INIT_SIZE 16
> > @@ -104,6 +105,9 @@ static struct type_vec *build_type_map(const policydb_t *p)
> > if (type_vec_init(&map[i]))
> > goto err;
> >
> > + if (!p->type_val_to_struct[i])
> > + continue;
> > +
> > if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
> > ebitmap_for_each_positive_bit(&p->type_attr_map[i],
> > n, k) {
> > @@ -114,11 +118,13 @@ static struct type_vec *build_type_map(const policydb_t *p)
> > ebitmap_t *types_i = &p->attr_type_map[i];
> >
> > for (k = 0; k < p->p_types.nprim; k++) {
> > - ebitmap_t *types_k = &p->attr_type_map[k];
> > + const ebitmap_t *types_k;
> >
> > - if (p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
> > + if (!p->type_val_to_struct[k] || p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
> > continue;
> >
> > + types_k = &p->attr_type_map[k];
> > +
> > if (ebitmap_contains(types_k, types_i)) {
> > if (type_vec_append(&map[i], k))
> > goto err;
> > @@ -438,6 +444,17 @@ int policydb_optimize(policydb_t *p)
> > if (p->policy_type != POLICY_KERN)
> > return -1;
> >
> > + if (p->policyvers >= POLICYDB_VERSION_AVTAB && p->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
> > + /*
> > + * For policy versions between 20 and 23, attributes exist in the policy,
> > + * but only in the type_attr_map. This means that there are gaps in both
> > + * the type_val_to_struct and p_type_val_to_name arrays and policy rules
> > + * can refer to those gaps.
> > + */
> > + ERR(NULL, "Optimizing policy versions between 20 and 23 is not supported");
> > + return -1;
> > + }
> > +
> > type_map = build_type_map(p);
> > if (!type_map)
> > return -1;
> > --
> > 2.34.1
> >
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2022-01-27 15:31 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-23 18:50 [PATCH] libsepol: handle type gaps when optimizing Christian Göttsche
2022-01-03 18:10 ` James Carter
2022-01-06 20:42 ` [PATCH v2] libsepol: handle type gaps Christian Göttsche
2022-01-12 15:55 ` James Carter
2022-01-19 15:43 ` Christian Göttsche
2022-01-19 18:11 ` James Carter
2022-01-25 13:30 ` [PATCH v3] " Christian Göttsche
2022-01-25 21:17 ` James Carter
2022-01-27 15:31 ` James Carter
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.