backport bugfix from upsteam

This commit is contained in:
huangzq6 2023-11-25 09:57:47 +08:00
parent b2dacd571d
commit 8b894704b7
8 changed files with 541 additions and 1 deletions

View File

@ -0,0 +1,91 @@
From 0d1445067c67d38e7d5c14155999afb10cc2e1a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 14 Jul 2023 20:44:12 +0200
Subject: [PATCH] hashtab: update
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Avoid overflowing number of elements in hashtab_insert().
Use identical type for hashed values to avoid implicit conversions.
Declare tag parameter of hashtab_hash_eval() const since it is only
printed.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
---
libsepol/include/sepol/policydb/hashtab.h | 2 +-
libsepol/src/hashtab.c | 14 +++++++-------
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/libsepol/include/sepol/policydb/hashtab.h b/libsepol/include/sepol/policydb/hashtab.h
index 060e8c9c5..3fcd1fdce 100644
--- a/libsepol/include/sepol/policydb/hashtab.h
+++ b/libsepol/include/sepol/policydb/hashtab.h
@@ -108,7 +108,7 @@ extern int hashtab_map(hashtab_t h,
hashtab_datum_t d,
void *args), void *args);
-extern void hashtab_hash_eval(hashtab_t h, char *tag);
+extern void hashtab_hash_eval(hashtab_t h, const char *tag);
#ifdef __cplusplus
}
diff --git a/libsepol/src/hashtab.c b/libsepol/src/hashtab.c
index 4a827fd31..b1a9bdc2f 100644
--- a/libsepol/src/hashtab.c
+++ b/libsepol/src/hashtab.c
@@ -103,10 +103,10 @@ static void hashtab_check_resize(hashtab_t h)
int hashtab_insert(hashtab_t h, hashtab_key_t key, hashtab_datum_t datum)
{
- int hvalue;
+ unsigned int hvalue;
hashtab_ptr_t prev, cur, newnode;
- if (!h)
+ if (!h || h->nel == UINT32_MAX)
return SEPOL_ENOMEM;
hashtab_check_resize(h);
@@ -144,7 +144,7 @@ int hashtab_remove(hashtab_t h, hashtab_key_t key,
void (*destroy) (hashtab_key_t k,
hashtab_datum_t d, void *args), void *args)
{
- int hvalue;
+ unsigned int hvalue;
hashtab_ptr_t cur, last;
if (!h)
@@ -176,7 +176,7 @@ int hashtab_remove(hashtab_t h, hashtab_key_t key,
hashtab_datum_t hashtab_search(hashtab_t h, const_hashtab_key_t key)
{
- int hvalue;
+ unsigned int hvalue;
hashtab_ptr_t cur;
if (!h)
@@ -240,10 +240,10 @@ int hashtab_map(hashtab_t h,
return SEPOL_OK;
}
-void hashtab_hash_eval(hashtab_t h, char *tag)
+void hashtab_hash_eval(hashtab_t h, const char *tag)
{
unsigned int i;
- int chain_len, slots_used, max_chain_len;
+ size_t chain_len, slots_used, max_chain_len;
hashtab_ptr_t cur;
slots_used = 0;
@@ -264,6 +264,6 @@ void hashtab_hash_eval(hashtab_t h, char *tag)
}
printf
- ("%s: %d entries and %d/%d buckets used, longest chain length %d\n",
+ ("%s: %d entries and %zu/%d buckets used, longest chain length %zu\n",
tag, h->nel, slots_used, h->size, max_chain_len);
}

View File

@ -0,0 +1,33 @@
From df666f70534ef225b97899f997b4077aeb285972 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Thu, 6 Jul 2023 15:57:18 +0200
Subject: [PATCH] libsepol: check for overflow in put_entry()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
put_entry() is used during writing binary policies. Avoid short writes
due to an overflow.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
---
libsepol/src/services.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libsepol/src/services.c b/libsepol/src/services.c
index 72772dbd29..6bddc287e1 100644
--- a/libsepol/src/services.c
+++ b/libsepol/src/services.c
@@ -1711,7 +1711,10 @@ int next_entry(void *buf, struct policy_file *fp, size_t bytes)
size_t put_entry(const void *ptr, size_t size, size_t n,
struct policy_file *fp)
{
- size_t bytes = size * n;
+ size_t bytes;
+
+ if (__builtin_mul_overflow(size, n, &bytes))
+ return 0;
switch (fp->type) {
case PF_USE_STDIO:

View File

@ -0,0 +1,257 @@
From e81c466bca9a06e2ada7d783fe31dd44c9e04432 Mon Sep 17 00:00:00 2001
From: James Carter <jwcart2@gmail.com>
Date: Thu, 20 Apr 2023 08:58:01 -0400
Subject: [PATCH] libsepol/cil: Fix class permission verification in CIL
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Before the CIL post processing phase (where expressions are evaluated,
various ebitmaps are set, etc) there is a pre-verification where
checks are made to find self references or loops in bounds, attribute
sets, and class permissions. The class permission checking is faulty
in two ways.
First, it does not check for the use of "all" in a permission expression
for a class that has no permissions. An error will still be generated
later and secilc will exit cleanly, but without an error message that
explains the problem.
Second, it does not properly handle lists in permission expressions.
For example, "(C ((P)))" is a legitimate class permission. The
permissions expression contains one item that is a list containing
one permission. This permission expression will be properly evaluated.
Unfortunately, the class permission verification assumes that each
item in the permission expression is either an operator or a
permission datum and a segmenation fault will occur.
Refactor the class permission checking to give a proper error when
"all" is used in a permission expression for a class that has no
permissions and so that it can handle lists in permission
expressions. Also, check for the actual flavor of each item in
the permission expression and return an error if an unexpected
flavor is found.
The failure to properly handle lists in permission expressions was
found by oss-fuzz (#58085).
Tested-by: Christian Göttsche <cgzones@googlemail.com>
Signed-off-by: James Carter <jwcart2@gmail.com>
---
libsepol/cil/src/cil_verify.c | 167 +++++++++++++++++++++++-----------
1 file changed, 114 insertions(+), 53 deletions(-)
diff --git a/libsepol/cil/src/cil_verify.c b/libsepol/cil/src/cil_verify.c
index 4640dc59de..3f58969df2 100644
--- a/libsepol/cil/src/cil_verify.c
+++ b/libsepol/cil/src/cil_verify.c
@@ -1700,31 +1700,109 @@ static int __add_perm_to_list(__attribute__((unused)) hashtab_key_t k, hashtab_d
return SEPOL_OK;
}
-static int __cil_verify_classperms(struct cil_list *classperms,
- struct cil_symtab_datum *orig,
- struct cil_symtab_datum *parent,
- struct cil_symtab_datum *cur,
- enum cil_flavor flavor,
- unsigned steps, unsigned limit)
+static int __cil_verify_classperms(struct cil_list *classperms, struct cil_symtab_datum *orig, struct cil_symtab_datum *cur, unsigned steps, unsigned limit);
+
+static int __cil_verify_map_perm(struct cil_class *class, struct cil_perm *perm, struct cil_symtab_datum *orig, unsigned steps, unsigned limit)
+{
+ int rc;
+
+ if (!perm->classperms) {
+ cil_tree_log(NODE(class), CIL_ERR, "No class permissions for map class %s, permission %s", DATUM(class)->name, DATUM(perm)->name);
+ goto exit;
+ }
+
+ rc = __cil_verify_classperms(perm->classperms, orig, &perm->datum, steps, limit);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(NODE(class), CIL_ERR, "There was an error verifying class permissions for map class %s, permission %s", DATUM(class)->name, DATUM(perm)->name);
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+
+static int __cil_verify_perms(struct cil_class *class, struct cil_list *perms, struct cil_symtab_datum *orig, unsigned steps, unsigned limit)
{
int rc = SEPOL_ERR;
- struct cil_list_item *curr;
+ int count = 0;
+ struct cil_list_item *i = NULL;
- if (classperms == NULL) {
- if (flavor == CIL_MAP_PERM) {
- cil_tree_log(NODE(cur), CIL_ERR, "Map class %s does not have a classmapping for %s", parent->name, cur->name);
+ if (!perms) {
+ cil_tree_log(NODE(class), CIL_ERR, "No permissions for class %s in class permissions", DATUM(class)->name);
+ goto exit;
+ }
+
+ cil_list_for_each(i, perms) {
+ count++;
+ if (i->flavor == CIL_LIST) {
+ rc = __cil_verify_perms(class, i->data, orig, steps, limit);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ } else if (i->flavor == CIL_DATUM) {
+ struct cil_perm *perm = i->data;
+ if (FLAVOR(perm) == CIL_MAP_PERM) {
+ rc = __cil_verify_map_perm(class, perm, orig, steps, limit);
+ if (rc != SEPOL_OK) {
+ goto exit;
+ }
+ }
+ } else if (i->flavor == CIL_OP) {
+ enum cil_flavor op = (enum cil_flavor)(uintptr_t)i->data;
+ if (op == CIL_ALL) {
+ struct cil_list *perm_list;
+ struct cil_list_item *j = NULL;
+ int count2 = 0;
+ cil_list_init(&perm_list, CIL_MAP_PERM);
+ cil_symtab_map(&class->perms, __add_perm_to_list, perm_list);
+ cil_list_for_each(j, perm_list) {
+ count2++;
+ struct cil_perm *perm = j->data;
+ if (FLAVOR(perm) == CIL_MAP_PERM) {
+ rc = __cil_verify_map_perm(class, perm, orig, steps, limit);
+ if (rc != SEPOL_OK) {
+ cil_list_destroy(&perm_list, CIL_FALSE);
+ goto exit;
+ }
+ }
+ }
+ cil_list_destroy(&perm_list, CIL_FALSE);
+ if (count2 == 0) {
+ cil_tree_log(NODE(class), CIL_ERR, "Operator \"all\" used for %s which has no permissions associated with it", DATUM(class)->name);
+ goto exit;
+ }
+ }
} else {
- cil_tree_log(NODE(cur), CIL_ERR, "Classpermission %s does not have a classpermissionset", cur->name);
+ cil_tree_log(NODE(class), CIL_ERR, "Permission list for %s has an unexpected flavor: %d", DATUM(class)->name, i->flavor);
+ goto exit;
}
+ }
+
+ if (count == 0) {
+ cil_tree_log(NODE(class), CIL_ERR, "Empty permissions list for class %s in class permissions", DATUM(class)->name);
+ goto exit;
+ }
+
+ return SEPOL_OK;
+
+exit:
+ return SEPOL_ERR;
+}
+
+static int __cil_verify_classperms(struct cil_list *classperms, struct cil_symtab_datum *orig, struct cil_symtab_datum *cur, unsigned steps, unsigned limit)
+{
+ int rc;
+ struct cil_list_item *i;
+
+ if (classperms == NULL) {
goto exit;
}
if (steps > 0 && orig == cur) {
- if (flavor == CIL_MAP_PERM) {
- cil_tree_log(NODE(cur), CIL_ERR, "Found circular class permissions involving the map class %s and permission %s", parent->name, cur->name);
- } else {
- cil_tree_log(NODE(cur), CIL_ERR, "Found circular class permissions involving the set %s", cur->name);
- }
+ cil_tree_log(NODE(cur), CIL_ERR, "Found circular class permissions involving %s", cur->name);
goto exit;
} else {
steps++;
@@ -1735,44 +1813,20 @@ static int __cil_verify_classperms(struct cil_list *classperms,
}
}
- cil_list_for_each(curr, classperms) {
- if (curr->flavor == CIL_CLASSPERMS) {
- struct cil_classperms *cp = curr->data;
- if (FLAVOR(cp->class) != CIL_CLASS) { /* MAP */
- struct cil_list_item *i = NULL;
- cil_list_for_each(i, cp->perms) {
- if (i->flavor != CIL_OP) {
- struct cil_perm *cmp = i->data;
- rc = __cil_verify_classperms(cmp->classperms, orig, &cp->class->datum, &cmp->datum, CIL_MAP_PERM, steps, limit);
- if (rc != SEPOL_OK) {
- goto exit;
- }
- } else {
- enum cil_flavor op = (enum cil_flavor)(uintptr_t)i->data;
- if (op == CIL_ALL) {
- struct cil_class *mc = cp->class;
- struct cil_list *perm_list;
- struct cil_list_item *j = NULL;
-
- cil_list_init(&perm_list, CIL_MAP_PERM);
- cil_symtab_map(&mc->perms, __add_perm_to_list, perm_list);
- cil_list_for_each(j, perm_list) {
- struct cil_perm *cmp = j->data;
- rc = __cil_verify_classperms(cmp->classperms, orig, &cp->class->datum, &cmp->datum, CIL_MAP_PERM, steps, limit);
- if (rc != SEPOL_OK) {
- cil_list_destroy(&perm_list, CIL_FALSE);
- goto exit;
- }
- }
- cil_list_destroy(&perm_list, CIL_FALSE);
- }
- }
- }
+ cil_list_for_each(i, classperms) {
+ if (i->flavor == CIL_CLASSPERMS) {
+ struct cil_classperms *cp = i->data;
+ rc = __cil_verify_perms(cp->class, cp->perms, orig, steps, limit);
+ if (rc != SEPOL_OK) {
+ goto exit;
}
} else { /* SET */
- struct cil_classperms_set *cp_set = curr->data;
+ struct cil_classperms_set *cp_set = i->data;
struct cil_classpermission *cp = cp_set->set;
- rc = __cil_verify_classperms(cp->classperms, orig, NULL, &cp->datum, CIL_CLASSPERMISSION, steps, limit);
+ if (!cp->classperms) {
+ cil_tree_log(NODE(cur), CIL_ERR, "Classpermission %s does not have a classpermissionset", DATUM(cp)->name);
+ }
+ rc = __cil_verify_classperms(cp->classperms, orig, &cp->datum, steps, limit);
if (rc != SEPOL_OK) {
goto exit;
}
@@ -1787,9 +1841,15 @@ static int __cil_verify_classperms(struct cil_list *classperms,
static int __cil_verify_classpermission(struct cil_tree_node *node)
{
+ int rc;
struct cil_classpermission *cp = node->data;
- return __cil_verify_classperms(cp->classperms, &cp->datum, NULL, &cp->datum, CIL_CLASSPERMISSION, 0, 2);
+ rc = __cil_verify_classperms(cp->classperms, &cp->datum, &cp->datum, 0, 2);
+ if (rc != SEPOL_OK) {
+ cil_tree_log(node, CIL_ERR, "Error verifying class permissions for classpermission %s", DATUM(cp)->name);
+ }
+
+ return rc;
}
struct cil_verify_map_args {
@@ -1804,8 +1864,9 @@ static int __verify_map_perm_classperms(__attribute__((unused)) hashtab_key_t k,
struct cil_perm *cmp = (struct cil_perm *)d;
int rc;
- rc = __cil_verify_classperms(cmp->classperms, &cmp->datum, &map_args->class->datum, &cmp->datum, CIL_MAP_PERM, 0, 2);
+ rc = __cil_verify_classperms(cmp->classperms, &cmp->datum, &cmp->datum, 0, 2);
if (rc != SEPOL_OK) {
+ cil_tree_log(NODE(cmp), CIL_ERR, "Error verifying class permissions for map class %s, permission %s", DATUM(map_args->class)->name, DATUM(cmp)->name);
map_args->rc = rc;
}

View File

@ -0,0 +1,51 @@
From f5d664ebeb09d837a0551f6df0c8f038937a1b67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 12 May 2023 11:23:11 +0200
Subject: [PATCH] libsepol: dump non-mls validatetrans rules as such
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The functions constraint_expr_to_str() prepare a string representation
for validatetrans and mlsvalidatetrans rules. To decide what keyword to
use the type of expression is consulted. Currently the extra target
type (CEXPR_XTARGET) is considered to be an MLS statement while its not,
e.g.:
validatetrans CLASS1 t3 == ATTR1;
Actually check for MLS expression types only.
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
---
libsepol/src/kernel_to_cil.c | 2 +-
libsepol/src/kernel_to_conf.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c
index e9cd89c299..7e279e3ff5 100644
--- a/libsepol/src/kernel_to_cil.c
+++ b/libsepol/src/kernel_to_cil.c
@@ -172,7 +172,7 @@ static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr
goto exit;
}
- if (curr->attr >= CEXPR_XTARGET) {
+ if (curr->attr >= CEXPR_L1L2) {
*use_mls = 1;
}
diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
index c48a71147a..4c93cc10c3 100644
--- a/libsepol/src/kernel_to_conf.c
+++ b/libsepol/src/kernel_to_conf.c
@@ -169,7 +169,7 @@ static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr
goto exit;
}
- if (curr->attr >= CEXPR_XTARGET) {
+ if (curr->attr >= CEXPR_L1L2) {
*use_mls = 1;
}

View File

@ -0,0 +1,28 @@
From ace9ec17ffaa1ad0be165cd8ad77998cb368ca2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 14 Jul 2023 20:44:13 +0200
Subject: [PATCH] libsepol: expand: use identical type to avoid implicit
conversion
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
---
libsepol/src/expand.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c
index 8795229a39..4c9f84cf9d 100644
--- a/libsepol/src/expand.c
+++ b/libsepol/src/expand.c
@@ -2350,7 +2350,7 @@ static int type_attr_map(hashtab_key_t key
policydb_t *p = state->out;
unsigned int i;
ebitmap_node_t *tnode;
- int value;
+ uint32_t value;
type = (type_datum_t *) datum;
value = type->s.value;

View File

@ -0,0 +1,28 @@
From ac015a3996e894754350ea8ae97e66644899a2c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 12 May 2023 11:29:59 +0200
Subject: [PATCH] libsepol: validate: check low category is not bigger than
high
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
---
libsepol/src/policydb_validate.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c
index e0d290ff32..b34f83ecb5 100644
--- a/libsepol/src/policydb_validate.c
+++ b/libsepol/src/policydb_validate.c
@@ -545,6 +545,8 @@ static int validate_mls_semantic_cat(const mls_semantic_cat_t *cat, const valida
goto bad;
if (validate_value(cat->high, cats))
goto bad;
+ if (cat->low > cat->high)
+ goto bad;
}
return 0;

View File

@ -0,0 +1,41 @@
From 4cf37608b563327ce433ce392931a9eb8bda9524 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 12 May 2023 11:29:58 +0200
Subject: [PATCH] libsepol: validate old style range trans classes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
For old style range transition rules the class defaults to process.
However the policy might not declare the process class leading to
setting a wrong bit later on via:
if (ebitmap_set_bit(&rtr->tclasses, rt->target_class - 1, 1))
UBSAN report:
policydb.c:3684:56: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'uint32_t' (aka 'unsigned int')
Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
Acked-by: James Carter <jwcart2@gmail.com>
---
libsepol/src/policydb.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index b79c19b94c..605d290a71 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -3650,10 +3650,10 @@ static int range_read(policydb_t * p, struct policy_file *fp)
if (rc < 0)
goto err;
rt->target_class = le32_to_cpu(buf[0]);
- if (!value_isvalid(rt->target_class, p->p_classes.nprim))
- goto err;
} else
rt->target_class = p->process_class;
+ if (!value_isvalid(rt->target_class, p->p_classes.nprim))
+ goto err;
r = calloc(1, sizeof(*r));
if (!r)
goto err;

View File

@ -1,11 +1,19 @@
Name: libsepol
Version: 3.5
Release: 1
Release: 2
Summary: SELinux binary policy manipulation library
License: LGPLv2+
URL: https://github.com/SELinuxProject/selinux/wiki/Releases
Source0: https://github.com/SELinuxProject/selinux/releases/download/%{version}/%{name}-%{version}.tar.gz
Patch0001: backport-hashtab-update.patch
Patch0002: backport-libsepol-check-for-overflow-in-put_entry.patch
Patch0003: backport-libsepol-dump-non-mls-validatetrans-rules-as-such.patch
Patch0004: backport-libsepol-expand-use-identical-type-to-avoid-implicit-conversion.patch
Patch0005: backport-libsepol-cil-Fix-class-permission-verification-in-CIL.patch
Patch0006: backport-libsepol-validate-old-style-range-trans-classes.patch
Patch0007: backport-libsepol-validate-check-low-category-is-not-bigger-than-high.patch
BuildRequires: gcc flex
%description
@ -65,6 +73,9 @@ make DESTDIR="%{buildroot}" LIBDIR="%{_libdir}" SHLIBDIR="%{_libdir}" install
%{_mandir}/man3/*
%changelog
* Sat Nov 25 2023 huangzq6 <huangzhenqiang2@huawei.com> - 3.5-2
- backport bugfix from upstream
* Mon Jul 17 2023 niuyaru <niuyaru@kylinos.cn> - 3.5-1
- update to 3.5