Skip to content

Commit 84b008a

Browse files
pvts-matPlaidCat
authored andcommitted
net/sched: tcindex: update imperfect hash filters respecting rcu
jira VULN-7633 cve CVE-2023-1281 commit-author Pedro Tammela <[email protected]> commit ee05917 The imperfect hash area can be updated while packets are traversing, which will cause a use-after-free when 'tcf_exts_exec()' is called with the destroyed tcf_ext. CPU 0: CPU 1: tcindex_set_parms tcindex_classify tcindex_lookup tcindex_lookup tcf_exts_change tcf_exts_exec [UAF] Stop operating on the shared area directly, by using a local copy, and update the filter with 'rcu_replace_pointer()'. Delete the old filter version only after a rcu grace period elapsed. Fixes: 9b0d444 ("net: sched: avoid atomic swap in tcf_exts_change") Reported-by: valis <[email protected]> Suggested-by: valis <[email protected]> Signed-off-by: Jamal Hadi Salim <[email protected]> Signed-off-by: Pedro Tammela <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]> (cherry picked from commit ee05917) Signed-off-by: Marcin Wcisło <[email protected]>
1 parent e62885c commit 84b008a

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

net/sched/cls_tcindex.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/skbuff.h>
1111
#include <linux/errno.h>
1212
#include <linux/slab.h>
13+
#include <linux/rcupdate.h>
1314
#include <net/act_api.h>
1415
#include <net/netlink.h>
1516
#include <net/pkt_cls.h>
@@ -313,6 +314,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
313314
struct tcindex_filter *f = NULL; /* make gcc behave */
314315
int err, balloc = 0;
315316
struct tcf_exts e;
317+
bool update_h = false;
316318

317319
err = tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
318320
if (err < 0)
@@ -427,10 +429,13 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
427429
}
428430
}
429431

430-
if (cp->perfect)
432+
if (cp->perfect) {
431433
r = cp->perfect + handle;
432-
else
433-
r = tcindex_lookup(cp, handle) ? : &new_filter_result;
434+
} else {
435+
/* imperfect area is updated in-place using rcu */
436+
update_h = !!tcindex_lookup(cp, handle);
437+
r = &new_filter_result;
438+
}
434439

435440
if (r == &new_filter_result) {
436441
f = kzalloc(sizeof(*f), GFP_KERNEL);
@@ -464,7 +469,28 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
464469

465470
rcu_assign_pointer(tp->root, cp);
466471

467-
if (r == &new_filter_result) {
472+
if (update_h) {
473+
struct tcindex_filter __rcu **fp;
474+
struct tcindex_filter *cf;
475+
476+
f->result.res = r->res;
477+
tcf_exts_change(&f->result.exts, &r->exts);
478+
479+
/* imperfect area bucket */
480+
fp = cp->h + (handle % cp->hash);
481+
482+
/* lookup the filter, guaranteed to exist */
483+
for (cf = rcu_dereference_bh_rtnl(*fp); cf;
484+
fp = &cf->next, cf = rcu_dereference_bh_rtnl(*fp))
485+
if (cf->key == handle)
486+
break;
487+
488+
f->next = cf->next;
489+
490+
cf = rcu_replace_pointer(*fp, f, 1);
491+
tcf_exts_get_net(&cf->result.exts);
492+
tcf_queue_work(&cf->rwork, tcindex_destroy_fexts_work);
493+
} else if (r == &new_filter_result) {
468494
struct tcindex_filter *nfp;
469495
struct tcindex_filter __rcu **fp;
470496

0 commit comments

Comments
 (0)