[PATCH] libsepol: cap max depth for __evaluate_classperms_list()

Stephen Smalley <[email protected]> Mon, 27 Jul 2026 09:59:57 -0400
Newsgroups org.kernel.vger.selinux
Message-ID <[email protected]>
__evaluate_classperms_list() is called recursively without
a depth limit, which can overflow the stack. Cap the depth
to avoid such overflows.

Reported-by: oss-fuzz (issue 479899924)
Signed-off-by: Stephen Smalley <[email protected]>
---
 libsepol/cil/src/cil_post.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
index 8845faed..183b0d49 100644
--- a/libsepol/cil/src/cil_post.c
+++ b/libsepol/cil/src/cil_post.c
@@ -2291,11 +2291,14 @@ exit:
 }
 
 static int __evaluate_classperms_list(struct cil_list *classperms,
-				      struct cil_db *db)
+				      struct cil_db *db, int depth)
 {
 	int rc = SEPOL_ERR;
 	struct cil_list_item *curr;
 
+	if (depth > 32)
+		return SEPOL_ERR;
+
 	cil_list_for_each(curr, classperms) {
 		if (curr->flavor == CIL_CLASSPERMS) {
 			struct cil_classperms *cp = curr->data;
@@ -2313,7 +2316,7 @@ static int __evaluate_classperms_list(struct cil_list *classperms,
 				cil_list_for_each(i, cp->perms) {
 					struct cil_perm *cmp = i->data;
 					rc = __evaluate_classperms_list(
-						cmp->classperms, db);
+						cmp->classperms, db, depth + 1);
 					if (rc != SEPOL_OK) {
 						goto exit;
 					}
@@ -2322,7 +2325,8 @@ static int __evaluate_classperms_list(struct cil_list *classperms,
 		} else { /* SET */
 			struct cil_classperms_set *cp_set = curr->data;
 			struct cil_classpermission *cp = cp_set->set;
-			rc = __evaluate_classperms_list(cp->classperms, db);
+			rc = __evaluate_classperms_list(cp->classperms, db,
+							depth + 1);
 			if (rc != SEPOL_OK) {
 				goto exit;
 			}
@@ -2347,7 +2351,7 @@ __evaluate_map_perm_classperms(__attribute__((unused)) hashtab_key_t k,
 	struct class_map_args *map_args = args;
 	struct cil_perm *cmp = (struct cil_perm *)d;
 
-	int rc = __evaluate_classperms_list(cmp->classperms, map_args->db);
+	int rc = __evaluate_classperms_list(cmp->classperms, map_args->db, 0);
 
 	if (rc != SEPOL_OK) {
 		map_args->rc = rc;
@@ -2393,7 +2397,7 @@ static int __cil_post_db_classperms_helper(struct cil_tree_node *node,
 	}
 	case CIL_CLASSPERMISSION: {
 		struct cil_classpermission *cp = node->data;
-		rc = __evaluate_classperms_list(cp->classperms, db);
+		rc = __evaluate_classperms_list(cp->classperms, db, 0);
 		if (rc != SEPOL_OK) {
 			goto exit;
 		}
@@ -2401,7 +2405,8 @@ static int __cil_post_db_classperms_helper(struct cil_tree_node *node,
 	}
 	case CIL_AVRULE: {
 		struct cil_avrule *avrule = node->data;
-		rc = __evaluate_classperms_list(avrule->perms.classperms, db);
+		rc = __evaluate_classperms_list(avrule->perms.classperms, db,
+						0);
 		if (rc != SEPOL_OK) {
 			goto exit;
 		}
@@ -2409,7 +2414,7 @@ static int __cil_post_db_classperms_helper(struct cil_tree_node *node,
 	}
 	case CIL_DENY_RULE: {
 		struct cil_deny_rule *deny = node->data;
-		rc = __evaluate_classperms_list(deny->classperms, db);
+		rc = __evaluate_classperms_list(deny->classperms, db, 0);
 		if (rc != SEPOL_OK) {
 			goto exit;
 		}
@@ -2418,7 +2423,7 @@ static int __cil_post_db_classperms_helper(struct cil_tree_node *node,
 	case CIL_CONSTRAIN:
 	case CIL_MLSCONSTRAIN: {
 		struct cil_constrain *constrain = node->data;
-		rc = __evaluate_classperms_list(constrain->classperms, db);
+		rc = __evaluate_classperms_list(constrain->classperms, db, 0);
 		if (rc != SEPOL_OK) {
 			goto exit;
 		}
-- 
2.55.0