From 84eda7845563ee9c0cc215fe9d0a3c67cb4903fd Mon Sep 17 00:00:00 2001 From: Ryan Sullivan Date: Thu, 1 Feb 2024 14:36:30 -0500 Subject: [KPATCH CVE-2023-4921] kpatch fixes for CVE-2023-4921 Kernels: 3.10.0-1160.95.1.el7 3.10.0-1160.99.1.el7 3.10.0-1160.102.1.el7 3.10.0-1160.105.1.el7 3.10.0-1160.108.1.el7 Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-7/-/merge_requests/67 Approved-by: Joe Lawrence (@joe.lawrence) Changes since last build: [x86_64]: igb_main.o: changed function: igb_configure l2cap_core.o: changed function: l2cap_chan_hold l2cap_core.o: changed function: l2cap_conn_get l2cap_core.o: changed function: l2cap_global_chan_by_psm l2cap_core.o: changed function: l2cap_recv_frame l2cap_core.o: new function: klp_l2cap_le_sig_cmd sch_atm.o: changed function: atm_tc_peek sch_atm.o: changed function: sch_atm_dequeue sch_drr.o: changed function: drr_dequeue sch_dsmark.o: changed function: dsmark_peek sch_hfsc.o: changed function: hfsc_enqueue sch_hfsc.o: changed function: qdisc_peek_len sch_multiq.o: changed function: multiq_peek sch_prio.o: changed function: prio_peek sch_qfq.o: changed function: qfq_change_class sch_qfq.o: changed function: qfq_dequeue sch_red.o: changed function: red_peek sch_sfb.o: changed function: sfb_peek sch_tbf.o: changed function: tbf_dequeue [ppc64le]: l2cap_core.o: changed function: __l2cap_chan_add l2cap_core.o: changed function: __l2cap_physical_cfm l2cap_core.o: changed function: __set_monitor_timer l2cap_core.o: changed function: __set_retrans_timer.part.24 l2cap_core.o: changed function: l2cap_ack_timeout l2cap_core.o: changed function: l2cap_build_conf_req l2cap_core.o: changed function: l2cap_chan_busy l2cap_core.o: changed function: l2cap_chan_close l2cap_core.o: changed function: l2cap_chan_connect l2cap_core.o: changed function: l2cap_chan_del l2cap_core.o: changed function: l2cap_chan_hold l2cap_core.o: changed function: l2cap_chan_put l2cap_core.o: changed function: l2cap_chan_send l2cap_core.o: changed function: l2cap_chan_timeout l2cap_core.o: changed function: l2cap_conn_add.part.28 l2cap_core.o: changed function: l2cap_conn_del l2cap_core.o: changed function: l2cap_conn_start l2cap_core.o: changed function: l2cap_connect l2cap_core.o: changed function: l2cap_connect_cfm l2cap_core.o: changed function: l2cap_connect_create_rsp l2cap_core.o: changed function: l2cap_data_channel l2cap_core.o: changed function: l2cap_disconn_cfm l2cap_core.o: changed function: l2cap_do_create l2cap_core.o: changed function: l2cap_do_start l2cap_core.o: changed function: l2cap_ertm_resend l2cap_core.o: changed function: l2cap_ertm_send l2cap_core.o: changed function: l2cap_global_fixed_chan l2cap_core.o: changed function: l2cap_handle_rej l2cap_core.o: changed function: l2cap_handle_srej l2cap_core.o: changed function: l2cap_logical_cfm l2cap_core.o: changed function: l2cap_monitor_timeout l2cap_core.o: changed function: l2cap_move_done l2cap_core.o: changed function: l2cap_move_setup l2cap_core.o: changed function: l2cap_parse_conf_rsp.constprop.36 l2cap_core.o: changed function: l2cap_pass_to_tx l2cap_core.o: changed function: l2cap_process_reqseq l2cap_core.o: changed function: l2cap_recv_frame l2cap_core.o: changed function: l2cap_retrans_timeout l2cap_core.o: changed function: l2cap_retransmit_all l2cap_core.o: changed function: l2cap_rx l2cap_core.o: changed function: l2cap_rx_state_recv l2cap_core.o: changed function: l2cap_security_cfm l2cap_core.o: changed function: l2cap_send_ack l2cap_core.o: changed function: l2cap_send_efs_conf_rsp l2cap_core.o: changed function: l2cap_send_i_or_rr_or_rnr l2cap_core.o: changed function: l2cap_send_move_chan_cfm l2cap_core.o: changed function: l2cap_send_move_chan_cfm_icid l2cap_core.o: changed function: l2cap_send_move_chan_req l2cap_core.o: changed function: l2cap_send_rr_or_rnr l2cap_core.o: changed function: l2cap_send_sframe l2cap_core.o: changed function: l2cap_send_srej l2cap_core.o: changed function: l2cap_send_srej_tail l2cap_core.o: changed function: l2cap_start_connection l2cap_core.o: new function: l2cap_connect_req sch_atm.o: changed function: atm_tc_bind_filter sch_atm.o: changed function: atm_tc_change sch_atm.o: changed function: atm_tc_delete sch_atm.o: changed function: atm_tc_destroy sch_atm.o: changed function: atm_tc_enqueue sch_atm.o: changed function: atm_tc_find sch_atm.o: changed function: atm_tc_graft sch_atm.o: changed function: atm_tc_leaf sch_atm.o: changed function: atm_tc_peek sch_atm.o: changed function: atm_tc_put sch_atm.o: changed function: atm_tc_reset sch_atm.o: changed function: atm_tc_tcf_block sch_atm.o: changed function: sch_atm_dequeue sch_drr.o: changed function: drr_dequeue sch_dsmark.o: changed function: dsmark_bind_filter sch_dsmark.o: changed function: dsmark_change sch_dsmark.o: changed function: dsmark_destroy sch_dsmark.o: changed function: dsmark_dump_class sch_dsmark.o: changed function: dsmark_init sch_dsmark.o: changed function: dsmark_peek sch_dsmark.o: changed function: dsmark_reset sch_hfsc.o: changed function: hfsc_change_class sch_hfsc.o: changed function: hfsc_dequeue sch_hfsc.o: changed function: hfsc_enqueue sch_multiq.o: changed function: multiq_peek sch_prio.o: changed function: prio_peek sch_qfq.o: changed function: qfq_change_class sch_qfq.o: changed function: qfq_dequeue sch_red.o: changed function: red_peek sch_sfb.o: changed function: sfb_peek sch_tbf.o: changed function: tbf_dequeue --------------------------- Modifications: - redirected to qdisc_peek_dequeued() by modifying functions that called '->peek(qdisc)' to call klp_cve_2023_4921_peek() rather than by modifying plug_qdisc_ops - don't remove existing WARN_ONCE instances to avoid kpatch-build "unreconcilable difference" error in .data.once section commit faf95907a10c29861882d7885b6e04ebe20057c8 Author: Davide Caratti Date: Fri Oct 27 17:22:42 2023 +0200 net: sched: sch_qfq: Fix UAF in qfq_dequeue() JIRA: https://issues.redhat.com/browse/RHEL-14397 CVE: CVE-2023-4921 Upstream Status: net.git commit 8fc134fee27f2263988ae38920bc03da416b03d8 commit 8fc134fee27f2263988ae38920bc03da416b03d8 Author: valis Date: Fri Sep 1 12:22:37 2023 -0400 net: sched: sch_qfq: Fix UAF in qfq_dequeue() When the plug qdisc is used as a class of the qfq qdisc it could trigger a UAF. This issue can be reproduced with following commands: tc qdisc add dev lo root handle 1: qfq tc class add dev lo parent 1: classid 1:1 qfq weight 1 maxpkt 512 tc qdisc add dev lo parent 1:1 handle 2: plug tc filter add dev lo parent 1: basic classid 1:1 ping -c1 127.0.0.1 and boom: [ 285.353793] BUG: KASAN: slab-use-after-free in qfq_dequeue+0xa7/0x7f0 [ 285.354910] Read of size 4 at addr ffff8880bad312a8 by task ping/144 [ 285.355903] [ 285.356165] CPU: 1 PID: 144 Comm: ping Not tainted 6.5.0-rc3+ #4 [ 285.357112] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014 [ 285.358376] Call Trace: [ 285.358773] [ 285.359109] dump_stack_lvl+0x44/0x60 [ 285.359708] print_address_description.constprop.0+0x2c/0x3c0 [ 285.360611] kasan_report+0x10c/0x120 [ 285.361195] ? qfq_dequeue+0xa7/0x7f0 [ 285.361780] qfq_dequeue+0xa7/0x7f0 [ 285.362342] __qdisc_run+0xf1/0x970 [ 285.362903] net_tx_action+0x28e/0x460 [ 285.363502] __do_softirq+0x11b/0x3de [ 285.364097] do_softirq.part.0+0x72/0x90 [ 285.364721] [ 285.365072] [ 285.365422] __local_bh_enable_ip+0x77/0x90 [ 285.366079] __dev_queue_xmit+0x95f/0x1550 [ 285.366732] ? __pfx_csum_and_copy_from_iter+0x10/0x10 [ 285.367526] ? __pfx___dev_queue_xmit+0x10/0x10 [ 285.368259] ? __build_skb_around+0x129/0x190 [ 285.368960] ? ip_generic_getfrag+0x12c/0x170 [ 285.369653] ? __pfx_ip_generic_getfrag+0x10/0x10 [ 285.370390] ? csum_partial+0x8/0x20 [ 285.370961] ? raw_getfrag+0xe5/0x140 [ 285.371559] ip_finish_output2+0x539/0xa40 [ 285.372222] ? __pfx_ip_finish_output2+0x10/0x10 [ 285.372954] ip_output+0x113/0x1e0 [ 285.373512] ? __pfx_ip_output+0x10/0x10 [ 285.374130] ? icmp_out_count+0x49/0x60 [ 285.374739] ? __pfx_ip_finish_output+0x10/0x10 [ 285.375457] ip_push_pending_frames+0xf3/0x100 [ 285.376173] raw_sendmsg+0xef5/0x12d0 [ 285.376760] ? do_syscall_64+0x40/0x90 [ 285.377359] ? __static_call_text_end+0x136578/0x136578 [ 285.378173] ? do_syscall_64+0x40/0x90 [ 285.378772] ? kasan_enable_current+0x11/0x20 [ 285.379469] ? __pfx_raw_sendmsg+0x10/0x10 [ 285.380137] ? __sock_create+0x13e/0x270 [ 285.380673] ? __sys_socket+0xf3/0x180 [ 285.381174] ? __x64_sys_socket+0x3d/0x50 [ 285.381725] ? entry_SYSCALL_64_after_hwframe+0x6e/0xd8 [ 285.382425] ? __rcu_read_unlock+0x48/0x70 [ 285.382975] ? ip4_datagram_release_cb+0xd8/0x380 [ 285.383608] ? __pfx_ip4_datagram_release_cb+0x10/0x10 [ 285.384295] ? preempt_count_sub+0x14/0xc0 [ 285.384844] ? __list_del_entry_valid+0x76/0x140 [ 285.385467] ? _raw_spin_lock_bh+0x87/0xe0 [ 285.386014] ? __pfx__raw_spin_lock_bh+0x10/0x10 [ 285.386645] ? release_sock+0xa0/0xd0 [ 285.387148] ? preempt_count_sub+0x14/0xc0 [ 285.387712] ? freeze_secondary_cpus+0x348/0x3c0 [ 285.388341] ? aa_sk_perm+0x177/0x390 [ 285.388856] ? __pfx_aa_sk_perm+0x10/0x10 [ 285.389441] ? check_stack_object+0x22/0x70 [ 285.390032] ? inet_send_prepare+0x2f/0x120 [ 285.390603] ? __pfx_inet_sendmsg+0x10/0x10 [ 285.391172] sock_sendmsg+0xcc/0xe0 [ 285.391667] __sys_sendto+0x190/0x230 [ 285.392168] ? __pfx___sys_sendto+0x10/0x10 [ 285.392727] ? kvm_clock_get_cycles+0x14/0x30 [ 285.393328] ? set_normalized_timespec64+0x57/0x70 [ 285.393980] ? _raw_spin_unlock_irq+0x1b/0x40 [ 285.394578] ? __x64_sys_clock_gettime+0x11c/0x160 [ 285.395225] ? __pfx___x64_sys_clock_gettime+0x10/0x10 [ 285.395908] ? _copy_to_user+0x3e/0x60 [ 285.396432] ? exit_to_user_mode_prepare+0x1a/0x120 [ 285.397086] ? syscall_exit_to_user_mode+0x22/0x50 [ 285.397734] ? do_syscall_64+0x71/0x90 [ 285.398258] __x64_sys_sendto+0x74/0x90 [ 285.398786] do_syscall_64+0x64/0x90 [ 285.399273] ? exit_to_user_mode_prepare+0x1a/0x120 [ 285.399949] ? syscall_exit_to_user_mode+0x22/0x50 [ 285.400605] ? do_syscall_64+0x71/0x90 [ 285.401124] entry_SYSCALL_64_after_hwframe+0x6e/0xd8 [ 285.401807] RIP: 0033:0x495726 [ 285.402233] Code: ff ff ff f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b8 0f 1f 00 41 89 ca 64 8b 04 25 18 00 00 00 85 c0 75 11 b8 2c 00 00 00 0f 09 [ 285.404683] RSP: 002b:00007ffcc25fb618 EFLAGS: 00000246 ORIG_RAX: 000000000000002c [ 285.405677] RAX: ffffffffffffffda RBX: 0000000000000040 RCX: 0000000000495726 [ 285.406628] RDX: 0000000000000040 RSI: 0000000002518750 RDI: 0000000000000000 [ 285.407565] RBP: 00000000005205ef R08: 00000000005f8838 R09: 000000000000001c [ 285.408523] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000002517634 [ 285.409460] R13: 00007ffcc25fb6f0 R14: 0000000000000003 R15: 0000000000000000 [ 285.410403] [ 285.410704] [ 285.410929] Allocated by task 144: [ 285.411402] kasan_save_stack+0x1e/0x40 [ 285.411926] kasan_set_track+0x21/0x30 [ 285.412442] __kasan_slab_alloc+0x55/0x70 [ 285.412973] kmem_cache_alloc_node+0x187/0x3d0 [ 285.413567] __alloc_skb+0x1b4/0x230 [ 285.414060] __ip_append_data+0x17f7/0x1b60 [ 285.414633] ip_append_data+0x97/0xf0 [ 285.415144] raw_sendmsg+0x5a8/0x12d0 [ 285.415640] sock_sendmsg+0xcc/0xe0 [ 285.416117] __sys_sendto+0x190/0x230 [ 285.416626] __x64_sys_sendto+0x74/0x90 [ 285.417145] do_syscall_64+0x64/0x90 [ 285.417624] entry_SYSCALL_64_after_hwframe+0x6e/0xd8 [ 285.418306] [ 285.418531] Freed by task 144: [ 285.418960] kasan_save_stack+0x1e/0x40 [ 285.419469] kasan_set_track+0x21/0x30 [ 285.419988] kasan_save_free_info+0x27/0x40 [ 285.420556] ____kasan_slab_free+0x109/0x1a0 [ 285.421146] kmem_cache_free+0x1c2/0x450 [ 285.421680] __netif_receive_skb_core+0x2ce/0x1870 [ 285.422333] __netif_receive_skb_one_core+0x97/0x140 [ 285.423003] process_backlog+0x100/0x2f0 [ 285.423537] __napi_poll+0x5c/0x2d0 [ 285.424023] net_rx_action+0x2be/0x560 [ 285.424510] __do_softirq+0x11b/0x3de [ 285.425034] [ 285.425254] The buggy address belongs to the object at ffff8880bad31280 [ 285.425254] which belongs to the cache skbuff_head_cache of size 224 [ 285.426993] The buggy address is located 40 bytes inside of [ 285.426993] freed 224-byte region [ffff8880bad31280, ffff8880bad31360) [ 285.428572] [ 285.428798] The buggy address belongs to the physical page: [ 285.429540] page:00000000f4b77674 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xbad31 [ 285.430758] flags: 0x100000000000200(slab|node=0|zone=1) [ 285.431447] page_type: 0xffffffff() [ 285.431934] raw: 0100000000000200 ffff88810094a8c0 dead000000000122 0000000000000000 [ 285.432757] raw: 0000000000000000 00000000800c000c 00000001ffffffff 0000000000000000 [ 285.433562] page dumped because: kasan: bad access detected [ 285.434144] [ 285.434320] Memory state around the buggy address: [ 285.434828] ffff8880bad31180: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 285.435580] ffff8880bad31200: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 285.436264] >ffff8880bad31280: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 285.436777] ^ [ 285.437106] ffff8880bad31300: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc [ 285.437616] ffff8880bad31380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 285.438126] ================================================================== [ 285.438662] Disabling lock debugging due to kernel taint Fix this by: 1. Changing sch_plug's .peek handler to qdisc_peek_dequeued(), a function compatible with non-work-conserving qdiscs 2. Checking the return value of qdisc_dequeue_peeked() in sch_qfq. Fixes: 462dbc9101ac ("pkt_sched: QFQ Plus: fair-queueing service at DRR cost") Reported-by: valis Signed-off-by: valis Signed-off-by: Jamal Hadi Salim Link: https://lore.kernel.org/r/20230901162237.11525-1-jhs@mojatatu.com Signed-off-by: Paolo Abeni Signed-off-by: Davide Caratti commit eb76ae2165f95d31ad199d706840140b271c719e Author: Davide Caratti Date: Thu Jan 25 15:45:42 2024 +0100 net: sched: sch_qfq: Use non-work-conserving warning handler JIRA: https://issues.redhat.com/browse/RHEL-14397 Upstream Status: net.git commit 6d25d1dc76bf5943a5c1f4bb74d66d5eac58eb77 commit 6d25d1dc76bf5943a5c1f4bb74d66d5eac58eb77 Author: Liu Jian Date: Mon Oct 23 14:47:29 2023 +0800 net: sched: sch_qfq: Use non-work-conserving warning handler A helper function for printing non-work-conserving alarms is added in commit b00355db3f88 ("pkt_sched: sch_hfsc: sch_htb: Add non-work-conserving warning handler."). In this commit, use qdisc_warn_nonwc() instead of WARN_ONCE() to handle the non-work-conserving warning in qfq Qdisc. Signed-off-by: Liu Jian Link: https://lore.kernel.org/r/20231023064729.370649-1-liujian56@huawei.com Signed-off-by: Paolo Abeni Signed-off-by: Davide Caratti Signed-off-by: Ryan Sullivan --- net/sched/klp_cve_2023_4921.h | 16 +++++++++++++ net/sched/sch_atm.c | 5 ++-- net/sched/sch_drr.c | 3 ++- net/sched/sch_dsmark.c | 3 ++- net/sched/sch_hfsc.c | 7 +++--- net/sched/sch_multiq.c | 4 +++- net/sched/sch_prio.c | 6 ++++- net/sched/sch_qfq.c | 43 ++++++++++++++++++++++++++--------- net/sched/sch_red.c | 3 ++- net/sched/sch_sfb.c | 3 ++- net/sched/sch_tbf.c | 3 ++- 11 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 net/sched/klp_cve_2023_4921.h diff --git a/net/sched/klp_cve_2023_4921.h b/net/sched/klp_cve_2023_4921.h new file mode 100644 index 000000000000..07a5624a487c --- /dev/null +++ b/net/sched/klp_cve_2023_4921.h @@ -0,0 +1,16 @@ +#ifndef __KLP_CVE_2023_4921__ +#define __KLP_CVE_2023_4921__ + +static inline struct sk_buff *klp_cve_2023_4921_peek(struct Qdisc *sch) +{ + /* + * kpatch workaround: can't modify plug_qdisc_ops structure, so + * provide a peek pivot based on the underlying qdisc ops id + */ + if (strcmp(sch->ops->id, "plug") == 0) + return qdisc_peek_dequeued(sch); + + return sch->ops->peek(sch); +} + +#endif diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 7c8966a42794..d58c84b3fba2 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -16,6 +16,7 @@ #include #include #include +#include "klp_cve_2023_4921.h" /* * The ATM queuing discipline provides a framework for invoking classifiers @@ -474,7 +475,7 @@ static void sch_atm_dequeue(unsigned long data) * If traffic is properly shaped, this won't generate nasty * little bursts. Otherwise, it may ... (but that's okay) */ - while ((skb = flow->q->ops->peek(flow->q))) { + while ((skb = klp_cve_2023_4921_peek(flow->q))) { if (!atm_may_send(flow->vcc, skb->truesize)) break; @@ -528,7 +529,7 @@ static struct sk_buff *atm_tc_peek(struct Qdisc *sch) pr_debug("atm_tc_peek(sch %p,[qdisc %p])\n", sch, p); - return p->link.q->ops->peek(p->link.q); + return klp_cve_2023_4921_peek(p->link.q); } static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 9bfe7b50115f..27dd8e610da2 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -17,6 +17,7 @@ #include #include #include +#include "klp_cve_2023_4921.h" struct drr_class { struct Qdisc_class_common common; @@ -378,7 +379,7 @@ static struct sk_buff *drr_dequeue(struct Qdisc *sch) goto out; while (1) { cl = list_first_entry(&q->active, struct drr_class, alist); - skb = cl->qdisc->ops->peek(cl->qdisc); + skb = klp_cve_2023_4921_peek(cl->qdisc); if (skb == NULL) { qdisc_warn_nonwc(__func__, cl->qdisc); goto out; diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index df08e15e6f19..06b6e03f89ea 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -17,6 +17,7 @@ #include #include #include +#include "klp_cve_2023_4921.h" /* * classid class marking @@ -327,7 +328,7 @@ static struct sk_buff *dsmark_peek(struct Qdisc *sch) pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p); - return p->q->ops->peek(p->q); + return klp_cve_2023_4921_peek(p->q); } static int dsmark_init(struct Qdisc *sch, struct nlattr *opt) diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index fb14b551f65d..466244c57737 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -67,6 +67,7 @@ #include #include #include +#include "klp_cve_2023_4921.h" /* * kernel internal service curve representation: @@ -834,7 +835,8 @@ qdisc_peek_len(struct Qdisc *sch) struct sk_buff *skb; unsigned int len; - skb = sch->ops->peek(sch); + skb = klp_cve_2023_4921_peek(sch); + if (unlikely(skb == NULL)) { qdisc_warn_nonwc("qdisc_peek_len", sch); return 0; @@ -1567,8 +1569,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) * to invalidate the deadline. */ if (cl->cl_flags & HFSC_RSC) - cl->qdisc->ops->peek(cl->qdisc); - + klp_cve_2023_4921_peek(cl->qdisc); } qdisc_qstats_backlog_inc(sch, skb); diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 31e0a284eeff..8f6e85b2c8b8 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -26,6 +26,7 @@ #include #include #include +#include "klp_cve_2023_4921.h" struct multiq_sched_data { u16 bands; @@ -145,7 +146,8 @@ static struct sk_buff *multiq_peek(struct Qdisc *sch) if (!netif_xmit_stopped( netdev_get_tx_queue(qdisc_dev(sch), curband))) { qdisc = q->queues[curband]; - skb = qdisc->ops->peek(qdisc); + skb = klp_cve_2023_4921_peek(qdisc); + if (skb) return skb; } diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index faf447b60b68..23526ef54f0c 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -21,6 +21,7 @@ #include #include #include +#include "klp_cve_2023_4921.h" struct prio_sched_data { int bands; @@ -103,7 +104,10 @@ static struct sk_buff *prio_peek(struct Qdisc *sch) for (prio = 0; prio < q->bands; prio++) { struct Qdisc *qdisc = q->queues[prio]; - struct sk_buff *skb = qdisc->ops->peek(qdisc); + struct sk_buff *skb; + + skb = klp_cve_2023_4921_peek(qdisc); + if (skb) return skb; } diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index ca8c79456c80..134cd66225c0 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include "klp_cve_2023_4921.h" /* Quick Fair Queueing Plus @@ -984,19 +986,24 @@ static void qfq_update_eligible(struct qfq_sched *q) } /* Dequeue head packet of the head class in the DRR queue of the aggregate. */ -static void agg_dequeue(struct qfq_aggregate *agg, - struct qfq_class *cl, unsigned int len) +static struct sk_buff *agg_dequeue(struct qfq_aggregate *agg, + struct qfq_class *cl, unsigned int len) { - qdisc_dequeue_peeked(cl->qdisc); + struct sk_buff *skb = qdisc_dequeue_peeked(cl->qdisc); + + if (!skb) + return NULL; cl->deficit -= (int) len; if (cl->qdisc->q.qlen == 0) /* no more packets, remove from list */ list_del(&cl->alist); - else if (cl->deficit < qdisc_pkt_len(cl->qdisc->ops->peek(cl->qdisc))) { + else if (cl->deficit < qdisc_pkt_len(klp_cve_2023_4921_peek(cl->qdisc))) { cl->deficit += agg->lmax; list_move_tail(&cl->alist, &agg->active); } + + return skb; } static inline struct sk_buff *qfq_peek_skb(struct qfq_aggregate *agg, @@ -1006,10 +1013,16 @@ static inline struct sk_buff *qfq_peek_skb(struct qfq_aggregate *agg, struct sk_buff *skb; *cl = list_first_entry(&agg->active, struct qfq_class, alist); - skb = (*cl)->qdisc->ops->peek((*cl)->qdisc); - if (skb == NULL) - WARN_ONCE(1, "qfq_dequeue: non-workconserving leaf\n"); - else + skb = klp_cve_2023_4921_peek((*cl)->qdisc); + if (skb == NULL) { + /* + * kpatch-build workaround: keep old WARN_ONCE to avoid + * create-diff-object unreconcilable difference from + * unsupported .data.once section change. + */ + WARN_ONCE(!jiffies, "qfq_dequeue: non-workconserving leaf\n"); + qdisc_warn_nonwc("qfq_dequeue", (*cl)->qdisc); + } else *len = qdisc_pkt_len(skb); return skb; @@ -1142,11 +1155,18 @@ static struct sk_buff *qfq_dequeue(struct Qdisc *sch) if (!skb) return NULL; - qdisc_qstats_backlog_dec(sch, skb); sch->q.qlen--; + + skb = agg_dequeue(in_serv_agg, cl, len); + + if (!skb) { + sch->q.qlen++; + return NULL; + } + + qdisc_qstats_backlog_dec(sch, skb); qdisc_bstats_update(sch, skb); - agg_dequeue(in_serv_agg, cl, len); /* If lmax is lowered, through qfq_change_class, for a class * owning pending packets with larger size than the new value * of lmax, then the following condition may hold. @@ -1224,6 +1244,7 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, } pr_debug("qfq_enqueue: cl = %x\n", cl->common.classid); + if (unlikely(cl->agg->lmax < qdisc_pkt_len(skb))) { pr_debug("qfq: increasing maxpkt from %u to %u for class %u", cl->agg->lmax, qdisc_pkt_len(skb), cl->common.classid); @@ -1252,7 +1273,7 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch, agg = cl->agg; /* if the queue was not empty, then done here */ if (cl->qdisc->q.qlen != 1) { - if (unlikely(skb == cl->qdisc->ops->peek(cl->qdisc)) && + if (unlikely(skb == klp_cve_2023_4921_peek(cl->qdisc)) && list_first_entry(&agg->active, struct qfq_class, alist) == cl && cl->deficit < qdisc_pkt_len(skb)) list_move_tail(&cl->alist, &agg->active); diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index e4789760457a..eea80e402219 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -22,6 +22,7 @@ #include #include #include +#include "klp_cve_2023_4921.h" /* Parameters, settable by user: @@ -135,7 +136,7 @@ static struct sk_buff *red_peek(struct Qdisc *sch) struct red_sched_data *q = qdisc_priv(sch); struct Qdisc *child = q->qdisc; - return child->ops->peek(child); + return klp_cve_2023_4921_peek(child); } static void red_reset(struct Qdisc *sch) diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index aeb509bde740..f8d75735351f 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -27,6 +27,7 @@ #include #include #include +#include "klp_cve_2023_4921.h" /* * SFB uses two B[l][n] : L x N arrays of bins (L levels, N bins per level) @@ -445,7 +446,7 @@ static struct sk_buff *sfb_peek(struct Qdisc *sch) struct sfb_sched_data *q = qdisc_priv(sch); struct Qdisc *child = q->qdisc; - return child->ops->peek(child); + return klp_cve_2023_4921_peek(child); } /* No sfb_drop -- impossible since the child doesn't return the dropped skb. */ diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 15a19519aa9c..9957adc1b951 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -21,6 +21,7 @@ #include #include #include +#include "klp_cve_2023_4921.h" /* Simple Token Bucket Filter. @@ -214,7 +215,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc *sch) struct tbf_sched_data *q = qdisc_priv(sch); struct sk_buff *skb; - skb = q->qdisc->ops->peek(q->qdisc); + skb = klp_cve_2023_4921_peek(q->qdisc); if (skb) { s64 now; -- 2.44.0