--- /dev/null
+From stable+bounces-163264-greg=kroah.com@vger.kernel.org Thu Jul 17 14:46:32 2025
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Date: Thu, 17 Jul 2025 05:45:51 -0700
+Subject: net_sched: sch_sfq: annotate data-races around q->perturb_period
+To: stable@vger.kernel.org
+Cc: edumazet@google.com, tavip@google.com, Simon Horman <horms@kernel.org>, Jakub Kicinski <kuba@kernel.org>, Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Message-ID: <20250717124556.589696-2-harshit.m.mogalapalli@oracle.com>
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit a17ef9e6c2c1cf0fc6cd6ca6a9ce525c67d1da7f ]
+
+sfq_perturbation() reads q->perturb_period locklessly.
+Add annotations to fix potential issues.
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://lore.kernel.org/r/20240430180015.3111398-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Harshit: Backport to 5.4.y, conflicts resolved due to missing commit:
+ d636fc5dd692 ("net: sched: add rcu annotations around
+ qdisc->qdisc_sleeping")in 5.4.y ]
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sched/sch_sfq.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/net/sched/sch_sfq.c
++++ b/net/sched/sch_sfq.c
+@@ -611,6 +611,7 @@ static void sfq_perturbation(struct time
+ struct Qdisc *sch = q->sch;
+ spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
+ siphash_key_t nkey;
++ int period;
+
+ get_random_bytes(&nkey, sizeof(nkey));
+ spin_lock(root_lock);
+@@ -619,8 +620,12 @@ static void sfq_perturbation(struct time
+ sfq_rehash(sch);
+ spin_unlock(root_lock);
+
+- if (q->perturb_period)
+- mod_timer(&q->perturb_timer, jiffies + q->perturb_period);
++ /* q->perturb_period can change under us from
++ * sfq_change() and sfq_destroy().
++ */
++ period = READ_ONCE(q->perturb_period);
++ if (period)
++ mod_timer(&q->perturb_timer, jiffies + period);
+ }
+
+ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
+@@ -662,7 +667,7 @@ static int sfq_change(struct Qdisc *sch,
+ q->quantum = ctl->quantum;
+ q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
+ }
+- q->perturb_period = ctl->perturb_period * HZ;
++ WRITE_ONCE(q->perturb_period, ctl->perturb_period * HZ);
+ if (ctl->flows)
+ q->maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS);
+ if (ctl->divisor) {
+@@ -724,7 +729,7 @@ static void sfq_destroy(struct Qdisc *sc
+ struct sfq_sched_data *q = qdisc_priv(sch);
+
+ tcf_block_put(q->block);
+- q->perturb_period = 0;
++ WRITE_ONCE(q->perturb_period, 0);
+ del_timer_sync(&q->perturb_timer);
+ sfq_free(q->ht);
+ sfq_free(q->slots);
--- /dev/null
+From stable+bounces-163260-greg=kroah.com@vger.kernel.org Thu Jul 17 14:46:20 2025
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Date: Thu, 17 Jul 2025 05:45:53 -0700
+Subject: net_sched: sch_sfq: don't allow 1 packet limit
+To: stable@vger.kernel.org
+Cc: edumazet@google.com, tavip@google.com, syzbot <syzkaller@googlegroups.com>, Jakub Kicinski <kuba@kernel.org>, Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Message-ID: <20250717124556.589696-4-harshit.m.mogalapalli@oracle.com>
+
+From: Octavian Purdila <tavip@google.com>
+
+[ Upstream commit 10685681bafce6febb39770f3387621bf5d67d0b ]
+
+The current implementation does not work correctly with a limit of
+1. iproute2 actually checks for this and this patch adds the check in
+kernel as well.
+
+This fixes the following syzkaller reported crash:
+
+UBSAN: array-index-out-of-bounds in net/sched/sch_sfq.c:210:6
+index 65535 is out of range for type 'struct sfq_head[128]'
+CPU: 0 PID: 2569 Comm: syz-executor101 Not tainted 5.10.0-smp-DEV #1
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024
+Call Trace:
+ __dump_stack lib/dump_stack.c:79 [inline]
+ dump_stack+0x125/0x19f lib/dump_stack.c:120
+ ubsan_epilogue lib/ubsan.c:148 [inline]
+ __ubsan_handle_out_of_bounds+0xed/0x120 lib/ubsan.c:347
+ sfq_link net/sched/sch_sfq.c:210 [inline]
+ sfq_dec+0x528/0x600 net/sched/sch_sfq.c:238
+ sfq_dequeue+0x39b/0x9d0 net/sched/sch_sfq.c:500
+ sfq_reset+0x13/0x50 net/sched/sch_sfq.c:525
+ qdisc_reset+0xfe/0x510 net/sched/sch_generic.c:1026
+ tbf_reset+0x3d/0x100 net/sched/sch_tbf.c:319
+ qdisc_reset+0xfe/0x510 net/sched/sch_generic.c:1026
+ dev_reset_queue+0x8c/0x140 net/sched/sch_generic.c:1296
+ netdev_for_each_tx_queue include/linux/netdevice.h:2350 [inline]
+ dev_deactivate_many+0x6dc/0xc20 net/sched/sch_generic.c:1362
+ __dev_close_many+0x214/0x350 net/core/dev.c:1468
+ dev_close_many+0x207/0x510 net/core/dev.c:1506
+ unregister_netdevice_many+0x40f/0x16b0 net/core/dev.c:10738
+ unregister_netdevice_queue+0x2be/0x310 net/core/dev.c:10695
+ unregister_netdevice include/linux/netdevice.h:2893 [inline]
+ __tun_detach+0x6b6/0x1600 drivers/net/tun.c:689
+ tun_detach drivers/net/tun.c:705 [inline]
+ tun_chr_close+0x104/0x1b0 drivers/net/tun.c:3640
+ __fput+0x203/0x840 fs/file_table.c:280
+ task_work_run+0x129/0x1b0 kernel/task_work.c:185
+ exit_task_work include/linux/task_work.h:33 [inline]
+ do_exit+0x5ce/0x2200 kernel/exit.c:931
+ do_group_exit+0x144/0x310 kernel/exit.c:1046
+ __do_sys_exit_group kernel/exit.c:1057 [inline]
+ __se_sys_exit_group kernel/exit.c:1055 [inline]
+ __x64_sys_exit_group+0x3b/0x40 kernel/exit.c:1055
+ do_syscall_64+0x6c/0xd0
+ entry_SYSCALL_64_after_hwframe+0x61/0xcb
+RIP: 0033:0x7fe5e7b52479
+Code: Unable to access opcode bytes at RIP 0x7fe5e7b5244f.
+RSP: 002b:00007ffd3c800398 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7
+RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fe5e7b52479
+RDX: 000000000000003c RSI: 00000000000000e7 RDI: 0000000000000000
+RBP: 00007fe5e7bcd2d0 R08: ffffffffffffffb8 R09: 0000000000000014
+R10: 0000000000000000 R11: 0000000000000246 R12: 00007fe5e7bcd2d0
+R13: 0000000000000000 R14: 00007fe5e7bcdd20 R15: 00007fe5e7b24270
+
+The crash can be also be reproduced with the following (with a tc
+recompiled to allow for sfq limits of 1):
+
+tc qdisc add dev dummy0 handle 1: root tbf rate 1Kbit burst 100b lat 1s
+../iproute2-6.9.0/tc/tc qdisc add dev dummy0 handle 2: parent 1:10 sfq limit 1
+ifconfig dummy0 up
+ping -I dummy0 -f -c2 -W0.1 8.8.8.8
+sleep 1
+
+Scenario that triggers the crash:
+
+* the first packet is sent and queued in TBF and SFQ; qdisc qlen is 1
+
+* TBF dequeues: it peeks from SFQ which moves the packet to the
+ gso_skb list and keeps qdisc qlen set to 1. TBF is out of tokens so
+ it schedules itself for later.
+
+* the second packet is sent and TBF tries to queues it to SFQ. qdisc
+ qlen is now 2 and because the SFQ limit is 1 the packet is dropped
+ by SFQ. At this point qlen is 1, and all of the SFQ slots are empty,
+ however q->tail is not NULL.
+
+At this point, assuming no more packets are queued, when sch_dequeue
+runs again it will decrement the qlen for the current empty slot
+causing an underflow and the subsequent out of bounds access.
+
+Reported-by: syzbot <syzkaller@googlegroups.com>
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Octavian Purdila <tavip@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20241204030520.2084663-2-tavip@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sched/sch_sfq.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/net/sched/sch_sfq.c
++++ b/net/sched/sch_sfq.c
+@@ -652,6 +652,10 @@ static int sfq_change(struct Qdisc *sch,
+ if (!p)
+ return -ENOMEM;
+ }
++ if (ctl->limit == 1) {
++ NL_SET_ERR_MSG_MOD(extack, "invalid limit");
++ return -EINVAL;
++ }
+ sch_tree_lock(sch);
+ if (ctl->quantum)
+ q->quantum = ctl->quantum;
--- /dev/null
+From stable+bounces-163265-greg=kroah.com@vger.kernel.org Thu Jul 17 14:46:33 2025
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Date: Thu, 17 Jul 2025 05:45:52 -0700
+Subject: net_sched: sch_sfq: handle bigger packets
+To: stable@vger.kernel.org
+Cc: edumazet@google.com, tavip@google.com, "Toke Høiland-Jørgensen" <toke@redhat.com>, "Jakub Kicinski" <kuba@kernel.org>, "Harshit Mogalapalli" <harshit.m.mogalapalli@oracle.com>
+Message-ID: <20250717124556.589696-3-harshit.m.mogalapalli@oracle.com>
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit e4650d7ae4252f67e997a632adfae0dd74d3a99a ]
+
+SFQ has an assumption on dealing with packets smaller than 64KB.
+
+Even before BIG TCP, TCA_STAB can provide arbitrary big values
+in qdisc_pkt_len(skb)
+
+It is time to switch (struct sfq_slot)->allot to a 32bit field.
+
+sizeof(struct sfq_slot) is now 64 bytes, giving better cache locality.
+
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
+Link: https://patch.msgid.link/20241008111603.653140-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sched/sch_sfq.c | 39 +++++++++++++--------------------------
+ 1 file changed, 13 insertions(+), 26 deletions(-)
+
+--- a/net/sched/sch_sfq.c
++++ b/net/sched/sch_sfq.c
+@@ -77,12 +77,6 @@
+ #define SFQ_EMPTY_SLOT 0xffff
+ #define SFQ_DEFAULT_HASH_DIVISOR 1024
+
+-/* We use 16 bits to store allot, and want to handle packets up to 64K
+- * Scale allot by 8 (1<<3) so that no overflow occurs.
+- */
+-#define SFQ_ALLOT_SHIFT 3
+-#define SFQ_ALLOT_SIZE(X) DIV_ROUND_UP(X, 1 << SFQ_ALLOT_SHIFT)
+-
+ /* This type should contain at least SFQ_MAX_DEPTH + 1 + SFQ_MAX_FLOWS values */
+ typedef u16 sfq_index;
+
+@@ -104,7 +98,7 @@ struct sfq_slot {
+ sfq_index next; /* next slot in sfq RR chain */
+ struct sfq_head dep; /* anchor in dep[] chains */
+ unsigned short hash; /* hash value (index in ht[]) */
+- short allot; /* credit for this slot */
++ int allot; /* credit for this slot */
+
+ unsigned int backlog;
+ struct red_vars vars;
+@@ -120,7 +114,6 @@ struct sfq_sched_data {
+ siphash_key_t perturbation;
+ u8 cur_depth; /* depth of longest slot */
+ u8 flags;
+- unsigned short scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */
+ struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
+ sfq_index *ht; /* Hash table ('divisor' slots) */
+@@ -459,7 +452,7 @@ enqueue:
+ */
+ q->tail = slot;
+ /* We could use a bigger initial quantum for new flows */
+- slot->allot = q->scaled_quantum;
++ slot->allot = q->quantum;
+ }
+ if (++sch->q.qlen <= q->limit)
+ return NET_XMIT_SUCCESS;
+@@ -496,7 +489,7 @@ next_slot:
+ slot = &q->slots[a];
+ if (slot->allot <= 0) {
+ q->tail = slot;
+- slot->allot += q->scaled_quantum;
++ slot->allot += q->quantum;
+ goto next_slot;
+ }
+ skb = slot_dequeue_head(slot);
+@@ -515,7 +508,7 @@ next_slot:
+ }
+ q->tail->next = next_a;
+ } else {
+- slot->allot -= SFQ_ALLOT_SIZE(qdisc_pkt_len(skb));
++ slot->allot -= qdisc_pkt_len(skb);
+ }
+ return skb;
+ }
+@@ -598,7 +591,7 @@ drop:
+ q->tail->next = x;
+ }
+ q->tail = slot;
+- slot->allot = q->scaled_quantum;
++ slot->allot = q->quantum;
+ }
+ }
+ sch->q.qlen -= dropped;
+@@ -628,7 +621,8 @@ static void sfq_perturbation(struct time
+ mod_timer(&q->perturb_timer, jiffies + period);
+ }
+
+-static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
++static int sfq_change(struct Qdisc *sch, struct nlattr *opt,
++ struct netlink_ext_ack *extack)
+ {
+ struct sfq_sched_data *q = qdisc_priv(sch);
+ struct tc_sfq_qopt *ctl = nla_data(opt);
+@@ -646,14 +640,10 @@ static int sfq_change(struct Qdisc *sch,
+ (!is_power_of_2(ctl->divisor) || ctl->divisor > 65536))
+ return -EINVAL;
+
+- /* slot->allot is a short, make sure quantum is not too big. */
+- if (ctl->quantum) {
+- unsigned int scaled = SFQ_ALLOT_SIZE(ctl->quantum);
+-
+- if (scaled <= 0 || scaled > SHRT_MAX)
+- return -EINVAL;
++ if ((int)ctl->quantum < 0) {
++ NL_SET_ERR_MSG_MOD(extack, "invalid quantum");
++ return -EINVAL;
+ }
+-
+ if (ctl_v1 && !red_check_params(ctl_v1->qth_min, ctl_v1->qth_max,
+ ctl_v1->Wlog, ctl_v1->Scell_log, NULL))
+ return -EINVAL;
+@@ -663,10 +653,8 @@ static int sfq_change(struct Qdisc *sch,
+ return -ENOMEM;
+ }
+ sch_tree_lock(sch);
+- if (ctl->quantum) {
++ if (ctl->quantum)
+ q->quantum = ctl->quantum;
+- q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
+- }
+ WRITE_ONCE(q->perturb_period, ctl->perturb_period * HZ);
+ if (ctl->flows)
+ q->maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS);
+@@ -762,12 +750,11 @@ static int sfq_init(struct Qdisc *sch, s
+ q->divisor = SFQ_DEFAULT_HASH_DIVISOR;
+ q->maxflows = SFQ_DEFAULT_FLOWS;
+ q->quantum = psched_mtu(qdisc_dev(sch));
+- q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
+ q->perturb_period = 0;
+ get_random_bytes(&q->perturbation, sizeof(q->perturbation));
+
+ if (opt) {
+- int err = sfq_change(sch, opt);
++ int err = sfq_change(sch, opt, extack);
+ if (err)
+ return err;
+ }
+@@ -878,7 +865,7 @@ static int sfq_dump_class_stats(struct Q
+ if (idx != SFQ_EMPTY_SLOT) {
+ const struct sfq_slot *slot = &q->slots[idx];
+
+- xstats.allot = slot->allot << SFQ_ALLOT_SHIFT;
++ xstats.allot = slot->allot;
+ qs.qlen = slot->qlen;
+ qs.backlog = slot->backlog;
+ }
--- /dev/null
+From stable+bounces-163262-greg=kroah.com@vger.kernel.org Thu Jul 17 14:46:23 2025
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Date: Thu, 17 Jul 2025 05:45:55 -0700
+Subject: net_sched: sch_sfq: move the limit validation
+To: stable@vger.kernel.org
+Cc: edumazet@google.com, tavip@google.com, syzbot <syzkaller@googlegroups.com>, Cong Wang <xiyou.wangcong@gmail.com>, "David S. Miller" <davem@davemloft.net>, Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Message-ID: <20250717124556.589696-6-harshit.m.mogalapalli@oracle.com>
+
+From: Octavian Purdila <tavip@google.com>
+
+[ Upstream commit b3bf8f63e6179076b57c9de660c9f80b5abefe70 ]
+
+It is not sufficient to directly validate the limit on the data that
+the user passes as it can be updated based on how the other parameters
+are changed.
+
+Move the check at the end of the configuration update process to also
+catch scenarios where the limit is indirectly updated, for example
+with the following configurations:
+
+tc qdisc add dev dummy0 handle 1: root sfq limit 2 flows 1 depth 1
+tc qdisc add dev dummy0 handle 1: root sfq limit 2 flows 1 divisor 1
+
+This fixes the following syzkaller reported crash:
+
+------------[ cut here ]------------
+UBSAN: array-index-out-of-bounds in net/sched/sch_sfq.c:203:6
+index 65535 is out of range for type 'struct sfq_head[128]'
+CPU: 1 UID: 0 PID: 3037 Comm: syz.2.16 Not tainted 6.14.0-rc2-syzkaller #0
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 12/27/2024
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:94 [inline]
+ dump_stack_lvl+0x201/0x300 lib/dump_stack.c:120
+ ubsan_epilogue lib/ubsan.c:231 [inline]
+ __ubsan_handle_out_of_bounds+0xf5/0x120 lib/ubsan.c:429
+ sfq_link net/sched/sch_sfq.c:203 [inline]
+ sfq_dec+0x53c/0x610 net/sched/sch_sfq.c:231
+ sfq_dequeue+0x34e/0x8c0 net/sched/sch_sfq.c:493
+ sfq_reset+0x17/0x60 net/sched/sch_sfq.c:518
+ qdisc_reset+0x12e/0x600 net/sched/sch_generic.c:1035
+ tbf_reset+0x41/0x110 net/sched/sch_tbf.c:339
+ qdisc_reset+0x12e/0x600 net/sched/sch_generic.c:1035
+ dev_reset_queue+0x100/0x1b0 net/sched/sch_generic.c:1311
+ netdev_for_each_tx_queue include/linux/netdevice.h:2590 [inline]
+ dev_deactivate_many+0x7e5/0xe70 net/sched/sch_generic.c:1375
+
+Reported-by: syzbot <syzkaller@googlegroups.com>
+Fixes: 10685681bafc ("net_sched: sch_sfq: don't allow 1 packet limit")
+Signed-off-by: Octavian Purdila <tavip@google.com>
+Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sched/sch_sfq.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/net/sched/sch_sfq.c
++++ b/net/sched/sch_sfq.c
+@@ -661,10 +661,6 @@ static int sfq_change(struct Qdisc *sch,
+ if (!p)
+ return -ENOMEM;
+ }
+- if (ctl->limit == 1) {
+- NL_SET_ERR_MSG_MOD(extack, "invalid limit");
+- return -EINVAL;
+- }
+
+ sch_tree_lock(sch);
+
+@@ -705,6 +701,12 @@ static int sfq_change(struct Qdisc *sch,
+ limit = min_t(u32, ctl->limit, maxdepth * maxflows);
+ maxflows = min_t(u32, maxflows, limit);
+ }
++ if (limit == 1) {
++ sch_tree_unlock(sch);
++ kfree(p);
++ NL_SET_ERR_MSG_MOD(extack, "invalid limit");
++ return -EINVAL;
++ }
+
+ /* commit configuration */
+ q->limit = limit;
--- /dev/null
+From stable+bounces-163263-greg=kroah.com@vger.kernel.org Thu Jul 17 14:46:31 2025
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Date: Thu, 17 Jul 2025 05:45:56 -0700
+Subject: net_sched: sch_sfq: reject invalid perturb period
+To: stable@vger.kernel.org
+Cc: edumazet@google.com, tavip@google.com, Gerrard Tai <gerrard.tai@starlabs.sg>, Jakub Kicinski <kuba@kernel.org>, Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Message-ID: <20250717124556.589696-7-harshit.m.mogalapalli@oracle.com>
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit 7ca52541c05c832d32b112274f81a985101f9ba8 ]
+
+Gerrard Tai reported that SFQ perturb_period has no range check yet,
+and this can be used to trigger a race condition fixed in a separate patch.
+
+We want to make sure ctl->perturb_period * HZ will not overflow
+and is positive.
+
+Tested:
+
+tc qd add dev lo root sfq perturb -10 # negative value : error
+Error: sch_sfq: invalid perturb period.
+
+tc qd add dev lo root sfq perturb 1000000000 # too big : error
+Error: sch_sfq: invalid perturb period.
+
+tc qd add dev lo root sfq perturb 2000000 # acceptable value
+tc -s -d qd sh dev lo
+qdisc sfq 8005: root refcnt 2 limit 127p quantum 64Kb depth 127 flows 128 divisor 1024 perturb 2000000sec
+ Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
+ backlog 0b 0p requeues 0
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: Gerrard Tai <gerrard.tai@starlabs.sg>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20250611083501.1810459-1-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sched/sch_sfq.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/net/sched/sch_sfq.c
++++ b/net/sched/sch_sfq.c
+@@ -653,6 +653,14 @@ static int sfq_change(struct Qdisc *sch,
+ NL_SET_ERR_MSG_MOD(extack, "invalid quantum");
+ return -EINVAL;
+ }
++
++ if (ctl->perturb_period < 0 ||
++ ctl->perturb_period > INT_MAX / HZ) {
++ NL_SET_ERR_MSG_MOD(extack, "invalid perturb period");
++ return -EINVAL;
++ }
++ perturb_period = ctl->perturb_period * HZ;
++
+ if (ctl_v1 && !red_check_params(ctl_v1->qth_min, ctl_v1->qth_max,
+ ctl_v1->Wlog, ctl_v1->Scell_log, NULL))
+ return -EINVAL;
+@@ -669,14 +677,12 @@ static int sfq_change(struct Qdisc *sch,
+ headdrop = q->headdrop;
+ maxdepth = q->maxdepth;
+ maxflows = q->maxflows;
+- perturb_period = q->perturb_period;
+ quantum = q->quantum;
+ flags = q->flags;
+
+ /* update and validate configuration */
+ if (ctl->quantum)
+ quantum = ctl->quantum;
+- perturb_period = ctl->perturb_period * HZ;
+ if (ctl->flows)
+ maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS);
+ if (ctl->divisor) {
--- /dev/null
+From stable+bounces-163261-greg=kroah.com@vger.kernel.org Thu Jul 17 14:46:23 2025
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Date: Thu, 17 Jul 2025 05:45:54 -0700
+Subject: net_sched: sch_sfq: use a temporary work area for validating configuration
+To: stable@vger.kernel.org
+Cc: edumazet@google.com, tavip@google.com, Cong Wang <xiyou.wangcong@gmail.com>, "David S. Miller" <davem@davemloft.net>, Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Message-ID: <20250717124556.589696-5-harshit.m.mogalapalli@oracle.com>
+
+From: Octavian Purdila <tavip@google.com>
+
+[ Upstream commit 8c0cea59d40cf6dd13c2950437631dd614fbade6 ]
+
+Many configuration parameters have influence on others (e.g. divisor
+-> flows -> limit, depth -> limit) and so it is difficult to correctly
+do all of the validation before applying the configuration. And if a
+validation error is detected late it is difficult to roll back a
+partially applied configuration.
+
+To avoid these issues use a temporary work area to update and validate
+the configuration and only then apply the configuration to the
+internal state.
+
+Signed-off-by: Octavian Purdila <tavip@google.com>
+Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sched/sch_sfq.c | 56 ++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 44 insertions(+), 12 deletions(-)
+
+--- a/net/sched/sch_sfq.c
++++ b/net/sched/sch_sfq.c
+@@ -631,6 +631,15 @@ static int sfq_change(struct Qdisc *sch,
+ struct red_parms *p = NULL;
+ struct sk_buff *to_free = NULL;
+ struct sk_buff *tail = NULL;
++ unsigned int maxflows;
++ unsigned int quantum;
++ unsigned int divisor;
++ int perturb_period;
++ u8 headdrop;
++ u8 maxdepth;
++ int limit;
++ u8 flags;
++
+
+ if (opt->nla_len < nla_attr_size(sizeof(*ctl)))
+ return -EINVAL;
+@@ -656,36 +665,59 @@ static int sfq_change(struct Qdisc *sch,
+ NL_SET_ERR_MSG_MOD(extack, "invalid limit");
+ return -EINVAL;
+ }
++
+ sch_tree_lock(sch);
++
++ limit = q->limit;
++ divisor = q->divisor;
++ headdrop = q->headdrop;
++ maxdepth = q->maxdepth;
++ maxflows = q->maxflows;
++ perturb_period = q->perturb_period;
++ quantum = q->quantum;
++ flags = q->flags;
++
++ /* update and validate configuration */
+ if (ctl->quantum)
+- q->quantum = ctl->quantum;
+- WRITE_ONCE(q->perturb_period, ctl->perturb_period * HZ);
++ quantum = ctl->quantum;
++ perturb_period = ctl->perturb_period * HZ;
+ if (ctl->flows)
+- q->maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS);
++ maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS);
+ if (ctl->divisor) {
+- q->divisor = ctl->divisor;
+- q->maxflows = min_t(u32, q->maxflows, q->divisor);
++ divisor = ctl->divisor;
++ maxflows = min_t(u32, maxflows, divisor);
+ }
+ if (ctl_v1) {
+ if (ctl_v1->depth)
+- q->maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH);
++ maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH);
+ if (p) {
+- swap(q->red_parms, p);
+- red_set_parms(q->red_parms,
++ red_set_parms(p,
+ ctl_v1->qth_min, ctl_v1->qth_max,
+ ctl_v1->Wlog,
+ ctl_v1->Plog, ctl_v1->Scell_log,
+ NULL,
+ ctl_v1->max_P);
+ }
+- q->flags = ctl_v1->flags;
+- q->headdrop = ctl_v1->headdrop;
++ flags = ctl_v1->flags;
++ headdrop = ctl_v1->headdrop;
+ }
+ if (ctl->limit) {
+- q->limit = min_t(u32, ctl->limit, q->maxdepth * q->maxflows);
+- q->maxflows = min_t(u32, q->maxflows, q->limit);
++ limit = min_t(u32, ctl->limit, maxdepth * maxflows);
++ maxflows = min_t(u32, maxflows, limit);
+ }
+
++ /* commit configuration */
++ q->limit = limit;
++ q->divisor = divisor;
++ q->headdrop = headdrop;
++ q->maxdepth = maxdepth;
++ q->maxflows = maxflows;
++ WRITE_ONCE(q->perturb_period, perturb_period);
++ q->quantum = quantum;
++ q->flags = flags;
++ if (p)
++ swap(q->red_parms, p);
++
+ qlen = sch->q.qlen;
+ while (sch->q.qlen > q->limit) {
+ dropped += sfq_drop(sch, &to_free);
--- /dev/null
+From stable+bounces-163575-greg=kroah.com@vger.kernel.org Mon Jul 21 13:49:35 2025
+From: skulkarni@mvista.com
+Date: Mon, 21 Jul 2025 17:18:46 +0530
+Subject: power: supply: bq24190: Fix use after free bug in bq24190_remove due to race condition
+To: stable@vger.kernel.org
+Cc: Zheng Wang <zyytlz.wz@163.com>, Sebastian Reichel <sebastian.reichel@collabora.com>, Shubham Kulkarni <skulkarni@mvista.com>
+Message-ID: <20250721114846.1360952-4-skulkarni@mvista.com>
+
+From: Zheng Wang <zyytlz.wz@163.com>
+
+[ Upstream commit 47c29d69212911f50bdcdd0564b5999a559010d4 ]
+
+In bq24190_probe, &bdi->input_current_limit_work is bound
+with bq24190_input_current_limit_work. When external power
+changed, it will call bq24190_charger_external_power_changed
+ to start the work.
+
+If we remove the module which will call bq24190_remove to make
+cleanup, there may be a unfinished work. The possible
+sequence is as follows:
+
+CPU0 CPUc1
+
+ |bq24190_input_current_limit_work
+bq24190_remove |
+power_supply_unregister |
+device_unregister |
+power_supply_dev_release|
+kfree(psy) |
+ |
+ | power_supply_get_property_from_supplier
+ | //use
+
+Fix it by finishing the work before cleanup in the bq24190_remove
+
+Fixes: 97774672573a ("power_supply: Initialize changed_work before calling device_add")
+Signed-off-by: Zheng Wang <zyytlz.wz@163.com>
+Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
+Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/power/supply/bq24190_charger.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/power/supply/bq24190_charger.c
++++ b/drivers/power/supply/bq24190_charger.c
+@@ -1845,6 +1845,7 @@ static int bq24190_remove(struct i2c_cli
+ struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
+ int error;
+
++ cancel_delayed_work_sync(&bdi->input_current_limit_work);
+ error = pm_runtime_resume_and_get(bdi->dev);
+ if (error < 0)
+ dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error);
--- /dev/null
+From stable+bounces-163573-greg=kroah.com@vger.kernel.org Mon Jul 21 13:49:58 2025
+From: skulkarni@mvista.com
+Date: Mon, 21 Jul 2025 17:18:44 +0530
+Subject: power: supply: bq24190_charger: Fix runtime PM imbalance on error
+To: stable@vger.kernel.org
+Cc: Dinghao Liu <dinghao.liu@zju.edu.cn>, "Rafael J . Wysocki" <rafael.j.wysocki@intel.com>, Sebastian Reichel <sebastian.reichel@collabora.com>, Shubham Kulkarni <skulkarni@mvista.com>
+Message-ID: <20250721114846.1360952-2-skulkarni@mvista.com>
+
+From: Dinghao Liu <dinghao.liu@zju.edu.cn>
+
+[ Upstream commit 1a37a039711610dd53ec03d8cab9e81875338225 ]
+
+pm_runtime_get_sync() increments the runtime PM usage counter even
+it returns an error code. Thus a pairing decrement is needed on
+the error handling path to keep the counter balanced.
+
+Signed-off-by: Dinghao Liu <dinghao.liu@zju.edu.cn>
+Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
+Stable-dep-of: 47c29d692129 ("power: supply: bq24190: Fix use after free bug in bq24190_remove due to race condition")
+Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/power/supply/bq24190_charger.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/drivers/power/supply/bq24190_charger.c
++++ b/drivers/power/supply/bq24190_charger.c
+@@ -484,8 +484,10 @@ static ssize_t bq24190_sysfs_store(struc
+ return ret;
+
+ ret = pm_runtime_get_sync(bdi->dev);
+- if (ret < 0)
++ if (ret < 0) {
++ pm_runtime_put_noidle(bdi->dev);
+ return ret;
++ }
+
+ ret = bq24190_write_mask(bdi, info->reg, info->mask, info->shift, v);
+ if (ret)
--- /dev/null
+From stable+bounces-163574-greg=kroah.com@vger.kernel.org Mon Jul 21 13:49:34 2025
+From: skulkarni@mvista.com
+Date: Mon, 21 Jul 2025 17:18:45 +0530
+Subject: power: supply: bq24190_charger: using pm_runtime_resume_and_get instead of pm_runtime_get_sync
+To: stable@vger.kernel.org
+Cc: Minghao Chi <chi.minghao@zte.com.cn>, Zeal Robot <zealci@zte.com.cn>, Sebastian Reichel <sebastian.reichel@collabora.com>, Shubham Kulkarni <skulkarni@mvista.com>
+Message-ID: <20250721114846.1360952-3-skulkarni@mvista.com>
+
+From: Minghao Chi <chi.minghao@zte.com.cn>
+
+[ Upstream commit d96a89407e5f682d1cb22569d91784506c784863 ]
+
+Using pm_runtime_resume_and_get is more appropriate
+for simplifing code
+
+Reported-by: Zeal Robot <zealci@zte.com.cn>
+Signed-off-by: Minghao Chi <chi.minghao@zte.com.cn>
+Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
+[ skulkarni: Minor changes in hunk #3/12 wrt the mainline commit ]
+Stable-dep-of: 47c29d692129 ("power: supply: bq24190: Fix use after free bug in bq24190_remove due to race condition")
+Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/power/supply/bq24190_charger.c | 63 +++++++++++----------------------
+ 1 file changed, 21 insertions(+), 42 deletions(-)
+
+--- a/drivers/power/supply/bq24190_charger.c
++++ b/drivers/power/supply/bq24190_charger.c
+@@ -448,11 +448,9 @@ static ssize_t bq24190_sysfs_show(struct
+ if (!info)
+ return -EINVAL;
+
+- ret = pm_runtime_get_sync(bdi->dev);
+- if (ret < 0) {
+- pm_runtime_put_noidle(bdi->dev);
++ ret = pm_runtime_resume_and_get(bdi->dev);
++ if (ret < 0)
+ return ret;
+- }
+
+ ret = bq24190_read_mask(bdi, info->reg, info->mask, info->shift, &v);
+ if (ret)
+@@ -483,11 +481,9 @@ static ssize_t bq24190_sysfs_store(struc
+ if (ret < 0)
+ return ret;
+
+- ret = pm_runtime_get_sync(bdi->dev);
+- if (ret < 0) {
+- pm_runtime_put_noidle(bdi->dev);
++ ret = pm_runtime_resume_and_get(bdi->dev);
++ if (ret < 0)
+ return ret;
+- }
+
+ ret = bq24190_write_mask(bdi, info->reg, info->mask, info->shift, v);
+ if (ret)
+@@ -506,10 +502,9 @@ static int bq24190_set_charge_mode(struc
+ struct bq24190_dev_info *bdi = rdev_get_drvdata(dev);
+ int ret;
+
+- ret = pm_runtime_get_sync(bdi->dev);
++ ret = pm_runtime_resume_and_get(bdi->dev);
+ if (ret < 0) {
+ dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", ret);
+- pm_runtime_put_noidle(bdi->dev);
+ return ret;
+ }
+
+@@ -539,10 +534,9 @@ static int bq24190_vbus_is_enabled(struc
+ int ret;
+ u8 val;
+
+- ret = pm_runtime_get_sync(bdi->dev);
++ ret = pm_runtime_resume_and_get(bdi->dev);
+ if (ret < 0) {
+ dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", ret);
+- pm_runtime_put_noidle(bdi->dev);
+ return ret;
+ }
+
+@@ -1083,11 +1077,9 @@ static int bq24190_charger_get_property(
+
+ dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+- ret = pm_runtime_get_sync(bdi->dev);
+- if (ret < 0) {
+- pm_runtime_put_noidle(bdi->dev);
++ ret = pm_runtime_resume_and_get(bdi->dev);
++ if (ret < 0)
+ return ret;
+- }
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+@@ -1157,11 +1149,9 @@ static int bq24190_charger_set_property(
+
+ dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+- ret = pm_runtime_get_sync(bdi->dev);
+- if (ret < 0) {
+- pm_runtime_put_noidle(bdi->dev);
++ ret = pm_runtime_resume_and_get(bdi->dev);
++ if (ret < 0)
+ return ret;
+- }
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+@@ -1431,11 +1421,9 @@ static int bq24190_battery_get_property(
+ dev_warn(bdi->dev, "warning: /sys/class/power_supply/bq24190-battery is deprecated\n");
+ dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+- ret = pm_runtime_get_sync(bdi->dev);
+- if (ret < 0) {
+- pm_runtime_put_noidle(bdi->dev);
++ ret = pm_runtime_resume_and_get(bdi->dev);
++ if (ret < 0)
+ return ret;
+- }
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+@@ -1479,11 +1467,9 @@ static int bq24190_battery_set_property(
+ dev_warn(bdi->dev, "warning: /sys/class/power_supply/bq24190-battery is deprecated\n");
+ dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+- ret = pm_runtime_get_sync(bdi->dev);
+- if (ret < 0) {
+- pm_runtime_put_noidle(bdi->dev);
++ ret = pm_runtime_resume_and_get(bdi->dev);
++ if (ret < 0)
+ return ret;
+- }
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+@@ -1637,10 +1623,9 @@ static irqreturn_t bq24190_irq_handler_t
+ int error;
+
+ bdi->irq_event = true;
+- error = pm_runtime_get_sync(bdi->dev);
++ error = pm_runtime_resume_and_get(bdi->dev);
+ if (error < 0) {
+ dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error);
+- pm_runtime_put_noidle(bdi->dev);
+ return IRQ_NONE;
+ }
+ bq24190_check_status(bdi);
+@@ -1860,11 +1845,9 @@ static int bq24190_remove(struct i2c_cli
+ struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
+ int error;
+
+- error = pm_runtime_get_sync(bdi->dev);
+- if (error < 0) {
++ error = pm_runtime_resume_and_get(bdi->dev);
++ if (error < 0)
+ dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error);
+- pm_runtime_put_noidle(bdi->dev);
+- }
+
+ bq24190_register_reset(bdi);
+ if (bdi->battery)
+@@ -1913,11 +1896,9 @@ static __maybe_unused int bq24190_pm_sus
+ struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
+ int error;
+
+- error = pm_runtime_get_sync(bdi->dev);
+- if (error < 0) {
++ error = pm_runtime_resume_and_get(bdi->dev);
++ if (error < 0)
+ dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error);
+- pm_runtime_put_noidle(bdi->dev);
+- }
+
+ bq24190_register_reset(bdi);
+
+@@ -1938,11 +1919,9 @@ static __maybe_unused int bq24190_pm_res
+ bdi->f_reg = 0;
+ bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
+
+- error = pm_runtime_get_sync(bdi->dev);
+- if (error < 0) {
++ error = pm_runtime_resume_and_get(bdi->dev);
++ if (error < 0)
+ dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", error);
+- pm_runtime_put_noidle(bdi->dev);
+- }
+
+ bq24190_register_reset(bdi);
+ bq24190_set_config(bdi);
usb-musb-fix-gadget-state-on-disconnect.patch
usb-dwc3-qcom-don-t-leave-bcr-asserted.patch
asoc-fsl_sai-force-a-software-reset-when-starting-in-consumer-mode.patch
+virtio-net-ensure-the-received-length-does-not-exceed-allocated-size.patch
+xhci-disable-stream-for-xhc-controller-with-xhci_broken_streams.patch
+power-supply-bq24190_charger-fix-runtime-pm-imbalance-on-error.patch
+power-supply-bq24190_charger-using-pm_runtime_resume_and_get-instead-of-pm_runtime_get_sync.patch
+power-supply-bq24190-fix-use-after-free-bug-in-bq24190_remove-due-to-race-condition.patch
+net_sched-sch_sfq-annotate-data-races-around-q-perturb_period.patch
+net_sched-sch_sfq-handle-bigger-packets.patch
+net_sched-sch_sfq-don-t-allow-1-packet-limit.patch
+net_sched-sch_sfq-use-a-temporary-work-area-for-validating-configuration.patch
+net_sched-sch_sfq-move-the-limit-validation.patch
+net_sched-sch_sfq-reject-invalid-perturb-period.patch
--- /dev/null
+From 315dbdd7cdf6aa533829774caaf4d25f1fd20e73 Mon Sep 17 00:00:00 2001
+From: Bui Quang Minh <minhquangbui99@gmail.com>
+Date: Mon, 30 Jun 2025 21:42:10 +0700
+Subject: virtio-net: ensure the received length does not exceed allocated size
+
+From: Bui Quang Minh <minhquangbui99@gmail.com>
+
+commit 315dbdd7cdf6aa533829774caaf4d25f1fd20e73 upstream.
+
+In xdp_linearize_page, when reading the following buffers from the ring,
+we forget to check the received length with the true allocate size. This
+can lead to an out-of-bound read. This commit adds that missing check.
+
+Cc: <stable@vger.kernel.org>
+Fixes: 4941d472bf95 ("virtio-net: do not reset during XDP set")
+Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Link: https://patch.msgid.link/20250630144212.48471-2-minhquangbui99@gmail.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ adapted virtqueue_get_buf() to virtqueue_get_buf_ctx() ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/virtio_net.c | 38 ++++++++++++++++++++++++++++++++++----
+ 1 file changed, 34 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/virtio_net.c
++++ b/drivers/net/virtio_net.c
+@@ -394,6 +394,26 @@ static unsigned int mergeable_ctx_to_tru
+ return (unsigned long)mrg_ctx & ((1 << MRG_CTX_HEADER_SHIFT) - 1);
+ }
+
++static int check_mergeable_len(struct net_device *dev, void *mrg_ctx,
++ unsigned int len)
++{
++ unsigned int headroom, tailroom, room, truesize;
++
++ truesize = mergeable_ctx_to_truesize(mrg_ctx);
++ headroom = mergeable_ctx_to_headroom(mrg_ctx);
++ tailroom = headroom ? sizeof(struct skb_shared_info) : 0;
++ room = SKB_DATA_ALIGN(headroom + tailroom);
++
++ if (len > truesize - room) {
++ pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
++ dev->name, len, (unsigned long)(truesize - room));
++ dev->stats.rx_length_errors++;
++ return -1;
++ }
++
++ return 0;
++}
++
+ /* Called from bottom half context */
+ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+ struct receive_queue *rq,
+@@ -639,7 +659,8 @@ static unsigned int virtnet_get_headroom
+ * across multiple buffers (num_buf > 1), and we make sure buffers
+ * have enough headroom.
+ */
+-static struct page *xdp_linearize_page(struct receive_queue *rq,
++static struct page *xdp_linearize_page(struct net_device *dev,
++ struct receive_queue *rq,
+ u16 *num_buf,
+ struct page *p,
+ int offset,
+@@ -659,18 +680,27 @@ static struct page *xdp_linearize_page(s
+ memcpy(page_address(page) + page_off, page_address(p) + offset, *len);
+ page_off += *len;
+
++ /* Only mergeable mode can go inside this while loop. In small mode,
++ * *num_buf == 1, so it cannot go inside.
++ */
+ while (--*num_buf) {
+ unsigned int buflen;
+ void *buf;
++ void *ctx;
+ int off;
+
+- buf = virtqueue_get_buf(rq->vq, &buflen);
++ buf = virtqueue_get_buf_ctx(rq->vq, &buflen, &ctx);
+ if (unlikely(!buf))
+ goto err_buf;
+
+ p = virt_to_head_page(buf);
+ off = buf - page_address(p);
+
++ if (check_mergeable_len(dev, ctx, buflen)) {
++ put_page(p);
++ goto err_buf;
++ }
++
+ /* guard against a misconfigured or uncooperative backend that
+ * is sending packet larger than the MTU.
+ */
+@@ -745,7 +775,7 @@ static struct sk_buff *receive_small(str
+ headroom = vi->hdr_len + header_offset;
+ buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+- xdp_page = xdp_linearize_page(rq, &num_buf, page,
++ xdp_page = xdp_linearize_page(dev, rq, &num_buf, page,
+ offset, header_offset,
+ &tlen);
+ if (!xdp_page)
+@@ -910,7 +940,7 @@ static struct sk_buff *receive_mergeable
+ if (unlikely(num_buf > 1 ||
+ headroom < virtnet_get_headroom(vi))) {
+ /* linearize data for XDP */
+- xdp_page = xdp_linearize_page(rq, &num_buf,
++ xdp_page = xdp_linearize_page(dev, rq, &num_buf,
+ page, offset,
+ VIRTIO_XDP_HEADROOM,
+ &len);
--- /dev/null
+From cd65ee81240e8bc3c3119b46db7f60c80864b90b Mon Sep 17 00:00:00 2001
+From: Hongyu Xie <xiehongyu1@kylinos.cn>
+Date: Fri, 27 Jun 2025 17:41:20 +0300
+Subject: xhci: Disable stream for xHC controller with XHCI_BROKEN_STREAMS
+
+From: Hongyu Xie <xiehongyu1@kylinos.cn>
+
+commit cd65ee81240e8bc3c3119b46db7f60c80864b90b upstream.
+
+Disable stream for platform xHC controller with broken stream.
+
+Fixes: 14aec589327a6 ("storage: accept some UAS devices if streams are unavailable")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Hongyu Xie <xiehongyu1@kylinos.cn>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20250627144127.3889714-3-mathias.nyman@linux.intel.com
+[ removed xhci_get_usb3_hcd() call ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/xhci-plat.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/xhci-plat.c
++++ b/drivers/usb/host/xhci-plat.c
+@@ -333,7 +333,8 @@ static int xhci_plat_probe(struct platfo
+ if (ret)
+ goto disable_usb_phy;
+
+- if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
++ if (HCC_MAX_PSA(xhci->hcc_params) >= 4 &&
++ !(xhci->quirks & XHCI_BROKEN_STREAMS))
+ xhci->shared_hcd->can_do_streams = 1;
+
+ ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);