forked from rpms/kernel
114 lines
3.7 KiB
Diff
114 lines
3.7 KiB
Diff
From a11b8451e966830bb9aeaf27a9464fe0ab59907d Mon Sep 17 00:00:00 2001
|
|
From: Jamal Hadi Salim <jhs@mojatatu.com>
|
|
Date: Tue, 8 Aug 2023 10:46:07 +0000
|
|
Subject: [PATCH 2/7] net/sched: tcindex: update imperfect hash filters
|
|
respecting rcu
|
|
|
|
commit ee059170b1f7e94e55fa6cadee544e176a6e59c2 upstream
|
|
Author: Pedro Tammela <pctammela@mojatatu.com>
|
|
Date: Thu Feb 9 11:37:39 2023 -0300
|
|
|
|
net/sched: tcindex: update imperfect hash filters respecting rcu
|
|
|
|
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 <sec@valis.email>
|
|
Suggested-by: valis <sec@valis.email>
|
|
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
|
|
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
|
|
Link: https://lore.kernel.org/r/20230209143739.279867-1-pctammela@mojatatu.com
|
|
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|
|
|
CVE: CVE-2023-1281
|
|
Signed-off-by: Nagappan Ramasamy Palaniappan <nagappan.ramasamy.palaniappan@oracle.com>
|
|
Reviewed-by: Reviewed-by: Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
|
|
Reviewed-by: Laurence Rochfort <laurence.rochfort@oracle.com>
|
|
---
|
|
net/sched/cls_tcindex.c | 34 ++++++++++++++++++++++++++++++----
|
|
1 file changed, 30 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
|
|
index df229a808..83042a101 100644
|
|
--- a/net/sched/cls_tcindex.c
|
|
+++ b/net/sched/cls_tcindex.c
|
|
@@ -11,6 +11,7 @@
|
|
#include <linux/errno.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/refcount.h>
|
|
+#include <linux/rcupdate.h>
|
|
#include <net/act_api.h>
|
|
#include <net/netlink.h>
|
|
#include <net/pkt_cls.h>
|
|
@@ -337,6 +338,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)
|
|
@@ -454,10 +456,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);
|
|
@@ -491,7 +496,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;
|
|
|
|
--
|
|
2.31.1
|
|
|