Skip to content

[CBR 7.9] CVE-2023-1281 #401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions include/linux/rcupdate.h
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,24 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
#define rcu_assign_pointer(p, v) \
__rcu_assign_pointer((p), (v), __rcu)

/**
* rcu_replace_pointer() - replace an RCU pointer, returning its old value
* @rcu_ptr: RCU pointer, whose old value is returned
* @ptr: regular pointer
* @c: the lockdep conditions under which the dereference will take place
*
* Perform a replacement, where @rcu_ptr is an RCU-annotated
* pointer and @c is the lockdep argument that is passed to the
* rcu_dereference_protected() call used to read that pointer. The old
* value of @rcu_ptr is returned, and @rcu_ptr is set to @ptr.
*/
#define rcu_replace_pointer(rcu_ptr, ptr, c) \
({ \
typeof(ptr) __tmp = rcu_dereference_protected((rcu_ptr), (c)); \
rcu_assign_pointer((rcu_ptr), (ptr)); \
__tmp; \
})

/**
* RCU_INIT_POINTER() - initialize an RCU protected pointer
*
Expand Down
34 changes: 30 additions & 4 deletions net/sched/cls_tcindex.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/skbuff.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/rcupdate.h>
#include <net/act_api.h>
#include <net/netlink.h>
#include <net/pkt_cls.h>
Expand Down Expand Up @@ -313,6 +314,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
struct tcindex_filter *f = NULL; /* make gcc behave */
int err, balloc = 0;
struct tcf_exts e;
bool update_h = false;

err = tcf_exts_init(&e, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE);
if (err < 0)
Expand Down Expand Up @@ -427,10 +429,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);
Expand Down Expand Up @@ -464,7 +469,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 == (u16)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;

Expand Down