Skip to content

Commit cc83433

Browse files
authored
kernel: prune redundant avtab nodes after deny rules (#3439)
Runtime deny rules clear permission bits from AVTAB_ALLOWED entries. When all permissions are removed from an existing entry, the update can leave an AVTAB_ALLOWED node with data == 0. Such zero-permission avtab nodes are redundant and can make external policy parsers, such as sepatch, reject /sys/fs/selinux/policy with errors like: Invalid access vector Invalid avtab Invalid policydb policy image is invalid This was observed when applying: deny appdomain cgroup_v2 dir search The rule itself is valid, but the runtime patch left a redundant avtab entry behind. Avoid creating new entries for deny updates when the target entry does not exist, and prune redundant nodes after access-vector rule updates by rebuilding the avtab and destroying the old table through avtab_destroy(). This preserves deny semantics while keeping the live policy parseable by policydb-based tools.
1 parent 8f496b9 commit cc83433

1 file changed

Lines changed: 89 additions & 10 deletions

File tree

kernel/selinux/sepolicy.c

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@
2222
static struct avtab_node *get_avtab_node(struct policydb *db, struct avtab_key *key,
2323
struct avtab_extended_perms *xperms);
2424

25+
static bool is_redundant_avtab_node(struct avtab_node *node);
26+
27+
static bool remove_avtab_node(struct policydb *db, struct avtab_node *node);
28+
2529
static bool add_rule(struct policydb *db, const char *s, const char *t, const char *c, const char *p, int effect,
2630
bool invert);
2731

28-
static void add_rule_raw(struct policydb *db, struct type_datum *src, struct type_datum *tgt, struct class_datum *cls,
32+
static bool add_rule_raw(struct policydb *db, struct type_datum *src, struct type_datum *tgt, struct class_datum *cls,
2933
struct perm_datum *perm, int effect, bool invert);
3034

3135
static void add_xperm_rule_raw(struct policydb *db, struct type_datum *src, struct type_datum *tgt,
@@ -114,6 +118,8 @@ static struct avtab_node *get_avtab_node(struct policydb *db, struct avtab_key *
114118
}
115119
/* this is used to get the node - insertion is actually unique */
116120
node = avtab_insert_nonunique(&db->te_avtab, key, &avdatum);
121+
if (!node)
122+
return NULL;
117123

118124
int grow_size = sizeof(struct avtab_key);
119125
grow_size += sizeof(struct avtab_datum);
@@ -128,6 +134,61 @@ static struct avtab_node *get_avtab_node(struct policydb *db, struct avtab_key *
128134
return node;
129135
}
130136

137+
static bool is_redundant_avtab_node(struct avtab_node *node)
138+
{
139+
if (node->key.specified & AVTAB_XPERMS)
140+
return node->datum.u.xperms == NULL;
141+
if (!(node->key.specified & AVTAB_AV))
142+
return false;
143+
if (node->key.specified & AVTAB_AUDITDENY)
144+
return node->datum.u.data == ~0U;
145+
return node->datum.u.data == 0U;
146+
}
147+
148+
static bool remove_avtab_node(struct policydb *db, struct avtab_node *node)
149+
{
150+
int i;
151+
int ret;
152+
int shrink_size = sizeof(struct avtab_key) + sizeof(struct avtab_datum);
153+
struct avtab removed = {};
154+
struct avtab_node *n;
155+
struct avtab_node *prev;
156+
157+
ret = avtab_alloc(&removed, 1);
158+
if (ret < 0)
159+
return false;
160+
161+
for (i = 0; i < db->te_avtab.nslot; i++) {
162+
prev = NULL;
163+
for (n = db->te_avtab.htable[i]; n; prev = n, n = n->next) {
164+
if (n != node)
165+
continue;
166+
167+
if (prev)
168+
prev->next = n->next;
169+
else
170+
db->te_avtab.htable[i] = n->next;
171+
172+
if (db->te_avtab.nel > 0)
173+
db->te_avtab.nel--;
174+
175+
if ((n->key.specified & AVTAB_XPERMS) && n->datum.u.xperms) {
176+
shrink_size += sizeof(u8) + sizeof(u8) + sizeof(u32) * ARRAY_SIZE(n->datum.u.xperms->perms.p);
177+
}
178+
n->next = NULL;
179+
removed.htable[0] = n;
180+
removed.nel = 1;
181+
avtab_destroy(&removed);
182+
if (db->len >= shrink_size)
183+
db->len -= shrink_size;
184+
return true;
185+
}
186+
}
187+
188+
avtab_destroy(&removed);
189+
return false;
190+
}
191+
131192
static bool add_rule(struct policydb *db, const char *s, const char *t, const char *c, const char *p, int effect,
132193
bool invert)
133194
{
@@ -174,26 +235,27 @@ static bool add_rule(struct policydb *db, const char *s, const char *t, const ch
174235
return false;
175236
}
176237
}
177-
add_rule_raw(db, src, tgt, cls, perm, effect, invert);
178-
return true;
238+
return add_rule_raw(db, src, tgt, cls, perm, effect, invert);
179239
}
180240

181-
static void add_rule_raw(struct policydb *db, struct type_datum *src, struct type_datum *tgt, struct class_datum *cls,
241+
static bool add_rule_raw(struct policydb *db, struct type_datum *src, struct type_datum *tgt, struct class_datum *cls,
182242
struct perm_datum *perm, int effect, bool invert)
183243
{
244+
bool success = true;
245+
184246
if (src == NULL) {
185247
struct hashtab_node *node;
186248
if (strip_av(effect, invert)) {
187249
ksu_hashtab_for_each(db->p_types.table, node)
188250
{
189-
add_rule_raw(db, (struct type_datum *)node->datum, tgt, cls, perm, effect, invert);
251+
success &= add_rule_raw(db, (struct type_datum *)node->datum, tgt, cls, perm, effect, invert);
190252
};
191253
} else {
192254
ksu_hashtab_for_each(db->p_types.table, node)
193255
{
194256
struct type_datum *type = (struct type_datum *)(node->datum);
195257
if (type->attribute) {
196-
add_rule_raw(db, type, tgt, cls, perm, effect, invert);
258+
success &= add_rule_raw(db, type, tgt, cls, perm, effect, invert);
197259
}
198260
};
199261
}
@@ -202,31 +264,42 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src, struct typ
202264
if (strip_av(effect, invert)) {
203265
ksu_hashtab_for_each(db->p_types.table, node)
204266
{
205-
add_rule_raw(db, src, (struct type_datum *)node->datum, cls, perm, effect, invert);
267+
success &= add_rule_raw(db, src, (struct type_datum *)node->datum, cls, perm, effect, invert);
206268
};
207269
} else {
208270
ksu_hashtab_for_each(db->p_types.table, node)
209271
{
210272
struct type_datum *type = (struct type_datum *)(node->datum);
211273
if (type->attribute) {
212-
add_rule_raw(db, src, type, cls, perm, effect, invert);
274+
success &= add_rule_raw(db, src, type, cls, perm, effect, invert);
213275
}
214276
};
215277
}
216278
} else if (cls == NULL) {
217279
struct hashtab_node *node;
218280
ksu_hashtab_for_each(db->p_classes.table, node)
219281
{
220-
add_rule_raw(db, src, tgt, (struct class_datum *)node->datum, perm, effect, invert);
282+
success &= add_rule_raw(db, src, tgt, (struct class_datum *)node->datum, perm, effect, invert);
221283
}
222284
} else {
223285
struct avtab_key key;
286+
struct avtab_node *node;
287+
224288
key.source_type = src->value;
225289
key.target_type = tgt->value;
226290
key.target_class = cls->value;
227291
key.specified = effect;
228292

229-
struct avtab_node *node = get_avtab_node(db, &key, NULL);
293+
if (invert && effect != AVTAB_AUDITDENY) {
294+
node = avtab_search_node(&db->te_avtab, &key);
295+
if (!node)
296+
return true;
297+
} else {
298+
node = get_avtab_node(db, &key, NULL);
299+
if (!node)
300+
return false;
301+
}
302+
230303
if (invert) {
231304
if (perm)
232305
node->datum.u.data &= ~(1U << (perm->value - 1));
@@ -238,7 +311,11 @@ static void add_rule_raw(struct policydb *db, struct type_datum *src, struct typ
238311
else
239312
node->datum.u.data = ~0U;
240313
}
314+
if (is_redundant_avtab_node(node))
315+
return remove_avtab_node(db, node);
241316
}
317+
318+
return success;
242319
}
243320

244321
#define ioctl_driver(x) (x >> 8 & 0xFF)
@@ -410,6 +487,8 @@ static bool add_type_rule(struct policydb *db, const char *s, const char *t, con
410487
key.specified = effect;
411488

412489
struct avtab_node *node = get_avtab_node(db, &key, NULL);
490+
if (!node)
491+
return false;
413492
node->datum.u.data = def->value;
414493

415494
return true;

0 commit comments

Comments
 (0)