mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
net/sched: dualpi2: clamp psched_mtu at all call sites
dualpi2_calculate_c_protection(), must_drop(), and get_memory_limit()
call psched_mtu() with no clamp. A huge MTU makes (s32)psched_mtu()
overflow in the signed multiply for c_protection_init, and 2 *
psched_mtu() wraps in get_memory_limit(). With a crafted size table
qdisc_pkt_len reaches ~2 GiB, causing a soft lockup / denial of service.
Clamp psched_mtu() to [1, 1<<20] at all three call sites.
Conditions to recreate the bug:
CONFIG_NET_SCH_DUALPI2=y. Requires CAP_NET_ADMIN (namespace-local via
unshare -Urn suffices).
tc qdisc add dev dummy0 root dualpi2
tc qdisc change dev dummy0 root dualpi2 stab data 32768 size_log 15 cell_log 0
Fixes: 320d031ad6 ("sched: Struct definition and parsing of dualpi2 qdisc")
Reported-by: Vega <vega@nebusec.ai>
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
Link: https://patch.msgid.link/QDISC-0CFC.v3.20260901204856@mojatatu.com.6
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
eb56a495f5
commit
3c01f1ca5d
|
|
@ -208,9 +208,11 @@ static void dualpi2_reset_c_protection(struct dualpi2_sched_data *q)
|
|||
static void dualpi2_calculate_c_protection(struct Qdisc *sch,
|
||||
struct dualpi2_sched_data *q, u32 wc)
|
||||
{
|
||||
u32 mtu = clamp_t(u32, psched_mtu(qdisc_dev(sch)), 1, 1 << 20);
|
||||
|
||||
q->c_protection_wc = wc;
|
||||
q->c_protection_wl = MAX_WC - wc;
|
||||
q->c_protection_init = (s32)psched_mtu(qdisc_dev(sch)) *
|
||||
q->c_protection_init = (s32)mtu *
|
||||
((int)q->c_protection_wc - (int)q->c_protection_wl);
|
||||
dualpi2_reset_c_protection(q);
|
||||
}
|
||||
|
|
@ -285,8 +287,9 @@ static bool must_drop(struct Qdisc *sch, struct dualpi2_sched_data *q,
|
|||
u64 local_l_prob;
|
||||
bool overload;
|
||||
u32 prob;
|
||||
u32 mtu = clamp_t(u32, psched_mtu(qdisc_dev(sch)), 1, 1 << 20);
|
||||
|
||||
if (sch->qstats.backlog < 2 * psched_mtu(qdisc_dev(sch)))
|
||||
if (sch->qstats.backlog < 2 * mtu)
|
||||
return false;
|
||||
|
||||
prob = READ_ONCE(q->pi2_prob);
|
||||
|
|
@ -712,7 +715,8 @@ static u32 get_memory_limit(struct Qdisc *sch, u32 limit)
|
|||
/* Apply rule of thumb, i.e., doubling the packet length,
|
||||
* to further include per packet overhead in memory_limit.
|
||||
*/
|
||||
u64 memlim = mul_u32_u32(limit, 2 * psched_mtu(qdisc_dev(sch)));
|
||||
u64 memlim = mul_u32_u32(limit, 2 * clamp_t(u32, psched_mtu(qdisc_dev(sch)),
|
||||
1, 1 << 20));
|
||||
|
||||
if (upper_32_bits(memlim))
|
||||
return U32_MAX;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user