diff --git a/patches.suse/net-sched-tcindex-update-imperfect-hash-filters-resp.patch b/patches.suse/net-sched-tcindex-update-imperfect-hash-filters-resp.patch new file mode 100644 index 0000000..b97b051 --- /dev/null +++ b/patches.suse/net-sched-tcindex-update-imperfect-hash-filters-resp.patch @@ -0,0 +1,100 @@ +From: Pedro Tammela +Date: Thu, 9 Feb 2023 11:37:39 -0300 +Subject: net/sched: tcindex: update imperfect hash filters respecting rcu +Patch-mainline: v6.2 +Git-commit: ee059170b1f7e94e55fa6cadee544e176a6e59c2 +References: CVE-2023-1281 bsc#1209634 + +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: 9b0d4446b569 ("net: sched: avoid atomic swap in tcf_exts_change") +Reported-by: valis +Suggested-by: valis +Signed-off-by: Jamal Hadi Salim +Signed-off-by: Pedro Tammela +Link: https://lore.kernel.org/r/20230209143739.279867-1-pctammela@mojatatu.com +Signed-off-by: Jakub Kicinski +Acked-by: Michal Kubecek + +--- + net/sched/cls_tcindex.c | 34 ++++++++++++++++++++++++++++++---- + 1 file changed, 30 insertions(+), 4 deletions(-) + +--- a/net/sched/cls_tcindex.c ++++ b/net/sched/cls_tcindex.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -338,6 +339,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, + struct tcf_result cr = {}; + int err, balloc = 0; + struct tcf_exts e; ++ bool update_h = false; + + err = tcf_exts_init(&e, net, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); + if (err < 0) +@@ -455,10 +457,13 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, + } + } + +- if (cp->perfect) ++ if (cp->perfect) { + r = cp->perfect + handle; +- else +- r = tcindex_lookup(cp, handle) ? : &new_filter_result; ++ } else { ++ /* imperfect area is updated in-place using rcu */ ++ update_h = !!tcindex_lookup(cp, handle); ++ r = &new_filter_result; ++ } + + if (r == &new_filter_result) { + f = kzalloc(sizeof(*f), GFP_KERNEL); +@@ -492,7 +497,28 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, + + rcu_assign_pointer(tp->root, cp); + +- if (r == &new_filter_result) { ++ if (update_h) { ++ struct tcindex_filter __rcu **fp; ++ struct tcindex_filter *cf; ++ ++ f->result.res = r->res; ++ tcf_exts_change(&f->result.exts, &r->exts); ++ ++ /* imperfect area bucket */ ++ fp = cp->h + (handle % cp->hash); ++ ++ /* lookup the filter, guaranteed to exist */ ++ for (cf = rcu_dereference_bh_rtnl(*fp); cf; ++ fp = &cf->next, cf = rcu_dereference_bh_rtnl(*fp)) ++ if (cf->key == handle) ++ break; ++ ++ f->next = cf->next; ++ ++ cf = rcu_replace_pointer(*fp, f, 1); ++ tcf_exts_get_net(&cf->result.exts); ++ tcf_queue_work(&cf->rwork, tcindex_destroy_fexts_work); ++ } else if (r == &new_filter_result) { + struct tcindex_filter *nfp; + struct tcindex_filter __rcu **fp; + diff --git a/series.conf b/series.conf index 2c01e83..945e885 100644 --- a/series.conf +++ b/series.conf @@ -17427,6 +17427,7 @@ patches.suse/misc-fastrpc-Fix-use-after-free-race-condition-for-m.patch patches.suse/gsmi-fix-null-deref-in-gsmi_get_variable.patch patches.suse/VMCI-Use-threaded-irqs-instead-of-tasklets.patch + patches.suse/net-sched-tcindex-update-imperfect-hash-filters-resp.patch ######################################################## # end of sorted patches