Re: [PATCH 1/1] audit: fix potential use-after-free in audit_del_rule()
Lain Anc <[email protected]> Fri, 24 Jul 2026 11:10:51 +0800
| Newsgroups | org.kernel.vger.audit |
|---|---|
| Message-ID | <CANZytUwnnaq0U3UU3R9ZhyyW=E0mF2+8uHFDtjodk8QMCcDK3Q@mail.gmail.com> |
Paul Moore <[email protected]> =E4=BA=8E2026=E5=B9=B47=E6=9C=8824=E6=97= =A5=E5=91=A8=E4=BA=94 05:57=E5=86=99=E9=81=93=EF=BC=9A > > On Jul 21, 2026 Ren Wei <[email protected]> wrote: > > > > `audit_del_rule()` destroys `e->rule.exe` via `audit_remove_mark_rule()= ` > > before unlinking the rule from RCU-visible filter lists and waiting for= a > > grace period. Concurrent readers in `audit_filter()` and > > `audit_filter_rules()` still dereference `e->rule.exe`, while the fsnot= ify > > mark can be freed on an independent lifetime path. This creates a use-a= fter-free > > window during rule deletion. > > > > Fix this by unlinking the rule from the RCU-visible lists and invoking > > `synchronize_rcu()` before calling `audit_remove_mark_rule()` (and othe= r > > rule removal helpers). This ensures that all existing RCU readers have = exited > > the critical section before any underlying resources are destroyed. > > > > Fixes: 34d99af52ad4 ("audit: implement audit by executable") > > Cc: [email protected] > > Reported-by: Vega <[email protected]> > > Assisted-by: Codex:gpt-5.4 > > Signed-off-by: Luxiao Xu <[email protected]> > > Signed-off-by: Ren Wei <[email protected]> > > --- > > kernel/auditfilter.c | 6 ++++-- > > 1 file changed, 4 insertions(+), 2 deletions(-) > > Thanks for identifying this and providing a patch, some initial thoughts > below ... > > > diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c > > index 4401119b5275..7f791afe5791 100644 > > --- a/kernel/auditfilter.c > > +++ b/kernel/auditfilter.c > > @@ -1045,6 +1045,10 @@ int audit_del_rule(struct audit_entry *entry) > > goto out; > > } > > > > + list_del_rcu(&e->list); > > + list_del(&e->rule.list); > > + synchronize_rcu(); > > I generally prefer to use call_rcu() instead of synchronize_rcu() when > possible. Did you consider creating a audit_del_rule_rcu() (or similar) > function which would perform the other cleanups/releases below this point > including the call to audit_free_rule_rcu() which could then be called > by call_rcu()? > > It's worth mentioning that I didn't verify all of the code involved to > know if this would work, be safe, etc., I just wanted to check to see if > you already had and decided synchronize_rcu() was the only option. > Thanks for reviewing the patch and for the suggestion! I did look into using call_rcu() for the cleanup, but we cannot do so due to sleeping constraints in RCU callbacks. Specifically, the cleanup helpers called during rule deletion (such as audit_remove_mark_rule(), audit_remove_watch_rule(), and audit_remove_tree_rule()) can sleep. For instance, removing a mark via audit_remove_mark_rule() eventually calls fsnotify_destroy_mark(), which acquires mutexes (e.g., group->mark_mutex) and can block. Since call_rcu() callbacks run in softirq (atomic) context, invoking these sleeping functions there would trigger a "scheduling while atomic" bug. audit_del_rule() runs in process context, which allows it to safely sleep during synchronize_rcu() and the subsequent rule/mark removals. Therefore, synchronize_rcu() appears to be the necessary choice here. > > if (e->rule.watch) > > audit_remove_watch_rule(&e->rule); > > > > @@ -1062,8 +1066,6 @@ int audit_del_rule(struct audit_entry *entry) > > audit_signals--; > > #endif > > > > - list_del_rcu(&e->list); > > - list_del(&e->rule.list); > > call_rcu(&e->rcu, audit_free_rule_rcu); > > > > out: > > -- > > 2.43.0 > > -- > paul-moore.com