From: Greg Kroah-Hartman Date: Wed, 29 Jul 2026 14:46:47 +0000 (+0200) Subject: 7.1-stable patches X-Git-Tag: v6.1.179~12 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=e4018c06b172c63b50010d6e5d3c014cc13cdbc4;p=thirdparty%2Fkernel%2Fstable-queue.git 7.1-stable patches added patches: gve-fix-rx-queue-stall-on-alloc-failure.patch ice-reject-out-of-range-ptype-in-ice_parser_profile_init.patch ice-use-read_once-to-access-cached-phc-time.patch ila-reload-ipv6-header-after-pskb_may_pull-in-checksum-adjust.patch mac802154-hold-an-interface-reference-across-the-scan-worker.patch mac802154-llsec-reject-frames-shorter-than-the-authentication-tag.patch mctp-serial-handle-zero-length-frames-to-prevent-rx-buffer-overflow.patch openvswitch-fix-gso-userspace-truncation-underflow.patch ovpn-fix-peer-refcount-leak-in-tcp-error-paths.patch ovpn-hold-peer-before-scheduling-keepalive-work.patch pppoe-reload-header-pointer-after-dev_hard_header.patch rtase-workaround-for-tx-hang-caused-by-hardware-packet-parsing.patch tcp-challenge-ack-for-non-exact-rst-in-syn-received.patch tcp-initialize-standalone-tcp-ao-response-padding.patch tipc-clear-sock-sk-on-the-failed-insert-path-in-tipc_sk_create.patch vsock-virtio-collapse-receive-queue-under-memory-pressure.patch vxlan-mdb-fix-source-list-corruption-on-a-failed-replace.patch watchdog-s32g_wdt-remove-incorrect-options-in-watchdog_info-struct.patch --- diff --git a/queue-7.1/gve-fix-rx-queue-stall-on-alloc-failure.patch b/queue-7.1/gve-fix-rx-queue-stall-on-alloc-failure.patch new file mode 100644 index 0000000000..1dbe02abdf --- /dev/null +++ b/queue-7.1/gve-fix-rx-queue-stall-on-alloc-failure.patch @@ -0,0 +1,147 @@ +From b65352a1bac64442ad95e64f385b40ccb9f1b0db Mon Sep 17 00:00:00 2001 +From: Eddie Phillips +Date: Thu, 9 Jul 2026 21:19:06 +0000 +Subject: gve: fix Rx queue stall on alloc failure + +From: Eddie Phillips + +commit b65352a1bac64442ad95e64f385b40ccb9f1b0db upstream. + +When the system is under extreme memory pressure, page allocations can +fail during the Rx buffer refill loop. If the number of buffers posted +to hardware falls below a critical low threshold and the refill loop +exits due to allocation failures, the queue can stall: + +1. The device drops incoming packets because there are no descriptors. +2. Since no packets are processed, no Rx completions are generated. +3. Because no completions occur, NAPI is never scheduled, preventing + the refill loop from running again even after memory is freed. + +This results in a permanent queue stall. + +Resolve this by introducing a starvation recovery timer for each Rx queue. +If the number of buffers posted to hardware falls below a critical low +threshold, start a timer to periodically reschedule NAPI. Once NAPI runs +and successfully refills the queue above the threshold, the timer is +not rescheduled. + +The threshold is set to 32 because a single maximum-sized Receive Segment +Coalescing (RSC) packet can consume up to 19 descriptors in the Rx path. +Lower thresholds (such as 8 or 16) would be insufficient to process a +complete maximum-sized RSC packet, risking packet drops or unexpected +hardware behavior under memory pressure. Setting the threshold to 32 +guarantees a safe margin to handle at least one full RSC packet. + +Cc: stable@vger.kernel.org +Fixes: 9b8dd5e5ea48 ("gve: DQO: Add RX path") +Reviewed-by: Jordan Rhee +Signed-off-by: Eddie Phillips +Signed-off-by: Harshitha Ramamurthy +Reviewed-by: Przemek Kitszel +Link: https://patch.msgid.link/20260709211906.3322883-1-hramamurthy@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/google/gve/gve.h | 3 ++ + drivers/net/ethernet/google/gve/gve_rx_dqo.c | 34 +++++++++++++++++++++++++++ + 2 files changed, 37 insertions(+) + +--- a/drivers/net/ethernet/google/gve/gve.h ++++ b/drivers/net/ethernet/google/gve/gve.h +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -41,6 +42,7 @@ + + /* Interval to schedule a stats report update, 20000ms. */ + #define GVE_STATS_REPORT_TIMER_PERIOD 20000 ++#define GVE_RX_NAPI_RESCHED_MS 20 /* msecs */ + + /* Numbers of NIC tx/rx stats in stats report. */ + #define NIC_TX_STATS_REPORT_NUM 0 +@@ -341,6 +343,7 @@ struct gve_rx_ring { + struct xdp_rxq_info xdp_rxq; + struct xsk_buff_pool *xsk_pool; + struct page_frag_cache page_cache; /* Page cache to allocate XDP frames */ ++ struct timer_list starvation_timer; /* for queue starvation recovery */ + }; + + /* A TX desc ring entry */ +--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c ++++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c +@@ -18,6 +18,16 @@ + #include + #include + ++static void gve_rx_starvation_timer(struct timer_list *t) ++{ ++ struct gve_rx_ring *rx = timer_container_of(rx, t, starvation_timer); ++ struct gve_priv *priv = rx->gve; ++ struct gve_notify_block *block; ++ ++ block = &priv->ntfy_blocks[rx->ntfy_id]; ++ napi_schedule(&block->napi); ++} ++ + static void gve_rx_free_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx) + { + struct device *hdev = &priv->pdev->dev; +@@ -120,6 +130,7 @@ void gve_rx_stop_ring_dqo(struct gve_pri + + if (rx->dqo.page_pool) + page_pool_disable_direct_recycling(rx->dqo.page_pool); ++ timer_shutdown_sync(&rx->starvation_timer); + gve_remove_napi(priv, ntfy_idx); + gve_rx_remove_from_block(priv, idx); + gve_rx_reset_ring_dqo(priv, idx); +@@ -208,8 +219,10 @@ static int gve_rx_alloc_hdr_bufs(struct + void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx) + { + int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); ++ struct gve_rx_ring *rx = &priv->rx[idx]; + + gve_rx_add_to_block(priv, idx); ++ timer_setup(&rx->starvation_timer, gve_rx_starvation_timer, 0); + gve_add_napi(priv, ntfy_idx, gve_napi_poll_dqo); + } + +@@ -365,6 +378,7 @@ void gve_rx_post_buffers_dqo(struct gve_ + struct gve_rx_compl_queue_dqo *complq = &rx->dqo.complq; + struct gve_rx_buf_queue_dqo *bufq = &rx->dqo.bufq; + struct gve_priv *priv = rx->gve; ++ u32 num_bufs_avail_to_hw; + u32 num_avail_slots; + u32 num_full_slots; + u32 num_posted = 0; +@@ -400,6 +414,26 @@ void gve_rx_post_buffers_dqo(struct gve_ + } + + rx->fill_cnt += num_posted; ++ ++ /* If the queue has fewer than GVE_RX_BUF_THRESH_DQO descriptors ++ * visible to the hardware, the hardware is in danger of starving ++ * and cannot trigger interrupts. ++ * ++ * We use a threshold of 32 because a single maximum-sized RSC ++ * packet can consume up to 19 descriptors in the Rx path. Lower ++ * thresholds (e.g., 8 or 16) would be unsafe as they could cause ++ * the device to drop/stall on a maximum-sized RSC packet. ++ * ++ * Start the timer to periodically reschedule NAPI and recover. ++ */ ++ num_bufs_avail_to_hw = ++ ((bufq->tail & ~(GVE_RX_BUF_THRESH_DQO - 1)) - ++ bufq->head) & bufq->mask; ++ ++ if (num_bufs_avail_to_hw < GVE_RX_BUF_THRESH_DQO) { ++ mod_timer(&rx->starvation_timer, ++ jiffies + msecs_to_jiffies(GVE_RX_NAPI_RESCHED_MS)); ++ } + } + + static void gve_rx_skb_csum(struct sk_buff *skb, diff --git a/queue-7.1/ice-reject-out-of-range-ptype-in-ice_parser_profile_init.patch b/queue-7.1/ice-reject-out-of-range-ptype-in-ice_parser_profile_init.patch new file mode 100644 index 0000000000..f0ee664942 --- /dev/null +++ b/queue-7.1/ice-reject-out-of-range-ptype-in-ice_parser_profile_init.patch @@ -0,0 +1,64 @@ +From 59abb87159c53605c063f6e2ceb215b5eba43ee6 Mon Sep 17 00:00:00 2001 +From: Aleksandr Loktionov +Date: Fri, 17 Jul 2026 11:53:33 -0700 +Subject: ice: reject out-of-range ptype in ice_parser_profile_init + +From: Aleksandr Loktionov + +commit 59abb87159c53605c063f6e2ceb215b5eba43ee6 upstream. + +set_bit(rslt->ptype, prof->ptypes) operates on a DECLARE_BITMAP of +ICE_FLOW_PTYPE_MAX (1024) bits. Nothing prevents a malicious VF from +providing ptype >= 1024 through VIRTCHNL, resulting in a write past +the end of the bitmap and a kernel page fault. + +Reproduced with a custom kernel module injecting a crafted +VIRTCHNL_OP_ADD_RSS_CFG on E810-C QSFP (8086:1592), +FW 4.91 0x800214af 1.3909.0, ICE COMMS DDP 1.3.53.0, +kernel 7.1.0-rc1. + +crash_parser: ice_parser_profile_init @ ffffffffc0d61b60 +crash_parser: setting ptype=0xffff (max valid=1023) +crash_parser: calling ice_parser_profile_init -- expect OOB crash! +BUG: kernel NULL pointer dereference, address: 0000000000000000 +Oops: Oops: 0002 [#1] SMP NOPTI +CPU: 56 UID: 0 PID: 165011 Comm: insmod Kdump: loaded Tainted: G S U OE 7.1.0-rc1 #1 +Hardware name: Intel Corporation S2600BPB/S2600BPB +RIP: 0010:ice_parser_profile_init+0x2d/0x1d0 [ice] +Call Trace: + + ? __pfx_ice_parser_profile_init+0x10/0x10 [ice] + crash_init+0x127/0xff0 [crash_parser] + do_one_initcall+0x45/0x310 + do_init_module+0x64/0x270 + init_module_from_file+0xcc/0xf0 + idempotent_init_module+0x17b/0x280 + __x64_sys_finit_module+0x6e/0xe0 + +Bail out early with -EINVAL when ptype is out of range. + +Fixes: e312b3a1e209 ("ice: add API for parser profile initialization") +Cc: stable@vger.kernel.org +Signed-off-by: Aleksandr Loktionov +Reviewed-by: Marcin Szycik +Tested-by: Rafal Romanowski +Signed-off-by: Tony Nguyen +Link: https://patch.msgid.link/20260717185340.3595286-12-anthony.l.nguyen@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/intel/ice/ice_parser.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/ethernet/intel/ice/ice_parser.c ++++ b/drivers/net/ethernet/intel/ice/ice_parser.c +@@ -2368,6 +2368,9 @@ int ice_parser_profile_init(struct ice_p + u16 proto_off = 0; + u16 off; + ++ if (rslt->ptype >= ICE_FLOW_PTYPE_MAX) ++ return -EINVAL; ++ + memset(prof, 0, sizeof(*prof)); + set_bit(rslt->ptype, prof->ptypes); + if (blk == ICE_BLK_SW) { diff --git a/queue-7.1/ice-use-read_once-to-access-cached-phc-time.patch b/queue-7.1/ice-use-read_once-to-access-cached-phc-time.patch new file mode 100644 index 0000000000..3b7f378960 --- /dev/null +++ b/queue-7.1/ice-use-read_once-to-access-cached-phc-time.patch @@ -0,0 +1,39 @@ +From 2915681b89f817677ab9f1166d95b595bc144f5f Mon Sep 17 00:00:00 2001 +From: Sergey Temerkhanov +Date: Fri, 17 Jul 2026 11:53:30 -0700 +Subject: ice: use READ_ONCE() to access cached PHC time + +From: Sergey Temerkhanov + +commit 2915681b89f817677ab9f1166d95b595bc144f5f upstream. + +ptp.cached_phc_time is a 64-bit value updated by a periodic work item +on one CPU and read locklessly on another. On 32-bit or non-atomic +architectures this can result in a torn read. Use READ_ONCE() to +enforce a single atomic load. + +Fixes: 77a781155a65 ("ice: enable receive hardware timestamping") +Cc: stable@vger.kernel.org +Signed-off-by: Sergey Temerkhanov +Signed-off-by: Aleksandr Loktionov +Reviewed-by: Simon Horman +Tested-by: Rinitha S (A Contingent worker at Intel) +Signed-off-by: Tony Nguyen +Link: https://patch.msgid.link/20260717185340.3595286-9-anthony.l.nguyen@intel.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/intel/ice/ice_ptp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/intel/ice/ice_ptp.c ++++ b/drivers/net/ethernet/intel/ice/ice_ptp.c +@@ -350,7 +350,7 @@ static u64 ice_ptp_extend_40b_ts(struct + return 0; + } + +- return ice_ptp_extend_32b_ts(pf->ptp.cached_phc_time, ++ return ice_ptp_extend_32b_ts(READ_ONCE(pf->ptp.cached_phc_time), + (in_tstamp >> 8) & mask); + } + diff --git a/queue-7.1/ila-reload-ipv6-header-after-pskb_may_pull-in-checksum-adjust.patch b/queue-7.1/ila-reload-ipv6-header-after-pskb_may_pull-in-checksum-adjust.patch new file mode 100644 index 0000000000..2a6a819100 --- /dev/null +++ b/queue-7.1/ila-reload-ipv6-header-after-pskb_may_pull-in-checksum-adjust.patch @@ -0,0 +1,83 @@ +From 92d3817649df2b0b6a008a686c8275c88d7ef594 Mon Sep 17 00:00:00 2001 +From: Michael Bommarito +Date: Tue, 14 Jul 2026 07:49:03 -0400 +Subject: ila: reload IPv6 header after pskb_may_pull in checksum adjust + +From: Michael Bommarito + +commit 92d3817649df2b0b6a008a686c8275c88d7ef594 upstream. + +ila_csum_adjust_transport() caches ip6h = ipv6_hdr(skb) before calling +pskb_may_pull(). On a non-linear skb whose transport header sits in a page +fragment, pskb_may_pull() can call __pskb_pull_tail() / pskb_expand_head() +and free the old skb head, leaving ip6h dangling; the following +get_csum_diff(ip6h, p) then reads freed memory. ila_update_ipv6_locator() +uses ip6h (and the iaddr derived from it) again after the csum-adjust +call and additionally writes the new locator through that pointer. + +Impact: a remote IPv6 packet routed through a configured ILA +csum-adjust-transport route or receive-side mapping triggers a +slab-use-after-free in ila_update_ipv6_locator() (KASAN). The route or +mapping requires CAP_NET_ADMIN to configure, but trigger packets are +unauthenticated once it exists. + +Reload ip6h after each pskb_may_pull() in ila_csum_adjust_transport() +before the csum-diff read. In ila_update_ipv6_locator() only the +ILA_CSUM_ADJUST_TRANSPORT case pulls the skb, so reload ip6h and iaddr in +that case alone before the destination-address write; the neutral-map +modes never pull and keep their cached pointers. + +Fixes: 33f11d16142b ("ila: Create net/ipv6/ila directory") +Cc: stable@vger.kernel.org +Signed-off-by: Michael Bommarito +Reviewed-by: Simon Horman +Reviewed-by: Antoine Tenart +Link: https://patch.msgid.link/20260714114903.3763420-1-michael.bommarito@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ila/ila_common.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/net/ipv6/ila/ila_common.c ++++ b/net/ipv6/ila/ila_common.c +@@ -85,6 +85,7 @@ static void ila_csum_adjust_transport(st + struct tcphdr *th = (struct tcphdr *) + (skb_network_header(skb) + nhoff); + ++ ip6h = ipv6_hdr(skb); + diff = get_csum_diff(ip6h, p); + inet_proto_csum_replace_by_diff(&th->check, skb, + diff, true, true); +@@ -96,6 +97,7 @@ static void ila_csum_adjust_transport(st + (skb_network_header(skb) + nhoff); + + if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { ++ ip6h = ipv6_hdr(skb); + diff = get_csum_diff(ip6h, p); + inet_proto_csum_replace_by_diff(&uh->check, skb, + diff, true, true); +@@ -110,6 +112,7 @@ static void ila_csum_adjust_transport(st + struct icmp6hdr *ih = (struct icmp6hdr *) + (skb_network_header(skb) + nhoff); + ++ ip6h = ipv6_hdr(skb); + diff = get_csum_diff(ip6h, p); + inet_proto_csum_replace_by_diff(&ih->icmp6_cksum, skb, + diff, true, true); +@@ -127,6 +130,15 @@ void ila_update_ipv6_locator(struct sk_b + switch (p->csum_mode) { + case ILA_CSUM_ADJUST_TRANSPORT: + ila_csum_adjust_transport(skb, p); ++ /* ++ * ila_csum_adjust_transport() calls pskb_may_pull(), which can ++ * reallocate the skb head and leave ip6h (and the iaddr derived ++ * from it) dangling; reload both before the write below. The ++ * other csum modes do not pull, so their cached pointers stay ++ * valid. ++ */ ++ ip6h = ipv6_hdr(skb); ++ iaddr = ila_a2i(&ip6h->daddr); + break; + case ILA_CSUM_NEUTRAL_MAP: + if (sir2ila) { diff --git a/queue-7.1/mac802154-hold-an-interface-reference-across-the-scan-worker.patch b/queue-7.1/mac802154-hold-an-interface-reference-across-the-scan-worker.patch new file mode 100644 index 0000000000..498fe030c5 --- /dev/null +++ b/queue-7.1/mac802154-hold-an-interface-reference-across-the-scan-worker.patch @@ -0,0 +1,78 @@ +From 234e5e898b713bc0b3a631b6f002897f43d046c8 Mon Sep 17 00:00:00 2001 +From: Ibrahim Hashimov +Date: Tue, 21 Jul 2026 23:12:28 +0200 +Subject: mac802154: hold an interface reference across the scan worker + +From: Ibrahim Hashimov + +commit 234e5e898b713bc0b3a631b6f002897f43d046c8 upstream. + +mac802154_scan_worker() captures the scanning sub-interface under RCU +and then keeps dereferencing sdata->dev after rcu_read_unlock() and +outside the rtnl -- in the failure traces, in +mac802154_transmit_beacon_req() (skb->dev = sdata->dev), and in the +end_scan cleanup. Nothing keeps that netdev alive across the worker +iteration. + +A concurrent DEL_INTERFACE or PHY removal can unregister the interface +once the worker drops the rtnl between its two drv_set_channel() +sections. unregister_netdevice() frees the netdev asynchronously from +netdev_run_todo() with the rtnl already dropped, so neither holding the +rtnl nor the per-PHY IEEE802154_IS_SCANNING flag prevents a stale worker +iteration from dereferencing the freed netdev -- a KASAN +slab-use-after-free, reachable by racing TRIGGER_SCAN against +DEL_INTERFACE (both CAP_NET_ADMIN). + +Pin the netdev with netdev_hold() while the RCU read lock is still held, +and release it at every worker exit. + +Fixes: 57588c71177f ("mac802154: Handle passive scanning") +Cc: stable@vger.kernel.org +Signed-off-by: Ibrahim Hashimov +Link: https://patch.msgid.link/20260721211228.34578-1-security@auditcode.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/mac802154/scan.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/net/mac802154/scan.c ++++ b/net/mac802154/scan.c +@@ -179,6 +179,7 @@ void mac802154_scan_worker(struct work_s + enum nl802154_scan_types scan_req_type; + struct ieee802154_sub_if_data *sdata; + unsigned int scan_duration = 0; ++ netdevice_tracker dev_tracker; + struct wpan_phy *wpan_phy; + u8 scan_req_duration; + u8 page, channel; +@@ -209,6 +210,14 @@ void mac802154_scan_worker(struct work_s + return; + } + ++ /* ++ * sdata->dev is dereferenced below after rcu_read_unlock() and outside ++ * the rtnl, and a concurrent DEL_INTERFACE / PHY teardown can free it ++ * asynchronously from netdev_run_todo(). Pin it with a reference taken ++ * while the RCU read lock is still held, and drop it at every exit. ++ */ ++ netdev_hold(sdata->dev, &dev_tracker, GFP_ATOMIC); ++ + wpan_phy = scan_req->wpan_phy; + scan_req_type = scan_req->type; + scan_req_duration = scan_req->duration; +@@ -262,12 +271,14 @@ void mac802154_scan_worker(struct work_s + "Scan page %u channel %u for %ums\n", + page, channel, jiffies_to_msecs(scan_duration)); + queue_delayed_work(local->mac_wq, &local->scan_work, scan_duration); ++ netdev_put(sdata->dev, &dev_tracker); + return; + + end_scan: + rtnl_lock(); + mac802154_scan_cleanup_locked(local, sdata, false); + rtnl_unlock(); ++ netdev_put(sdata->dev, &dev_tracker); + } + + int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata, diff --git a/queue-7.1/mac802154-llsec-reject-frames-shorter-than-the-authentication-tag.patch b/queue-7.1/mac802154-llsec-reject-frames-shorter-than-the-authentication-tag.patch new file mode 100644 index 0000000000..efb11839a3 --- /dev/null +++ b/queue-7.1/mac802154-llsec-reject-frames-shorter-than-the-authentication-tag.patch @@ -0,0 +1,55 @@ +From fd3a3f28ed60c6af4b2a39933b151d6b27842c3b Mon Sep 17 00:00:00 2001 +From: Doruk Tan Ozturk +Date: Thu, 16 Jul 2026 21:34:23 +0200 +Subject: mac802154: llsec: reject frames shorter than the authentication tag + +From: Doruk Tan Ozturk + +commit fd3a3f28ed60c6af4b2a39933b151d6b27842c3b upstream. + +llsec_do_decrypt_auth() computes the associated-data length for the +AEAD request as + + assoclen += datalen - authlen; + +where datalen is the number of bytes after the MAC header and authlen +(4, 8 or 16) is the length of the authentication tag. Nothing verifies +that the frame actually carries at least authlen payload bytes. A +secured frame whose payload is shorter than the tag makes +datalen - authlen negative; assoclen is then passed to +aead_request_set_ad() as an unsigned value close to 4 GiB, so +crypto_aead_decrypt() walks far off the end of the scatterlist that +only spans the real frame. + +The frame is fully attacker-controlled and reaches this path from any +IEEE 802.15.4 peer in radio range. Reject frames whose payload is +shorter than the authentication tag before the subtraction. + +Dynamically reproduced on a KASAN kernel as a general-protection-fault +in the AEAD scatterwalk, and the fix confirmed. + +Fixes: 4c14a2fb5d14 ("mac802154: add llsec decryption method") +Cc: stable@vger.kernel.org +Reviewed-by: Simon Horman +Signed-off-by: Doruk Tan Ozturk +Link: https://patch.msgid.link/20260716193423.32498-1-doruk@0sec.ai +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/mac802154/llsec.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/net/mac802154/llsec.c ++++ b/net/mac802154/llsec.c +@@ -891,6 +891,11 @@ llsec_do_decrypt_auth(struct sk_buff *sk + data = skb_mac_header(skb) + skb->mac_len; + datalen = skb_tail_pointer(skb) - data; + ++ if (datalen < authlen) { ++ kfree_sensitive(req); ++ return -EBADMSG; ++ } ++ + sg_init_one(&sg, skb_mac_header(skb), assoclen + datalen); + + if (!(hdr->sec.level & IEEE802154_SCF_SECLEVEL_ENC)) { diff --git a/queue-7.1/mctp-serial-handle-zero-length-frames-to-prevent-rx-buffer-overflow.patch b/queue-7.1/mctp-serial-handle-zero-length-frames-to-prevent-rx-buffer-overflow.patch new file mode 100644 index 0000000000..510ce50353 --- /dev/null +++ b/queue-7.1/mctp-serial-handle-zero-length-frames-to-prevent-rx-buffer-overflow.patch @@ -0,0 +1,93 @@ +From 793b9b729f1e8de57be8c8daf1a9838be96cabed Mon Sep 17 00:00:00 2001 +From: Doruk Tan Ozturk +Date: Wed, 15 Jul 2026 10:20:21 +0200 +Subject: mctp: serial: handle zero-length frames to prevent rx buffer overflow + +From: Doruk Tan Ozturk + +commit 793b9b729f1e8de57be8c8daf1a9838be96cabed upstream. + +The MCTP serial receive state machine reads a frame length byte in +mctp_serial_push_header() case 2 and validates it upper-bound-only: + + if (c > MCTP_SERIAL_FRAME_MTU) { + dev->rxstate = STATE_ERR; + } else { + dev->rxlen = c; + dev->rxpos = 0; + dev->rxstate = STATE_DATA; + ... + } + +A length of zero passes this check, so rxlen is set to 0 and the state +machine advances to STATE_DATA. In mctp_serial_push() STATE_DATA, the +incoming byte is stored and rxpos incremented before the terminator is +tested: + + dev->rxbuf[dev->rxpos] = c; + dev->rxpos++; + dev->rxstate = STATE_DATA; + if (dev->rxpos == dev->rxlen) { + dev->rxpos = 0; + dev->rxstate = STATE_TRAILER; + } + +With rxlen == 0 the "rxpos == rxlen" terminator can never fire (rxpos is +already 1 on the first data byte), so subsequent bytes are written past +the end of the fixed 74-byte rxbuf, which is the last member of the +netdev private area. Every following data byte is an attacker-controlled +1-byte out-of-bounds heap write, and the overflow continues until a +frame (0x7e) or escape byte resets the parser -- effectively unbounded. + +Reaching this requires CAP_NET_ADMIN to attach the N_MCTP line +discipline and bring the resulting mctpserialN netdev up, after which +the bytes arrive via the tty receive path. + +Route a zero-length frame straight to STATE_TRAILER instead of +STATE_DATA. The trailer/framing bytes are still consumed, and the frame +resolves to a zero-length skb that the MCTP core rejects; the parser +never enters STATE_DATA with rxlen == 0, so the out-of-bounds write can +no longer occur. + +KASAN, on a frame of 0x7e 0x01 0x00 followed by data bytes (before this +change): + + UBSAN: array-index-out-of-bounds in drivers/net/mctp/mctp-serial.c:370 + index 74 is out of range for type 'u8 [74]' + BUG: KASAN: slab-out-of-bounds in mctp_serial_tty_receive_buf + Write of size 1 at addr ... by task kworker/u16:0 + mctp_serial_tty_receive_buf + tty_ldisc_receive_buf + flush_to_ldisc + Allocated by task 152: + alloc_netdev_mqs + mctp_serial_open + +v2: route zero-length frames to STATE_TRAILER instead of STATE_ERR so + the trailer/framing bytes are still consumed (Jeremy Kerr). + +Found by 0sec automated security-research tooling (https://0sec.ai). +Fixes: a0c2ccd9b5ad ("mctp: Add MCTP-over-serial transport binding") +Cc: stable@vger.kernel.org +Suggested-by: Jeremy Kerr +Assisted-by: 0sec:multi-model +Signed-off-by: Doruk Tan Ozturk +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260715082021.46315-1-doruk@0sec.ai +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/mctp/mctp-serial.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/mctp/mctp-serial.c ++++ b/drivers/net/mctp/mctp-serial.c +@@ -318,7 +318,7 @@ static void mctp_serial_push_header(stru + } else { + dev->rxlen = c; + dev->rxpos = 0; +- dev->rxstate = STATE_DATA; ++ dev->rxstate = c > 0 ? STATE_DATA : STATE_TRAILER; + dev->rxfcs = crc_ccitt_byte(dev->rxfcs, c); + } + break; diff --git a/queue-7.1/openvswitch-fix-gso-userspace-truncation-underflow.patch b/queue-7.1/openvswitch-fix-gso-userspace-truncation-underflow.patch new file mode 100644 index 0000000000..b77402b636 --- /dev/null +++ b/queue-7.1/openvswitch-fix-gso-userspace-truncation-underflow.patch @@ -0,0 +1,198 @@ +From 4032f8ed10fcb84d41c508dfb04be96589f78dfe Mon Sep 17 00:00:00 2001 +From: Kyle Zeng +Date: Tue, 7 Jul 2026 15:16:35 -0700 +Subject: openvswitch: fix GSO userspace truncation underflow + +From: Kyle Zeng + +commit 4032f8ed10fcb84d41c508dfb04be96589f78dfe upstream. + +OVS_ACTION_ATTR_TRUNC currently stores a delta from the original skb +length in OVS_CB(skb)->cutlen. When a later userspace action segments a +GSO skb, queue_gso_packets() reuses that delta for each smaller segment. +A segment can then reach queue_userspace_packet() with cutlen greater +than skb->len, underflowing the length passed to skb_zerocopy(). + +Store the maximum preserved length instead and bound each consumer +against the current skb length. Use U32_MAX as the no-truncation +sentinel so the value remains valid if skb geometry changes before a +consumer handles it. + +Fixes: f2a4d086ed4c ("openvswitch: Add packet truncation support.") +Cc: stable@vger.kernel.org +Assisted-by: Codex:gpt-5.5 +Signed-off-by: Kyle Zeng +Reviewed-by: Ilya Maximets +Reviewed-by: Aaron Conole +Link: https://patch.msgid.link/20260707221635.27489-1-kylebot@openai.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/openvswitch/actions.c | 19 +++++++------------ + net/openvswitch/datapath.c | 25 ++++++++++++++----------- + net/openvswitch/datapath.h | 2 +- + net/openvswitch/vport.c | 2 +- + 4 files changed, 23 insertions(+), 25 deletions(-) + +--- a/net/openvswitch/actions.c ++++ b/net/openvswitch/actions.c +@@ -837,12 +837,8 @@ static void do_output(struct datapath *d + u16 mru = OVS_CB(skb)->mru; + u32 cutlen = OVS_CB(skb)->cutlen; + +- if (unlikely(cutlen > 0)) { +- if (skb->len - cutlen > ovs_mac_header_len(key)) +- pskb_trim(skb, skb->len - cutlen); +- else +- pskb_trim(skb, ovs_mac_header_len(key)); +- } ++ if (unlikely(cutlen < skb->len)) ++ pskb_trim(skb, max(cutlen, ovs_mac_header_len(key))); + + if (likely(!mru || + (skb->len <= mru + vport->dev->hard_header_len))) { +@@ -1234,7 +1230,7 @@ static void execute_psample(struct datap + + psample_group.net = ovs_dp_get_net(dp); + md.in_ifindex = OVS_CB(skb)->input_vport->dev->ifindex; +- md.trunc_size = skb->len - OVS_CB(skb)->cutlen; ++ md.trunc_size = min(skb->len, OVS_CB(skb)->cutlen); + md.rate_as_probability = 1; + + rate = OVS_CB(skb)->probability ? OVS_CB(skb)->probability : U32_MAX; +@@ -1284,22 +1280,21 @@ static int do_execute_actions(struct dat + clone = skb_clone(skb, GFP_ATOMIC); + if (clone) + do_output(dp, clone, port, key); +- OVS_CB(skb)->cutlen = 0; ++ OVS_CB(skb)->cutlen = U32_MAX; + break; + } + + case OVS_ACTION_ATTR_TRUNC: { + struct ovs_action_trunc *trunc = nla_data(a); + +- if (skb->len > trunc->max_len) +- OVS_CB(skb)->cutlen = skb->len - trunc->max_len; ++ OVS_CB(skb)->cutlen = trunc->max_len; + break; + } + + case OVS_ACTION_ATTR_USERSPACE: + output_userspace(dp, skb, key, a, attr, + len, OVS_CB(skb)->cutlen); +- OVS_CB(skb)->cutlen = 0; ++ OVS_CB(skb)->cutlen = U32_MAX; + if (nla_is_last(a, rem)) { + consume_skb(skb); + return 0; +@@ -1453,7 +1448,7 @@ static int do_execute_actions(struct dat + + case OVS_ACTION_ATTR_PSAMPLE: + execute_psample(dp, skb, a); +- OVS_CB(skb)->cutlen = 0; ++ OVS_CB(skb)->cutlen = U32_MAX; + if (nla_is_last(a, rem)) { + consume_skb(skb); + return 0; +--- a/net/openvswitch/datapath.c ++++ b/net/openvswitch/datapath.c +@@ -276,7 +276,7 @@ void ovs_dp_process_packet(struct sk_buf + upcall.portid = ovs_vport_find_upcall_portid(p, skb); + + upcall.mru = OVS_CB(skb)->mru; +- error = ovs_dp_upcall(dp, skb, key, &upcall, 0); ++ error = ovs_dp_upcall(dp, skb, key, &upcall, U32_MAX); + switch (error) { + case 0: + case -EAGAIN: +@@ -457,7 +457,8 @@ static int queue_userspace_packet(struct + struct sk_buff *nskb = NULL; + struct sk_buff *user_skb = NULL; /* to be queued to userspace */ + struct nlattr *nla; +- size_t len; ++ size_t msg_size; ++ size_t skb_len; + unsigned int hlen; + int err, dp_ifindex; + u64 hash; +@@ -478,7 +479,8 @@ static int queue_userspace_packet(struct + skb = nskb; + } + +- if (nla_attr_size(skb->len) > USHRT_MAX) { ++ skb_len = min(skb->len, cutlen); ++ if (nla_attr_size(skb_len) > USHRT_MAX) { + err = -EFBIG; + goto out; + } +@@ -493,13 +495,13 @@ static int queue_userspace_packet(struct + * padding logic. Only perform zerocopy if padding is not required. + */ + if (dp->user_features & OVS_DP_F_UNALIGNED) +- hlen = skb_zerocopy_headlen(skb); ++ hlen = min(skb_zerocopy_headlen(skb), cutlen); + else +- hlen = skb->len; ++ hlen = skb_len; + +- len = upcall_msg_size(upcall_info, hlen - cutlen, +- OVS_CB(skb)->acts_origlen); +- user_skb = genlmsg_new(len, GFP_ATOMIC); ++ msg_size = upcall_msg_size(upcall_info, hlen, ++ OVS_CB(skb)->acts_origlen); ++ user_skb = genlmsg_new(msg_size, GFP_ATOMIC); + if (!user_skb) { + err = -ENOMEM; + goto out; +@@ -560,7 +562,7 @@ static int queue_userspace_packet(struct + } + + /* Add OVS_PACKET_ATTR_LEN when packet is truncated */ +- if (cutlen > 0 && ++ if (skb_len < skb->len && + nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, skb->len)) { + err = -ENOBUFS; + goto out; +@@ -585,9 +587,9 @@ static int queue_userspace_packet(struct + err = -ENOBUFS; + goto out; + } +- nla->nla_len = nla_attr_size(skb->len - cutlen); ++ nla->nla_len = nla_attr_size(skb_len); + +- err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen); ++ err = skb_zerocopy(user_skb, skb, skb_len, hlen); + if (err) + goto out; + +@@ -644,6 +646,7 @@ static int ovs_packet_cmd_execute(struct + packet->ignore_df = 1; + } + OVS_CB(packet)->mru = mru; ++ OVS_CB(packet)->cutlen = U32_MAX; + + if (a[OVS_PACKET_ATTR_HASH]) { + hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]); +--- a/net/openvswitch/datapath.h ++++ b/net/openvswitch/datapath.h +@@ -118,7 +118,7 @@ struct datapath { + * @mru: The maximum received fragement size; 0 if the packet is not + * fragmented. + * @acts_origlen: The netlink size of the flow actions applied to this skb. +- * @cutlen: The number of bytes from the packet end to be removed. ++ * @cutlen: The number of bytes in the packet to preserve on output. + * @probability: The sampling probability that was applied to this skb; 0 means + * no sampling has occurred; U32_MAX means 100% probability. + * @upcall_pid: Netlink socket PID to use for sending this packet to userspace; +--- a/net/openvswitch/vport.c ++++ b/net/openvswitch/vport.c +@@ -502,7 +502,7 @@ int ovs_vport_receive(struct vport *vpor + + OVS_CB(skb)->input_vport = vport; + OVS_CB(skb)->mru = 0; +- OVS_CB(skb)->cutlen = 0; ++ OVS_CB(skb)->cutlen = U32_MAX; + OVS_CB(skb)->probability = 0; + OVS_CB(skb)->upcall_pid = 0; + if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) { diff --git a/queue-7.1/ovpn-fix-peer-refcount-leak-in-tcp-error-paths.patch b/queue-7.1/ovpn-fix-peer-refcount-leak-in-tcp-error-paths.patch new file mode 100644 index 0000000000..fba0d747ec --- /dev/null +++ b/queue-7.1/ovpn-fix-peer-refcount-leak-in-tcp-error-paths.patch @@ -0,0 +1,64 @@ +From 63bbe18fc03062f483c627838a566a707b62da79 Mon Sep 17 00:00:00 2001 +From: Pavitra Jha +Date: Sat, 23 May 2026 05:02:43 -0400 +Subject: ovpn: fix peer refcount leak in TCP error paths + +From: Pavitra Jha + +commit 63bbe18fc03062f483c627838a566a707b62da79 upstream. + +When either the TCP RX or TX error path calls ovpn_peer_hold() followed +by schedule_work(&peer->tcp.defer_del_work), and the work item is already +pending from the other path, schedule_work() returns false and the work +runs only once. Since ovpn_tcp_peer_del_work() calls ovpn_peer_put() +exactly once, the extra reference taken by the losing path is never +dropped, leaking the peer object. + +The race window: + + CPU0 (strparser/RX error): CPU1 (tcp_tx_work/TX error): + ovpn_peer_hold() <- refcnt+1 ovpn_peer_hold() <- refcnt+2 + schedule_work() <- queued schedule_work() <- NO-OP + (work already pending) + ovpn_tcp_peer_del_work runs: + ovpn_peer_del() + ovpn_peer_put() <- refcnt+1 + <- peer never freed + +Fix by checking the return value of schedule_work() in both paths and +calling ovpn_peer_put() to drop the extra reference if the work was +already pending. ovpn_peer_hold() is kept unconditional in the TX path +as it cannot fail at that point. + +Fixes: a6a5e87b3ee4 ("ovpn: avoid sleep in atomic context in TCP RX error path") +Cc: stable@vger.kernel.org +Signed-off-by: Pavitra Jha +Reviewed-by: Sabrina Dubroca +Signed-off-by: Antonio Quartulli +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ovpn/tcp.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/ovpn/tcp.c ++++ b/drivers/net/ovpn/tcp.c +@@ -151,7 +151,8 @@ err: + /* take reference for deferred peer deletion. should never fail */ + if (WARN_ON(!ovpn_peer_hold(peer))) + goto err_nopeer; +- schedule_work(&peer->tcp.defer_del_work); ++ if (!schedule_work(&peer->tcp.defer_del_work)) ++ ovpn_peer_put(peer); + ovpn_dev_dstats_rx_dropped(peer->ovpn->dev); + err_nopeer: + kfree_skb(skb); +@@ -283,7 +284,8 @@ static void ovpn_tcp_send_sock(struct ov + * stream therefore we abort the connection + */ + ovpn_peer_hold(peer); +- schedule_work(&peer->tcp.defer_del_work); ++ if (!schedule_work(&peer->tcp.defer_del_work)) ++ ovpn_peer_put(peer); + + /* we bail out immediately and keep tx_in_progress set + * to true. This way we prevent more TX attempts diff --git a/queue-7.1/ovpn-hold-peer-before-scheduling-keepalive-work.patch b/queue-7.1/ovpn-hold-peer-before-scheduling-keepalive-work.patch new file mode 100644 index 0000000000..368eede7a3 --- /dev/null +++ b/queue-7.1/ovpn-hold-peer-before-scheduling-keepalive-work.patch @@ -0,0 +1,47 @@ +From a4710ae2e7e322fdaefb4be8604228279cfaf48c Mon Sep 17 00:00:00 2001 +From: Shuvam Pandey +Date: Sat, 23 May 2026 20:38:27 +0545 +Subject: ovpn: hold peer before scheduling keepalive work + +From: Shuvam Pandey + +commit a4710ae2e7e322fdaefb4be8604228279cfaf48c upstream. + +ovpn_peer_keepalive_send() passes its peer reference to +ovpn_xmit_special(), which ultimately drops it. The keepalive scheduler +currently queues the work first and takes the reference only after +schedule_work() reports that the work was queued. + +Once schedule_work() queues the item, another CPU may run the worker +before the caller gets to ovpn_peer_hold(). In that case the worker can +consume a reference that was not acquired for it, corrupting the peer +lifetime accounting. + +Take the peer reference before queueing the work and drop it again when +the work was already pending. + +Fixes: 3ecfd9349f40 ("ovpn: implement keepalive mechanism") +Cc: stable@vger.kernel.org +Signed-off-by: Shuvam Pandey +Reviewed-by: Sabrina Dubroca +Signed-off-by: Antonio Quartulli +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ovpn/peer.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/ovpn/peer.c ++++ b/drivers/net/ovpn/peer.c +@@ -1285,8 +1285,10 @@ static time64_t ovpn_peer_keepalive_work + netdev_dbg(peer->ovpn->dev, + "sending keepalive to peer %u\n", + peer->id); +- if (schedule_work(&peer->keepalive_work)) +- ovpn_peer_hold(peer); ++ if (WARN_ON(!ovpn_peer_hold(peer))) ++ return 0; ++ if (!schedule_work(&peer->keepalive_work)) ++ ovpn_peer_put(peer); + } + + if (next_run1 < next_run2) diff --git a/queue-7.1/pppoe-reload-header-pointer-after-dev_hard_header.patch b/queue-7.1/pppoe-reload-header-pointer-after-dev_hard_header.patch new file mode 100644 index 0000000000..fd5472dcfc --- /dev/null +++ b/queue-7.1/pppoe-reload-header-pointer-after-dev_hard_header.patch @@ -0,0 +1,44 @@ +From e9c238f6fe42fb1b4dba3a578277de32cb487937 Mon Sep 17 00:00:00 2001 +From: Asim Viladi Oglu Manizada +Date: Wed, 22 Jul 2026 09:38:43 +0000 +Subject: pppoe: reload header pointer after dev_hard_header() + +From: Asim Viladi Oglu Manizada + +commit e9c238f6fe42fb1b4dba3a578277de32cb487937 upstream. + +pppoe_sendmsg() saves a pointer to the PPPoE header before calling +dev_hard_header(). Device header callbacks are allowed to reallocate the +skb head, invalidating pointers into it. + +This can happen when a send is blocked in copy_from_user() while the first +non-Ethernet port is added to an empty team device. The team's delegated +GRE header callback then expands the skb head. PPPoE subsequently writes +six bytes through the stale pointer into the freed head. + +Reload the PPPoE header through the skb's network-header offset after +device header creation. pskb_expand_head() updates that offset when it +relocates the head. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Asim Viladi Oglu Manizada +Reviewed-by: Vadim Fedorenko +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260722093814.3017176-1-manizada@pm.me +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ppp/pppoe.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -824,6 +824,7 @@ static int pppoe_sendmsg(struct socket * + dev_hard_header(skb, dev, ETH_P_PPP_SES, + po->pppoe_pa.remote, NULL, total_len); + ++ ph = pppoe_hdr(skb); + memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); + + ph->length = htons(total_len); diff --git a/queue-7.1/rtase-workaround-for-tx-hang-caused-by-hardware-packet-parsing.patch b/queue-7.1/rtase-workaround-for-tx-hang-caused-by-hardware-packet-parsing.patch new file mode 100644 index 0000000000..5c960ef62c --- /dev/null +++ b/queue-7.1/rtase-workaround-for-tx-hang-caused-by-hardware-packet-parsing.patch @@ -0,0 +1,301 @@ +From 1c50efa1faf3a1a96e100b07ec7a2f3164d90bee Mon Sep 17 00:00:00 2001 +From: Justin Lai +Date: Thu, 9 Jul 2026 18:34:56 +0800 +Subject: rtase: Workaround for TX hang caused by hardware packet parsing + +From: Justin Lai + +commit 1c50efa1faf3a1a96e100b07ec7a2f3164d90bee upstream. + +The hardware performs packet parsing before packet transmission. +Parsing incomplete IPv4, IPv6, TCP, or UDP headers may trigger a TX +hang because the hardware parser expects additional protocol header +data that is not present in the packet. + +The hardware performs additional PTP parsing on UDP packets identified +by destination ports 319/320 at the expected UDP destination port +offset. + +If such a packet has transport data smaller than RTASE_MIN_PAD_LEN, +the hardware parser expects additional packet data and may trigger a +TX hang. + +To avoid these hardware issues, the driver applies the following +workarounds. + +Drop malformed packets that may trigger this hardware issue before +transmission. + +For IPv4 non-initial fragments, the hardware does not check the +fragment offset before parsing the expected transport header location. +As a result, these packets are still subject to transport header +parsing even though they do not contain a transport header. If the +transport data is shorter than the minimum transport header required +by the hardware parser, pad the transport data to the minimum +transport header length required by the hardware parser. Packets that +also match the hardware PTP parsing conditions continue to follow the +corresponding workaround. + +For IPv6 fragmented packets, neither of the above hardware issues +occurs because the hardware only continues packet parsing when the +IPv6 Base Header Next Header field directly indicates UDP. Packets +carrying a Fragment Header do not continue through the subsequent +packet parsing stages. + +For packets identified for hardware PTP parsing, pad the transport +data so it reaches RTASE_MIN_PAD_LEN before transmission. + +Fixes: d6e882b89fdf ("rtase: Implement .ndo_start_xmit function") +Cc: stable@vger.kernel.org +Signed-off-by: Justin Lai +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260709103456.83789-1-justinlai0215@realtek.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/realtek/rtase/rtase.h | 8 + drivers/net/ethernet/realtek/rtase/rtase_main.c | 197 ++++++++++++++++++++++++ + 2 files changed, 205 insertions(+) + +--- a/drivers/net/ethernet/realtek/rtase/rtase.h ++++ b/drivers/net/ethernet/realtek/rtase/rtase.h +@@ -188,6 +188,12 @@ enum rtase_sw_flag_content { + RTASE_SWF_MSIX_ENABLED = BIT(2), + }; + ++enum rtase_parse_result { ++ RTASE_PARSE_OK, ++ RTASE_PARSE_SKIP, ++ RTASE_PARSE_DROP, ++}; ++ + #define RSVD_MASK 0x3FFFC000 + + struct rtase_tx_desc { +@@ -359,4 +365,6 @@ struct rtase_private { + + #define RTASE_MSS_MASK GENMASK(28, 18) + ++#define RTASE_MIN_PAD_LEN 47 ++ + #endif /* RTASE_H */ +--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c ++++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c +@@ -61,6 +61,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1249,6 +1250,199 @@ static u32 rtase_tx_csum(struct sk_buff + return csum_cmd; + } + ++static enum rtase_parse_result rtase_get_l3_proto(struct sk_buff *skb, ++ __be16 *proto, ++ u32 *network_offset) ++{ ++ struct vlan_hdr *vh, _vh; ++ struct ethhdr *eh, _eh; ++ u32 offset = ETH_HLEN; ++ ++ eh = skb_header_pointer(skb, 0, sizeof(_eh), &_eh); ++ if (!eh) ++ return RTASE_PARSE_DROP; ++ ++ *proto = eh->h_proto; ++ ++ while (eth_type_vlan(*proto)) { ++ vh = skb_header_pointer(skb, offset, sizeof(_vh), &_vh); ++ if (!vh) ++ return RTASE_PARSE_DROP; ++ ++ *proto = vh->h_vlan_encapsulated_proto; ++ offset += VLAN_HLEN; ++ } ++ ++ *network_offset = offset; ++ ++ return RTASE_PARSE_OK; ++} ++ ++static bool rtase_pad_to_transport_len(struct sk_buff *skb, ++ u32 transport_offset, ++ u32 pad_to_len) ++{ ++ u32 trans_data_len; ++ u32 pad_len; ++ ++ trans_data_len = skb->len - transport_offset; ++ if (trans_data_len >= pad_to_len) ++ return true; ++ ++ if (skb_is_nonlinear(skb)) { ++ if (skb_linearize(skb)) ++ return false; ++ } ++ ++ pad_len = pad_to_len - trans_data_len; ++ if (__skb_put_padto(skb, skb->len + pad_len, false)) ++ return false; ++ ++ return true; ++} ++ ++static enum rtase_parse_result rtase_get_transport_offset(struct sk_buff *skb, ++ u32 *transport_offset, ++ u8 *transport_proto, ++ u32 *pad_to_len) ++{ ++ enum rtase_parse_result ret; ++ struct ipv6hdr *i6h, _i6h; ++ struct iphdr *ih, _ih; ++ bool non_first_frag; ++ __be16 proto; ++ u32 offset; ++ u32 no; ++ ++ ret = rtase_get_l3_proto(skb, &proto, &no); ++ if (ret != RTASE_PARSE_OK) ++ return ret; ++ ++ switch (proto) { ++ case htons(ETH_P_IP): ++ ih = skb_header_pointer(skb, no, sizeof(_ih), &_ih); ++ if (!ih) ++ return RTASE_PARSE_DROP; ++ ++ if (ih->ihl < 5) ++ return RTASE_PARSE_DROP; ++ ++ offset = no + ih->ihl * 4; ++ if (offset > skb->len) ++ return RTASE_PARSE_DROP; ++ ++ non_first_frag = ntohs(ih->frag_off) & IP_OFFSET; ++ ++ if (ih->protocol == IPPROTO_TCP) { ++ if (skb->len - offset < sizeof(struct tcphdr)) { ++ if (non_first_frag) { ++ *transport_offset = offset; ++ *transport_proto = IPPROTO_TCP; ++ *pad_to_len = sizeof(struct tcphdr); ++ ++ return RTASE_PARSE_OK; ++ } ++ ++ return RTASE_PARSE_DROP; ++ } ++ ++ return RTASE_PARSE_SKIP; ++ } ++ ++ if (ih->protocol != IPPROTO_UDP) ++ return RTASE_PARSE_SKIP; ++ ++ *transport_offset = offset; ++ *transport_proto = IPPROTO_UDP; ++ ++ if (skb->len - offset < sizeof(struct udphdr)) { ++ if (non_first_frag) { ++ *pad_to_len = sizeof(struct udphdr); ++ ++ return RTASE_PARSE_OK; ++ } ++ ++ return RTASE_PARSE_DROP; ++ } ++ ++ return RTASE_PARSE_OK; ++ ++ case htons(ETH_P_IPV6): ++ i6h = skb_header_pointer(skb, no, sizeof(_i6h), &_i6h); ++ if (!i6h) ++ return RTASE_PARSE_DROP; ++ ++ offset = no + sizeof(*i6h); ++ ++ if (i6h->nexthdr == IPPROTO_TCP) { ++ if (skb->len - offset < sizeof(struct tcphdr)) ++ return RTASE_PARSE_DROP; ++ ++ return RTASE_PARSE_SKIP; ++ } ++ ++ if (i6h->nexthdr != IPPROTO_UDP) ++ return RTASE_PARSE_SKIP; ++ ++ if (skb->len - offset < sizeof(struct udphdr)) ++ return RTASE_PARSE_DROP; ++ ++ *transport_offset = offset; ++ *transport_proto = IPPROTO_UDP; ++ ++ return RTASE_PARSE_OK; ++ ++ default: ++ return RTASE_PARSE_SKIP; ++ } ++} ++ ++static bool rtase_skb_pad(struct sk_buff *skb) ++{ ++ enum rtase_parse_result ret; ++ u32 transport_offset; ++ __be16 *dest, _dest; ++ u32 trans_data_len; ++ u32 pad_to_len = 0; ++ u8 transport_proto; ++ u16 dest_port; ++ ++ ret = rtase_get_transport_offset(skb, &transport_offset, ++ &transport_proto, &pad_to_len); ++ if (ret == RTASE_PARSE_SKIP) { ++ return true; ++ } else if (ret == RTASE_PARSE_DROP) { ++ netdev_dbg(skb->dev, "drop malformed packet\n"); ++ return false; ++ } ++ ++ if (pad_to_len && ++ !rtase_pad_to_transport_len(skb, transport_offset, pad_to_len)) ++ return false; ++ ++ if (transport_proto != IPPROTO_UDP) ++ return true; ++ ++ trans_data_len = skb->len - transport_offset; ++ if (trans_data_len < offsetof(struct udphdr, len) || ++ trans_data_len >= RTASE_MIN_PAD_LEN) ++ return true; ++ ++ dest = skb_header_pointer(skb, ++ transport_offset + ++ offsetof(struct udphdr, dest), ++ sizeof(_dest), &_dest); ++ if (!dest) ++ return true; ++ ++ dest_port = ntohs(*dest); ++ if (dest_port != PTP_EV_PORT && dest_port != PTP_GEN_PORT) ++ return true; ++ ++ return rtase_pad_to_transport_len(skb, transport_offset, ++ RTASE_MIN_PAD_LEN); ++} ++ + static int rtase_xmit_frags(struct rtase_ring *ring, struct sk_buff *skb, + u32 opts1, u32 opts2) + { +@@ -1362,6 +1556,9 @@ static netdev_tx_t rtase_start_xmit(stru + opts2 |= rtase_tx_csum(skb, dev); + } + ++ if (!rtase_skb_pad(skb)) ++ goto err_dma_0; ++ + frags = rtase_xmit_frags(ring, skb, opts1, opts2); + if (unlikely(frags < 0)) + goto err_dma_0; diff --git a/queue-7.1/series b/queue-7.1/series index 04d98dd14c..e5459cf89b 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -675,4 +675,22 @@ rbd-reset-positive-result-codes-to-zero-in-object-map-update-path.patch smb-client-handle-status_stopped_on_symlink-responses-without-a-symlink-target.patch ksmbd-defer-destroy_previous_session-until-after-ntlm-authentication.patch ksmbd-validate-minimum-pdu-size-for-transform-requests.patch +gve-fix-rx-queue-stall-on-alloc-failure.patch +ice-reject-out-of-range-ptype-in-ice_parser_profile_init.patch +ice-use-read_once-to-access-cached-phc-time.patch +ila-reload-ipv6-header-after-pskb_may_pull-in-checksum-adjust.patch +mac802154-hold-an-interface-reference-across-the-scan-worker.patch +mac802154-llsec-reject-frames-shorter-than-the-authentication-tag.patch +mctp-serial-handle-zero-length-frames-to-prevent-rx-buffer-overflow.patch +openvswitch-fix-gso-userspace-truncation-underflow.patch +ovpn-fix-peer-refcount-leak-in-tcp-error-paths.patch +ovpn-hold-peer-before-scheduling-keepalive-work.patch +pppoe-reload-header-pointer-after-dev_hard_header.patch +rtase-workaround-for-tx-hang-caused-by-hardware-packet-parsing.patch +tcp-initialize-standalone-tcp-ao-response-padding.patch +tcp-challenge-ack-for-non-exact-rst-in-syn-received.patch +tipc-clear-sock-sk-on-the-failed-insert-path-in-tipc_sk_create.patch +vsock-virtio-collapse-receive-queue-under-memory-pressure.patch +vxlan-mdb-fix-source-list-corruption-on-a-failed-replace.patch +watchdog-s32g_wdt-remove-incorrect-options-in-watchdog_info-struct.patch mm-slab-prevent-unbounded-recursion-in-free-path-with-new-kmalloc-type.patch diff --git a/queue-7.1/tcp-challenge-ack-for-non-exact-rst-in-syn-received.patch b/queue-7.1/tcp-challenge-ack-for-non-exact-rst-in-syn-received.patch new file mode 100644 index 0000000000..0d7bef7e15 --- /dev/null +++ b/queue-7.1/tcp-challenge-ack-for-non-exact-rst-in-syn-received.patch @@ -0,0 +1,165 @@ +From a28c4fcbf774e23b4779cae468e3497a5ad1f4a1 Mon Sep 17 00:00:00 2001 +From: Yuxiang Yang +Date: Fri, 17 Jul 2026 08:14:42 +0000 +Subject: tcp: challenge ACK for non-exact RST in SYN-RECEIVED + +From: Yuxiang Yang + +commit a28c4fcbf774e23b4779cae468e3497a5ad1f4a1 upstream. + +The SYN-RECEIVED request-socket path in tcp_check_req() accepts an +in-window RST without requiring SEG.SEQ to exactly match RCV.NXT. A +non-exact RST therefore removes the request instead of eliciting a +challenge ACK. + +RFC 9293 section 3.10.7.4 applies the RFC 5961 reset check in +SYN-RECEIVED: an exact RST resets the connection, while a non-exact +in-window RST must trigger a challenge ACK and be dropped. + +Apply that check before the ACK-field validation, following the RFC +sequence-number, RST, then ACK processing order. Factor the per-netns +challenge ACK quota out of tcp_send_challenge_ack() so request sockets +can share it. Use the request socket's send_ack() callback and its own +out-of-window ACK timestamp to send and rate-limit the response. + +Reported-by: Yuxiang Yang +Reported-by: Yizhou Zhao +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Fixes: 282f23c6ee34 ("tcp: implement RFC 5961 3.2") +Cc: stable@vger.kernel.org +Signed-off-by: Yuxiang Yang +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260717081443.809393-2-yangyx22@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + include/net/tcp.h | 2 + + net/ipv4/tcp_input.c | 56 ++++++++++++++++++++++++++++++++++++----------- + net/ipv4/tcp_minisocks.c | 12 +++++++++- + 3 files changed, 56 insertions(+), 14 deletions(-) + +--- a/include/net/tcp.h ++++ b/include/net/tcp.h +@@ -1965,6 +1965,8 @@ static inline void tcp_fast_path_check(s + + bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb, + int mib_idx, u32 *last_oow_ack_time); ++void tcp_reqsk_send_challenge_ack(struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req); + + static inline void tcp_mib_init(struct net *net) + { +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -4038,24 +4038,17 @@ static void tcp_send_ack_reflect_ect(str + __tcp_send_ack(sk, tp->rcv_nxt, flags); + } + +-/* RFC 5961 7 [ACK Throttling] */ +-static void tcp_send_challenge_ack(struct sock *sk, bool accecn_reflector) ++/* Consume one slot from the per-netns RFC 5961 challenge ACK quota. ++ * Returns true if a challenge ACK may be sent. ++ */ ++static bool tcp_challenge_ack_allowed(struct net *net) + { +- struct tcp_sock *tp = tcp_sk(sk); +- struct net *net = sock_net(sk); + u32 count, now, ack_limit; + +- /* First check our per-socket dupack rate limit. */ +- if (__tcp_oow_rate_limited(net, +- LINUX_MIB_TCPACKSKIPPEDCHALLENGE, +- &tp->last_oow_ack_time)) +- return; +- + ack_limit = READ_ONCE(net->ipv4.sysctl_tcp_challenge_ack_limit); + if (ack_limit == INT_MAX) +- goto send_ack; ++ return true; + +- /* Then check host-wide RFC 5961 rate limit. */ + now = jiffies / HZ; + if (now != READ_ONCE(net->ipv4.tcp_challenge_timestamp)) { + u32 half = (ack_limit + 1) >> 1; +@@ -4067,12 +4060,49 @@ static void tcp_send_challenge_ack(struc + count = READ_ONCE(net->ipv4.tcp_challenge_count); + if (count > 0) { + WRITE_ONCE(net->ipv4.tcp_challenge_count, count - 1); +-send_ack: ++ return true; ++ } ++ return false; ++} ++ ++/* RFC 5961 7 [ACK Throttling] */ ++static void tcp_send_challenge_ack(struct sock *sk, bool accecn_reflector) ++{ ++ struct tcp_sock *tp = tcp_sk(sk); ++ struct net *net = sock_net(sk); ++ ++ /* First check our per-socket dupack rate limit. */ ++ if (__tcp_oow_rate_limited(net, ++ LINUX_MIB_TCPACKSKIPPEDCHALLENGE, ++ &tp->last_oow_ack_time)) ++ return; ++ ++ /* Then check the per-netns RFC 5961 rate limit. */ ++ if (tcp_challenge_ack_allowed(net)) { + NET_INC_STATS(net, LINUX_MIB_TCPCHALLENGEACK); + tcp_send_ack_reflect_ect(sk, accecn_reflector); + } + } + ++/* Send a challenge ACK from a SYN-RECEIVED request socket. Uses ++ * __tcp_oow_rate_limited() directly so that an RST carrying payload ++ * cannot bypass the per-request rate limit. ++ */ ++void tcp_reqsk_send_challenge_ack(struct sock *sk, struct sk_buff *skb, ++ struct request_sock *req) ++{ ++ struct net *net = sock_net(sk); ++ ++ if (__tcp_oow_rate_limited(net, LINUX_MIB_TCPACKSKIPPEDCHALLENGE, ++ &tcp_rsk(req)->last_oow_ack_time)) ++ return; ++ ++ if (tcp_challenge_ack_allowed(net)) { ++ NET_INC_STATS(net, LINUX_MIB_TCPCHALLENGEACK); ++ req->rsk_ops->send_ack(sk, skb, req); ++ } ++} ++ + static void tcp_store_ts_recent(struct tcp_sock *tp) + { + tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval; +--- a/net/ipv4/tcp_minisocks.c ++++ b/net/ipv4/tcp_minisocks.c +@@ -835,7 +835,7 @@ struct sock *tcp_check_req(struct sock * + * elsewhere and is checked directly against the child socket rather + * than req because user data may have been sent out. + */ +- if ((flg & TCP_FLAG_ACK) && !fastopen && ++ if ((flg & TCP_FLAG_ACK) && !(flg & TCP_FLAG_RST) && !fastopen && + (TCP_SKB_CB(skb)->ack_seq != + tcp_rsk(req)->snt_isn + 1)) + return sk; +@@ -874,6 +874,16 @@ struct sock *tcp_check_req(struct sock * + flg &= ~TCP_FLAG_SYN; + } + ++ /* RFC 5961 section 3.2, as clarified by RFC 9293 section ++ * 3.10.7.4, requires a challenge ACK for a non-exact ++ * in-window RST in SYN-RECEIVED. ++ */ ++ if ((flg & TCP_FLAG_RST) && ++ TCP_SKB_CB(skb)->seq != tcp_rsk(req)->rcv_nxt) { ++ tcp_reqsk_send_challenge_ack(sk, skb, req); ++ return NULL; ++ } ++ + /* RFC793: "second check the RST bit" and + * "fourth, check the SYN bit" + */ diff --git a/queue-7.1/tcp-initialize-standalone-tcp-ao-response-padding.patch b/queue-7.1/tcp-initialize-standalone-tcp-ao-response-padding.patch new file mode 100644 index 0000000000..2a4d955593 --- /dev/null +++ b/queue-7.1/tcp-initialize-standalone-tcp-ao-response-padding.patch @@ -0,0 +1,67 @@ +From e1a9d3cc11829c5414a75eb39c704f461936eb24 Mon Sep 17 00:00:00 2001 +From: Yizhou Zhao +Date: Mon, 13 Jul 2026 18:56:30 +0800 +Subject: tcp: initialize standalone TCP-AO response padding + +From: Yizhou Zhao + +commit e1a9d3cc11829c5414a75eb39c704f461936eb24 upstream. + +tcp_v4_send_ack() and tcp_v6_send_response() construct standalone TCP +responses with TCP-AO options. The option length carries the actual MAC +length, but the TCP header length includes the option rounded up to a +four-byte boundary. + +tcp_ao_hash_hdr() writes the MAC only. Thus, when the MAC length is not +four-byte aligned, the one to three bytes after the MAC are left +uninitialized and may be transmitted. For the normal TCP-AO hashing +mode, those bytes also have to be initialized before computing the MAC. + +Initialize only the alignment padding in the TCP-AO branches, before +hashing the header. Use TCPOPT_NOP, as in the normal TCP-AO output path. +This avoids adding work to non-AO TCP responses while preserving a valid +authenticated header. + +Fixes: decde2586b34 ("net/tcp: Add TCP-AO sign to twsk") +Fixes: da7dfaa6d6f7 ("net/tcp: Consistently align TCP-AO option in the header") +Cc: stable@vger.kernel.org +Reported-by: Yizhou Zhao +Reported-by: Yuxiang Yang +Reported-by: Ao Wang +Reported-by: Xuewei Feng +Reported-by: Qi Li +Reported-by: Ke Xu +Suggested-by: Eric Dumazet +Signed-off-by: Yizhou Zhao +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260713105631.8616-1-zhaoyz24@mails.tsinghua.edu.cn +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp_ipv4.c | 3 +++ + net/ipv6/tcp_ipv6.c | 2 ++ + 2 files changed, 5 insertions(+) + +--- a/net/ipv4/tcp_ipv4.c ++++ b/net/ipv4/tcp_ipv4.c +@@ -971,6 +971,9 @@ static void tcp_v4_send_ack(const struct + key->rcv_next); + arg.iov[0].iov_len += tcp_ao_len_aligned(key->ao_key); + rep.th.doff = arg.iov[0].iov_len / 4; ++ memset((u8 *)&rep.opt[offset] + tcp_ao_maclen(key->ao_key), ++ TCPOPT_NOP, tcp_ao_len_aligned(key->ao_key) - ++ tcp_ao_len(key->ao_key)); + + tcp_ao_hash_hdr(AF_INET, (char *)&rep.opt[offset], + key->ao_key, key->traffic_key, +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -915,6 +915,8 @@ static void tcp_v6_send_response(const s + (tcp_ao_len(key->ao_key) << 16) | + (key->ao_key->sndid << 8) | + (key->rcv_next)); ++ memset((u8 *)topt + tcp_ao_maclen(key->ao_key), TCPOPT_NOP, ++ tcp_ao_len_aligned(key->ao_key) - tcp_ao_len(key->ao_key)); + + tcp_ao_hash_hdr(AF_INET6, (char *)topt, key->ao_key, + key->traffic_key, diff --git a/queue-7.1/tipc-clear-sock-sk-on-the-failed-insert-path-in-tipc_sk_create.patch b/queue-7.1/tipc-clear-sock-sk-on-the-failed-insert-path-in-tipc_sk_create.patch new file mode 100644 index 0000000000..3fa7bcaa04 --- /dev/null +++ b/queue-7.1/tipc-clear-sock-sk-on-the-failed-insert-path-in-tipc_sk_create.patch @@ -0,0 +1,82 @@ +From ba0533fc163f905fe817cfabdf8ed4058da44800 Mon Sep 17 00:00:00 2001 +From: Daehyeon Ko <4ncienth@gmail.com> +Date: Tue, 14 Jul 2026 22:19:39 +0900 +Subject: tipc: clear sock->sk on the failed-insert path in tipc_sk_create() + +From: Daehyeon Ko <4ncienth@gmail.com> + +commit ba0533fc163f905fe817cfabdf8ed4058da44800 upstream. + +When tipc_sk_create() fails to insert the new socket (tipc_sk_insert() +returns non-zero), its error path frees the sk with sk_free() but leaves +sock->sk pointing at the freed object: + + if (tipc_sk_insert(tsk)) { + sk_free(sk); + pr_warn("Socket create failed; port number exhausted\n"); + return -EINVAL; + } + +This is harmless for plain socket(): the syscall layer clears sock->ops +before releasing, so tipc_release() is never called. It is not harmless +on the accept() path. tipc_accept() creates the pre-allocated child +socket with tipc_sk_create(net, new_sock, 0, kern); on failure it leaves +new_sock->sk dangling and new_sock->ops non-NULL, and do_accept() then +fput()s the new file, so __sock_release() -> tipc_release() runs +lock_sock(new_sock->sk) on the freed sk -- a use-after-free write of the +sk_lock spinlock. + +tipc_release() already guards this exact "failed accept() releases a +pre-allocated child" case with "if (sk == NULL) return 0;", but the +guard is bypassed because tipc_sk_create() left sock->sk non-NULL +(dangling) rather than NULL. + +Clear sock->sk on the failed-insert path so the existing tipc_release() +NULL check fires and the use-after-free is avoided. + +The tipc_sk_insert() failure is reached when the per-netns socket +rhashtable hits its max_size (tsk_rht_params.max_size = 1048576, ~2M +elements) -- i.e. once a netns holds ~2M TIPC sockets every insert +returns -E2BIG. + + BUG: KASAN: slab-use-after-free in lock_sock_nested (net/core/sock.c:3839) + Write of size 8 at addr ffff8880047cdc38 by task init/1 + lock_sock_nested (net/core/sock.c:3839) + tipc_release (net/tipc/socket.c:638) + __sock_release (net/socket.c:710) + sock_close (net/socket.c:1501) + __fput (fs/file_table.c:512) + Allocated by task 1: + sk_alloc (net/core/sock.c:2308) + tipc_sk_create (net/tipc/socket.c:487) + tipc_accept (net/tipc/socket.c:2744) + do_accept (net/socket.c:2034) + Freed by task 1: + __sk_destruct (net/core/sock.c:2391) + tipc_sk_create (net/tipc/socket.c:504) + tipc_accept (net/tipc/socket.c:2744) + do_accept (net/socket.c:2034) + +Fixes: 00aff3590fc0 ("net: tipc: fix possible refcount leak in tipc_sk_create()") +Cc: stable@vger.kernel.org +Reviewed-by: Tung Nguyen +Reviewed-by: Breno Leitao +Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> +Reviewed-by: Simon Horman +Link: https://patch.msgid.link/20260714131939.1255974-1-4ncienth@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/tipc/socket.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net/tipc/socket.c ++++ b/net/tipc/socket.c +@@ -501,6 +501,7 @@ static int tipc_sk_create(struct net *ne + tipc_set_sk_state(sk, TIPC_OPEN); + if (tipc_sk_insert(tsk)) { + sk_free(sk); ++ sock->sk = NULL; + pr_warn("Socket create failed; port number exhausted\n"); + return -EINVAL; + } diff --git a/queue-7.1/vsock-virtio-collapse-receive-queue-under-memory-pressure.patch b/queue-7.1/vsock-virtio-collapse-receive-queue-under-memory-pressure.patch new file mode 100644 index 0000000000..240dbb5dd9 --- /dev/null +++ b/queue-7.1/vsock-virtio-collapse-receive-queue-under-memory-pressure.patch @@ -0,0 +1,250 @@ +From 2a12c05aef213ff304ecc9e2f351de20731946b8 Mon Sep 17 00:00:00 2001 +From: Stefano Garzarella +Date: Wed, 8 Jul 2026 12:29:03 +0200 +Subject: vsock/virtio: collapse receive queue under memory pressure + +From: Stefano Garzarella + +commit 2a12c05aef213ff304ecc9e2f351de20731946b8 upstream. + +When many small packets accumulate in the receive queue, the skb overhead +can exceed buf_alloc even while the payload is within bounds. This causes +virtio_transport_inc_rx_pkt() to reject packets, leading to connection +resets during large transfers under backpressure. + +The issue was reported by Brien, who has a reproducer, but it is also +easily reproducible with iperf-vsock [1] using a small packet size: + + iperf3 --vsock -c $CID -l 129 + +which fails immediately without this patch but with commit 059b7dbd20a6 +("vsock/virtio: fix potential unbounded skb queue"). + +Inspired by TCP's tcp_collapse() which solves a similar problem, add +virtio_transport_collapse_rx_queue() that walks the receive queue and +re-copies data into compact linear skbs to reduce the overhead. + +The collapse is triggered proactively from when the number of skb queued +is close to exceeding the overhead budget. + +A pre-scan counts the eligible bytes to size each allocation precisely, +avoiding waste for isolated small packets. Partially consumed skbs are +kept as-is to preserve buf_used/fwd_cnt accounting, EOM-marked skbs to +maintain SEQPACKET message boundaries, and skbs already larger than the +collapse target because they already have a good data-to-overhead ratio. + +Walking a large queue may take a significant amount of time and cache +misses, causing traffic burstiness. To limit this, the collapse stops +once enough room is freed for this packet and the next one, but may +opportunistically free more to fill each collapsed skb to capacity. + +[1] https://github.com/stefano-garzarella/iperf-vsock + +Fixes: 059b7dbd20a6 ("vsock/virtio: fix potential unbounded skb queue") +Cc: stable@vger.kernel.org +Reported-by: Brien Oberstein +Closes: https://lore.kernel.org/netdev/618701dd023e$063de350$12b9a9f0$@gmail.com/ +Tested-by: Brien Oberstein +Signed-off-by: Stefano Garzarella +Acked-by: Michael S. Tsirkin +Reviewed-by: Bobby Eshleman +Link: https://patch.msgid.link/20260708102904.50732-2-sgarzare@redhat.com +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + net/vmw_vsock/virtio_transport_common.c | 165 +++++++++++++++++++++++++++++++- + 1 file changed, 164 insertions(+), 1 deletion(-) + +--- a/net/vmw_vsock/virtio_transport_common.c ++++ b/net/vmw_vsock/virtio_transport_common.c +@@ -26,6 +26,13 @@ + /* Threshold for detecting small packets to copy */ + #define GOOD_COPY_LEN 128 + ++/* Max payload that can be collapsed into a single linear skb, using the same ++ * allocation threshold as virtio_vsock_alloc_skb() to avoid adding pressure ++ * on the page allocator. ++ */ ++#define MAX_COLLAPSE_LEN \ ++ SKB_MAX_ORDER(VIRTIO_VSOCK_SKB_HEADROOM, PAGE_ALLOC_COSTLY_ORDER) ++ + static void virtio_transport_cancel_close_work(struct vsock_sock *vsk, + bool cancel_timeout); + static s64 virtio_transport_has_space(struct virtio_vsock_sock *vvs); +@@ -420,6 +427,145 @@ static int virtio_transport_send_pkt_inf + return ret; + } + ++static bool virtio_transport_can_collapse(struct sk_buff *skb) ++{ ++ /* skbs that are partially consumed, mark a SEQPACKET message boundary, ++ * or are already large enough should not be collapsed: they either ++ * need special accounting, carry protocol state, or already have a ++ * good data-to-overhead ratio. ++ */ ++ if (VIRTIO_VSOCK_SKB_CB(skb)->offset) ++ return false; ++ if (le32_to_cpu(virtio_vsock_hdr(skb)->flags) & VIRTIO_VSOCK_SEQ_EOM) ++ return false; ++ if (skb->len >= MAX_COLLAPSE_LEN) ++ return false; ++ return true; ++} ++ ++/* Iterate through the packets in the queue starting from the current skb to ++ * count the number of bytes we can collapse. ++ */ ++static unsigned int ++virtio_transport_collapse_size(struct sk_buff *skb, struct sk_buff_head *queue) ++{ ++ unsigned int target = skb->len - VIRTIO_VSOCK_SKB_CB(skb)->offset; ++ ++ while ((skb = skb_peek_next(skb, queue)) && ++ virtio_transport_can_collapse(skb)) { ++ unsigned int len = skb->len - VIRTIO_VSOCK_SKB_CB(skb)->offset; ++ ++ if (len > MAX_COLLAPSE_LEN - target) ++ return target; ++ ++ target += len; ++ } ++ ++ return target; ++} ++ ++/* Called under lock_sock to compact the receive queue by merging small skbs. ++ * @min_to_free: minimum number of skbs to eliminate from the queue. May free ++ * more to fill each collapsed skb to capacity. ++ */ ++static void ++virtio_transport_collapse_rx_queue(struct virtio_vsock_sock *vvs, ++ u32 min_to_free) ++{ ++ struct sk_buff *skb, *next_skb, *new_skb = NULL; ++ struct sk_buff_head new_queue; ++ u32 saved = 0; ++ ++ __skb_queue_head_init(&new_queue); ++ ++ skb_queue_walk_safe(&vvs->rx_queue, skb, next_skb) { ++ struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb); ++ u32 src_off = VIRTIO_VSOCK_SKB_CB(skb)->offset; ++ u32 src_len = skb->len - src_off; ++ bool keep; ++ ++ keep = !virtio_transport_can_collapse(skb); ++ if (keep) { ++ /* Finalize pending collapsed skb to preserve packet ++ * ordering. ++ */ ++ if (new_skb) { ++ __skb_queue_tail(&new_queue, new_skb); ++ new_skb = NULL; ++ saved--; ++ } ++ goto next; ++ } ++ ++ /* Finalize if this packet won't fit in the remaining tailroom, ++ * so we can allocate a right-sized new_skb. ++ */ ++ if (new_skb && src_len > skb_tailroom(new_skb)) { ++ __skb_queue_tail(&new_queue, new_skb); ++ new_skb = NULL; ++ saved--; ++ } ++ ++ if (!new_skb) { ++ unsigned int alloc_size; ++ ++ /* Check after finalizing to opportunistically fill ++ * each collapsed skb to capacity, merging more skbs ++ * than strictly required. ++ */ ++ if (saved >= min_to_free) ++ break; ++ ++ alloc_size = virtio_transport_collapse_size(skb, &vvs->rx_queue); ++ ++ /* Only this skb's data is eligible, nothing to merge ++ * with. Keep as-is. ++ */ ++ if (alloc_size <= src_len) { ++ keep = true; ++ goto next; ++ } ++ ++ new_skb = virtio_vsock_alloc_linear_skb(alloc_size + ++ VIRTIO_VSOCK_SKB_HEADROOM, GFP_KERNEL); ++ if (!new_skb) ++ break; ++ ++ memcpy(virtio_vsock_hdr(new_skb), hdr, ++ sizeof(struct virtio_vsock_hdr)); ++ virtio_vsock_hdr(new_skb)->len = 0; ++ } ++ ++ /* Cannot fail since src_off/src_len are within bounds, but if ++ * it does, discard new_skb to avoid queuing corrupted data. ++ */ ++ if (WARN_ON_ONCE(skb_copy_bits(skb, src_off, ++ skb_put(new_skb, src_len), ++ src_len))) { ++ kfree_skb(new_skb); ++ new_skb = NULL; ++ break; ++ } ++ ++ le32_add_cpu(&virtio_vsock_hdr(new_skb)->len, src_len); ++ virtio_vsock_hdr(new_skb)->flags |= hdr->flags; ++ ++next: ++ __skb_unlink(skb, &vvs->rx_queue); ++ if (keep) { ++ __skb_queue_tail(&new_queue, skb); ++ } else { ++ consume_skb(skb); ++ saved++; ++ } ++ } ++ ++ if (new_skb) ++ __skb_queue_tail(&new_queue, new_skb); ++ ++ skb_queue_splice(&new_queue, &vvs->rx_queue); ++} ++ + static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs, + u32 len) + { +@@ -1354,12 +1500,29 @@ virtio_transport_recv_enqueue(struct vso + { + struct virtio_vsock_sock *vvs = vsk->trans; + bool can_enqueue, free_pkt = false; ++ u32 len, queue_max, queue_len; + struct virtio_vsock_hdr *hdr; +- u32 len; + + hdr = virtio_vsock_hdr(skb); + len = le32_to_cpu(hdr->len); + ++ /* virtio_transport_inc_rx_pkt() rejects packets when the per-skb ++ * overhead (skb_queue_len * SKB_TRUESIZE(0)) exceeds buf_alloc. ++ * Proactively collapse the queue before that happens. ++ * No rx_lock needed: lock_sock is held by caller, preventing ++ * concurrent enqueue or dequeue. ++ */ ++ queue_max = vvs->buf_alloc / SKB_TRUESIZE(0); ++ queue_len = skb_queue_len(&vvs->rx_queue); ++ if (queue_len >= queue_max) { ++ /* Walking a large queue may take a significant amount of time ++ * and cache misses, causing traffic burstiness. Limit the ++ * collapse to freeing room for this packet and the next one. ++ * It may free more to fill each collapsed skb to capacity. ++ */ ++ virtio_transport_collapse_rx_queue(vvs, queue_len + 2 - queue_max); ++ } ++ + spin_lock_bh(&vvs->rx_lock); + + can_enqueue = virtio_transport_inc_rx_pkt(vvs, len); diff --git a/queue-7.1/vxlan-mdb-fix-source-list-corruption-on-a-failed-replace.patch b/queue-7.1/vxlan-mdb-fix-source-list-corruption-on-a-failed-replace.patch new file mode 100644 index 0000000000..f35476f49f --- /dev/null +++ b/queue-7.1/vxlan-mdb-fix-source-list-corruption-on-a-failed-replace.patch @@ -0,0 +1,131 @@ +From dcd9b465965422b9654f6026e8a2fa8984f74c3c Mon Sep 17 00:00:00 2001 +From: James Raphael Tiovalen +Date: Tue, 21 Jul 2026 00:04:24 +0800 +Subject: vxlan: mdb: Fix source list corruption on a failed replace + +From: James Raphael Tiovalen + +commit dcd9b465965422b9654f6026e8a2fa8984f74c3c upstream. + +When replacing the source list of an MDB remote entry, all existing +sources are first marked for deletion and vxlan_mdb_remote_srcs_add() +is then called to add the new source list. Sources present in the new +list have their deletion mark cleared, and any sources left marked +afterwards are removed. + +If vxlan_mdb_remote_srcs_add() fails partway through, its error path +deletes all entries on the remote's source list. That rollback is only +correct for its other caller, vxlan_mdb_remote_add(), where the remote +was just allocated and the list contains solely entries added during +the call. On the replace path the list also holds pre-existing sources, +so a failed replace tears them down together with their (S, G) +forwarding entries instead of leaving the entry unchanged. + +This is reachable from an existing (*, G) remote. An EXCLUDE filter +that loses sources starts forwarding traffic that should be blocked, +while an INCLUDE filter that loses sources drops traffic that should be +forwarded. + +Mark entries created during the current pass with a new +VXLAN_SGRP_F_NEW flag. On failure, delete only those entries and clear +the deletion mark on the pre-existing ones, so a failed replace leaves +the source list untouched. Retain the flag until the whole operation +succeeds and then clear it. Also stop vxlan_mdb_remote_src_add() from +deleting a pre-existing entry it only looked up when adding that +entry's forwarding entry fails. + +Fixes: a3a48de5eade ("vxlan: mdb: Add MDB control path support") +Cc: stable@vger.kernel.org +Signed-off-by: James Raphael Tiovalen +Reviewed-by: Ido Schimmel +Reviewed-by: Antoine Tenart +Reviewed-by: Nikolay Aleksandrov +Link: https://patch.msgid.link/20260720160428.249356-1-jamestiotio@gmail.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/vxlan/vxlan_mdb.c | 30 ++++++++++++++++++------------ + 1 file changed, 18 insertions(+), 12 deletions(-) + +--- a/drivers/net/vxlan/vxlan_mdb.c ++++ b/drivers/net/vxlan/vxlan_mdb.c +@@ -42,6 +42,7 @@ struct vxlan_mdb_remote { + }; + + #define VXLAN_SGRP_F_DELETE BIT(0) ++#define VXLAN_SGRP_F_NEW BIT(1) + + struct vxlan_mdb_src_entry { + struct hlist_node node; +@@ -844,6 +845,7 @@ vxlan_mdb_remote_src_add(const struct vx + ent = vxlan_mdb_remote_src_entry_add(remote, &src->addr); + if (!ent) + return -ENOMEM; ++ ent->flags |= VXLAN_SGRP_F_NEW; + } else if (!(cfg->nlflags & NLM_F_REPLACE)) { + NL_SET_ERR_MSG_MOD(extack, "Source entry already exists"); + return -EEXIST; +@@ -853,15 +855,16 @@ vxlan_mdb_remote_src_add(const struct vx + if (err) + goto err_src_del; + +- /* Clear flags in case source entry was marked for deletion as part of +- * replace flow. ++ /* Clear the deletion mark so the entry survives the replace sweep. ++ * The new mark is retained until the whole operation succeeds. + */ +- ent->flags = 0; ++ ent->flags &= ~VXLAN_SGRP_F_DELETE; + + return 0; + + err_src_del: +- vxlan_mdb_remote_src_entry_del(ent); ++ if (ent->flags & VXLAN_SGRP_F_NEW) ++ vxlan_mdb_remote_src_entry_del(ent); + return err; + } + +@@ -889,11 +892,19 @@ static int vxlan_mdb_remote_srcs_add(con + goto err_src_del; + } + ++ hlist_for_each_entry(ent, &remote->src_list, node) ++ ent->flags &= ~VXLAN_SGRP_F_NEW; ++ + return 0; + + err_src_del: +- hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) +- vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote, ent); ++ hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) { ++ if (ent->flags & VXLAN_SGRP_F_NEW) ++ vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote, ++ ent); ++ else ++ ent->flags &= ~VXLAN_SGRP_F_DELETE; ++ } + return err; + } + +@@ -1069,7 +1080,7 @@ vxlan_mdb_remote_srcs_replace(const stru + + err = vxlan_mdb_remote_srcs_add(cfg, remote, extack); + if (err) +- goto err_clear_delete; ++ return err; + + hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) { + if (ent->flags & VXLAN_SGRP_F_DELETE) +@@ -1078,11 +1089,6 @@ vxlan_mdb_remote_srcs_replace(const stru + } + + return 0; +- +-err_clear_delete: +- hlist_for_each_entry(ent, &remote->src_list, node) +- ent->flags &= ~VXLAN_SGRP_F_DELETE; +- return err; + } + + static int vxlan_mdb_remote_replace(const struct vxlan_mdb_config *cfg, diff --git a/queue-7.1/watchdog-s32g_wdt-remove-incorrect-options-in-watchdog_info-struct.patch b/queue-7.1/watchdog-s32g_wdt-remove-incorrect-options-in-watchdog_info-struct.patch new file mode 100644 index 0000000000..793ffcabe8 --- /dev/null +++ b/queue-7.1/watchdog-s32g_wdt-remove-incorrect-options-in-watchdog_info-struct.patch @@ -0,0 +1,40 @@ +From 2b37415618bfc6a83d4aceb00fd8d6491096f2ed Mon Sep 17 00:00:00 2001 +From: Ethan Nelson-Moore +Date: Mon, 4 May 2026 19:44:09 -0700 +Subject: watchdog: s32g_wdt: remove incorrect options in watchdog_info struct + +From: Ethan Nelson-Moore + +commit 2b37415618bfc6a83d4aceb00fd8d6491096f2ed upstream. + +The s32g_wdt driver uses two incorrect constants in the options field +of its watchdog_info struct. This bit mask should contain WDIOF_* +constants, but the driver uses two WDIOC_* ioctl constants (in addition +to correct WDIOF_* constants). This causes many incorrect bits to be +set in the bit mask. The functionality indicated by these ioctl +constants is supported by all drivers using the watchdog framework, so +this patch simply removes them. + +Fixes: bd3f54ec559b ("watchdog: Add the Watchdog Timer for the NXP S32 platform") +Cc: stable@vger.kernel.org # 6.18+ +Signed-off-by: Ethan Nelson-Moore +Acked-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20260505024409.60301-1-enelsonmoore@gmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Greg Kroah-Hartman +--- + drivers/watchdog/s32g_wdt.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/watchdog/s32g_wdt.c ++++ b/drivers/watchdog/s32g_wdt.c +@@ -56,8 +56,7 @@ MODULE_PARM_DESC(early_enable, + + static const struct watchdog_info s32g_wdt_info = { + .identity = "s32g watchdog", +- .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | +- WDIOC_GETTIMEOUT | WDIOC_GETTIMELEFT, ++ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, + }; + + static struct s32g_wdt_device *wdd_to_s32g_wdt(struct watchdog_device *wdd)