Skip to contentSkip to conversation

5.10.265-rc1 review

PATCH In review Greg Kroah-Hartman 8 participants 397 messages Aug 17 – Aug 18 Stable branch Page 3 of 3

lore
Share & tools
lore
author maintainer
#295 lore raw

PATCH 295/389 can: peak_usb: add bounds check for USB channel index

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: James Gao <[email protected]>

commit 39132f166ca8ce00ae60d8a9068e06a60943cc4b upstream.

The channel control index ctrl_idx is derived from rx->len which comes directly from a device USB payload. The mask 0x0f allows values 0-15, but the array size of usb_if->dev[] is only 2. Values 2-15 cause heap out-of-bounds read, eventually causing kernel panic in the IRQ context.

Add bounds checking for ctrl_idx before the array access in both pcan_usb_pro_handle_canmsg() and pcan_usb_pro_handle_error().

---
 drivers/net/can/usb/peak_usb/pcan_usb_pro.c |   20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)
drivers/net/can/usb/peak_usb/pcan_usb_pro.c +16 -4
@@ -521,12 +521,18 @@ static int pcan_usb_pro_handle_canmsg(st
 				      struct pcan_usb_pro_rxmsg *rx)
 {
 	const unsigned int ctrl_idx = (rx->len >> 4) & 0x0f;
-	struct peak_usb_device *dev = usb_if->dev[ctrl_idx];
-	struct net_device *netdev = dev->netdev;
+	struct peak_usb_device *dev;
+	struct net_device *netdev;
 	struct can_frame *can_frame;
 	struct sk_buff *skb;
 	struct skb_shared_hwtstamps *hwts;
 
+	if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
+		return -EINVAL;
+
+	dev = usb_if->dev[ctrl_idx];
+	netdev = dev->netdev;
+
 	skb = alloc_can_skb(netdev, &can_frame);
 	if (!skb)
 		return -ENOMEM;
@@ -558,14 +564,20 @@ static int pcan_usb_pro_handle_error(str
 {
 	const u16 raw_status = le16_to_cpu(er->status);
 	const unsigned int ctrl_idx = (er->channel >> 4) & 0x0f;
-	struct peak_usb_device *dev = usb_if->dev[ctrl_idx];
-	struct net_device *netdev = dev->netdev;
+	struct peak_usb_device *dev;
+	struct net_device *netdev;
 	struct can_frame *can_frame;
 	enum can_state new_state = CAN_STATE_ERROR_ACTIVE;
 	u8 err_mask = 0;
 	struct sk_buff *skb;
 	struct skb_shared_hwtstamps *hwts;
 
+	if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
+		return -EINVAL;
+
+	dev = usb_if->dev[ctrl_idx];
+	netdev = dev->netdev;
+
 	/* nothing should be sent while in BUS_OFF state */
 	if (dev->can.state == CAN_STATE_BUS_OFF)
 		return 0;
author maintainer
#296 lore raw

PATCH 296/389 can: peak_usb: peak_usb_start(): fix double free of transfer buffer on URB submit error

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Maoyi Xie <[email protected]>

commit 9b3d5a6d952c38bbcf07f903cbeadefdb56b9bc9 upstream.

In peak_usb_start(), each RX URB transfer buffer is allocated with kmalloc() and the URB is flagged URB_FREE_BUFFER so that the final usb_free_urb() also frees the transfer buffer.

If usb_submit_urb() fails, the error path frees the buffer explicitly with kfree(buf) and then calls usb_free_urb(urb). Because URB_FREE_BUFFER is set, usb_free_urb() -> urb_destroy() frees the same buffer a second time, a double free of the transfer buffer.

  BUG: KASAN: double-free in usb_free_urb.part.0+0x91/0xb0
  Free of addr ffff8881069ccb80 by task trigger.sh/285

  Call Trace:
   kfree+0x113/0x3c0
   usb_free_urb.part.0+0x91/0xb0

Drop the redundant kfree(buf); usb_free_urb() already releases the transfer buffer. This mirrors commit 03819abbeb11 ("net: usb: lan78xx: Fix double free issue with interrupt buffer allocation").

---
 drivers/net/can/usb/peak_usb/pcan_usb_core.c |    1 -
 1 file changed, 1 deletion(-)
drivers/net/can/usb/peak_usb/pcan_usb_core.c +0 -1
@@ -444,7 +444,6 @@ static int peak_usb_start(struct peak_us
 				netif_device_detach(dev->netdev);
 
 			usb_unanchor_urb(urb);
-			kfree(buf);
 			usb_free_urb(urb);
 			break;
 		}
author maintainer
#297 lore raw

PATCH 297/389 can: peak_usb: validate uCAN receive record lengths

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

commit 93fcab2c6968446316bbb49548848df604d6346f upstream.

pcan_usb_fd_decode_buf() walks uCAN records packed in one USB receive buffer.

Require each record to contain the fixed header for its type, and verify CAN payload bytes before copying them into the skb.

Fixes 0a25e1f4f185 ("can: peak_usb: add support for PEAK new CANFD USB adapters")
---
 drivers/net/can/usb/peak_usb/pcan_usb_fd.c |   40 ++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)
drivers/net/can/usb/peak_usb/pcan_usb_fd.c +39 -1
@@ -502,6 +502,13 @@ static int pcan_usb_fd_decode_canmsg(str
 		cfd->len = get_can_dlc(pucan_msg_get_dlc(rm));
 	}
 
+	if (!(rx_msg_flags & PUCAN_MSG_RTR) &&
+	    le16_to_cpu(rx_msg->size) - offsetof(struct pucan_rx_msg, d) <
+	    cfd->len) {
+		kfree_skb(skb);
+		return -EBADMSG;
+	}
+
 	cfd->can_id = le32_to_cpu(rm->can_id);
 
 	if (rx_msg_flags & PUCAN_MSG_EXT_ID)
@@ -651,6 +658,24 @@ static void pcan_usb_fd_decode_ts(struct
 		peak_usb_set_ts_now(&usb_if->time_ref, le32_to_cpu(ts->ts_low));
 }
 
+static size_t pcan_usb_fd_rx_msg_min_size(u16 rx_msg_type)
+{
+	switch (rx_msg_type) {
+	case PUCAN_MSG_CAN_RX:
+		return offsetof(struct pucan_rx_msg, d);
+	case PCAN_UFD_MSG_CALIBRATION:
+		return sizeof(struct pcan_ufd_ts_msg);
+	case PUCAN_MSG_ERROR:
+		return sizeof(struct pucan_error_msg);
+	case PUCAN_MSG_STATUS:
+		return sizeof(struct pucan_status_msg);
+	case PCAN_UFD_MSG_OVERRUN:
+		return sizeof(struct pcan_ufd_ovr_msg);
+	default:
+		return sizeof(struct pucan_msg);
+	}
+}
+
 /* callback for bulk IN urb */
 static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
 {
@@ -665,6 +690,12 @@ static int pcan_usb_fd_decode_buf(struct
 	msg_end = urb->transfer_buffer + urb->actual_length;
 	for (; msg_ptr < msg_end;) {
 		u16 rx_msg_type, rx_msg_size;
+		size_t rx_msg_min_size;
+
+		if (msg_end - msg_ptr < sizeof(*rx_msg)) {
+			err = -EBADMSG;
+			break;
+		}
 
 		rx_msg = (struct pucan_msg *)msg_ptr;
 		if (!rx_msg->size) {
@@ -676,12 +707,19 @@ static int pcan_usb_fd_decode_buf(struct
 		rx_msg_type = le16_to_cpu(rx_msg->type);
 
 		/* check if the record goes out of current packet */
-		if (msg_ptr + rx_msg_size > msg_end) {
+		if (rx_msg_size > msg_end - msg_ptr) {
 			netdev_err(netdev,
 				   "got frag rec: should inc usb rx buf sze\n");
 			err = -EBADMSG;
 			break;
 		}
+
+		rx_msg_min_size = pcan_usb_fd_rx_msg_min_size(rx_msg_type);
+		if (rx_msg_size < rx_msg_min_size) {
+			netdev_err(netdev, "got short rec\n");
+			err = -EBADMSG;
+			break;
+		}
 
 		switch (rx_msg_type) {
 		case PUCAN_MSG_CAN_RX:
author maintainer
#298 lore raw

PATCH 298/389 drm/vc4: Zero the tile state data array before each BIN job

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Maíra Canal <[email protected]>

commit 48a570c964d8e37d353381e4195106277e17f5cb upstream.

The binner BO is a single 16MB buffer split into 512KB slots that are handed out to jobs at submission time and recycled as jobs complete, without ever being cleared. Each slot holds the job's Tile State Data Array (TSDA) at its start, followed by the tile allocation pool.

While the tile allocation pool is only walked by the render thread through branches the binner generated during the current job, the TSDA is the PTB's own per-tile bookkeeping and is consumed by the hardware itself. Although the kernel sets the "Auto-initialise Tile State Data Array" flag in the tile binning mode configuration, the PTB demonstrably still acts on stale tile state left by the slot's previous user: the binner ends up creating invalid command streams with invalid primitive streams and branches, which can cause GPU hangs as observed in [1][2].

Zero the TSDA when the job's binning slot is configured. This clears 48 bytes per tile (~24KB for a 1080p frame) in the submission path, and guarantees the PTB never sees another job's tile state.

The tile count is only checked for being non-zero today, so the 8-bit fields it comes from can describe a tile state array almost six times larger than the slot it has to live in. Bound it before the slot is handed out, since such size decides how much of the slot is left for the tile alloc pool.

---
 drivers/gpu/drm/vc4/vc4_validate.c |   29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)
drivers/gpu/drm/vc4/vc4_validate.c +23 -6
@@ -379,6 +379,23 @@ validate_tile_binning_config(VALIDATE_AR
 		return -EINVAL;
 	}
 
+	/* The tile state data array is 48 bytes per tile, and we put it at
+	 * the start of a BO containing both it and the tile alloc.
+	 */
+	tile_state_size = 48 * tile_count;
+
+	/* Since the tile alloc array will follow us, align. */
+	tile_state_size = roundup(tile_state_size, 4096);
+
+	/* Reject configurations whose tile state would leave no room for
+	 * the tile alloc pool that follows it in the slot.
+	 */
+	if (tile_state_size >= vc4->bin_alloc_size) {
+		DRM_DEBUG("Tile binning config of %dx%d too large\n",
+			  exec->bin_tiles_x, exec->bin_tiles_y);
+		return -EINVAL;
+	}
+
 	bin_slot = vc4_v3d_get_bin_slot(vc4);
 	if (bin_slot < 0) {
 		if (bin_slot != -EINTR && bin_slot != -ERESTARTSYS) {
@@ -394,13 +411,13 @@ validate_tile_binning_config(VALIDATE_AR
 	exec->bin_slots |= BIT(bin_slot);
 	bin_addr = vc4->bin_bo->base.paddr + bin_slot * vc4->bin_alloc_size;
 
-	/* The tile state data array is 48 bytes per tile, and we put it at
-	 * the start of a BO containing both it and the tile alloc.
-	 */
-	tile_state_size = 48 * tile_count;
+	exec->tile_alloc_offset = bin_addr + tile_state_size;
 
-	/* Since the tile alloc array will follow us, align. */
-	exec->tile_alloc_offset = bin_addr + roundup(tile_state_size, 4096);
+	/* The TSDA area must be zeroed out before use, otherwise the PTB might
+	 * consume a stale tile state.
+	 */
+	memset(vc4->bin_bo->base.vaddr + bin_slot * vc4->bin_alloc_size, 0,
+	       tile_state_size);
 
 	*(uint8_t *)(validated + 14) =
 		((flags & ~(VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK |
author maintainer
#299 lore raw

PATCH 299/389 drm/amdgpu: cap GTT size to physical RAM on APUs

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Harkirat Gill <[email protected]>

commit 5e70f6804b4d6256058c360b10e044ee04ea4a4e upstream.

On APUs, the GTT pool is backed by system RAM, but its size is not bound to the non-carveout memory that actually backs it. A user can end up with GTT + VRAM exceeding total physical memory through the following sequence:

- Have a large non-carveout memory space (~128GB) and accordingly set a large GTT (~100GB) via the ttm module parameter.
- Lower the non-carveout memory space in BIOS by increasing the UMA Frame Buffer Size (VRAM) to 64GB.
- The previously set GTT value (~100GB) persists, even though the new non-carveout space (64GB) can no longer back it.

This leads to a case where kernel reports GTT (100GB) + VRAM (64GB) despite the sum being greater than total physical memory (128GB).

Cap the GTT size to totalram_pages() on APUs. totalram_pages() already excludes the VRAM carveout, so the resulting GTT can never exceed the system RAM that actually backs it.

Assisted-by Claude:claude-opus-4
(cherry picked from commit 5dafdd649280c7dc6c22c8f877da3f54fcc441e1)
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +12 -0
@@ -1979,6 +1979,18 @@ int amdgpu_ttm_init(struct amdgpu_device
 	else
 		gtt_size = (uint64_t)amdgpu_gtt_size << 20;
 
+	/* Cap GTT so that it does not exceed total physical RAM. */
+	if (adev->flags & AMD_IS_APU) {
+		u64 phys_ram = (u64)totalram_pages() << PAGE_SHIFT;
+
+		if (gtt_size > phys_ram) {
+			gtt_size = phys_ram;
+			dev_info(adev->dev,
+				 "Capping GTT to %uM to not exceed available system memory\n",
+				 (unsigned int)(gtt_size / (1024 * 1024)));
+		}
+	}
+
 	/* Initialize GTT memory pool */
 	r = amdgpu_gtt_mgr_init(adev, gtt_size);
 	if (r) {
author maintainer
#300 lore raw

PATCH 300/389 drm/vmwgfx: validate DRAW_PRIMITIVES header size before division

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zack Rusin <[email protected]>

commit 85891d174707d8bddcec7a888fb4e1d17def34f3 upstream.

vmw_cmd_draw() computes

	maxnum = (header->size - sizeof(cmd->body)) / sizeof(*decl);

where header->size is u32 and is taken straight from the user-supplied command stream. When header->size is less than sizeof(cmd->body) the unsigned subtraction wraps to nearly 4 GiB, producing a huge maxnum. Any user-controlled cmd->body.numVertexDecls then passes the bound and the loop dereferences decl[i] far past the end of the kernel command bounce buffer, producing an out-of-bounds read of kernel memory.

Reject undersized headers up front.

Fixes 7a73ba7469cb ("drm/vmwgfx: Use TTM handles instead of SIDs as user-space surface handles.")
Assisted-by Claude:claude-opus-4.7
---
 drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +7 -1
@@ -1590,11 +1590,17 @@ static int vmw_cmd_draw(struct vmw_priva
 	uint32_t maxnum;
 	int ret;
 
+	cmd = container_of(header, typeof(*cmd), header);
+
+	if (unlikely(header->size < sizeof(cmd->body))) {
+		VMW_DEBUG_USER("Illegal DRAW_PRIMITIVES header size.\n");
+		return -EINVAL;
+	}
+
 	ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
 	if (unlikely(ret != 0))
 		return ret;
 
-	cmd = container_of(header, typeof(*cmd), header);
 	maxnum = (header->size - sizeof(cmd->body)) / sizeof(*decl);
 
 	if (unlikely(cmd->body.numVertexDecls > maxnum)) {
author maintainer
#301 lore raw

PATCH 301/389 drm/vmwgfx: bound DMA command body size against suffix pointer

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zack Rusin <[email protected]>

commit f4f1db96bfd68b81053693ba53405b6f510ac16c upstream.

vmw_cmd_dma() locates the DMA suffix at

	(unsigned long) &cmd->body + header->size - sizeof(*suffix)

without checking that header->size is large enough to contain both cmd->body and the suffix. An undersized header makes the suffix pointer underflow back into the previous command in the bounce buffer. The verifier later writes suffix->maximumOffset, clobbering verified fields of an already-relocated earlier command -- a TOCTOU on the device-visible command stream that lets one command rewrite another's GMR id, surface id, or other authenticated fields.

Reject the command if the body is too small for the suffix to fit.

Fixes 4e4ddd477743 ("drm/vmwgfx: Fix queries if no dma buffer thrashing is occuring.")
Assisted-by Claude:claude-opus-4.7
---
 drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c |    6 ++++++
 1 file changed, 6 insertions(+)
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +6 -0
@@ -1529,6 +1529,12 @@ static int vmw_cmd_dma(struct vmw_privat
 	bool dirty;
 
 	cmd = container_of(header, typeof(*cmd), header);
+
+	if (unlikely(header->size < sizeof(cmd->body) + sizeof(*suffix))) {
+		VMW_DEBUG_USER("Illegal SVGA_3D_CMD_SURFACE_DMA size.\n");
+		return -EINVAL;
+	}
+
 	suffix = (SVGA3dCmdSurfaceDMASuffix *)((unsigned long) &cmd->body +
 					       header->size - sizeof(*suffix));
 
author maintainer
#302 lore raw

PATCH 302/389 HID: logitech-dj: Fix maxfield check in DJ short report validation

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: HyeongJun An <[email protected]>

commit 590cc4d782487632a52f37c2171bee1eeea29627 upstream.

Commit b6a57912854e ("HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT related user initiated OOB write") added validation for the DJ short output report, but the error path dereferences rep->field[0] even when rep->maxfield is zero.

Commit 8b9a097eb2fc ("HID: logitech-dj: fix wrong detection of bad DJ_SHORT output report") made the check conditional on rep being present, but a crafted descriptor can still create report ID 0x20 with only padding output items. hid-core registers the report, ignores the padding field, and leaves rep->maxfield as zero.

In that case the validation enters the rep->maxfield < 1 branch and then dereferences rep->field[0]->report_count while printing the error message, causing a NULL pointer dereference during probe. This is reproducible with uhid by emulating a Logitech receiver with a padding-only DJ short output report:

  BUG: KASAN: null-ptr-deref in logi_dj_probe+0xb1/0x754 [hid_logitech_dj]
  Read of size 4 at addr 0000000000000028 by task kworker/4:1/129
  ...
  Call Trace:
   logi_dj_probe+0xb1/0x754 [hid_logitech_dj]
   hid_device_probe+0x329/0x3f0 [hid]
   really_probe+0x162/0x570
   __device_attach+0x137/0x2c0
   bus_probe_device+0x38/0xc0
   device_add+0xa56/0xce0
   hid_add_device+0x19c/0x280 [hid]
   uhid_device_add_worker+0x2c/0xb0 [uhid]

Reject the zero-field report before printing the field report_count.

Fixes b6a57912854e ("HID: logitech-dj: Prevent REPORT_ID_DJ_SHORT related user initiated OOB write")
Assisted-by Claude:claude-opus-4-8
---
 drivers/hid/hid-logitech-dj.c |    9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/hid/hid-logitech-dj.c +7 -2
@@ -1715,8 +1715,13 @@ static int logi_dj_probe(struct hid_devi
 	output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
 	rep = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
 
-	if (rep && (rep->maxfield < 1 ||
-		    rep->field[0]->report_count != DJREPORT_SHORT_LENGTH - 1)) {
+	if (rep && rep->maxfield < 1) {
+		hid_err(hdev, "Expected size of DJ short report is %d, but got 0",
+			DJREPORT_SHORT_LENGTH - 1);
+		return -EINVAL;
+	}
+
+	if (rep && rep->field[0]->report_count != DJREPORT_SHORT_LENGTH - 1) {
 		hid_err(hdev, "Expected size of DJ short report is %d, but got %d",
 			DJREPORT_SHORT_LENGTH - 1, rep->field[0]->report_count);
 		return -EINVAL;
author maintainer
#303 lore raw

PATCH 303/389 mm/huge_memory: unlock i_mmap_rwsem before releasing after-split folios

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kiryl Shutsemau (Meta) <[email protected]>

[ Upstream commit e923bd21058ea02fd0dcd3549d151d143fd036e5 ]

__folio_split() keeps dereferencing the mapping after the split:
shmem_uncharge(mapping->host) and remap_page() while the folios are still frozen/locked, and i_mmap_unlock_read(mapping) at the very end, after the after-split folios have been unlocked and freed.

Nothing holds an inode reference across that. The split relies on @folio -- which the beyond-EOF drop loop never removes, as it starts at folio_next(folio) -- staying locked and in the page cache to hold off eviction. But the unlock loop unlocks @folio before i_mmap_unlock_read() runs. If the caller's @lock_at is a tail beyond EOF, as memory_failure() passes when splitting a poisoned tail of a shmem THP that reaches past i_size during truncation, it too is gone from the page cache; so once @folio is unlocked no locked, in-cache folio pins the inode, and a concurrent final iput() can evict and RCU-free it before i_mmap_unlock_read() touches i_mmap_rwsem:

  BUG: KASAN: slab-use-after-free in __up_read+0x634/0x790
   i_mmap_unlock_read include/linux/fs.h:537 [inline]
   __folio_split+0x732/0x1640 mm/huge_memory.c:4100
   try_to_split_thp_page+0xab/0x390 mm/memory-failure.c:1675
   memory_failure+0x1394/0x26e0 mm/memory-failure.c:2470

  Freed by task 4601:
   shmem_free_in_core_inode+0x54/0xb0 mm/shmem.c:5177
   evict+0x57f/0xac0 fs/inode.c:870

Do every mapping dereference while @folio still pins the inode: drop i_mmap_rwsem right after remap_page(), before the loop that unlocks and frees the after-split folios, and clear @mapping so the exit path does not unlock it again. shmem_uncharge() and remap_page() already run before that point, so after this nothing past the unlock loop touches the inode or the mapping.

This is now a rule the split depends on, alongside keeping @folio frozen until the page cache is updated: no inode or mapping dereference once the after-split folios start being unlocked.

(cherry picked from commit e923bd21058ea02fd0dcd3549d151d143fd036e5) [ kas: adapt to the __split_huge_page()/split_huge_page_to_list()
two-function split: pass @mapping into __split_huge_page() and drop it there, before the loop that frees the after-split subpages while the head is still locked; the caller then skips its own i_mmap unlock ]

---
 mm/huge_memory.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)
mm/huge_memory.c +14 -2
index fdcf89e3b1d27..f620861d00995 100644
@@ -2445,7 +2445,7 @@ static void __split_huge_page_tail(struct page *head, int tail,
 }
 
 static void __split_huge_page(struct page *page, struct list_head *list,
-		pgoff_t end, unsigned long flags)
+		pgoff_t end, unsigned long flags, struct address_space *mapping)
 {
 	struct page *head = compound_head(page);
 	pg_data_t *pgdat = page_pgdat(head);
@@ -2515,6 +2515,16 @@ static void __split_huge_page(struct page *page, struct list_head *list,
 		split_swap_cluster(entry);
 	}
 
+	/*
+	 * Drop the mapping while the head page is still locked and thus pins
+	 * the inode. The loop below may free the after-split subpages --
+	 * including the head, when @page is a tail beyond EOF that the split
+	 * dropped from the page cache -- which could otherwise let the inode,
+	 * and @mapping, be freed before this unlock.
+	 */
+	if (mapping)
+		i_mmap_unlock_read(mapping);
+
 	for (i = 0; i < nr; i++) {
 		struct page *subpage = head + i;
 		if (subpage == page)
@@ -2746,7 +2756,9 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
 				__dec_node_page_state(head, NR_FILE_THPS);
 		}
 
-		__split_huge_page(page, list, end, flags);
+		__split_huge_page(page, list, end, flags, mapping);
+		/* __split_huge_page() dropped the i_mmap lock */
+		mapping = NULL;
 		ret = 0;
 	} else {
 		spin_unlock(&ds_queue->split_queue_lock);
Signature · 1 line
2.53.0
author maintainer
#304 lore raw

PATCH 304/389 Bluetooth: SCO: Fix UAF on sco_sock_timeout

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Luiz Augusto von Dentz <[email protected]>

commit 1bf4470a3939c678fb822073e9ea77a0560bc6bb upstream.

conn->sk maybe have been unlinked/freed while waiting for sco_conn_lock so this checks if the conn->sk is still valid by checking if it part of sco_sk_list.

[ Resolved trivial conflicts in net/bluetooth/sco.c, removed extra reference on sk ]

---
 include/net/bluetooth/bluetooth.h |  1 +
 net/bluetooth/af_bluetooth.c      | 22 ++++++++++++++++++++++
 net/bluetooth/sco.c               | 17 ++++++++++++-----
 3 files changed, 35 insertions(+), 5 deletions(-)
include/net/bluetooth/bluetooth.h +1 -0
index 43b4386018e26..85bab90a6921c 100644
@@ -317,6 +317,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *s);
 void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
 struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
 			   struct proto *prot, int proto, gfp_t prio, int kern);
+bool bt_sock_linked(struct bt_sock_list *l, struct sock *s);
 int  bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
 		     int flags);
 int  bt_sock_stream_recvmsg(struct socket *sock, struct msghdr *msg,
net/bluetooth/af_bluetooth.c +22 -0
index b983ec52a99a1..16bea865e6d64 100644
@@ -184,6 +184,28 @@ void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
 }
 EXPORT_SYMBOL(bt_sock_unlink);
 
+bool bt_sock_linked(struct bt_sock_list *l, struct sock *s)
+{
+	struct sock *sk;
+
+	if (!l || !s)
+		return false;
+
+	read_lock(&l->lock);
+
+	sk_for_each(sk, &l->head) {
+		if (s == sk) {
+			read_unlock(&l->lock);
+			return true;
+		}
+	}
+
+	read_unlock(&l->lock);
+
+	return false;
+}
+EXPORT_SYMBOL(bt_sock_linked);
+
 void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
 {
 	const struct cred *old_cred;
net/bluetooth/sco.c +12 -5
index 01a01d6f01c30..2fbd9c93440ce 100644
@@ -76,6 +76,16 @@ struct sco_pinfo {
 #define SCO_CONN_TIMEOUT	(HZ * 40)
 #define SCO_DISCONN_TIMEOUT	(HZ * 2)
 
+static struct sock *sco_sock_hold(struct sco_conn *conn)
+{
+	if (!conn || !bt_sock_linked(&sco_sk_list, conn->sk))
+		return NULL;
+
+	sock_hold(conn->sk);
+
+	return conn->sk;
+}
+
 static void sco_sock_timeout(struct work_struct *work)
 {
 	struct sco_conn *conn = container_of(work, struct sco_conn,
@@ -87,9 +97,7 @@ static void sco_sock_timeout(struct work_struct *work)
 		sco_conn_unlock(conn);
 		return;
 	}
-	sk = conn->sk;
-	if (sk)
-		sock_hold(sk);
+	sk = sco_sock_hold(conn);
 	sco_conn_unlock(conn);
 
 	if (!sk)
@@ -192,11 +200,10 @@ static void sco_conn_del(struct hci_conn *hcon, int err)
 
 	/* Kill socket */
 	sco_conn_lock(conn);
-	sk = conn->sk;
+	sk = sco_sock_hold(conn);
 	sco_conn_unlock(conn);
 
 	if (sk) {
-		sock_hold(sk);
 		bh_lock_sock(sk);
 		sco_sock_clear_timer(sk);
 		sco_chan_del(sk, err);
Signature · 1 line
2.53.0
author maintainer
#305 lore raw

PATCH 305/389 Bluetooth: SCO: Fix use-after-free in sco_recv_frame() due to missing sock_hold

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hyunwoo Kim <[email protected]>

[ Upstream commit 598dbba9919c5e36c54fe1709b557d64120cb94b ]

sco_recv_frame() reads conn->sk under sco_conn_lock() but immediately releases the lock without holding a reference to the socket. A concurrent close() can free the socket between the lock release and the subsequent sk->sk_state access, resulting in a use-after-free.

Other functions in the same file (sco_sock_timeout(), sco_conn_del()) correctly use sco_sock_hold() to safely hold a reference under the lock.

Fix by using sco_sock_hold() to take a reference before releasing the lock, and adding sock_put() on all exit paths.

---
 net/bluetooth/sco.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
net/bluetooth/sco.c +7 -3
index 2fbd9c93440ce..b49b2d6bb778e 100644
@@ -312,7 +312,7 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
 	struct sock *sk;
 
 	sco_conn_lock(conn);
-	sk = conn->sk;
+	sk = sco_sock_hold(conn);
 	sco_conn_unlock(conn);
 
 	if (!sk)
@@ -321,11 +321,15 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
 	BT_DBG("sk %p len %d", sk, skb->len);
 
 	if (sk->sk_state != BT_CONNECTED)
-		goto drop;
+		goto drop_put;
 
-	if (!sock_queue_rcv_skb(sk, skb))
+	if (!sock_queue_rcv_skb(sk, skb)) {
+		sock_put(sk);
 		return;
+	}
 
+drop_put:
+	sock_put(sk);
 drop:
 	kfree_skb(skb);
 }
Signature · 1 line
2.53.0
author maintainer
#306 lore raw

PATCH 306/389 net: openvswitch: fix skb leak on flow key update failure during recirculation

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ilya Maximets <[email protected]>

[ Upstream commit e1cf066244dad576221b7123a0e5005967f25a20 ]

do_execute_actions() returns right away when execute_recirc() fails on the last action as it assumes this function always takes ownership of the skb when 'last' is true. But when the flow key update fails, the function doesn't free the skb and it ends up leaked.

This is a very unlikely scenario as it requires the packet to become unparseable by applying a set of actions on a previously parseable skb, but should be fixed nevertheless.

Reported by Sashiko.

Fixes 971427f353f3 ("openvswitch: Add recirc and hash action.")
[OVS drop reasons are not available in 5.10, hence plain kfree_skb()]
---
 net/openvswitch/actions.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
net/openvswitch/actions.c +8 -1
index ffd56da14c745..99fff9d6596c8 100644
@@ -1100,6 +1100,10 @@ static int execute_masked_set_action(struct sk_buff *skb,
 	return err;
 }
 
+/* When 'last' is true, recirc() should always consume the 'skb'.
+ * Otherwise, recirc() should keep 'skb' intact regardless what
+ * actions are executed on recirculation.
+ */
 static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
 			  struct sw_flow_key *key,
 			  const struct nlattr *a, bool last)
@@ -1110,8 +1114,11 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
 		int err;
 
 		err = ovs_flow_key_update(skb, key);
-		if (err)
+		if (err) {
+			if (last)
+				kfree_skb(skb);
 			return err;
+		}
 	}
 	BUG_ON(!is_flow_key_valid(key));
 
Signature · 1 line
2.53.0
author maintainer
#307 lore raw

PATCH 307/389 firmware: stratix10-svc: fix memory leaks and list corruption bugs

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tze Yee Ng <[email protected]>

[ Upstream commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c ]

Fix a memory leak when gen_pool_alloc() fails by freeing pmem on the error path. Switch pmem allocation from devm_kzalloc() to kzalloc() with explicit kfree() in the free path to match its list-managed lifetime. Remove the erroneous list_del(&svc_data_mem) which corrupted the list head on failed lookups.

Fixes 7ca5ce896524 ("firmware: add Intel Stratix10 service layer driver")
(cherry picked from commit 9119ceb76e987c2ec2b549ea100e3268ce3a1c7c)
---
 drivers/firmware/stratix10-svc.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/firmware/stratix10-svc.c +5 -4
index 6b6a819fcddfa..ae6d942ab2d75 100644
@@ -911,13 +911,15 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
 	struct gen_pool *genpool = chan->ctrl->genpool;
 	size_t s = roundup(size, 1 << genpool->min_alloc_order);
 
-	pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL);
+	pmem = kzalloc(sizeof(*pmem), GFP_KERNEL);
 	if (!pmem)
 		return ERR_PTR(-ENOMEM);
 
 	va = gen_pool_alloc(genpool, s);
-	if (!va)
+	if (!va) {
+		kfree(pmem);
 		return ERR_PTR(-ENOMEM);
+	}
 
 	memset((void *)va, 0, s);
 	pa = gen_pool_virt_to_phys(genpool, va);
@@ -950,10 +952,9 @@ void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
 				       (unsigned long)kaddr, pmem->size);
 			pmem->vaddr = NULL;
 			list_del(&pmem->node);
+			kfree(pmem);
 			return;
 		}
-
-	list_del(&svc_data_mem);
 }
 EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
 
Signature · 1 line
2.53.0
author maintainer
#308 lore raw

PATCH 308/389 gpio: pch: use raw_spinlock_t for the register lock

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Junjie Cao <[email protected]>

[ Upstream commit a02b8950d619123da64f69b70fe1dadef217dfe4 ]

pch_irq_type() is registered as the irq_chip .irq_set_type callback and takes chip->spinlock with spin_lock_irqsave(). This callback is reached from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled. That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is an rtmutex-backed sleeping lock, so acquiring it there is invalid.

This was confirmed on a PREEMPT_RT kernel with lockdep (PROVE_RAW_LOCK_NESTING and DEBUG_ATOMIC_SLEEP). A grounded PoC mirrored pch_irq_type()'s locking and drove it through the real genirq carrier irq_set_irq_type() -> __irq_set_trigger() -> chip->irq_set_type(), i.e. the same __irq_set_trigger() edge that __setup_irq() takes for a requested IRQ. With the original spin_lock_irqsave() edge lockdep reported an invalid wait context, immediately followed by:

  BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48
  in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 95, name: insmod
  hardirqs last disabled at (3784): _raw_spin_lock_irqsave+0x4f/0x60
   rt_spin_lock+0x3a/0x1c0
   repro_irq_set_type+0x64/0xa0 [pch_repro]
   __irq_set_trigger+0x69/0x140
   irq_set_irq_type+0x78/0xd0

Switching the mirrored lock to raw_spinlock_t made both splats go away.

Convert the register lock to raw_spinlock_t. The same lock also serializes the GPIO direction/value callbacks and the suspend/resume register save/restore, but all of those critical sections only perform MMIO register accesses (ioread32()/iowrite32()) and irq_set_handler_locked(); none of them contain sleepable operations. Keeping this register lock non-sleeping is therefore appropriate for the irqchip callbacks and does not change the GPIO-side locking contract.

This is the same class of issue and fix as recently addressed for other GPIO controllers, e.g. commit 286533cb14a3 ("gpio: sch: use raw_spinlock_t in the irq startup path") and commit 90f0109019e6 ("gpio: eic-sprd: use raw_spinlock_t in the irq startup path").

Fixes 38eb18a6f92d ("gpio-pch: Support interrupt function")
(cherry picked from commit a02b8950d619123da64f69b70fe1dadef217dfe4)
---
 drivers/gpio/gpio-pch.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)
drivers/gpio/gpio-pch.c +14 -14
index a552df298a974..af4b3b7f3033d 100644
@@ -92,7 +92,7 @@ struct pch_gpio {
 	struct pch_gpio_reg_data pch_gpio_reg;
 	int irq_base;
 	enum pch_type_t ioh;
-	spinlock_t spinlock;
+	raw_spinlock_t spinlock;
 };
 
 static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
@@ -101,7 +101,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
 	struct pch_gpio *chip =	gpiochip_get_data(gpio);
 	unsigned long flags;
 
-	spin_lock_irqsave(&chip->spinlock, flags);
+	raw_spin_lock_irqsave(&chip->spinlock, flags);
 	reg_val = ioread32(&chip->reg->po);
 	if (val)
 		reg_val |= BIT(nr);
@@ -109,7 +109,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
 		reg_val &= ~BIT(nr);
 
 	iowrite32(reg_val, &chip->reg->po);
-	spin_unlock_irqrestore(&chip->spinlock, flags);
+	raw_spin_unlock_irqrestore(&chip->spinlock, flags);
 }
 
 static int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr)
@@ -127,7 +127,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
 	u32 reg_val;
 	unsigned long flags;
 
-	spin_lock_irqsave(&chip->spinlock, flags);
+	raw_spin_lock_irqsave(&chip->spinlock, flags);
 
 	reg_val = ioread32(&chip->reg->po);
 	if (val)
@@ -141,7 +141,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,
 	pm |= BIT(nr);
 	iowrite32(pm, &chip->reg->pm);
 
-	spin_unlock_irqrestore(&chip->spinlock, flags);
+	raw_spin_unlock_irqrestore(&chip->spinlock, flags);
 
 	return 0;
 }
@@ -152,12 +152,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
 	u32 pm;
 	unsigned long flags;
 
-	spin_lock_irqsave(&chip->spinlock, flags);
+	raw_spin_lock_irqsave(&chip->spinlock, flags);
 	pm = ioread32(&chip->reg->pm);
 	pm &= BIT(gpio_pins[chip->ioh]) - 1;
 	pm &= ~BIT(nr);
 	iowrite32(pm, &chip->reg->pm);
-	spin_unlock_irqrestore(&chip->spinlock, flags);
+	raw_spin_unlock_irqrestore(&chip->spinlock, flags);
 
 	return 0;
 }
@@ -259,7 +259,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
 		return 0;
 	}
 
-	spin_lock_irqsave(&chip->spinlock, flags);
+	raw_spin_lock_irqsave(&chip->spinlock, flags);
 
 	/* Set interrupt mode */
 	im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
@@ -271,7 +271,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type)
 	else if (type & IRQ_TYPE_EDGE_BOTH)
 		irq_set_handler_locked(d, handle_edge_irq);
 
-	spin_unlock_irqrestore(&chip->spinlock, flags);
+	raw_spin_unlock_irqrestore(&chip->spinlock, flags);
 	return 0;
 }
 
@@ -378,7 +378,7 @@ static int pch_gpio_probe(struct pci_dev *pdev,
 
 	chip->reg = chip->base;
 	pci_set_drvdata(pdev, chip);
-	spin_lock_init(&chip->spinlock);
+	raw_spin_lock_init(&chip->spinlock);
 	pch_gpio_setup(chip);
 
 	ret = devm_gpiochip_add_data(&pdev->dev, &chip->gpio, chip);
@@ -415,9 +415,9 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev)
 	struct pch_gpio *chip = dev_get_drvdata(dev);
 	unsigned long flags;
 
-	spin_lock_irqsave(&chip->spinlock, flags);
+	raw_spin_lock_irqsave(&chip->spinlock, flags);
 	pch_gpio_save_reg_conf(chip);
-	spin_unlock_irqrestore(&chip->spinlock, flags);
+	raw_spin_unlock_irqrestore(&chip->spinlock, flags);
 
 	return 0;
 }
@@ -427,11 +427,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)
 	struct pch_gpio *chip = dev_get_drvdata(dev);
 	unsigned long flags;
 
-	spin_lock_irqsave(&chip->spinlock, flags);
+	raw_spin_lock_irqsave(&chip->spinlock, flags);
 	iowrite32(0x01, &chip->reg->reset);
 	iowrite32(0x00, &chip->reg->reset);
 	pch_gpio_restore_reg_conf(chip);
-	spin_unlock_irqrestore(&chip->spinlock, flags);
+	raw_spin_unlock_irqrestore(&chip->spinlock, flags);
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#309 lore raw

PATCH 309/389 mount: honour SB_NOUSER in the new mount API

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Al Viro <[email protected]>

[ Upstream commit 6dd3c6884cd9defb511284b566cef5ac8f657dbf ]

One should *not* be allowed to mount one of those, new API or not.

[Denis: rename new_mnt -> newmount.mnt]
[Denis: use goto err_unlock instead of direct return]
---
 fs/namespace.c | 5 +++++
 1 file changed, 5 insertions(+)
fs/namespace.c +5 -0
index e9b8d516f1919..fcb9ab4617754 100644
@@ -3657,6 +3657,11 @@ SYSCALL_DEFINE3(fsmount, int, fs_fd, unsigned int, flags,
 		ret = PTR_ERR(newmount.mnt);
 		goto err_unlock;
 	}
+	if (newmount.mnt->mnt_sb->s_flags & SB_NOUSER) {
+		mntput(newmount.mnt);
+		ret = -EINVAL;
+		goto err_unlock;
+	}
 	newmount.dentry = dget(fc->root);
 	newmount.mnt->mnt_flags = mnt_flags;
 
Signature · 1 line
2.53.0
author maintainer
#310 lore raw

PATCH 310/389 s390/zcrypt: Fix missing mem scrub at clear key import in cca_clr2cipherkey()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Harald Freudenberger <[email protected]>

[ Upstream commit 01476391aecef36a3b789ee844357b22fbc90665 ]

The helper function _ip_cprb_helper() uses internal buffer memory for building and processing CPRBs. After use this buffer was never scrubbed which could lead to leaving for example clear key material in memory which could be exposed via tricky reuse of this same memory.

Extend the _ip_cprb_helper() function with another parameter 'scrub' used to steer scrubbing of this buffer. So now the caller has the opportunity to decide if scrubbing is needed or not.

Extend the clear key to secure key token import process in function cca_clr2cipherkey() to tell the helper function from above to scrub the cprb buffer when the clear key value is part of the request data.

Add explicit scrubbing on return from function cca_clr2cipherkey() for the random EXOR buffer and the cprb buffer.

Overall this cleans the internal used buffer in case of clear key import to prevent sensitive data to get exposed.

Fixes 4bc123b18ce6 ("s390/zcrypt: Add low level functions for CCA AES cipher keys")
---
 drivers/s390/crypto/zcrypt_ccamisc.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)
drivers/s390/crypto/zcrypt_ccamisc.c +13 -7
index 7af5176623bc1..7875519491dbd 100644
@@ -943,7 +943,8 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
 			   const u8 *clr_key_value,
 			   int clr_key_bit_size,
 			   u8 *key_token,
-			   int *key_token_size)
+			   int *key_token_size,
+			   bool scrub)
 {
 	int rc, n;
 	u8 *mem, *ptr;
@@ -1084,7 +1085,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
 	*key_token_size = t->len;
 
 out:
-	free_cprbmem(mem, PARMBSIZE, 0);
+	free_cprbmem(mem, PARMBSIZE, scrub);
 	return rc;
 }
 
@@ -1127,7 +1128,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
 	 * 4/4 COMPLETE the secure cipher key import
 	 */
 	rc = _ip_cprb_helper(card, dom, "AES     ", "FIRST   ", "MIN3PART",
-			     exorbuf, keybitsize, token, &tokensize);
+			     exorbuf, keybitsize, token, &tokensize,
+			     true);
 	if (rc) {
 		DEBUG_ERR(
 			"%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n",
@@ -1135,7 +1137,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
 		goto out;
 	}
 	rc = _ip_cprb_helper(card, dom, "AES     ", "ADD-PART", NULL,
-			     clrkey, keybitsize, token, &tokensize);
+			     clrkey, keybitsize, token, &tokensize,
+			     true);
 	if (rc) {
 		DEBUG_ERR(
 			"%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n",
@@ -1143,7 +1146,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
 		goto out;
 	}
 	rc = _ip_cprb_helper(card, dom, "AES     ", "ADD-PART", NULL,
-			     exorbuf, keybitsize, token, &tokensize);
+			     exorbuf, keybitsize, token, &tokensize,
+			     true);
 	if (rc) {
 		DEBUG_ERR(
 			"%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n",
@@ -1151,7 +1155,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
 		goto out;
 	}
 	rc = _ip_cprb_helper(card, dom, "AES     ", "COMPLETE", NULL,
-			     NULL, keybitsize, token, &tokensize);
+			     NULL, keybitsize, token, &tokensize,
+			     true);
 	if (rc) {
 		DEBUG_ERR(
 			"%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n",
@@ -1169,7 +1174,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
 	*keybufsize = tokensize;
 
 out:
-	kfree(token);
+	memzero_explicit(exorbuf, sizeof(exorbuf));
+	kfree_sensitive(token);
 	return rc;
 }
 EXPORT_SYMBOL(cca_clr2cipherkey);
Signature · 1 line
2.53.0
author maintainer
#311 lore raw

PATCH 311/389 nfs4: take a reference on the nfs_client when running FREE_STATEID

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Scott Mayhew <[email protected]>

[ Upstream commit 576acc259146af848cec0940f573f7125a116b9f ]

During umount, the session slot tables are freed. If there are outstanding FREE_STATEID tasks, a use-after-free and slab corruption can occur when rpc_exit_task calls rpc_call_done -> nfs41_sequence_done -> nfs4_sequence_process/nfs41_sequence_free_slot.

Prevent that from happening by taking a reference on the nfs_client in nfs41_free_stateid and putting it in nfs41_free_stateid_release.

Stable-dep-of: cf616096a0f3 ("NFS: Pin the 'struct nfs_server' during a FREE_STATEID call")

---
 fs/nfs/nfs4proc.c | 8 ++++++++
 1 file changed, 8 insertions(+)
fs/nfs/nfs4proc.c +8 -0
index 170e9eaf536af..bd97e0b61e70d 100644
@@ -10135,6 +10135,10 @@ static void nfs41_free_stateid_done(struct rpc_task *task, void *calldata)
 
 static void nfs41_free_stateid_release(void *calldata)
 {
+	struct nfs_free_stateid_data *data = calldata;
+	struct nfs_client *clp = data->server->nfs_client;
+
+	nfs_put_client(clp);
 	kfree(calldata);
 }
 
@@ -10171,6 +10175,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
 	};
 	struct nfs_free_stateid_data *data;
 	struct rpc_task *task;
+	struct nfs_client *clp = server->nfs_client;
+
+	if (!refcount_inc_not_zero(&clp->cl_count))
+		return -EIO;
 
 	nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
 		&task_setup.rpc_client, &msg);
Signature · 1 line
2.53.0
author maintainer
#312 lore raw

PATCH 312/389 NFS: Pin the struct nfs_server during a FREE_STATEID call

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anna Schumaker <[email protected]>

[ Upstream commit cf616096a0f3a2b60f7d68b6b39674a6867ded9c ]

Dan Aloni reports that he was able to hit a use-after-free bug if a FREE_STATEID operation gets delayed for whatever reason. Fix this by bumping the refcount of the 'struct nfs_server' object for the duration of the FREE_STATEID so it doesn't get cleaned up from underneath us while operations are still in flight.

Fixes 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call")
---
 fs/nfs/nfs4proc.c | 5 +++++
 1 file changed, 5 insertions(+)
fs/nfs/nfs4proc.c +5 -0
index bd97e0b61e70d..c455f6a8f61ae 100644
@@ -10138,6 +10138,7 @@ static void nfs41_free_stateid_release(void *calldata)
 	struct nfs_free_stateid_data *data = calldata;
 	struct nfs_client *clp = data->server->nfs_client;
 
+	nfs_sb_deactive(data->server->super);
 	nfs_put_client(clp);
 	kfree(calldata);
 }
@@ -10179,6 +10180,10 @@ static int nfs41_free_stateid(struct nfs_server *server,
 
 	if (!refcount_inc_not_zero(&clp->cl_count))
 		return -EIO;
+	if (!nfs_sb_active(server->super)) {
+		nfs_put_client(clp);
+		return -EIO;
+	}
 
 	nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
 		&task_setup.rpc_client, &msg);
Signature · 1 line
2.53.0
author maintainer
#313 lore raw

PATCH 313/389 ARM: npcm: Fix OF node refcount leaks in SMP setup

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yuho Choi <[email protected]>

[ Upstream commit 8eb052f48331474c2789d07b7f11165c323bd2f9 ]

npcm7xx_smp_boot_secondary() and npcm7xx_smp_prepare_cpus() look up the GCR and SCU nodes with of_find_compatible_node(). The returned nodes are used for of_iomap(), but the node references are never released.

of_iomap() does not consume the device node reference, and iounmap() only releases the MMIO mapping. Drop each node reference after the corresponding mapping attempt.

Fixes 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs")
---
 arch/arm/mach-npcm/platsmp.c | 2 ++
 1 file changed, 2 insertions(+)
arch/arm/mach-npcm/platsmp.c +2 -0
index 21633c70fe7fe..fe63edc9886df 100644
@@ -35,6 +35,7 @@ static int npcm7xx_smp_boot_secondary(unsigned int cpu,
 		goto out;
 	}
 	gcr_base = of_iomap(gcr_np, 0);
+	of_node_put(gcr_np);
 	if (!gcr_base) {
 		pr_err("could not iomap gcr");
 		ret = -ENOMEM;
@@ -63,6 +64,7 @@ static void __init npcm7xx_smp_prepare_cpus(unsigned int max_cpus)
 		return;
 	}
 	scu_base = of_iomap(scu_np, 0);
+	of_node_put(scu_np);
 	if (!scu_base) {
 		pr_err("could not iomap scu");
 		return;
Signature · 1 line
2.53.0
author maintainer
#314 lore raw

PATCH 314/389 bonding: alb: re-check primary_is_promisc under RTNL in bond_alb_monitor

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xiang Mei (Microsoft) <[email protected]>

[ Upstream commit 683c6ba6e58e6ed1037831ea97dd58d9c0e76b8d ]

bond_alb_monitor() reads primary_is_promisc under RCU, then drops RCU and takes RTNL via rtnl_trylock() before undoing the promiscuity it set on the active slave. In that window the active slave can change under RTNL (RTM_DELLINK -> __bond_release_one() -> bond_alb_handle_active_change()), which already drops the promiscuity and clears primary_is_promisc. The monitor still acts on the stale decision: if the slave was removed with no failover, curr_active_slave is now NULL and the deref faults; if it failed over, the stale dev_set_promiscuity(-1) underflows the new slave's promiscuity counter and pins it in IFF_PROMISC.

  Oops: general protection fault, probably for non-canonical address ...
  KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
  Workqueue: b42 bond_alb_monitor
  RIP: 0010:bond_alb_monitor (drivers/net/bonding/bond_alb.c:1600)
   process_one_work (kernel/workqueue.c:3322)
   worker_thread (kernel/workqueue.c:3486)
   kthread (kernel/kthread.c:436)
   ret_from_fork (arch/x86/kernel/process.c:158)
  Kernel panic - not syncing: Fatal exception

Re-check primary_is_promisc (and curr_active_slave) after taking RTNL so the monitor only undoes an increment it still owns. The other bonding monitors already re-read state under RTNL in their commit phase (bond_miimon_commit/bond_ab_arp_commit); bond_alb_monitor() was the only one acting on the pre-trylock decision.

---
 drivers/net/bonding/bond_alb.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/net/bonding/bond_alb.c +6 -4
index 81a5e7622ea7d..dff22eddc885a 100644
@@ -1528,8 +1528,8 @@ void bond_alb_monitor(struct work_struct *work)
 	struct bonding *bond = container_of(work, struct bonding,
 					    alb_work.work);
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+	struct slave *slave, *curr;
 	struct list_head *iter;
-	struct slave *slave;
 
 	if (!bond_has_slaves(bond)) {
 		atomic_set(&bond_info->tx_rebalance_counter, 0);
@@ -1591,9 +1591,11 @@ void bond_alb_monitor(struct work_struct *work)
 			 * because a slave was disabled then
 			 * it can now leave promiscuous mode.
 			 */
-			dev_set_promiscuity(rtnl_dereference(bond->curr_active_slave)->dev,
-					    -1);
-			bond_info->primary_is_promisc = 0;
+			curr = rtnl_dereference(bond->curr_active_slave);
+			if (bond_info->primary_is_promisc && curr) {
+				dev_set_promiscuity(curr->dev, -1);
+				bond_info->primary_is_promisc = 0;
+			}
 
 			rtnl_unlock();
 			rcu_read_lock();
Signature · 1 line
2.53.0
author maintainer
#315 lore raw

PATCH 315/389 bpf: Preserve pointer state for commuted arithmetic

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yiyang Chen <[email protected]>

[ Upstream commit a4c6f804b44c5c790269b25e0e61cf4e9f117c86 ]

When scalar += pointer is handled in adjust_ptr_min_max_vals(), the destination register inherits the pointer state from the source pointer. Copying only selected fields is fragile because pointer provenance is tracked by several bpf_reg_state fields.

Use the caller's temporary offset register to preserve the scalar operand while replacing the destination with the full pointer state. This preserves the frame number for PTR_TO_STACK registers and keeps parent identity fields consistent.

---
 kernel/bpf/verifier.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)
kernel/bpf/verifier.c +8 -7
index 058c05e7f144c..9866599171782 100644
@@ -6301,11 +6301,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 		break;
 	}
 
-	/* In case of 'scalar += pointer', dst_reg inherits pointer type and id.
-	 * The id may be overwritten later if we create a new variable offset.
+	/* For 'scalar += pointer', dst_reg inherits the complete pointer
+	 * register state. Individual fields may be adjusted later by pointer
+	 * arithmetic. Callers guarantee that below does not overwrite off_reg.
 	 */
-	dst_reg->type = ptr_reg->type;
-	dst_reg->id = ptr_reg->id;
+	if (dst_reg != ptr_reg)
+		*dst_reg = *ptr_reg;
 
 	if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
 	    !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
@@ -6373,7 +6374,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 		}
 		break;
 	case BPF_SUB:
-		if (dst_reg == off_reg) {
+		if (dst_reg != ptr_reg) {
 			/* scalar -= pointer.  Creates an unknown scalar */
 			verbose(env, "R%d tried to subtract pointer from scalar\n",
 				dst);
@@ -7232,8 +7233,8 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
 				err = mark_chain_precision(env, insn->dst_reg);
 				if (err)
 					return err;
-				return adjust_ptr_min_max_vals(env, insn,
-							       src_reg, dst_reg);
+				off_reg = *dst_reg;
+				return adjust_ptr_min_max_vals(env, insn, src_reg, &off_reg);
 			}
 		} else if (ptr_reg) {
 			/* pointer += scalar */
Signature · 1 line
2.53.0
author maintainer
#316 lore raw

PATCH 316/389 net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in smc_llc_event_handler()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mahanta Jambigi <[email protected]>

[ Upstream commit 976245094925bab9bc39366b2e9ab44ffcde61d0 ]

The SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT branch in smc_llc_event_handler() stores an incoming qentry into the local LLC flow without first checking whether a qentry is already pending. If a malicious or buggy peer sends a second CONFIRM_LINK or ADD_LINK_CONT request while a flow is active and flow->qentry is already set, smc_llc_flow_qentry_set() overwrites the pointer without freeing the previous allocation, leaking one kmalloc-96 object per spurious message.

The sibling SMC_LLC_DELETE_LINK branch already has the correct !flow->qentry guard. Apply the same guard to the CONFIRM_LINK/ADD_LINK_CONT branch so that a duplicate message when qentry is already occupied falls through to break and is freed by the kfree(qentry) at the out: label, rather than silently leaking the existing allocation.

The response direction (smc_llc_rx_response()) is unaffected: it already guards with flow->qentry at the equivalent site and drops duplicate responses correctly.

---
 net/smc/smc_llc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/smc/smc_llc.c +2 -1
index d5ee961ca72d5..572d02bfd3eda 100644
@@ -1582,7 +1582,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)
 		return;
 	case SMC_LLC_CONFIRM_LINK:
 	case SMC_LLC_ADD_LINK_CONT:
-		if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
+		if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE &&
+		    !lgr->llc_flow_lcl.qentry) {
 			/* a flow is waiting for this message */
 			smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
 			wake_up(&lgr->llc_msg_waiter);
Signature · 1 line
2.53.0
author maintainer
#317 lore raw

PATCH 317/389 net/sched: cls_route: fix fastmap use-after-free on filter

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jamal Hadi Salim <[email protected]>

[ Upstream commit 47d7f7051253bdc02b1d245d87e38f16d31a74df ]

The route4 classifier maintains a 16-slot fastmap cache that stores raw struct route4_filter pointers indexed by (id, iif). The reader (route4_classify) populates this cache via route4_set_fastmap() for every classified packet that hits a filter. The writer (route4_delete, route4_change) clears the cache via route4_reset_fastmap() before RCU-deferred kfree of the filter.

This creates a UAF race:
1. Reader walks the RCU-protected bucket chain, finds filter f
2. Writer unlinks f, calls route4_reset_fastmap(), then tcf_queue_work()
3. Reader calls route4_set_fastmap() and writes f into the cache *after* the writer's reset, caching a pointer about to be freed
4. After the RCU grace period, kfree(f) executes
5. Next classified packet on the same (id, iif) tuple hits the stale

    fastmap entry and reads f->res from freed memory

Reproduced with an mdelay(100) accelerator in route4_set_fastmap() and a concurrent add/delete stress test (provided by both zdi and Santosh). Both triggered KASAN slab-use-after-free reports in the route4 fastmap paths.

Fix:
Introduce a per-filter boolean dying flag to suppress stale fastmap republishing by in-flight readers.

---
 net/sched/cls_route.c | 35 ++++++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 9 deletions(-)
net/sched/cls_route.c +26 -9
index 1ad4b3e60eb3b..695c91961e33b 100644
@@ -51,6 +51,7 @@ struct route4_filter {
 	struct tcf_result	res;
 	struct tcf_exts		exts;
 	u32			handle;
+	bool			dying;
 	struct route4_bucket	*bkt;
 	struct tcf_proto	*tp;
 	struct rcu_work		rwork;
@@ -65,9 +66,11 @@ static inline int route4_fastmap_hash(u32 id, int iif)
 
 static DEFINE_SPINLOCK(fastmap_lock);
 static void
-route4_reset_fastmap(struct route4_head *head)
+route4_reset_fastmap(struct route4_head *head, struct route4_filter *f)
 {
 	spin_lock_bh(&fastmap_lock);
+	if (f)
+		f->dying = true;
 	memset(head->fastmap, 0, sizeof(head->fastmap));
 	spin_unlock_bh(&fastmap_lock);
 }
@@ -80,9 +83,11 @@ route4_set_fastmap(struct route4_head *head, u32 id, int iif,
 
 	/* fastmap updates must look atomic to aling id, iff, filter */
 	spin_lock_bh(&fastmap_lock);
-	head->fastmap[h].id = id;
-	head->fastmap[h].iif = iif;
-	head->fastmap[h].filter = f;
+	if (f == ROUTE4_FAILURE || !f->dying) {
+		head->fastmap[h].id = id;
+		head->fastmap[h].iif = iif;
+		head->fastmap[h].filter = f;
+	}
 	spin_unlock_bh(&fastmap_lock);
 }
 
@@ -295,6 +300,13 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
 					next = rtnl_dereference(f->next);
 					RCU_INIT_POINTER(b->ht[h2], next);
 					tcf_unbind_filter(tp, &f->res);
+					/* Mark the filter dying under fastmap_lock so
+					 * any in-flight reader that still holds it
+					 * will skip the republish in route4_set_fastmap().
+					 */
+					spin_lock_bh(&fastmap_lock);
+					f->dying = true;
+					spin_unlock_bh(&fastmap_lock);
 					if (tcf_exts_get_net(&f->exts))
 						route4_queue_work(f);
 					else
@@ -305,6 +317,11 @@ static void route4_destroy(struct tcf_proto *tp, bool rtnl_held,
 			kfree_rcu(b, rcu);
 		}
 	}
+
+	/* All filters are unlinked and marked dying, so no in-flight
+	 * reader can republish a stale entry after this reset.
+	 */
+	route4_reset_fastmap(head, NULL);
 	kfree_rcu(head, rcu);
 }
 
@@ -332,11 +349,11 @@ static int route4_delete(struct tcf_proto *tp, void *arg, bool *last,
 			/* unlink it */
 			RCU_INIT_POINTER(*fp, rtnl_dereference(f->next));
 
-			/* Remove any fastmap lookups that might ref filter
-			 * notice we unlink'd the filter so we can't get it
-			 * back in the fastmap.
+			/* Clear any fastmap entries that may ref this filter and
+			 * mark it dying so in-flight readers can't republish it
+			 * after the reset.
 			 */
-			route4_reset_fastmap(head);
+			route4_reset_fastmap(head, f);
 
 			/* Delete it */
 			tcf_unbind_filter(tp, &f->res);
@@ -551,7 +568,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
 		}
 	}
 
-	route4_reset_fastmap(head);
+	route4_reset_fastmap(head, fold);
 	*arg = f;
 	if (fold) {
 		tcf_unbind_filter(tp, &fold->res);
Signature · 1 line
2.53.0
author maintainer
#318 lore raw

PATCH 318/389 net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jiawen Liu <[email protected]>

[ Upstream commit f307a7dc32097c11413178fca437a10d20890bc2 ]

hix5hd2_dev_remove() calls netif_napi_del() before unregister_netdev(). This is not needed because free_netdev() deletes all NAPI instances attached to the net_device.

Remove the redundant call and let the networking core tear down the NAPI instance during unregister_netdev(). The probe error path still keeps its explicit netif_napi_del(), because the device has not been registered there.

Fixes 57c5bc9ad7d7 ("net: hisilicon: add hix5hd2 mac driver")
---
 drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 1 -
 1 file changed, 1 deletion(-)
drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +0 -1
index 43f3146caf07e..18495d80e2e74 100644
@@ -1291,7 +1291,6 @@ static int hix5hd2_dev_remove(struct platform_device *pdev)
 	struct net_device *ndev = platform_get_drvdata(pdev);
 	struct hix5hd2_priv *priv = netdev_priv(ndev);
 
-	netif_napi_del(&priv->napi);
 	unregister_netdev(ndev);
 	mdiobus_unregister(priv->bus);
 	mdiobus_free(priv->bus);
Signature · 1 line
2.53.0
author maintainer
#319 lore raw

PATCH 319/389 net/mlx5: Remove second FW tracer check

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Leon Romanovsky <[email protected]>

[ Upstream commit 7e615b9978021a034124166d4fa3dc4fc0ea4b16 ]

The FW tracer check is called twice, so delete one of them.

Stable-dep-of: af39eb111ce6 ("net/mlx5: fw_tracer, return NULL on create error")

---
 drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 2 +-
 drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c       | 7 +------
 2 files changed, 2 insertions(+), 7 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +1 -1
index f3985421e739e..a83bfdfe51325 100644
@@ -1205,7 +1205,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
 	int err;
 
 	if (IS_ERR_OR_NULL(tracer))
-		return -EINVAL;
+		return 0;
 
 	dev = tracer->dev;
 	mlx5_fw_tracer_cleanup(tracer);
drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +1 -6
index a2d9904e10492..d2bf20035e20d 100644
@@ -208,16 +208,11 @@ static void mlx5_fw_live_patch_event(struct work_struct *work)
 	struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset,
 						      fw_live_patch_work);
 	struct mlx5_core_dev *dev = fw_reset->dev;
-	struct mlx5_fw_tracer *tracer;
 
 	mlx5_core_info(dev, "Live patch updated firmware version: %d.%d.%d\n", fw_rev_maj(dev),
 		       fw_rev_min(dev), fw_rev_sub(dev));
 
-	tracer = dev->tracer;
-	if (IS_ERR_OR_NULL(tracer))
-		return;
-
-	if (mlx5_fw_tracer_reload(tracer))
+	if (mlx5_fw_tracer_reload(dev->tracer))
 		mlx5_core_err(dev, "Failed to reload FW tracer\n");
 }
 
Signature · 1 line
2.53.0
author maintainer
#320 lore raw

PATCH 320/389 net/mlx5: fw_tracer, return NULL on create error

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Michael Guralnik <[email protected]>

[ Upstream commit af39eb111ce6b5eba9c08513b62c4868eb7e7fd5 ]

Tracer creation can fail by returning either NULL or ERR_PTR. The return value is stored without a check on the device, and users treat ERR_PTR and NULL the same way.
This also causes a crash in the core dump logic, which is missing the ERR_PTR check and ends up dereferencing it, as shown in the trace below.

Switch tracer creation to return NULL on failure only, so callers only need a single NULL check.

  Internal error: Oops: 0000000096000006 [#1]  SMP
  Modules linked in: mlx5_ib ib_uverbs ib_core ipv6 mlx5_core
  CPU: 1 UID: 0 PID: 12 Comm: kworker/u16:0 Not tainted 6.19.7 #1 PREEMPT(none)
  Workqueue: mlx5_health0001:01:00.0 mlx5_fw_reporter_err_work [mlx5_core]
  pstate: a3400009 (NzCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
  pc : mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core]
  lr : mlx5_fw_tracer_trigger_core_dump_general+0x40/0xe0 [mlx5_core]
  sp : ffff800081cf3c40
  x29: ffff800081cf3c90 x28: 0000000000000000 x27: 0000000000000000
  x26: ffff000080018828 x25: 0000000000000000 x24: ffff000080304a05
  x23: ffff800081cf3d80 x22: ffff0000847e01a0 x21: 0000000000000000
  x20: ffff0000847e01a0 x19: ffffffffffffffa1 x18: ffff80008310bbf0
  x17: ffff800080119650 x16: ffff80008010df54 x15: ffff80008010d4ac
  x14: ffff800079c202e4 x13: ffff80008002fe60 x12: ffff800080119650
  x11: ffff80008010df54 x10: ffff80008010d4ac x9 : ffff800079c203d8
  x8 : ffff800081cf3c88 x7 : 0000000000000000 x6 : 0000000000000000
  x5 : 0000000000000000 x4 : 0000000000000008 x3 : 0000000000000030
  x2 : 0000000000000008 x1 : 0000000000000000 x0 : 00000000c5c4000e
  Call trace:
   mlx5_fw_tracer_trigger_core_dump_general+0x58/0xe0 [mlx5_core] (P)
   mlx5_fw_reporter_dump+0x30/0x2e0 [mlx5_core]
   devlink_health_do_dump+0x9c/0x160
   devlink_health_report+0x1c0/0x288
   mlx5_fw_reporter_err_work+0xac/0xc0 [mlx5_core]
   process_one_work+0x15c/0x3d8
   worker_thread+0x18c/0x320
   kthread+0x148/0x228
   ret_from_fork+0x10/0x20
  Code: b9400000 5ac00800 7a401800 540003ca (3940a260)
  ---[ end trace 0000000000000000 ]---
  Kernel panic - not syncing: Oops: Fatal exception
  SMP: stopping secondary CPUs
  Kernel Offset: disabled
  CPU features: 0x000000,00078031,75fce5a1,35fffe67
  Memory Limit: none
  ---[ end Kernel panic - not syncing: Oops: Fatal exception ]---
---
 .../ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +7 -9
index a83bfdfe51325..9817de5590b56 100644
@@ -1036,13 +1036,11 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
 
 	tracer = kvzalloc(sizeof(*tracer), GFP_KERNEL);
 	if (!tracer)
-		return ERR_PTR(-ENOMEM);
+		return NULL;
 
 	tracer->work_queue = create_singlethread_workqueue("mlx5_fw_tracer");
-	if (!tracer->work_queue) {
-		err = -ENOMEM;
+	if (!tracer->work_queue)
 		goto free_tracer;
-	}
 
 	tracer->dev = dev;
 
@@ -1082,7 +1080,7 @@ struct mlx5_fw_tracer *mlx5_fw_tracer_create(struct mlx5_core_dev *dev)
 	destroy_workqueue(tracer->work_queue);
 free_tracer:
 	kvfree(tracer);
-	return ERR_PTR(err);
+	return NULL;
 }
 
 static int fw_tracer_event(struct notifier_block *nb, unsigned long action, void *data);
@@ -1093,7 +1091,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
 	struct mlx5_core_dev *dev;
 	int err;
 
-	if (IS_ERR_OR_NULL(tracer))
+	if (!tracer)
 		return 0;
 
 	dev = tracer->dev;
@@ -1136,7 +1134,7 @@ int mlx5_fw_tracer_init(struct mlx5_fw_tracer *tracer)
 /* Stop tracer + Cleanup HW resources */
 void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
 {
-	if (IS_ERR_OR_NULL(tracer))
+	if (!tracer)
 		return;
 
 	mlx5_core_dbg(tracer->dev, "FWTracer: Cleanup, is owner ? (%d)\n",
@@ -1155,7 +1153,7 @@ void mlx5_fw_tracer_cleanup(struct mlx5_fw_tracer *tracer)
 /* Free software resources (Buffers, etc ..) */
 void mlx5_fw_tracer_destroy(struct mlx5_fw_tracer *tracer)
 {
-	if (IS_ERR_OR_NULL(tracer))
+	if (!tracer)
 		return;
 
 	mlx5_core_dbg(tracer->dev, "FWTracer: Destroy\n");
@@ -1204,7 +1202,7 @@ int mlx5_fw_tracer_reload(struct mlx5_fw_tracer *tracer)
 	struct mlx5_core_dev *dev;
 	int err;
 
-	if (IS_ERR_OR_NULL(tracer))
+	if (!tracer)
 		return 0;
 
 	dev = tracer->dev;
Signature · 1 line
2.53.0
author maintainer
#321 lore raw

PATCH 321/389 counter: microchip-tcb-capture: Fix DT channel validation

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Babanpreet Singh <[email protected]>

[ Upstream commit f1a3a9946aab611dd2200c01ff122f64b033dad2 ]

mchp_tc_probe() reads the devicetree "reg" cell - a u32, per the API contract of of_property_read_u32_index() - into a signed int, so the bounds check "channel > 2" fails to reject cell values at or above 0x80000000: reinterpreted as a negative int, they compare below 2 and pass validation.

A malformed devicetree can therefore drive a negative channel into the ATMEL_TC_REG() offset arithmetic, making the driver access syscon regmap offsets outside the TC block's register window, and into the "t%d_clk" clock-name formatting, where it truncates clk_name (sized for "t0_clk".."t2_clk").

Declare channel as u32, matching the API contract; the unsigned comparison then rejects everything except channels 0..2. Adjust the format specifier to %u accordingly, which also resolves the W=1 warning that exposed the gap:

microchip-tcb-capture.c:520:56: warning: '%d' directive output may
be truncated writing between 1 and 11 bytes into a region of size 6 [-Wformat-truncation=]
note: directive argument in the range [-2147483648, 2]

No behavior change for well-formed devicetrees: channels 0..2 take identical paths before and after.

Fixes 106b104137fd ("counter: Add microchip TCB capture counter")
Assisted-by Claude:claude-fable-5 [gcc W=1]
---
 drivers/counter/microchip-tcb-capture.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/counter/microchip-tcb-capture.c +2 -2
index 40d02df8acf75..822c072ffa20e 100644
@@ -317,7 +317,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
 	char clk_name[7];
 	struct regmap *regmap;
 	struct clk *clk[3];
-	int channel;
+	u32 channel;
 	int ret, i;
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -352,7 +352,7 @@ static int mchp_tc_probe(struct platform_device *pdev)
 
 		priv->channel[i] = channel;
 
-		snprintf(clk_name, sizeof(clk_name), "t%d_clk", channel);
+		snprintf(clk_name, sizeof(clk_name), "t%u_clk", channel);
 
 		clk[i] = of_clk_get_by_name(np->parent, clk_name);
 		if (IS_ERR(clk[i])) {
Signature · 1 line
2.53.0
author maintainer
#322 lore raw

PATCH 322/389 udp: fix potential use-after-free in tunnel segmentation

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xuanqiang Luo <[email protected]>

[ Upstream commit d0f86fb36eb260abd10007b62c9dcc1028e03e61 ]

__skb_udp_tunnel_segment() gets the UDP header before ensuring the tunnel header is in the skb head. If the pull reallocates skb->head, the saved UDP header pointer is no longer valid.

Get the UDP header after the pull to avoid a potential use-after-free.

Fixes dbef491ebe7f ("udp: Use uh->len instead of skb->len to compute checksum in segmentation")
---
 net/ipv4/udp_offload.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
net/ipv4/udp_offload.c +3 -1
index 5d4413fe41952..4285d25d9982d 100644
@@ -20,17 +20,19 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
 	int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
 	bool remcsum, need_csum, offload_csum, gso_partial;
 	struct sk_buff *segs = ERR_PTR(-EINVAL);
-	struct udphdr *uh = udp_hdr(skb);
 	u16 mac_offset = skb->mac_header;
 	__be16 protocol = skb->protocol;
 	u16 mac_len = skb->mac_len;
 	int udp_offset, outer_hlen;
+	struct udphdr *uh;
 	__wsum partial;
 	bool need_ipsec;
 
 	if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
 		goto out;
 
+	uh = udp_hdr(skb);
+
 	/* Adjust partial header checksum to negate old length.
 	 * We cannot rely on the value contained in uh->len as it is
 	 * possible that the actual value exceeds the boundaries of the
Signature · 1 line
2.53.0
author maintainer
#323 lore raw

PATCH 323/389 net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK filter

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Toke Høiland-Jørgensen <[email protected]>

[ Upstream commit 2a33516f9ef59ad11844d4fc152f889449b5daf3 ]

The sch_cake ACK filter parses packets to find the TCP header and filter duplicated ACKs if the flow is backlogged. The parsing code contains a WARN_ON(1) which can be triggered by a malformed IP header in certain cases. Depending on the system configuration, this leads either to either spamming dmesg with warnings, or a panic if panic_on_warn is set.

The code already correctly skips the offending packet in the branch that triggers the warning, so the WARN_ON itself doesn't really serve any purpose. So just drop it altogether to avoid the inconvenient side effects.

---
 net/sched/sch_cake.c | 1 -
 1 file changed, 1 deletion(-)
net/sched/sch_cake.c +0 -1
index 45b175e53aac0..8e3010a183822 100644
@@ -1281,7 +1281,6 @@ static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
 
 			seglen = ntohs(ipv6h_check->payload_len);
 		} else {
-			WARN_ON(1);  /* shouldn't happen */
 			continue;
 		}
 
Signature · 1 line
2.53.0
author maintainer
#324 lore raw

PATCH 324/389 net: openvswitch: Fix kerneldoc warnings

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Andrew Lunn <[email protected]>

[ Upstream commit 210bba6790dc150c0dd65da2cbc4de39e5fa3a74 ]

net/openvswitch/flow.c:303: warning: Function parameter or member 'key_vh' not described in 'parse_vlan_tag' net/openvswitch/flow.c:303: warning: Function parameter or member 'skb' not described in 'parse_vlan_tag' net/openvswitch/flow.c:303: warning: Function parameter or member 'untag_vlan' not described in 'parse_vlan_tag' net/openvswitch/vport.c:122: warning: Function parameter or member 'parms' not described in 'ovs_vport_alloc'

Stable-dep-of: cf6f8b29befb ("net/openvswitch: check Ethernet header length in key_extract()")

---
 net/openvswitch/flow.c  | 4 ++++
 net/openvswitch/vport.c | 4 +++-
 2 files changed, 7 insertions(+), 1 deletion(-)
net/openvswitch/flow.c +4 -0
index 94531289ed26a..beacb1b46706e 100644
@@ -294,6 +294,10 @@ static bool icmp6hdr_ok(struct sk_buff *skb)
 
 /**
  * Parse vlan tag from vlan header.
+ * @skb: skb containing frame to parse
+ * @key_vh: pointer to parsed vlan tag
+ * @untag_vlan: should the vlan header be removed from the frame
+ *
  * Returns ERROR on memory error.
  * Returns 0 if it encounters a non-vlan or incomplete packet.
  * Returns 1 after successfully parsing vlan tag.
net/openvswitch/vport.c +3 -1
index ced707ff6dd97..2c876424864d2 100644
@@ -111,10 +111,12 @@ struct vport *ovs_vport_locate(const struct net *net, const char *name)
  *
  * @priv_size: Size of private data area to allocate.
  * @ops: vport device ops
+ * @parms: information about new vport.
  *
  * Allocate and initialize a new vport defined by @ops.  The vport will contain
  * a private data area of size @priv_size that can be accessed using
- * vport_priv().  vports that are no longer needed should be released with
+ * vport_priv().  Some parameters of the vport will be initialized from @parms.
+ * @vports that are no longer needed should be released with
  * vport_free().
  */
 struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
Signature · 1 line
2.53.0
author maintainer
#325 lore raw

PATCH 325/389 net: openvswitch: fix kernel-doc warnings in flow.c

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Randy Dunlap <[email protected]>

[ Upstream commit d6e712aa7e6a3d5a9633f4bcbe2237f3edc292bd ]

Repair kernel-doc notation in a few places to make it conform to the expected format.

Fixes the following kernel-doc warnings:

flow.c:296: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
* Parse vlan tag from vlan header.
flow.c:296: warning: missing initial short description on line:
* Parse vlan tag from vlan header.
flow.c:537: warning: No description found for return value of 'key_extract_l3l4'
flow.c:769: warning: No description found for return value of 'key_extract'

Stable-dep-of: cf6f8b29befb ("net/openvswitch: check Ethernet header length in key_extract()")

---
 net/openvswitch/flow.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
net/openvswitch/flow.c +7 -6
index beacb1b46706e..862d376930d79 100644
@@ -293,14 +293,14 @@ static bool icmp6hdr_ok(struct sk_buff *skb)
 }
 
 /**
- * Parse vlan tag from vlan header.
+ * parse_vlan_tag - Parse vlan tag from vlan header.
  * @skb: skb containing frame to parse
  * @key_vh: pointer to parsed vlan tag
  * @untag_vlan: should the vlan header be removed from the frame
  *
- * Returns ERROR on memory error.
- * Returns 0 if it encounters a non-vlan or incomplete packet.
- * Returns 1 after successfully parsing vlan tag.
+ * Return: ERROR on memory error.
+ * %0 if it encounters a non-vlan or incomplete packet.
+ * %1 after successfully parsing vlan tag.
  */
 static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh,
 			  bool untag_vlan)
@@ -533,6 +533,7 @@ static int parse_nsh(struct sk_buff *skb, struct sw_flow_key *key)
  *       L3 header
  * @key: output flow key
  *
+ * Return: %0 if successful, otherwise a negative errno value.
  */
 static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
 {
@@ -749,8 +750,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
  *
  * The caller must ensure that skb->len >= ETH_HLEN.
  *
- * Returns 0 if successful, otherwise a negative errno value.
- *
  * Initializes @skb header fields as follows:
  *
  *    - skb->mac_header: the L2 header.
@@ -765,6 +764,8 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
  *
  *    - skb->protocol: the type of the data starting at skb->network_header.
  *      Equals to key->eth.type.
+ *
+ * Return: %0 if successful, otherwise a negative errno value.
  */
 static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 {
Signature · 1 line
2.53.0
author maintainer
#326 lore raw

PATCH 326/389 net/openvswitch: check Ethernet header length in key_extract()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cen Zhang (Microsoft) <[email protected]>

[ Upstream commit cf6f8b29befb92173659bcef6a441d274947bfae ]

When a packet arrives on an ARPHRD_NONE device (e.g. TUN), ovs_flow_key_extract() trusts the user-provided skb->protocol field: if it is ETH_P_TEB, the packet is classified as MAC_PROTO_ETHERNET and key_extract() is called without ensuring the skb has ETH_HLEN (14) bytes of linear data. key_extract() unconditionally pulls 2 * ETH_ALEN bytes for MAC addresses and parse_ethertype() pulls 2 more, either of which triggers a kernel BUG in __skb_pull() when the linear area is too small.

kernel BUG at include/linux/skbuff.h:2848!

  RIP: 0010:key_extract+0xa7e/0xd90 net/openvswitch/flow.c:933
  ovs_flow_key_extract+0x419/0xa70
  ovs_vport_receive+0x222/0x390
  netdev_frame_hook+0x3e0/0x630
  tun_get_user+0x2d0c/0x38e0

Fixed by calling check_header() in key_extract() before accessing the Ethernet header.

---
 net/openvswitch/flow.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
net/openvswitch/flow.c +7 -4
index 862d376930d79..3f8a0d05161c5 100644
@@ -748,8 +748,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
  * Ethernet header
  * @key: output flow key
  *
- * The caller must ensure that skb->len >= ETH_HLEN.
- *
  * Initializes @skb header fields as follows:
  *
  *    - skb->mac_header: the L2 header.
@@ -769,8 +767,6 @@ static int key_extract_l3l4(struct sk_buff *skb, struct sw_flow_key *key)
  */
 static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 {
-	struct ethhdr *eth;
-
 	/* Flags are always used as part of stats */
 	key->tp.flags = 0;
 
@@ -785,6 +781,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
 		skb_reset_network_header(skb);
 		key->eth.type = skb->protocol;
 	} else {
+		struct ethhdr *eth;
+		int err;
+
+		err = check_header(skb, ETH_HLEN);
+		if (unlikely(err))
+			return err;
+
 		eth = eth_hdr(skb);
 		ether_addr_copy(key->eth.src, eth->h_source);
 		ether_addr_copy(key->eth.dst, eth->h_dest);
Signature · 1 line
2.53.0
author maintainer
#327 lore raw

PATCH 327/389 bnxt_en: Do not set EOP on RX AGG BDs on 5760X chips

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Michael Chan <[email protected]>

[ Upstream commit 30f253f8d9a01d532fdb7ec6c8a9d4c15fe29241 ]

With End-of-Packet padding (EOP) set, the chip will disable Relaxed Ordering (RO) of TPA data packets. A TPA segment with EOP set will be padded to the next cache boundary and can potentially overwrite the beginning bytes of the next TPA segment when RO is enabled on 5760X. To prevent that, the chip disables RO for TPA when EOP is set.

To take advantge of RO and higher performance, do not set EOP on 5760X chips when TPA is enabled. Define a proper RX_BD_FLAGS_AGG_EOP constant to make it clear that we are setting EOP.

Stable-dep-of: c3faf548a00f ("bnxt_en: Disable EOP for TPA on all chips to prevent data corruption")

---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++++-
 drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
 2 files changed, 9 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +8 -1
index 6dd4104025297..07fe6e55f28a6 100644
@@ -3391,7 +3391,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
 
 	if ((bp->flags & BNXT_FLAG_AGG_RINGS)) {
 		type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
-			RX_BD_TYPE_RX_AGG_BD | RX_BD_FLAGS_SOP;
+			RX_BD_TYPE_RX_AGG_BD;
+
+		/* On P7, setting EOP will cause the chip to disable
+		 * Relaxed Ordering (RO) for TPA data.  Disable EOP for
+		 * potentially higher performance with RO.
+		 */
+		if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
+			type |= RX_BD_FLAGS_AGG_EOP;
 
 		bnxt_init_rxbd_pages(ring, type);
 	}
drivers/net/ethernet/broadcom/bnxt/bnxt.h +1 -0
index c2122d5cda622..1a7ff21f8cdb8 100644
@@ -99,6 +99,7 @@ struct rx_bd {
 	 #define RX_BD_TYPE_48B_BD_SIZE				 (2 << 4)
 	 #define RX_BD_TYPE_64B_BD_SIZE				 (3 << 4)
 	#define RX_BD_FLAGS_SOP					(1 << 6)
+	#define RX_BD_FLAGS_AGG_EOP				(1 << 6)
 	#define RX_BD_FLAGS_EOP					(1 << 7)
 	#define RX_BD_FLAGS_BUFFERS				(3 << 8)
 	 #define RX_BD_FLAGS_1_BUFFER_PACKET			 (0 << 8)
Signature · 1 line
2.53.0
author maintainer
#328 lore raw

PATCH 328/389 bnxt_en: Disable EOP for TPA on all chips to prevent data corruption

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Michael Chan <[email protected]>

[ Upstream commit c3faf548a00f4c17100cc9204746975fa46a73b9 ]

EOP (End of frame padding) on the AGG ring may cause overlapping of zero padding at the end of one segment with the next segment's data. If Relaxed Ordering (RO) is enabled, the zero padding may overwrite valid data in the next segment and corrupt the data. Older chips (P5 and older) do not automatically disable RO when EOP is enabled. On some ARM systems, data corruption was reported on 57508 (P5) chips with RO enabled.

Always disable EOP on all chips on the AGG rings when TPA is enabled to fix the data corruption.

Fixes bfcd8d791ec1 ("bnxt_en: Add fast path logic for TPA on 57500 chips.")
---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/net/ethernet/broadcom/bnxt/bnxt.c +7 -4
index 07fe6e55f28a6..f36b2bae37999 100644
@@ -3393,11 +3393,14 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
 		type = ((u32)BNXT_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
 			RX_BD_TYPE_RX_AGG_BD;
 
-		/* On P7, setting EOP will cause the chip to disable
-		 * Relaxed Ordering (RO) for TPA data.  Disable EOP for
-		 * potentially higher performance with RO.
+		/* Disable EOP if TPA is enabled to prevent overlapping zero
+		 * padding with the next segment's data.  On P7_PLUS, EOP will
+		 * automatically disable Relaxed Ordering (RO) to prevent
+		 * potential data corruption (and may degrade performance).  On
+		 * older chips, RO will not be automatically disabled and may
+		 * cause corruption.
 		 */
-		if (BNXT_CHIP_P5_AND_MINUS(bp) || !(bp->flags & BNXT_FLAG_TPA))
+		if (!(bp->flags & BNXT_FLAG_TPA))
 			type |= RX_BD_FLAGS_AGG_EOP;
 
 		bnxt_init_rxbd_pages(ring, type);
Signature · 1 line
2.53.0
author maintainer
#329 lore raw

PATCH 329/389 sctp: fix addip_serial increment on ASCONF_ACK allocation failure

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Qing Luo <[email protected]>

[ Upstream commit aa2e13ae8d3cbe2c15ef4f7e971b2de0832794aa ]

In sctp_process_asconf(), when sctp_make_asconf_ack() fails to allocate the ASCONF_ACK chunk due to memory pressure, the code jumps to the done label where asoc->peer.addip_serial is unconditionally incremented.

This leaves the peer's ASCONF (serial N) unacknowledged while the local endpoint now expects serial N+1. When the peer retransmits serial N, it falls into the serial < addip_serial + 1 branch ,
which attempts to look up a cached ACK for serial N. No cached ACK exists since the allocation failed, so the retransmission is silently discarded. The peer eventually times out and ABORTs the association.

Move the addip_serial increment inside the if (asconf_ack) block so that the serial number is only advanced when the ASCONF_ACK is successfully created and cached. This way, on allocation failure, the serial number is unchanged and the peer's retransmitted ASCONF will be correctly re-processed.

---
 net/sctp/sm_make_chunk.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
net/sctp/sm_make_chunk.c +1 -2
index 651fd41996ae1..06309c1869da0 100644
@@ -3316,12 +3316,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
 			goto done;
 	}
 done:
-	asoc->peer.addip_serial++;
-
 	/* If we are sending a new ASCONF_ACK hold a reference to it in assoc
 	 * after freeing the reference to old asconf ack if any.
 	 */
 	if (asconf_ack) {
+		asoc->peer.addip_serial++;
 		sctp_chunk_hold(asconf_ack);
 		list_add_tail(&asconf_ack->transmitted_list,
 			      &asoc->asconf_ack_list);
Signature · 1 line
2.53.0
author maintainer
#330 lore raw

PATCH 330/389 net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Henry Martin <[email protected]>

[ Upstream commit afa58b7384913c8773d837acdb07b035690ec5d2 ]

ncsi_send_cmd_nl() takes the number of bytes to copy from the attacker-controlled ncsi_pkt_hdr.length field of the in-band packet header, while the source buffer is the NCSI_ATTR_DATA netlink attribute whose readable size is nla_len() - sizeof(ncsi_pkt_hdr). The two length sources are never cross-checked: only nla_len() >= sizeof(struct ncsi_pkt_hdr) is enforced.

With hdr->length set larger than the attribute payload (up to 65535 against at most 2032 readable bytes), ncsi_cmd_handler_oem() copies past the end of the netlink attribute buffer with unsafe_memcpy(), leaking up to ~64KB of kernel heap memory into the transmitted NCSI command packet. The destination skb is sized by the declared payload, so the write side does not overflow - this is a pure OOB read / information leak, reachable with CAP_NET_ADMIN on systems with a registered NCSI device (e.g. OpenBMC on Aspeed BMC SoCs, where NET_NCSI=y is standard).

Reject commands whose declared payload extends past the end of the data attribute.

The issue was found by the autokbug dynamic kernel fuzzer at Tencent Yunding Lab.

Fixes 9771b8ccdfa6 ("net/ncsi: Extend NC-SI Netlink interface to allow user space to send NC-SI command")
---
 net/ncsi/ncsi-netlink.c | 4 ++++
 1 file changed, 4 insertions(+)
net/ncsi/ncsi-netlink.c +4 -0
index db350b8f5d88b..82b22368a540a 100644
@@ -461,6 +461,10 @@ static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info)
 	nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN;
 	nca.info = info;
 	nca.payload = ntohs(hdr->length);
+	if (nca.payload > len - sizeof(*hdr)) {
+		ret = -EINVAL;
+		goto out_netlink;
+	}
 	nca.data = data + sizeof(*hdr);
 
 	ret = ncsi_xmit_cmd(&nca);
Signature · 1 line
2.53.0
author maintainer
#331 lore raw

PATCH 331/389 net: marvell: prestera: try to load previous fw version

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Vadym Kochan <[email protected]>

[ Upstream commit 47f26018a414ff640527be4ca814168e0b71eaf3 ]

Lets try to load previous fw version in case the latest one is missing on existing system.

Stable-dep-of: 8ae344eb540a ("net: prestera: validate firmware header length")

---
 .../ethernet/marvell/prestera/prestera_pci.c  | 83 ++++++++++++++-----
 1 file changed, 61 insertions(+), 22 deletions(-)
drivers/net/ethernet/marvell/prestera/prestera_pci.c +61 -22
index be5677623455c..39cd3d5010147 100644
@@ -16,6 +16,9 @@
 #define PRESTERA_SUPP_FW_MAJ_VER	2
 #define PRESTERA_SUPP_FW_MIN_VER	0
 
+#define PRESTERA_PREV_FW_MAJ_VER	2
+#define PRESTERA_PREV_FW_MIN_VER	0
+
 #define PRESTERA_FW_PATH_FMT	"mrvl/prestera/mvsw_prestera_fw-v%u.%u.img"
 
 #define PRESTERA_FW_HDR_MAGIC		0x351D9D06
@@ -166,6 +169,8 @@ struct prestera_fw_evtq {
 };
 
 struct prestera_fw {
+	struct prestera_fw_rev rev_supp;
+	const struct firmware *bin;
 	struct workqueue_struct *wq;
 	struct prestera_device dev;
 	u8 __iomem *ldr_regs;
@@ -576,25 +581,24 @@ static void prestera_fw_rev_parse(const struct prestera_fw_header *hdr,
 static int prestera_fw_rev_check(struct prestera_fw *fw)
 {
 	struct prestera_fw_rev *rev = &fw->dev.fw_rev;
-	u16 maj_supp = PRESTERA_SUPP_FW_MAJ_VER;
-	u16 min_supp = PRESTERA_SUPP_FW_MIN_VER;
 
-	if (rev->maj == maj_supp && rev->min >= min_supp)
+	if (rev->maj == fw->rev_supp.maj && rev->min >= fw->rev_supp.min)
 		return 0;
 
 	dev_err(fw->dev.dev, "Driver supports FW version only '%u.%u.x'",
-		PRESTERA_SUPP_FW_MAJ_VER, PRESTERA_SUPP_FW_MIN_VER);
+		fw->rev_supp.maj, fw->rev_supp.min);
 
 	return -EINVAL;
 }
 
-static int prestera_fw_hdr_parse(struct prestera_fw *fw,
-				 const struct firmware *img)
+static int prestera_fw_hdr_parse(struct prestera_fw *fw)
 {
-	struct prestera_fw_header *hdr = (struct prestera_fw_header *)img->data;
 	struct prestera_fw_rev *rev = &fw->dev.fw_rev;
+	struct prestera_fw_header *hdr;
 	u32 magic;
 
+	hdr = (struct prestera_fw_header *)fw->bin->data;
+
 	magic = be32_to_cpu(hdr->magic_number);
 	if (magic != PRESTERA_FW_HDR_MAGIC) {
 		dev_err(fw->dev.dev, "FW img hdr magic is invalid");
@@ -609,11 +613,52 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw,
 	return prestera_fw_rev_check(fw);
 }
 
+static int prestera_fw_get(struct prestera_fw *fw)
+{
+	int ver_maj = PRESTERA_SUPP_FW_MAJ_VER;
+	int ver_min = PRESTERA_SUPP_FW_MIN_VER;
+	char fw_path[128];
+	int err;
+
+pick_fw_ver:
+	snprintf(fw_path, sizeof(fw_path), PRESTERA_FW_PATH_FMT,
+		 ver_maj, ver_min);
+
+	err = request_firmware_direct(&fw->bin, fw_path, fw->dev.dev);
+	if (err) {
+		if (ver_maj == PRESTERA_SUPP_FW_MAJ_VER) {
+			ver_maj = PRESTERA_PREV_FW_MAJ_VER;
+			ver_min = PRESTERA_PREV_FW_MIN_VER;
+
+			dev_warn(fw->dev.dev,
+				 "missing latest %s firmware, fall-back to previous %u.%u version\n",
+				 fw_path, ver_maj, ver_min);
+
+			goto pick_fw_ver;
+		} else {
+			dev_err(fw->dev.dev, "failed to request previous firmware: %s\n",
+				fw_path);
+			return err;
+		}
+	}
+
+	dev_info(fw->dev.dev, "Loading %s ...", fw_path);
+
+	fw->rev_supp.maj = ver_maj;
+	fw->rev_supp.min = ver_min;
+	fw->rev_supp.sub = 0;
+
+	return 0;
+}
+
+static void prestera_fw_put(struct prestera_fw *fw)
+{
+	release_firmware(fw->bin);
+}
+
 static int prestera_fw_load(struct prestera_fw *fw)
 {
 	size_t hlen = sizeof(struct prestera_fw_header);
-	const struct firmware *f;
-	char fw_path[128];
 	int err;
 
 	err = prestera_ldr_wait_reg32(fw, PRESTERA_LDR_READY_REG,
@@ -632,30 +677,24 @@ static int prestera_fw_load(struct prestera_fw *fw)
 
 	fw->ldr_wr_idx = 0;
 
-	snprintf(fw_path, sizeof(fw_path), PRESTERA_FW_PATH_FMT,
-		 PRESTERA_SUPP_FW_MAJ_VER, PRESTERA_SUPP_FW_MIN_VER);
-
-	err = request_firmware_direct(&f, fw_path, fw->dev.dev);
-	if (err) {
-		dev_err(fw->dev.dev, "failed to request firmware file\n");
+	err = prestera_fw_get(fw);
+	if (err)
 		return err;
-	}
 
-	err = prestera_fw_hdr_parse(fw, f);
+	err = prestera_fw_hdr_parse(fw);
 	if (err) {
 		dev_err(fw->dev.dev, "FW image header is invalid\n");
 		goto out_release;
 	}
 
-	prestera_ldr_write(fw, PRESTERA_LDR_IMG_SIZE_REG, f->size - hlen);
+	prestera_ldr_write(fw, PRESTERA_LDR_IMG_SIZE_REG, fw->bin->size - hlen);
 	prestera_ldr_write(fw, PRESTERA_LDR_CTL_REG, PRESTERA_LDR_CTL_DL_START);
 
-	dev_info(fw->dev.dev, "Loading %s ...", fw_path);
-
-	err = prestera_ldr_fw_send(fw, f->data + hlen, f->size - hlen);
+	err = prestera_ldr_fw_send(fw, fw->bin->data + hlen,
+				   fw->bin->size - hlen);
 
 out_release:
-	release_firmware(f);
+	prestera_fw_put(fw);
 	return err;
 }
 
Signature · 1 line
2.53.0
author maintainer
#332 lore raw

PATCH 332/389 net: prestera: validate firmware header length

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pengpeng Hou <[email protected]>

[ Upstream commit 8ae344eb540af3f457179b52bc6061416752485c ]

prestera_fw_hdr_parse() reads the firmware header before checking that the firmware image contains that header.

Reject images shorter than struct prestera_fw_header before decoding the magic and version fields.

Fixes 4c2703dfd7fabb ("net: marvell: prestera: Add PCI interface support")
---
 drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/marvell/prestera/prestera_pci.c +3 -0
index 39cd3d5010147..bdc57f4245930 100644
@@ -597,6 +597,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)
 	struct prestera_fw_header *hdr;
 	u32 magic;
 
+	if (fw->bin->size < sizeof(*hdr))
+		return -EINVAL;
+
 	hdr = (struct prestera_fw_header *)fw->bin->data;
 
 	magic = be32_to_cpu(hdr->magic_number);
Signature · 1 line
2.53.0
author maintainer
#333 lore raw

PATCH 333/389 net: remove WARN_ON_ONCE() from sk_mc_loop()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit b8a39a09ae4eaae04309e1e38ed6a1101d967496 ]

sk_mc_loop() can be called for sockets that are neither AF_INET nor AF_INET6 (e.g. AF_PACKET sockets when sending packets via raw/packet socket over virtual devices such as VRF or ipvlan).

In such cases, sk_family is not AF_INET/AF_INET6 and sk_mc_loop() falls through the switch statement and triggers WARN_ON_ONCE(1).

Non-INET sockets do not support IP_MULTICAST_LOOP or IPV6_MULTICAST_LOOP options, so loopback should default to true without generating a warning.

Fixes f60e5990d9c1 ("ipv6: protect skb->sk accesses from recursive dereference inside the stack")
Reported-by [email protected]
---
 net/core/sock.c | 1 -
 1 file changed, 1 deletion(-)
net/core/sock.c +0 -1
index 963ea323362ad..b51a154ec5913 100644
@@ -699,7 +699,6 @@ bool sk_mc_loop(struct sock *sk)
 		return inet6_sk(sk)->mc_loop;
 #endif
 	}
-	WARN_ON_ONCE(1);
 	return true;
 }
 EXPORT_SYMBOL(sk_mc_loop);
Signature · 1 line
2.53.0
author maintainer
#334 lore raw

PATCH 334/389 net: qrtr: ns: Raise lookup limit to 128

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Łukasz Patron <[email protected]>

[ Upstream commit 7fc1c937b6b37c77df4ba374c37435ab06a2e945 ]

Current limit of 64 is not enough for Sony Xperia 10 VII (SM6475).

After merging v6.6.142 into a downstream AOSP device, it's stuck on boot animation and following log spam can be observed in dmesg:

E qrtr : ctrl_cmd_new_lookup(): QRTR client node exceeds max lookup limit!
E qrtr : qrtr_ns_worker(): failed while handling packet from 1:16600

No idea why it needs more than 64 client lookups, but it appears to work fine with 128 as it did when there were no limits.

I don't really have a good way to investigate what it needs all these lookups for as most of the userspace is closed source.

Fixes 5640227d9a21 ("net: qrtr: ns: Limit the maximum number of lookups")
---
 net/qrtr/ns.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/qrtr/ns.c +1 -1
index 3ebb5d39e153f..4246d21da5d14 100644
@@ -77,7 +77,7 @@ struct qrtr_node {
  */
 #define QRTR_NS_MAX_NODES   512
 #define QRTR_NS_MAX_SERVERS 256
-#define QRTR_NS_MAX_LOOKUPS 64
+#define QRTR_NS_MAX_LOOKUPS 128
 
 static u16 node_count;
 
Signature · 1 line
2.53.0
author maintainer
#335 lore raw

PATCH 335/389 ata: pata_sl82c105: fix bridge revision use-after-free

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hongyan Xu <[email protected]>

[ Upstream commit 7700a31039cdc6715cb6cce7e7a664ee4e945f67 ]

pci_get_slot() returns a referenced PCI device. Commit 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision") replaced a configuration-space read with direct access to the cached revision field, but left that access after pci_dev_put(). The bridge may therefore be freed before its revision is read.

Read the revision before dropping the reference.

Fixes 44c10138fd4b ("PCI: Change all drivers to use pci_device->revision")
---
 drivers/ata/pata_sl82c105.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/ata/pata_sl82c105.c +3 -1
index ac7ddd87f188d..78275b2479df2 100644
@@ -265,6 +265,7 @@ static struct ata_port_operations sl82c105_port_ops = {
 static int sl82c105_bridge_revision(struct pci_dev *pdev)
 {
 	struct pci_dev *bridge;
+	u8 revision;
 
 	/*
 	 * The bridge should be part of the same device, but function 0.
@@ -286,8 +287,9 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
 	/*
 	 * We need to find function 0's revision, not function 1
 	 */
+	revision = bridge->revision;
 	pci_dev_put(bridge);
-	return bridge->revision;
+	return revision;
 }
 
 static void sl82c105_fixup(struct pci_dev *pdev)
Signature · 1 line
2.53.0
author maintainer
#336 lore raw

PATCH 336/389 sctp: clear control chunk transport if it is being removed

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xin Long <[email protected]>

[ Upstream commit c9158ceaf27780ef64534ad72f44ffde3f8ccc49 ]

sctp_make_heartbeat_ack() caches the destination transport in chunk->transport without taking a reference. When src_out_of_asoc_ok is enabled, the HEARTBEAT ACK may remain queued on control_chunk_list instead of being transmitted immediately.

If the peer transport is removed while the chunk is still queued, sctp_assoc_rm_peer() drops the transport and schedules it for RCU freeing, but only clears cached transport pointers in out_chunk_list. The queued control chunk therefore retains a dangling transport pointer.

Once an ASCONF_ACK clears the suppression and the queued control chunk is transmitted, SCTP dereferences the stale transport pointer, leading to a use-after-free.

Fix this by also clearing chunk->transport for queued control chunks in control_chunk_list when removing the transport.

---
 net/sctp/associola.c | 4 ++++
 1 file changed, 4 insertions(+)
net/sctp/associola.c +4 -0
index 86d86ec9d90aa..122f0a948430f 100644
@@ -572,6 +572,10 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
 		if (ch->transport == peer)
 			ch->transport = NULL;
 
+	list_for_each_entry(ch, &asoc->outqueue.control_chunk_list, list)
+		if (ch->transport == peer)
+			ch->transport = NULL;
+
 	asoc->peer.transport_count--;
 
 	sctp_ulpevent_notify_peer_addr_change(peer, SCTP_ADDR_REMOVED, 0);
Signature · 1 line
2.53.0
author maintainer
#337 lore raw

PATCH 337/389 sctp: remove the unessessary hold for idev in sctp_v6_err

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xin Long <[email protected]>

[ Upstream commit 237a6a2e318c1ed7429e72f2640054bdda91646f ]

Same as in tcp_v6_err() and __udp6_lib_err(), there's no need to hold idev in sctp_v6_err(), so just call __in6_dev_get() instead.

Stable-dep-of: af0e5cdd031f ("tls: don't abort the connection on signal-interrupted sends")

---
 net/sctp/ipv6.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)
net/sctp/ipv6.c +2 -10
index a9cfe4d62df83..984ec00ad6384 100644
@@ -125,7 +125,6 @@ static struct notifier_block sctp_inet6addr_notifier = {
 static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 			u8 type, u8 code, int offset, __be32 info)
 {
-	struct inet6_dev *idev;
 	struct sock *sk;
 	struct sctp_association *asoc;
 	struct sctp_transport *transport;
@@ -134,8 +133,6 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	int err, ret = 0;
 	struct net *net = dev_net(skb->dev);
 
-	idev = in6_dev_get(skb->dev);
-
 	/* Fix up skb to look at the embedded net header. */
 	saveip	 = skb->network_header;
 	savesctp = skb->transport_header;
@@ -146,9 +143,8 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	skb->network_header   = saveip;
 	skb->transport_header = savesctp;
 	if (!sk) {
-		__ICMP6_INC_STATS(net, idev, ICMP6_MIB_INERRORS);
-		ret = -ENOENT;
-		goto out;
+		__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
+		return -ENOENT;
 	}
 
 	/* Warning:  The sock lock is held.  Remember to call
@@ -184,10 +180,6 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
 out_unlock:
 	sctp_err_finish(sk, transport);
-out:
-	if (likely(idev != NULL))
-		in6_dev_put(idev);
-
 	return ret;
 }
 
Signature · 1 line
2.53.0
author maintainer
#338 lore raw

PATCH 338/389 sctp: extract sctp_v6_err_handle function from sctp_v6_err

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xin Long <[email protected]>

[ Upstream commit f6549bd37b927655c6fecad88428a731cd8a4a34 ]

This patch is to extract sctp_v6_err_handle() from sctp_v6_err() to only handle the icmp err after the sock lookup, and it also makes the code clearer.

sctp_v6_err_handle() will be used in sctp over udp's err handling in the following patch.

Stable-dep-of: af0e5cdd031f ("tls: don't abort the connection on signal-interrupted sends")

---
 net/sctp/ipv6.c | 76 ++++++++++++++++++++++++++-----------------------
 1 file changed, 40 insertions(+), 36 deletions(-)
net/sctp/ipv6.c +40 -36
index 984ec00ad6384..48bd3b52d56d0 100644
@@ -121,50 +121,28 @@ static struct notifier_block sctp_inet6addr_notifier = {
 	.notifier_call = sctp_inet6addr_event,
 };
 
-/* ICMP error handler. */
-static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-			u8 type, u8 code, int offset, __be32 info)
+static void sctp_v6_err_handle(struct sctp_transport *t, struct sk_buff *skb,
+			       __u8 type, __u8 code, __u32 info)
 {
-	struct sock *sk;
-	struct sctp_association *asoc;
-	struct sctp_transport *transport;
+	struct sctp_association *asoc = t->asoc;
+	struct sock *sk = asoc->base.sk;
 	struct ipv6_pinfo *np;
-	__u16 saveip, savesctp;
-	int err, ret = 0;
-	struct net *net = dev_net(skb->dev);
-
-	/* Fix up skb to look at the embedded net header. */
-	saveip	 = skb->network_header;
-	savesctp = skb->transport_header;
-	skb_reset_network_header(skb);
-	skb_set_transport_header(skb, offset);
-	sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
-	/* Put back, the original pointers. */
-	skb->network_header   = saveip;
-	skb->transport_header = savesctp;
-	if (!sk) {
-		__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
-		return -ENOENT;
-	}
-
-	/* Warning:  The sock lock is held.  Remember to call
-	 * sctp_err_finish!
-	 */
+	int err = 0;
 
 	switch (type) {
 	case ICMPV6_PKT_TOOBIG:
 		if (ip6_sk_accept_pmtu(sk))
-			sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
-		goto out_unlock;
+			sctp_icmp_frag_needed(sk, asoc, t, info);
+		return;
 	case ICMPV6_PARAMPROB:
 		if (ICMPV6_UNK_NEXTHDR == code) {
-			sctp_icmp_proto_unreachable(sk, asoc, transport);
-			goto out_unlock;
+			sctp_icmp_proto_unreachable(sk, asoc, t);
+			return;
 		}
 		break;
 	case NDISC_REDIRECT:
-		sctp_icmp_redirect(sk, transport, skb);
-		goto out_unlock;
+		sctp_icmp_redirect(sk, t, skb);
+		return;
 	default:
 		break;
 	}
@@ -174,13 +152,39 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	if (!sock_owned_by_user(sk) && np->recverr) {
 		sk->sk_err = err;
 		sk->sk_error_report(sk);
-	} else {  /* Only an error on timeout */
+	} else {
 		sk->sk_err_soft = err;
 	}
+}
+
+/* ICMP error handler. */
+static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+		       u8 type, u8 code, int offset, __be32 info)
+{
+	struct net *net = dev_net(skb->dev);
+	struct sctp_transport *transport;
+	struct sctp_association *asoc;
+	__u16 saveip, savesctp;
+	struct sock *sk;
+
+	/* Fix up skb to look at the embedded net header. */
+	saveip	 = skb->network_header;
+	savesctp = skb->transport_header;
+	skb_reset_network_header(skb);
+	skb_set_transport_header(skb, offset);
+	sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
+	/* Put back, the original pointers. */
+	skb->network_header   = saveip;
+	skb->transport_header = savesctp;
+	if (!sk) {
+		__ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
+		return -ENOENT;
+	}
 
-out_unlock:
+	sctp_v6_err_handle(transport, skb, type, code, ntohl(info));
 	sctp_err_finish(sk, transport);
-	return ret;
+
+	return 0;
 }
 
 static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
Signature · 1 line
2.53.0
author maintainer
#339 lore raw

PATCH 339/389 sctp: extract sctp_v4_err_handle function from sctp_v4_err

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xin Long <[email protected]>

[ Upstream commit d83060759a652ccb64d7486fe38c8347b4a64048 ]

This patch is to extract sctp_v4_err_handle() from sctp_v4_err() to only handle the icmp err after the sock lookup, and it also makes the code clearer.

sctp_v4_err_handle() will be used in sctp over udp's err handling in the following patch.

Stable-dep-of: af0e5cdd031f ("tls: don't abort the connection on signal-interrupted sends")

---
 net/sctp/input.c | 106 ++++++++++++++++++++++-------------------------
 1 file changed, 49 insertions(+), 57 deletions(-)
net/sctp/input.c +49 -57
index 3c7761199f200..731d12e8038c5 100644
@@ -556,6 +556,49 @@ void sctp_err_finish(struct sock *sk, struct sctp_transport *t)
 	sctp_transport_put(t);
 }
 
+static void sctp_v4_err_handle(struct sctp_transport *t, struct sk_buff *skb,
+			       __u8 type, __u8 code, __u32 info)
+{
+	struct sctp_association *asoc = t->asoc;
+	struct sock *sk = asoc->base.sk;
+	int err = 0;
+
+	switch (type) {
+	case ICMP_PARAMETERPROB:
+		err = EPROTO;
+		break;
+	case ICMP_DEST_UNREACH:
+		if (code > NR_ICMP_UNREACH)
+			return;
+		if (code == ICMP_FRAG_NEEDED) {
+			sctp_icmp_frag_needed(sk, asoc, t, SCTP_TRUNC4(info));
+			return;
+		}
+		if (code == ICMP_PROT_UNREACH) {
+			sctp_icmp_proto_unreachable(sk, asoc, t);
+			return;
+		}
+		err = icmp_err_convert[code].errno;
+		break;
+	case ICMP_TIME_EXCEEDED:
+		if (code == ICMP_EXC_FRAGTIME)
+			return;
+
+		err = EHOSTUNREACH;
+		break;
+	case ICMP_REDIRECT:
+		sctp_icmp_redirect(sk, t, skb);
+	default:
+		return;
+	}
+	if (!sock_owned_by_user(sk) && inet_sk(sk)->recverr) {
+		sk->sk_err = err;
+		sk->sk_error_report(sk);
+	} else {  /* Only an error on timeout */
+		sk->sk_err_soft = err;
+	}
+}
+
 /*
  * This routine is called by the ICMP module when it gets some
  * sort of error condition.  If err < 0 then the socket should
@@ -574,22 +617,19 @@ void sctp_err_finish(struct sock *sk, struct sctp_transport *t)
 int sctp_v4_err(struct sk_buff *skb, __u32 info)
 {
 	const struct iphdr *iph = (const struct iphdr *)skb->data;
-	const int ihlen = iph->ihl * 4;
 	const int type = icmp_hdr(skb)->type;
 	const int code = icmp_hdr(skb)->code;
-	struct sock *sk;
-	struct sctp_association *asoc = NULL;
+	struct net *net = dev_net(skb->dev);
 	struct sctp_transport *transport;
-	struct inet_sock *inet;
+	struct sctp_association *asoc;
 	__u16 saveip, savesctp;
-	int err;
-	struct net *net = dev_net(skb->dev);
+	struct sock *sk;
 
 	/* Fix up skb to look at the embedded net header. */
 	saveip = skb->network_header;
 	savesctp = skb->transport_header;
 	skb_reset_network_header(skb);
-	skb_set_transport_header(skb, ihlen);
+	skb_set_transport_header(skb, iph->ihl * 4);
 	sk = sctp_err_lookup(net, AF_INET, skb, sctp_hdr(skb), &asoc, &transport);
 	/* Put back, the original values. */
 	skb->network_header = saveip;
@@ -598,58 +638,10 @@ int sctp_v4_err(struct sk_buff *skb, __u32 info)
 		__ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
 		return -ENOENT;
 	}
-	/* Warning:  The sock lock is held.  Remember to call
-	 * sctp_err_finish!
-	 */
-
-	switch (type) {
-	case ICMP_PARAMETERPROB:
-		err = EPROTO;
-		break;
-	case ICMP_DEST_UNREACH:
-		if (code > NR_ICMP_UNREACH)
-			goto out_unlock;
-
-		/* PMTU discovery (RFC1191) */
-		if (ICMP_FRAG_NEEDED == code) {
-			sctp_icmp_frag_needed(sk, asoc, transport,
-					      SCTP_TRUNC4(info));
-			goto out_unlock;
-		} else {
-			if (ICMP_PROT_UNREACH == code) {
-				sctp_icmp_proto_unreachable(sk, asoc,
-							    transport);
-				goto out_unlock;
-			}
-		}
-		err = icmp_err_convert[code].errno;
-		break;
-	case ICMP_TIME_EXCEEDED:
-		/* Ignore any time exceeded errors due to fragment reassembly
-		 * timeouts.
-		 */
-		if (ICMP_EXC_FRAGTIME == code)
-			goto out_unlock;
-
-		err = EHOSTUNREACH;
-		break;
-	case ICMP_REDIRECT:
-		sctp_icmp_redirect(sk, transport, skb);
-		/* Fall through to out_unlock. */
-	default:
-		goto out_unlock;
-	}
-
-	inet = inet_sk(sk);
-	if (!sock_owned_by_user(sk) && inet->recverr) {
-		sk->sk_err = err;
-		sk->sk_error_report(sk);
-	} else {  /* Only an error on timeout */
-		sk->sk_err_soft = err;
-	}
 
-out_unlock:
+	sctp_v4_err_handle(transport, skb, type, code, info);
 	sctp_err_finish(sk, transport);
+
 	return 0;
 }
 
Signature · 1 line
2.53.0
author maintainer
#340 lore raw

PATCH 340/389 tls: dont abort the connection on signal-interrupted sends

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Maximilian Immanuel Brandtner <[email protected]>

[ Upstream commit af0e5cdd031f4f4a8f6d4160bfbda4f36872b0ed ]

When a signal interrupts a blocking send, tls_tx_records() treats the resulting -ERESTARTSYS as a transmission failure and marks the socket errored via tls_err_abort() with the raw error code. Later syscalls return the kernel-internal errno 512 (ERESTARTSYS) to userspace, as the signal it stems from is no longer pending during syscall exit and thus never translated.

An interrupted send is not a connection error: the partially sent record stays queued and is resent later. Interrupt error codes are therefore excluded from the abort in the same way as -EAGAIN.

---
 net/tls/tls_sw.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/tls/tls_sw.c +1 -1
index 29650fa546664..c2344a46dddda 100644
@@ -430,7 +430,7 @@ int tls_tx_records(struct sock *sk, int flags)
 	}
 
 tx_err:
-	if (rc < 0 && rc != -EAGAIN)
+	if (rc < 0 && rc != -EAGAIN && rc != -EINTR && rc != -ERESTARTSYS)
 		tls_err_abort(sk, rc);
 
 	return rc;
Signature · 1 line
2.53.0
author maintainer
#341 lore raw

PATCH 341/389 spi: spi-fsl-dspi: Avoid setup_accel logic for DMA transfers

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Larisa Grigore <[email protected]>

[ Upstream commit cac7e5054115fcc41b1cb050af8e8971f7c9b22b ]

Repacking multiple smaller words into larger ones to make use of the full FIFO doesn't save anything in DMA mode, so don't bother doing it.

---
 drivers/spi/spi-fsl-dspi.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
drivers/spi/spi-fsl-dspi.c +7 -6
index 580fdcbcd9b6c..2bf8cc137d31e 100644
@@ -751,8 +751,12 @@ static void dspi_setup_accel(struct fsl_dspi *dspi)
 	struct spi_transfer *xfer = dspi->cur_transfer;
 	bool odd = !!(dspi->len & 1);
 
-	/* No accel for frames not multiple of 8 bits at the moment */
-	if (xfer->bits_per_word % 8)
+	/*
+	 * No accel for DMA transfers or frames not multiples of 8 bits at the
+	 * moment.
+	 */
+	if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE ||
+	    xfer->bits_per_word % 8)
 		goto no_accel;
 
 	if (!odd && dspi->len <= dspi->devtype_data->fifo_size * 2) {
@@ -761,10 +765,7 @@ static void dspi_setup_accel(struct fsl_dspi *dspi)
 		dspi->oper_bits_per_word = 8;
 	} else {
 		/* Start off with maximum supported by hardware */
-		if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
-			dspi->oper_bits_per_word = 32;
-		else
-			dspi->oper_bits_per_word = 16;
+		dspi->oper_bits_per_word = 32;
 
 		/*
 		 * And go down only if the buffer can't be sent with
Signature · 1 line
2.53.0
author maintainer
#342 lore raw

PATCH 342/389 ALSA: usb-audio: Evaluate packsize caps at the right place

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Takashi Iwai <[email protected]>

[ Upstream commit 52521e8398839105ef8eb22b3f0993f9b0d11a57 ]

We introduced the upper bound checks of the packet sizes by the ep->maxframesize for avoiding the URB submission errors. However, the check was applied at an incorrect place in the function snd_usb_endpoint_set_params() where ep->maxframesize isn't defined yet; the value is defined at a bit later position. So this ended up with a failure at the first run while the second run works.

For fixing it, move the check at the correct place, right after the calculation of ep->maxframesize in the same function.

Fixes 7fe8dec3f628 ("ALSA: usb-audio: Cap the packet size pre-calculations")

[王YP: Move the check to snd_usb_pcm_prepare(). For linux-5.10.y,

       ep->maxframesize is calculated in `snd_usb_pcm_prepare()`.]
---
 sound/usb/endpoint.c | 3 ---
 sound/usb/pcm.c      | 7 +++++++
 2 files changed, 7 insertions(+), 3 deletions(-)
sound/usb/endpoint.c +0 -3
index 3ac4251f9cde6..730744104df61 100644
@@ -1101,9 +1101,6 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
 		return -EINVAL;
 	}
 
-	ep->packsize[0] = min(ep->packsize[0], ep->maxframesize);
-	ep->packsize[1] = min(ep->packsize[1], ep->maxframesize);
-
 	/* calculate the frequency in 16.16 format */
 	ep->freqm = ep->freqn;
 	ep->freqshift = INT_MIN;
sound/usb/pcm.c +7 -0
index f4494d0549172..802ed1dbd23b0 100644
@@ -953,6 +953,13 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
 	subs->data_endpoint->curframesize =
 		bytes_to_frames(runtime, subs->data_endpoint->curpacksize);
 
+	subs->data_endpoint->packsize[0] = min(
+		subs->data_endpoint->packsize[0],
+		subs->data_endpoint->maxframesize);
+	subs->data_endpoint->packsize[1] = min(
+		subs->data_endpoint->packsize[1],
+		subs->data_endpoint->maxframesize);
+
 	/* reset the pointer */
 	subs->hwptr_done = 0;
 	subs->transfer_done = 0;
Signature · 1 line
2.53.0
author maintainer
#343 lore raw

PATCH 343/389 Input: evdev - sanitize event type index when fetching event masks

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dmitry Torokhov <[email protected]>

commit 3abd29c61d2ef37c4102cf755b18be53bb9dbea6 upstream.

The user-supplied event type index passed to EVIOCGMASK / EVIOCSMASK ioctls is used to index the static counts array in evdev_get_mask_cnt() and client evmasks array in evdev_get_mask().

While the event type is architecturally bounded by EV_CNT, speculative execution may mispredict bounds checks and perform out-of-bounds loads.

Sanitize the event type index in evdev_get_mask_cnt() branchlessly using array_index_mask_nospec(). This clamps the index to 0 for safe array access and forces the returned count to 0 speculatively when the index is out of bounds.

We do not need additional array_index_nospec() calls in evdev_get_mask() because evdev_get_mask_cnt() speculatively forces the count (and resulting xfer_size) to 0 for out-of-bounds types, preventing any speculative memory access to client evmasks array.

---
 drivers/input/evdev.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/input/evdev.c +4 -1
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/input/mt.h>
 #include <linux/major.h>
+#include <linux/nospec.h>
 #include <linux/device.h>
 #include <linux/cdev.h>
 #include "input-compat.h"
@@ -67,8 +68,10 @@ static size_t evdev_get_mask_cnt(unsigne
 		[EV_SND]	= SND_CNT,
 		[EV_FF]		= FF_CNT,
 	};
+	unsigned long mask = array_index_mask_nospec(type, EV_CNT);
 
-	return (type < EV_CNT) ? counts[type] : 0;
+	/* Returns 0 for out-of-bounds types, including speculatively */
+	return counts[type & mask] & mask;
 }
 
 /* requires the buffer lock to be held */
author maintainer
#344 lore raw

PATCH 344/389 ALSA: usb-audio: fix OOB write on Type II inbound URBs

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Baul Lee <[email protected]>

commit 69ee44e1a23be62318189dc4b37fa4ad94053269 upstream.

data_ep_set_params() sizes each URB transfer buffer before it adds the Format Type II transfer delimiter:

	u->packets = urb_packs;
	u->buffer_size = maxsize * u->packets;

	if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
		u->packets++; /* for transfer delimiter */
	u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);

buffer_size is computed from the pre-increment packet count and never recomputed, so for a Type II endpoint the buffer is one packet short of the packet count the URB is built with.

prepare_inbound_urb() then lays out one iso frame per packet and never consults buffer_size:

	offs = 0;
	for (i = 0; i < urb_ctx->packets; i++) {
		urb->iso_frame_desc[i].offset = offs;
		urb->iso_frame_desc[i].length = ep->curpacksize;
		offs += ep->curpacksize;
	}

	urb->transfer_buffer_length = offs;
	urb->number_of_packets = urb_ctx->packets;

The last descriptor therefore points one packet past the end of the transfer buffer, where the host controller writes device data on every inbound transfer. prepare_silent_urb() and prepare_playback_urb() bound their fill loops by ctx->buffer_size, so only capture is affected.

fmt_type comes from the device's audio streaming descriptors, so any device advertising a Type II capture format hits this once userspace sets hw_params on the stream.

KASAN on 7.2.0-rc5 (arm64) with a dummy_hcd/raw-gadget device, one report per inbound transfer:

  BUG: KASAN: slab-out-of-bounds in dummy_timer
  Write of size 64 at addr ffff0000186171c0 by task cons02/166
   __asan_memcpy
   dummy_timer
   hrtimer_run_softirq
  Allocated by task 166:
   usb_alloc_coherent
   snd_usb_endpoint_set_params
  The buggy address is located 0 bytes to the right of
   allocated 64-byte region [ffff000018617180, ffff0000186171c0)

Compute buffer_size after the delimiter packet has been accounted for, and bound the fill loop by buffer_size, as prepare_silent_urb() already does on the outbound side. This grows every Type II URB allocation by one maxsize packet.

Discovered by XBOW, triaged by Baul Lee <[email protected]>

---
 sound/usb/endpoint.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
sound/usb/endpoint.c +4 -2
@@ -301,13 +301,15 @@ static inline void prepare_inbound_urb(s
 	case SND_USB_ENDPOINT_TYPE_DATA:
 		offs = 0;
 		for (i = 0; i < urb_ctx->packets; i++) {
+			if (offs + ep->curpacksize > urb_ctx->buffer_size)
+				break;
 			urb->iso_frame_desc[i].offset = offs;
 			urb->iso_frame_desc[i].length = ep->curpacksize;
 			offs += ep->curpacksize;
 		}
 
 		urb->transfer_buffer_length = offs;
-		urb->number_of_packets = urb_ctx->packets;
+		urb->number_of_packets = i;
 		break;
 
 	case SND_USB_ENDPOINT_TYPE_SYNC:
@@ -961,10 +963,10 @@ static int data_ep_set_params(struct snd
 		u->index = i;
 		u->ep = ep;
 		u->packets = urb_packs;
-		u->buffer_size = maxsize * u->packets;
 
 		if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
 			u->packets++; /* for transfer delimiter */
+		u->buffer_size = maxsize * u->packets;
 		u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
 		if (!u->urb)
 			goto out_of_memory;
author maintainer
#345 lore raw

PATCH 345/389 usb: atm: cxacru: properly kill rcv_urb on error in cxacru_cm()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aleksandr Nogikh <[email protected]>

commit c2f811314be351d86b6ab41e9297ae80d8da6f86 upstream.

If cxacru_cm() encounters an error while submitting or waiting for snd_urb, it aborts and returns the error without killing the already submitted rcv_urb. This leaves the rcv_urb active.

When this happens during initialization (e.g., in cxacru_atm_start()), the driver may ignore the error and proceed to call cxacru_poll_status(), which invokes cxacru_cm() again. Attempting to submit the still-active rcv_urb triggers a warning in usb_submit_urb():

cxacru 1-1:1.0: send of cm 0x84 failed (-104)
ATM dev 0: cxacru_atm_start: CHIP_ADSL_LINE_START returned -104

------------[ cut here ]------------
URB ffff88812658d200 submitted while active
WARNING: drivers/usb/core/urb.c:379 at usb_submit_urb+0x79/0x18b0
drivers/usb/core/urb.c:379
...
Call Trace:
 <TASK>
 cxacru_cm+0x21a/0xf10 drivers/usb/atm/cxacru.c:631
 cxacru_cm_get_array drivers/usb/atm/cxacru.c:722 [inline]
 cxacru_poll_status+0x178/0x1110 drivers/usb/atm/cxacru.c:828
 cxacru_atm_start+0x185/0x360 drivers/usb/atm/cxacru.c:814
 usbatm_atm_init+0x144/0x3a0 drivers/usb/atm/usbatm.c:927
 usbatm_usb_probe+0x15cb/0x1db0 drivers/usb/atm/usbatm.c:1178
 cxacru_usb_probe+0x17f/0x220 drivers/usb/atm/cxacru.c:1370

...

To fix this, ensure that rcv_urb is properly killed if cxacru_cm() aborts early. We can safely call usb_kill_urb() on rcv_urb in the error path, as it is safe to call even if the URB is not active (e.g., if it failed to submit in the first place, or if it already completed).

Fixes 1b0e61465234 ("[PATCH] USB ATM: driver for the Conexant AccessRunner chipset cxacru")
Cc stable <[email protected]>
Assisted-by Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by [email protected]
---
 drivers/usb/atm/cxacru.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/usb/atm/cxacru.c +2 -0
@@ -700,6 +700,8 @@ static int cxacru_cm(struct cxacru_data
 	ret = offd;
 	usb_dbg(instance->usbatm, "cm %#x\n", cm);
 fail:
+	if (ret < 0)
+		usb_kill_urb(instance->rcv_urb);
 	mutex_unlock(&instance->cm_serialize);
 err:
 	return ret;
author maintainer
#346 lore raw

PATCH 346/389 usb: gadget: f_ncm: Use unsigned int for ndp_index

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sonali Pradhan <[email protected]>

commit 6b1c8a9403a26cb0fed7a648916c74dc236da591 upstream.

The variable ndp_index is declared as a signed integer, but it stores the return value of get_ncm(), which is unsigned.

A malicious host can supply a large offset that overflows the signed ndp_index, making it negative. Because ndp_index is compared against unsigned bounds, this negative value bypasses sanity checks and leads to an out-of-bounds read when calculating the address of the NDP block (ntb_ptr + ndp_index).

Fix this by changing ndp_index to unsigned int to ensure consistent unsigned comparisons throughout the function.

Fixes 370af734dfaf ("usb: gadget: NCM: RX function support multiple NDPs")
Cc stable <[email protected]>
---
 drivers/usb/gadget/function/f_ncm.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/function/f_ncm.c +1 -1
@@ -1183,7 +1183,7 @@ static int ncm_unwrap_ntb(struct gether
 	unsigned char	*ntb_ptr = skb->data;
 	__le16		*tmp;
 	unsigned	index, index2;
-	int		ndp_index;
+	unsigned int	ndp_index;
 	unsigned	dg_len, dg_len2;
 	unsigned	ndp_len;
 	unsigned	block_len;
author maintainer
#347 lore raw

PATCH 347/389 ipvs: add totalconns for dest

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Julian Anastasov <[email protected]>

commit 04d2feaed8d0103c498727191ba04001d5100e67 upstream.

Replace the inactconns dest counter with totalconns, now inactconns can be obtained from totalconns - activeconns. This reduces the atomic inc/dec ops for TCP/SCTP from 6 to 4 if the connection is established and then closed.

---
 include/net/ip_vs.h                   |   17 ++++++++++++-----
 net/netfilter/ipvs/ip_vs_conn.c       |   24 +++++++-----------------
 net/netfilter/ipvs/ip_vs_ctl.c        |   10 +++++-----
 net/netfilter/ipvs/ip_vs_lc.c         |    4 ++--
 net/netfilter/ipvs/ip_vs_proto_sctp.c |    2 --
 net/netfilter/ipvs/ip_vs_proto_tcp.c  |    2 --
 net/netfilter/ipvs/ip_vs_sync.c       |    7 ++-----
 7 files changed, 28 insertions(+), 38 deletions(-)
include/net/ip_vs.h +12 -5
@@ -675,7 +675,7 @@ struct ip_vs_dest {
 
 	/* connection counters and thresholds */
 	atomic_t		activeconns;	/* active connections */
-	atomic_t		inactconns;	/* inactive connections */
+	atomic_t		totalconns;	/* total connections */
 	atomic_t		persistconns;	/* persistent connections */
 	__u32			u_threshold;	/* upper threshold */
 	__u32			l_threshold;	/* lower threshold */
@@ -1704,14 +1704,21 @@ void ip_vs_unregister_hooks(struct netns
 static inline int
 ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
 {
-	/* We think the overhead of processing active connections is 256
+	/* We think the overhead of processing active connections is 257
 	 * times higher than that of inactive connections in average. (This
-	 * 256 times might not be accurate, we will change it later) We
+	 * 257 times might not be accurate, we will change it later) We
 	 * use the following formula to estimate the overhead now:
-	 *		  dest->activeconns*256 + dest->inactconns
+	 *		  dest->activeconns*256 + dest->totalconns
 	 */
 	return (atomic_read(&dest->activeconns) << 8) +
-		atomic_read(&dest->inactconns);
+		atomic_read(&dest->totalconns);
+}
+
+static inline int
+ip_vs_dest_inactconns(const struct ip_vs_dest *dest)
+{
+	return max(atomic_read(&dest->totalconns) -
+		   atomic_read(&dest->activeconns), 0);
 }
 
 #endif	/* _NET_IP_VS_H */
net/netfilter/ipvs/ip_vs_conn.c +7 -17
@@ -570,12 +570,6 @@ static inline void ip_vs_bind_xmit_v6(st
 #endif
 
 
-static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest)
-{
-	return atomic_read(&dest->activeconns)
-		+ atomic_read(&dest->inactconns);
-}
-
 /*
  *	Bind a connection entry with a virtual service destination
  *	Called just after a new connection entry is created.
@@ -633,8 +627,7 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, s
 		 */
 		if (!(flags & IP_VS_CONN_F_INACTIVE))
 			atomic_inc(&dest->activeconns);
-		else
-			atomic_inc(&dest->inactconns);
+		atomic_inc(&dest->totalconns);
 	} else {
 		/* It is a persistent connection/template, so increase
 		   the persistent connection counter */
@@ -642,7 +635,7 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, s
 	}
 
 	if (dest->u_threshold != 0 &&
-	    ip_vs_dest_totalconns(dest) >= dest->u_threshold)
+	    atomic_read(&dest->totalconns) >= dest->u_threshold)
 		dest->flags |= IP_VS_DEST_F_OVERLOAD;
 }
 
@@ -724,13 +717,10 @@ static inline void ip_vs_unbind_dest(str
 
 	/* Update the connection counters */
 	if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
-		/* It is a normal connection, so decrease the inactconns
-		   or activeconns counter */
-		if (cp->flags & IP_VS_CONN_F_INACTIVE) {
-			atomic_dec(&dest->inactconns);
-		} else {
+		/* It is a normal connection, so decrease the counters */
+		if (!(cp->flags & IP_VS_CONN_F_INACTIVE))
 			atomic_dec(&dest->activeconns);
-		}
+		atomic_dec(&dest->totalconns);
 	} else {
 		/* It is a persistent connection/template, so decrease
 		   the persistent connection counter */
@@ -738,10 +728,10 @@ static inline void ip_vs_unbind_dest(str
 	}
 
 	if (dest->l_threshold != 0) {
-		if (ip_vs_dest_totalconns(dest) < dest->l_threshold)
+		if (atomic_read(&dest->totalconns) < dest->l_threshold)
 			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
 	} else if (dest->u_threshold != 0) {
-		if (ip_vs_dest_totalconns(dest) * 4 < dest->u_threshold * 3)
+		if (atomic_read(&dest->totalconns) * 4 < dest->u_threshold * 3)
 			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
 	} else {
 		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
net/netfilter/ipvs/ip_vs_ctl.c +5 -5
@@ -1011,7 +1011,7 @@ ip_vs_new_dest(struct ip_vs_service *svc
 	dest->port = udest->port;
 
 	atomic_set(&dest->activeconns, 0);
-	atomic_set(&dest->inactconns, 0);
+	atomic_set(&dest->totalconns, 0);
 	atomic_set(&dest->persistconns, 0);
 	refcount_set(&dest->refcnt, 1);
 
@@ -2223,7 +2223,7 @@ static int ip_vs_info_seq_show(struct se
 					   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
 					   atomic_read(&dest->weight),
 					   atomic_read(&dest->activeconns),
-					   atomic_read(&dest->inactconns));
+					   ip_vs_dest_inactconns(dest));
 			else
 #endif
 				seq_printf(seq,
@@ -2234,7 +2234,7 @@ static int ip_vs_info_seq_show(struct se
 					   ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
 					   atomic_read(&dest->weight),
 					   atomic_read(&dest->activeconns),
-					   atomic_read(&dest->inactconns));
+					   ip_vs_dest_inactconns(dest));
 
 		}
 	}
@@ -2715,7 +2715,7 @@ __ip_vs_get_dest_entries(struct netns_ip
 			entry.u_threshold = dest->u_threshold;
 			entry.l_threshold = dest->l_threshold;
 			entry.activeconns = atomic_read(&dest->activeconns);
-			entry.inactconns = atomic_read(&dest->inactconns);
+			entry.inactconns = ip_vs_dest_inactconns(dest);
 			entry.persistconns = atomic_read(&dest->persistconns);
 			ip_vs_copy_stats(&kstats, &dest->stats);
 			ip_vs_export_stats_user(&entry.stats, &kstats);
@@ -3319,7 +3319,7 @@ static int ip_vs_genl_fill_dest(struct s
 	    nla_put_u32(skb, IPVS_DEST_ATTR_ACTIVE_CONNS,
 			atomic_read(&dest->activeconns)) ||
 	    nla_put_u32(skb, IPVS_DEST_ATTR_INACT_CONNS,
-			atomic_read(&dest->inactconns)) ||
+			ip_vs_dest_inactconns(dest)) ||
 	    nla_put_u32(skb, IPVS_DEST_ATTR_PERSIST_CONNS,
 			atomic_read(&dest->persistconns)) ||
 	    nla_put_u16(skb, IPVS_DEST_ATTR_ADDR_FAMILY, dest->af))
net/netfilter/ipvs/ip_vs_lc.c +2 -2
@@ -31,7 +31,7 @@ ip_vs_lc_schedule(struct ip_vs_service *
 
 	/*
 	 * Simply select the server with the least number of
-	 *        (activeconns<<5) + inactconns
+	 *        (activeconns*256) + totalconns
 	 * Except whose weight is equal to zero.
 	 * If the weight is equal to zero, it means that the server is
 	 * quiesced, the existing connections to the server still get
@@ -57,7 +57,7 @@ ip_vs_lc_schedule(struct ip_vs_service *
 			      IP_VS_DBG_ADDR(least->af, &least->addr),
 			      ntohs(least->port),
 			      atomic_read(&least->activeconns),
-			      atomic_read(&least->inactconns));
+			      ip_vs_dest_inactconns(least));
 
 	return least;
 }
net/netfilter/ipvs/ip_vs_proto_sctp.c +0 -2
@@ -443,12 +443,10 @@ set_sctp_state(struct ip_vs_proto_data *
 			if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
 				(next_state != IP_VS_SCTP_S_ESTABLISHED)) {
 				atomic_dec(&dest->activeconns);
-				atomic_inc(&dest->inactconns);
 				cp->flags |= IP_VS_CONN_F_INACTIVE;
 			} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
 				   (next_state == IP_VS_SCTP_S_ESTABLISHED)) {
 				atomic_inc(&dest->activeconns);
-				atomic_dec(&dest->inactconns);
 				cp->flags &= ~IP_VS_CONN_F_INACTIVE;
 			}
 		}
net/netfilter/ipvs/ip_vs_proto_tcp.c +0 -2
@@ -555,12 +555,10 @@ set_tcp_state(struct ip_vs_proto_data *p
 			if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
 			    !tcp_state_active(new_state)) {
 				atomic_dec(&dest->activeconns);
-				atomic_inc(&dest->inactconns);
 				cp->flags |= IP_VS_CONN_F_INACTIVE;
 			} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
 				   tcp_state_active(new_state)) {
 				atomic_inc(&dest->activeconns);
-				atomic_dec(&dest->inactconns);
 				cp->flags &= ~IP_VS_CONN_F_INACTIVE;
 			}
 		}
net/netfilter/ipvs/ip_vs_sync.c +2 -5
@@ -879,13 +879,10 @@ static void ip_vs_proc_conn(struct netns
 		spin_lock_bh(&cp->lock);
 		if ((cp->flags ^ flags) & IP_VS_CONN_F_INACTIVE &&
 		    !(flags & IP_VS_CONN_F_TEMPLATE) && dest) {
-			if (flags & IP_VS_CONN_F_INACTIVE) {
+			if (flags & IP_VS_CONN_F_INACTIVE)
 				atomic_dec(&dest->activeconns);
-				atomic_inc(&dest->inactconns);
-			} else {
+			else
 				atomic_inc(&dest->activeconns);
-				atomic_dec(&dest->inactconns);
-			}
 		}
 		flags &= IP_VS_CONN_F_BACKUP_UPD_MASK;
 		flags |= cp->flags & ~IP_VS_CONN_F_BACKUP_UPD_MASK;
author maintainer
#348 lore raw

PATCH 348/389 ipvs: properly update the overload flag on dest edit

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Julian Anastasov <[email protected]>

commit 8f843441c4e7eae8ea83491e8c203c2b192edcf5 upstream.

The upper/lower connection thresholds for dest can be changed, so use ip_vs_dest_update_overload() to properly update the dest overload flag.

The thresholds were not limited, fit them in the 0 .. INT_MAX range as already done in ipvsadm.

As the thresholds are also read when connections are created and expired, use WRITE_ONCE/READ_ONCE to access them.

As the lower threshold is optional, use (u - (u >> 2)) to calculate the 75% default value based on the upper threshold by preserving the integer rounding, as suggested by Yizhou Zhao.

Trigger flag update when totalconns reaches one of the thresholds and use dst_lock to serialize the updating.

---
 include/net/ip_vs.h             |    3 +
 net/netfilter/ipvs/ip_vs_conn.c |   27 +++++-----------
 net/netfilter/ipvs/ip_vs_ctl.c  |   67 +++++++++++++++++++++++++++++++++++-----
 3 files changed, 72 insertions(+), 25 deletions(-)
include/net/ip_vs.h +3 -0
@@ -679,6 +679,7 @@ struct ip_vs_dest {
 	atomic_t		persistconns;	/* persistent connections */
 	__u32			u_threshold;	/* upper threshold */
 	__u32			l_threshold;	/* lower threshold */
+	__u32			l_threshold_val;/* used lower threshold */
 
 	/* for destination cache */
 	spinlock_t		dst_lock;	/* lock of dst_cache */
@@ -1457,6 +1458,8 @@ static inline void ip_vs_dest_put_and_fr
 		kfree(dest);
 }
 
+void ip_vs_dest_update_overload(struct ip_vs_dest *dest, int mode);
+
 /* IPVS sync daemon data and function prototypes
  * (from ip_vs_sync.c)
  */
net/netfilter/ipvs/ip_vs_conn.c +10 -17
@@ -621,22 +621,22 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, s
 
 	/* Update the connection counters */
 	if (!(flags & IP_VS_CONN_F_TEMPLATE)) {
+		int tc;
+
 		/* It is a normal connection, so modify the counters
 		 * according to the flags, later the protocol can
 		 * update them on state change
 		 */
 		if (!(flags & IP_VS_CONN_F_INACTIVE))
 			atomic_inc(&dest->activeconns);
-		atomic_inc(&dest->totalconns);
+		tc = atomic_inc_return(&dest->totalconns);
+		if (tc == READ_ONCE(dest->u_threshold))
+			ip_vs_dest_update_overload(dest, 1);
 	} else {
 		/* It is a persistent connection/template, so increase
 		   the persistent connection counter */
 		atomic_inc(&dest->persistconns);
 	}
-
-	if (dest->u_threshold != 0 &&
-	    atomic_read(&dest->totalconns) >= dest->u_threshold)
-		dest->flags |= IP_VS_DEST_F_OVERLOAD;
 }
 
 
@@ -717,27 +717,20 @@ static inline void ip_vs_unbind_dest(str
 
 	/* Update the connection counters */
 	if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
+		int tc;
+
 		/* It is a normal connection, so decrease the counters */
 		if (!(cp->flags & IP_VS_CONN_F_INACTIVE))
 			atomic_dec(&dest->activeconns);
-		atomic_dec(&dest->totalconns);
+		tc = atomic_fetch_dec(&dest->totalconns);
+		if (tc == READ_ONCE(dest->l_threshold_val))
+			ip_vs_dest_update_overload(dest, -1);
 	} else {
 		/* It is a persistent connection/template, so decrease
 		   the persistent connection counter */
 		atomic_dec(&dest->persistconns);
 	}
 
-	if (dest->l_threshold != 0) {
-		if (atomic_read(&dest->totalconns) < dest->l_threshold)
-			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
-	} else if (dest->u_threshold != 0) {
-		if (atomic_read(&dest->totalconns) * 4 < dest->u_threshold * 3)
-			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
-	} else {
-		if (dest->flags & IP_VS_DEST_F_OVERLOAD)
-			dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
-	}
-
 	ip_vs_dest_put(dest);
 }
 
net/netfilter/ipvs/ip_vs_ctl.c +59 -8

103 lines not on this page · raw message

author maintainer
#349 lore raw

PATCH 349/389 ipvs: clear IPv4 options after rebasing tunnel ICMP errors

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kyle Zeng <[email protected]>

commit e0ba936287dfe9783426aac27e5fd76fe35b38c9 upstream.

ip_vs_in_icmp() rebases an skb from the outer ICMP packet to the quoted original request before passing it to icmp_send(). However, IPCB(skb)->opt still describes the outer IPv4 header.

A timestamp option in the outer header can therefore leave an offset that points into the quoted transport header after the rebase. __ip_options_echo() treats a byte at that stale location as the option length and copies it into the fixed-size option storage on the __icmp_send() stack, causing a stack out-of-bounds write.

Clear the stale option metadata after resetting the network header. Keep the remaining control block fields, including the ingress interface used by the ICMP response path.

Fixes f2edb9f7706d ("ipvs: implement passive PMTUD for IPIP packets")
Assisted-by Codex:gpt-5.6-sol Codex:gpt-5.5-cyber
---
 net/netfilter/ipvs/ip_vs_core.c |    1 +
 1 file changed, 1 insertion(+)
net/netfilter/ipvs/ip_vs_core.c +1 -0
@@ -1837,6 +1837,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, s
 		if (pskb_pull(skb, offset2) == NULL)
 			goto ignore_tunnel;
 		skb_reset_network_header(skb);
+		memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 		/* Ensure the IP header is present in headroom */
 		if (!pskb_may_pull(skb, hlen_orig))
 			goto ignore_tunnel;
author maintainer
#350 lore raw

PATCH 350/389 net/packet: reset the MAC header on the packet-socket transmit path

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Doruk Tan Ozturk <[email protected]>

commit c2707480cfbf19c7619acc9c089d17f20869821f upstream.

packet_parse_headers() resets the MAC header only for a SOCK_RAW frame whose socket did not bind a protocol. A protocol-bound SOCK_RAW socket, any SOCK_DGRAM frame, and the legacy SOCK_PACKET path therefore leave skb->mac_header unset here.

For frames sent via __dev_queue_xmit() this is harmless: it resets the MAC header unconditionally. But the packet-socket PACKET_QDISC_BYPASS path uses dev_direct_xmit(), which does not, so the frame reaches ndo_start_xmit() with the MAC header unset. A driver that reads eth_hdr(skb) on transmit then dereferences skb->head + (u16)~0, an out-of-bounds access ~64 KiB past the head -- the same class fixed for one consumer in commit f5089008f90c ("macsec: do not read an unset MAC header in macsec_encrypt()").

packet_parse_headers() runs only on the transmit path, where skb->data points at the start of the L2 header for every packet-socket type regardless of its length: SOCK_RAW and SOCK_PACKET carry a user-supplied header and SOCK_DGRAM has one built by dev_hard_header(). Reset the MAC header unconditionally, mirroring __dev_queue_xmit(), so the frame is anchored on the bypass path too.

Found by 0sec (https://0sec.ai) using automated source analysis; verified against source and matched to the macsec KASAN report in f5089008f90c. Compile-tested.

---
 net/packet/af_packet.c |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
net/packet/af_packet.c +4 -3
@@ -1938,11 +1938,12 @@ static void packet_parse_headers(struct
 {
 	int depth;
 
+	/* On TX skb->data is the L2 header; anchor it for all socket types. */
+	skb_reset_mac_header(skb);
+
 	if ((!skb->protocol || skb->protocol == htons(ETH_P_ALL)) &&
-	    sock->type == SOCK_RAW) {
-		skb_reset_mac_header(skb);
+	    sock->type == SOCK_RAW)
 		skb->protocol = dev_parse_header_protocol(skb);
-	}
 
 	/* Move network header to the right position for VLAN tagged packets */
 	if (likely(skb->dev->type == ARPHRD_ETHER) &&
author maintainer
#351 lore raw

PATCH 351/389 net: openvswitch: reallocate update replies for mismatched IDs

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhiling Zou <[email protected]>

commit 5d1c224dd914579524a183a514c12b95095d12ce upstream.

ovs_flow_cmd_new() preallocates the optional reply skb before it takes ovs_mutex and before it knows which existing flow will be updated.

That is normally fine because the skb is sized from the request flow identifier. That identifier also becomes the inserted flow's identifier. For updates, however, a request with a UFID may miss the UFID lookup and then fall back to the flow key lookup. That lookup can legitimately find an existing key-identified flow. UFIDs are optional and the flow key is the primary identifier.

For echoed replies, ovs_flow_cmd_fill_info() writes the matched flow's identifier, not the request identifier used for the preallocation. A short request UFID can therefore leave too little room for the key identifier. The fill can then fail with -EMSGSIZE and hit the BUG_ON(error < 0) in the update path.

Once the update target has been resolved, reallocate the reply skb if the matched flow needs a larger reply than the request identifier allowed. Do this before replacing the actions so the request can still fail cleanly if the rare extra allocation fails.

---
 net/openvswitch/datapath.c |   29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)
net/openvswitch/datapath.c +26 -3
@@ -1045,9 +1045,8 @@ static int ovs_flow_cmd_new(struct sk_bu
 			error = -EEXIST;
 			goto err_unlock_ovs;
 		}
-		/* The flow identifier has to be the same for flow updates.
-		 * Look for any overlapping flow.
-		 */
+
+		/* Look for any overlapping flow. */
 		if (unlikely(!ovs_flow_cmp(flow, &match))) {
 			if (ovs_identifier_is_key(&flow->id))
 				flow = ovs_flow_tbl_lookup_exact(&dp->table,
@@ -1059,6 +1058,30 @@ static int ovs_flow_cmd_new(struct sk_bu
 				goto err_unlock_ovs;
 			}
 		}
+
+		if (unlikely(reply)) {
+			size_t cur, req;
+
+			cur = ovs_flow_cmd_msg_size(acts, &new_flow->id,
+						    ufid_flags);
+			req = ovs_flow_cmd_msg_size(acts, &flow->id,
+						    ufid_flags);
+			if (cur < req) {
+				struct sk_buff *resized;
+
+				resized = ovs_flow_cmd_alloc_info(acts,
+								  &flow->id,
+								  info, false,
+								  ufid_flags);
+				if (IS_ERR(resized)) {
+					error = PTR_ERR(resized);
+					goto err_unlock_ovs;
+				}
+				kfree_skb(reply);
+				reply = resized;
+			}
+		}
+
 		/* Update actions. */
 		old_acts = ovsl_dereference(flow->sf_acts);
 		rcu_assign_pointer(flow->sf_acts, acts);
author maintainer
#352 lore raw

PATCH 352/389 net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Qihang Tang <[email protected]>

commit 3b9a324e646d3657a8d9806dfbfe4f3e4066e882 upstream.

dev_validate_header() reads dev->hard_header_len directly when zero-padding short link layer headers for CAP_SYS_RAWIO holders:

    if (capable(CAP_SYS_RAWIO)) {
        memset(ll_header + len, 0, dev->hard_header_len - len);
        return true;
    }

Packet send paths call dev_validate_header() on skbs whose headroom was allocated from an earlier hard_header_len read. If the device is reconfigured so that dev->hard_header_len increases before validation, the memset writes past the reserved buffer, an out-of-bounds write.

This out-of-bounds write is masked in some SOCK_RAW paths today because the same concurrent increase can first make skb_push() exceed the reserved headroom and trigger skb_under_panic(). Remove the zero-padding branch before making those hard_header_len reads consistent, so the snapshot fixes do not turn a loud panic into a silent overwrite.

This path is only reached for variable length L2 protocols, where len < hard_header_len but len >= min_header_len. No remaining in-tree variable length L2 protocol implements header_ops->validate, and the CAP_SYS_RAWIO bypass that zero-pads and accepts short headers has no real value beyond allowing testing of intentionally malformed input.

Drop the CAP_SYS_RAWIO branch. The remaining reads of dev->hard_header_len in dev_validate_header() are comparisons only and have no memory safety impact.

---
 include/linux/netdevice.h |    5 -----
 1 file changed, 5 deletions(-)
include/linux/netdevice.h +0 -5
@@ -3208,11 +3208,6 @@ static inline bool dev_validate_header(c
 	if (len < dev->min_header_len)
 		return false;
 
-	if (capable(CAP_SYS_RAWIO)) {
-		memset(ll_header + len, 0, dev->hard_header_len - len);
-		return true;
-	}
-
 	if (dev->header_ops && dev->header_ops->validate)
 		return dev->header_ops->validate(ll_header, len);
 
author maintainer
#353 lore raw

PATCH 353/389 netfilter: ebt_nflog: pin the NFLOG backend

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chengfeng Ye <[email protected]>

commit 30825970339c107bacaf7f61af90fcdb1f597ca1 upstream.

nf_log_unregister() runs after the per-net teardown so its final RCU grace period also drains readers that obtained the logger from a per-net binding. However, ebt_nflog passes an explicit ULOG log type to nf_log_packet() without holding a reference on the selected logger module, unlike the xt_NFLOG and nft_log frontends.

An ebtables nflog rule can therefore remain callable while nfnetlink_log is unloaded. The resulting interleaving is:

CPU 0 CPU 1
nfnetlink_log_fini()

    unregister_pernet_subsys()
      kfree(nfnl_log_pernet(net))
                                      ebt_nflog_tg()
                                        nf_log_packet()
                                          nfulnl_log_packet()
                                            instance_lookup_get_rcu()

The global ULOG logger is still registered at this point, so CPU 1 dereferences the per-net state after CPU 0 has freed it. KASAN reported:

  BUG: KASAN: slab-use-after-free in instance_lookup_get_rcu
  Read of size 8 at addr ff110001052e6210 by task poc/92
  Call Trace:
   instance_lookup_get_rcu+0x1ce/0x1f0 [nfnetlink_log]
   nfulnl_log_packet+0x248/0x2fb0 [nfnetlink_log]
   nf_log_packet+0x204/0x300
   ebt_nflog_tg+0x351/0x550
   ebt_do_table+0xedf/0x22b0
  Allocated by task 90:
   __kmalloc_noprof+0x186/0x470
   ops_init+0x6d/0x420
   register_pernet_operations+0x2f6/0x670
   register_pernet_subsys+0x23/0x40
  Freed by task 93:
   kfree+0x131/0x3c0
   ops_undo_list+0x3e3/0x700
   unregister_pernet_operations+0x232/0x490
   unregister_pernet_subsys+0x1c/0x30
   nfnetlink_log_fini+0x34/0x450 [nfnetlink_log]

Acquire the ULOG logger module reference when an ebt_nflog rule is validated and release it when the rule is destroyed. Request the NFLOG backend for legacy callers when needed, matching xt_NFLOG. This prevents module teardown until all ebt_nflog rules have stopped using the logger.

Fixes c83fa19603bd ("netfilter: nf_log: don't call synchronize_rcu in nf_log_unset")
---
 net/bridge/netfilter/ebt_nflog.c |   17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)
net/bridge/netfilter/ebt_nflog.c +16 -1
@@ -41,11 +41,25 @@ ebt_nflog_tg(struct sk_buff *skb, const
 static int ebt_nflog_tg_check(const struct xt_tgchk_param *par)
 {
 	struct ebt_nflog_info *info = par->targinfo;
+	int ret;
 
 	if (info->flags & ~EBT_NFLOG_MASK)
 		return -EINVAL;
 	info->prefix[EBT_NFLOG_PREFIX_SIZE - 1] = '\0';
-	return 0;
+
+	ret = nf_logger_find_get(par->family, NF_LOG_TYPE_ULOG);
+	if (ret != 0 && !par->nft_compat) {
+		request_module("%s", "nfnetlink_log");
+
+		ret = nf_logger_find_get(par->family, NF_LOG_TYPE_ULOG);
+	}
+
+	return ret;
+}
+
+static void ebt_nflog_tg_destroy(const struct xt_tgdtor_param *par)
+{
+	nf_logger_put(par->family, NF_LOG_TYPE_ULOG);
 }
 
 static struct xt_target ebt_nflog_tg_reg __read_mostly = {
@@ -54,6 +68,7 @@ static struct xt_target ebt_nflog_tg_reg
 	.family     = NFPROTO_BRIDGE,
 	.target     = ebt_nflog_tg,
 	.checkentry = ebt_nflog_tg_check,
+	.destroy    = ebt_nflog_tg_destroy,
 	.targetsize = sizeof(struct ebt_nflog_info),
 	.me         = THIS_MODULE,
 };
author maintainer
#354 lore raw

PATCH 354/389 vt: add permission check for KDSKBMETA ioctl

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Joshua Rogers <[email protected]>

commit a7ad0034453ba4c353f9b8f810ee2569de33d283 upstream.

KDSKBMETA modifies keyboard meta mode but lacks the !perm check that all other keyboard setter ioctls in vt_k_ioctl() enforce, allowing a process to change meta mode on a non-controlling console without authorization.

---
 drivers/tty/vt/vt_ioctl.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/tty/vt/vt_ioctl.c +2 -0
@@ -408,6 +408,8 @@ static int vt_k_ioctl(struct tty_struct
 	/* this could be folded into KDSKBMODE, but for compatibility
 	   reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
 	case KDSKBMETA:
+		if (!perm)
+			return -EPERM;
 		return vt_do_kdskbmeta(console, arg);
 
 	case KDGKBMETA:
author maintainer
#355 lore raw

PATCH 355/389 vt: stabilize tty reference in kbd_keycode with tty_port_tty_get

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Joshua Rogers <[email protected]>

commit e25d47a526939ad44b75f778b8a7500562b84fc1 upstream.

kbd_keycode() reads vc->port.tty without acquiring a tty reference, racing against con_shutdown() which clears port.tty under a different lock. Use tty_port_tty_get()/tty_kref_put() to hold a proper reference for the duration the tty pointer is needed.

---
 drivers/tty/vt/keyboard.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/tty/vt/keyboard.c +4 -1
@@ -1367,7 +1367,7 @@ static void kbd_keycode(unsigned int key
 	struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
 	int rc;
 
-	tty = vc->port.tty;
+	tty = tty_port_tty_get(&vc->port);
 
 	if (tty && (!tty->driver_data)) {
 		/* No driver data? Strange. Okay we fix it then. */
@@ -1430,9 +1430,12 @@ static void kbd_keycode(unsigned int key
 		 * characters get aren't echoed locally. This makes key repeat
 		 * usable with slow applications and under heavy loads.
 		 */
+		tty_kref_put(tty);
 		return;
 	}
 
+	tty_kref_put(tty);
+
 	param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
 	param.ledstate = kbd->ledflagstate;
 	key_map = key_maps[shift_final];
author maintainer
#356 lore raw

PATCH 356/389 Input: evdev - fix information leak in evdev_pass_values()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dmitry Torokhov <[email protected]>

commit 90f305f2c7a30257c683e13f4bf7c798eea992a0 upstream.

In evdev_pass_values(), the input_event structure is allocated on the kernel stack and populated field-by-field. However, it is never fully initialized. On architectures where struct input_event contains explicit or implicit padding (such as the 32-bit __pad field on SPARC64), these padding bytes are left uninitialized.

When this event structure is subsequently passed to the client buffer and later copied to userspace, the uninitialized padding bytes leak kernel stack memory, potentially exposing sensitive information.

Similar issues exist in __evdev_queue_syn_dropped and __pass_event.

Fix this by explicitly zeroing the entire event structure with memset() before populating its fields. This ensures all padding bytes are cleared before the data crosses the security boundary.

---
 drivers/input/evdev.c |   22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)
drivers/input/evdev.c +12 -10
@@ -149,11 +149,11 @@ static void __evdev_queue_syn_dropped(st
 	struct timespec64 ts = ktime_to_timespec64(ev_time[client->clk_type]);
 	struct input_event ev;
 
+	memset(&ev, 0, sizeof(ev));
 	ev.input_event_sec = ts.tv_sec;
 	ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
 	ev.type = EV_SYN;
 	ev.code = SYN_DROPPED;
-	ev.value = 0;
 
 	client->buffer[client->head++] = ev;
 	client->head &= client->bufsize - 1;
@@ -221,20 +221,20 @@ static void __pass_event(struct evdev_cl
 	client->head &= client->bufsize - 1;
 
 	if (unlikely(client->head == client->tail)) {
+		struct input_event ev;
+
+		memset(&ev, 0, sizeof(ev));
+		ev.input_event_sec = event->input_event_sec;
+		ev.input_event_usec = event->input_event_usec;
+		ev.type = EV_SYN;
+		ev.code = SYN_DROPPED;
+
 		/*
 		 * This effectively "drops" all unconsumed events, leaving
 		 * EV_SYN/SYN_DROPPED plus the newest event in the queue.
 		 */
 		client->tail = (client->head - 2) & (client->bufsize - 1);
-
-		client->buffer[client->tail] = (struct input_event) {
-			.input_event_sec = event->input_event_sec,
-			.input_event_usec = event->input_event_usec,
-			.type = EV_SYN,
-			.code = SYN_DROPPED,
-			.value = 0,
-		};
-
+		client->buffer[client->tail] = ev;
 		client->packet_head = client->tail;
 	}
 
@@ -256,6 +256,8 @@ static void evdev_pass_values(struct evd
 	if (client->revoked)
 		return;
 
+	memset(&event, 0, sizeof(event));
+
 	ts = ktime_to_timespec64(ev_time[client->clk_type]);
 	event.input_event_sec = ts.tv_sec;
 	event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
author maintainer
#357 lore raw

PATCH 357/389 Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Marco Elver <[email protected]>

[ Upstream commit b66774b48dd98f07254951f74ea6f513efe7ff8b ]

l2cap_chan_timeout() runs asynchronously and accesses chan->conn. If the connection is torn down while the timer is running or pending, chan->conn can be freed, leading to a use-after-free when the timer worker attempts to lock conn->lock:

| BUG: KASAN: slab-use-after-free in instrument_atomic_read_write include/linux/instrumented.h:112 [inline]
| BUG: KASAN: slab-use-after-free in atomic_long_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:4456 [inline]
| BUG: KASAN: slab-use-after-free in __mutex_trylock_fast kernel/locking/mutex.c:161 [inline]
| BUG: KASAN: slab-use-after-free in mutex_lock+0x4f/0xa0 kernel/locking/mutex.c:318
| Write of size 8 at addr ffff8881298d9550 by task kworker/2:1/83
|
| CPU: 2 UID: 0 PID: 83 Comm: kworker/2:1 Not tainted 7.1.0-rc6-next-20260601-dirty #6 PREEMPT(full)
| Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
| Workqueue: events l2cap_chan_timeout
| Call Trace:
|  <TASK>
|  instrument_atomic_read_write include/linux/instrumented.h:112 [inline]
|  atomic_long_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:4456 [inline]
|  __mutex_trylock_fast kernel/locking/mutex.c:161 [inline]
|  mutex_lock+0x4f/0xa0 kernel/locking/mutex.c:318
|  l2cap_chan_timeout+0x5d/0x1b0 net/bluetooth/l2cap_core.c:422
|  process_one_work kernel/workqueue.c:3326 [inline]
|  process_scheduled_works+0x7c8/0xfb0 kernel/workqueue.c:3409
|  worker_thread+0x8a9/0xcf0 kernel/workqueue.c:3490
|  kthread+0x346/0x430 kernel/kthread.c:436
|  ret_from_fork+0x1a3/0x470 arch/x86/kernel/process.c:158
|  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
|  </TASK>
|
| Allocated by task 320:
|  l2cap_conn_add+0xa7/0x820 net/bluetooth/l2cap_core.c:7075
|  l2cap_connect_cfm+0xdb/0xd70 net/bluetooth/l2cap_core.c:7452
|  hci_connect_cfm include/net/bluetooth/hci_core.h:2139 [inline]
|  hci_remote_features_evt+0x52f/0x9f0 net/bluetooth/hci_event.c:3760
|  hci_event_func net/bluetooth/hci_event.c:7796 [inline]
|  hci_event_packet+0x561/0xa70 net/bluetooth/hci_event.c:7847
|  hci_rx_work+0x370/0x890 net/bluetooth/hci_core.c:4040
|  process_one_work kernel/workqueue.c:3326 [inline]
|  process_scheduled_works+0x7c8/0xfb0 kernel/workqueue.c:3409
|  worker_thread+0x8a9/0xcf0 kernel/workqueue.c:3490
|  kthread+0x346/0x430 kernel/kthread.c:436
|  ret_from_fork+0x1a3/0x470 arch/x86/kernel/process.c:158
|  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
|
| Freed by task 322:
|  hci_disconn_cfm include/net/bluetooth/hci_core.h:2154 [inline]
|  hci_conn_hash_flush+0x101/0x1f0 net/bluetooth/hci_conn.c:2736
|  hci_dev_close_sync+0x889/0xde0 net/bluetooth/hci_sync.c:5405
|  hci_dev_do_close net/bluetooth/hci_core.c:502 [inline]
|  hci_unregister_dev+0x1f7/0x370 net/bluetooth/hci_core.c:2679
|  vhci_release+0x12a/0x180 drivers/bluetooth/hci_vhci.c:690
|  __fput+0x369/0x890 fs/file_table.c:510
|  task_work_run+0x160/0x1d0 kernel/task_work.c:233
|  get_signal+0xf5b/0x1120 kernel/signal.c:2810
|  arch_do_signal_or_restart+0x4d/0x600 arch/x86/kernel/signal.c:337
|  __exit_to_user_mode_loop kernel/entry/common.c:64 [inline]
|  exit_to_user_mode_loop+0x85/0x510 kernel/entry/common.c:98
|  do_syscall_64+0x263/0x3d0 arch/x86/entry/syscall_64.c:100
|  entry_SYSCALL_64_after_hwframe+0x77/0x7f
|
| The buggy address belongs to the object at ffff8881298d9400
|  which belongs to the cache kmalloc-512 of size 512
| The buggy address is located 336 bytes inside of
|  freed 512-byte region [ffff8881298d9400, ffff8881298d9600)

Fix it by having chan->conn hold a reference to l2cap_conn (via l2cap_conn_get) when the channel is added to the connection, and releasing it in the channel destructor. This ensures the l2cap_conn remains alive as long as the channel exists.

A new FLAG_DEL channel flag is introduced to indicate that the channel has been deleted from its connection. l2cap_chan_del() atomically sets this flag using test_and_set_bit() instead of setting chan->conn to NULL. All asynchronous workers (l2cap_chan_timeout, l2cap_ack_timeout, l2cap_monitor_timeout, l2cap_retrans_timeout) and l2cap_chan_send() check FLAG_DEL to determine whether the channel has been torn down, rather than testing chan->conn for NULL.

Fixes 8c8e620467a7 ("Bluetooth: L2CAP: use chan timer to close channels in cleanup_listen()")
Cc Siwei Zhang <[email protected]>
Cc Luiz Augusto von Dentz <[email protected]>
Assisted-by Gemini:gemini-3.1-pro-preview
Change-Id Ie9862976d25c3e6d386689cd198ebe5ab4cc5509
---
 include/net/bluetooth/l2cap.h |  1 +
 net/bluetooth/l2cap_core.c    | 36 +++++++++++++++++++++--------------
 2 files changed, 23 insertions(+), 14 deletions(-)
include/net/bluetooth/l2cap.h +1 -0
index d2db84b77bfbe..af590a802eba4 100644
@@ -775,6 +775,7 @@ enum {
 	FLAG_ECRED_CONN_REQ_SENT,
 	FLAG_PENDING_SECURITY,
 	FLAG_HOLD_HCI_CONN,
+	FLAG_DEL,
 };
 
 /* Lock nesting levels for L2CAP channels. We need these because lockdep
net/bluetooth/l2cap_core.c +22 -14
index c9c3bef3ae895..1c2114930f86f 100644
@@ -435,7 +435,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
 
 	BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
 
-	if (!conn) {
+	if (!conn || test_bit(FLAG_DEL, &chan->flags)) {
 		l2cap_chan_put(chan);
 		return;
 	}
@@ -446,6 +446,9 @@ static void l2cap_chan_timeout(struct work_struct *work)
 	 */
 	l2cap_chan_lock(chan);
 
+	if (test_bit(FLAG_DEL, &chan->flags))
+		goto unlock;
+
 	if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
 		reason = ECONNREFUSED;
 	else if (chan->state == BT_CONNECT &&
@@ -458,10 +461,11 @@ static void l2cap_chan_timeout(struct work_struct *work)
 
 	chan->ops->close(chan);
 
+unlock:
 	l2cap_chan_unlock(chan);
-	l2cap_chan_put(chan);
 
 	mutex_unlock(&conn->chan_lock);
+	l2cap_chan_put(chan);
 }
 
 struct l2cap_chan *l2cap_chan_create(void)
@@ -511,6 +515,9 @@ static void l2cap_chan_destroy(struct kref *kref)
 	list_del(&chan->global_l);
 	write_unlock(&chan_list_lock);
 
+	if (chan->conn)
+		l2cap_conn_put(chan->conn);
+
 	kfree(chan);
 }
 
@@ -593,7 +600,7 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
 	conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
-	chan->conn = conn;
+	chan->conn = l2cap_conn_get(conn);
 
 	switch (chan->chan_type) {
 	case L2CAP_CHAN_CONN_ORIENTED:
@@ -648,31 +655,28 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 
 void l2cap_chan_del(struct l2cap_chan *chan, int err)
 {
-	struct l2cap_conn *conn = chan->conn;
-
 	__clear_chan_timer(chan);
 
-	BT_DBG("chan %p, conn %p, err %d, state %s", chan, conn, err,
+	BT_DBG("chan %p, err %d, state %s", chan, err,
 	       state_to_string(chan->state));
 
 	chan->ops->teardown(chan, err);
 
-	if (conn) {
-		struct amp_mgr *mgr = conn->hcon->amp_mgr;
+	if (chan->conn && !test_and_set_bit(FLAG_DEL, &chan->flags)) {
+		struct amp_mgr *mgr = chan->conn->hcon->amp_mgr;
+
 		/* Delete from channel list */
 		list_del(&chan->list);
 
 		l2cap_chan_put(chan);
 
-		chan->conn = NULL;
-
 		/* Reference was only held for non-fixed channels or
 		 * fixed channels that explicitly requested it using the
 		 * FLAG_HOLD_HCI_CONN flag.
 		 */
 		if (chan->chan_type != L2CAP_CHAN_FIXED ||
 		    test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
-			hci_conn_drop(conn->hcon);
+			hci_conn_drop(chan->conn->hcon);
 
 		if (mgr && mgr->bredr_chan == chan)
 			mgr->bredr_chan = NULL;
@@ -2046,7 +2050,7 @@ static void l2cap_monitor_timeout(struct work_struct *work)
 
 	l2cap_chan_lock(chan);
 
-	if (!chan->conn) {
+	if (!chan->conn || test_bit(FLAG_DEL, &chan->flags)) {
 		l2cap_chan_unlock(chan);
 		l2cap_chan_put(chan);
 		return;
@@ -2067,7 +2071,7 @@ static void l2cap_retrans_timeout(struct work_struct *work)
 
 	l2cap_chan_lock(chan);
 
-	if (!chan->conn) {
+	if (!chan->conn || test_bit(FLAG_DEL, &chan->flags)) {
 		l2cap_chan_unlock(chan);
 		l2cap_chan_put(chan);
 		return;
@@ -2692,7 +2696,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
 	int err;
 	struct sk_buff_head seg_queue;
 
-	if (!chan->conn)
+	if (!chan->conn || test_bit(FLAG_DEL, &chan->flags))
 		return -ENOTCONN;
 
 	/* Connectionless channel */
@@ -3293,12 +3297,16 @@ static void l2cap_ack_timeout(struct work_struct *work)
 
 	l2cap_chan_lock(chan);
 
+	if (test_bit(FLAG_DEL, &chan->flags))
+		goto unlock;
+
 	frames_to_ack = __seq_offset(chan, chan->buffer_seq,
 				     chan->last_acked_seq);
 
 	if (frames_to_ack)
 		l2cap_send_rr_or_rnr(chan, 0);
 
+unlock:
 	l2cap_chan_unlock(chan);
 	l2cap_chan_put(chan);
 }
Signature · 1 line
2.53.0
author maintainer
#358 lore raw

PATCH 358/389 Bluetooth: 6lowpan: Fix using chan->conn as indication to no remote netdev

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Luiz Augusto von Dentz <[email protected]>

[ Upstream commit d38eaf611839b85ade3dd3db309dbc8aaaaf0095 ]

b66774b48dd9 ("Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref") don't reset the chan->conn to NULL anymore making the bt# netdev not be remove once the last l2cap_chan_del is removed.

Instead of restoring the original behavior this remove the logic of keeping the interface after the last channel is removed because it never worked as intended and the l2cap_chan_del always detach its l2cap_conn which results in always removing the channel anyway.

Fixes b66774b48dd9 ("Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref")
---
 net/bluetooth/6lowpan.c | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)
net/bluetooth/6lowpan.c +3 -15
index 096f6fc5d30bf..a71855268d33f 100644
@@ -804,20 +804,10 @@ static void chan_close_cb(struct l2cap_chan *chan)
 	struct lowpan_btle_dev *dev = NULL;
 	struct lowpan_peer *peer;
 	int err = -ENOENT;
-	bool last = false, remove = true;
+	bool last = false;
 
 	BT_DBG("chan %p conn %p", chan, chan->conn);
 
-	if (chan->conn && chan->conn->hcon) {
-		if (!is_bt_6lowpan(chan->conn->hcon))
-			return;
-
-		/* If conn is set, then the netdev is also there and we should
-		 * not remove it.
-		 */
-		remove = false;
-	}
-
 	spin_lock(&devices_lock);
 
 	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
@@ -844,10 +834,8 @@ static void chan_close_cb(struct l2cap_chan *chan)
 
 		ifdown(dev->netdev);
 
-		if (remove) {
-			INIT_WORK(&entry->delete_netdev, delete_netdev);
-			schedule_work(&entry->delete_netdev);
-		}
+		INIT_WORK(&entry->delete_netdev, delete_netdev);
+		schedule_work(&entry->delete_netdev);
 	} else {
 		spin_unlock(&devices_lock);
 	}
Signature · 1 line
2.53.0
author maintainer
#359 lore raw

PATCH 359/389 ima: fix out-of-bounds read in xattr_verify()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Lincoln Wallace <[email protected]>

[ Upstream commit 5ff232d31106f45ac87c3b64e1d35a0667777797 ]

The digest-length check in xattr_verify() mixes int and size_t:

	if (xattr_len - sizeof(xattr_value->type) - hash_start >=
			iint->ima_hash->length)

sizeof() yields size_t, so the usual arithmetic conversions promote the whole left-hand side to unsigned 64-bit before the subtraction runs. For a truncated xattr this underflows instead of going negative:
a 1-byte IMA_XATTR_DIGEST_NG xattr (xattr_len == 1, hash_start == 1) turns "1 - 1 - 1" into SIZE_MAX, which is trivially >= ima_hash->length. The check then passes and the following memcmp() reads iint->ima_hash->length bytes starting past the end of the buffer vfs_getxattr_alloc() allocated for it.

Nothing upstream clamps xattr_len back into a safe range first:
ima_get_hash_algo() only special-cases xattr_len < 2 to pick a default algorithm, and evm_verifyxattr() returns INTEGRITY_UNKNOWN rather than failing when no HMAC key is loaded, so a truncated security.ima value reaches the length check as-is.

Rewrite the comparison so every operand stays a signed int and no implicit conversion to size_t can occur.

Fixes 3ea7a56067e6 ("ima: provide hash algo info in the xattr")
---
 security/integrity/ima/ima_appraise.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
security/integrity/ima/ima_appraise.c +7 -2
index 7122a359a268e..615a20b9eb52b 100644
@@ -242,8 +242,13 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint,
 			break;
 		}
 		clear_bit(IMA_DIGSIG, &iint->atomic_flags);
-		if (xattr_len - sizeof(xattr_value->type) - hash_start >=
-				iint->ima_hash->length)
+		/*
+		 * Use addition, not subtraction: sizeof() forces unsigned
+		 * math and a short xattr_len would wrap around, bypassing
+		 * this bounds check.
+		 */
+		if (xattr_len >= (int)sizeof(xattr_value->type) + hash_start +
+				(int)iint->ima_hash->length)
 			/*
 			 * xattr length may be longer. md5 hash in previous
 			 * version occupied 20 bytes in xattr, instead of 16
Signature · 1 line
2.53.0
author maintainer
#360 lore raw

PATCH 360/389 futex: Prevent robust futex exit race some more

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Keno Fischer <[email protected]>

commit 6d4514ca9cdf61fec4ec634cf50386f6f7e69748 upstream.

A robust futex unlock stores 0 over the whole futex value - wiping FUTEX_WAITERS - and wakes a single waiter. That wakeup is a one-shot
notification: the protocol relies on its recipient to either acquire the futex (and eventually unlock while aware of the remaining contention) or re-arm FUTEX_WAITERS before sleeping again. If the woken waiter is killed before it can do either, the kernel must jump in and wake the next task down the line.

This is a known complication of the futex protocol with a previous partial fix in commit ca16d5bee598 ("futex: Prevent robust futex exit race"). Unfortunately, that fix is insufficient.

If a third task re-acquired the futex through the uncontended fast path in the meantime, the notification is lost: robust exit processing sees that it is owned by another task and does nothing, while the new owner sees no FUTEX_WAITERS when it unlocks and wakes nobody. The remaining waiters sleep forever behind a free futex:

A owns the futex, B and C sleep in FUTEX_WAIT

                                        uval == A | FUTEX_WAITERS
  A robust unlock: store 0, FUTEX_WAKE(1) wakes B
                                        uval == 0
  D fast path acquire: cmpxchg(0 -> D)
                                        uval == D, no FUTEX_WAITERS

B killed before acting on the wakeup
B exit walk, pending op: owner D != B -> no action D unlock: no FUTEX_WAITERS -> no wake
C sleeps forever

This is clearly a shortcoming in the implementation, which fails to keep the FUTEX_WAITERS bit consistent.

Work around this by augmenting the robust list exit processing to also perform the extra wakeup if the futex word is owned by another thread but FUTEX_WAITERS is not set.

This does not fix the problem of a non-contended take over/release and free sequence, which has been discussed for years and has been addressed by commit 3ca9595d9fb6 ("futex: Add support for unlocking robust futexes") and subsequent changes, but failed to take the problem described above into account.

A more complete solution which is based on the in kernel unlock of contended robust futexes has been discussed in the context of this change and should show up in mainline sooner than later.

[ tglx: Amend change log slightly and fixup coding style ]

Fixes ca16d5bee598 ("futex: Prevent robust futex exit race")
Assisted-by ClaudeCode:claude-fable-5 tla+
---
 kernel/futex/core.c | 82 +++++++++++++++++++++++++++++++--------------
 1 file changed, 56 insertions(+), 26 deletions(-)
kernel/futex/core.c +56 -26
index df86c0e494184..d772b8ab29817 100644
@@ -3428,8 +3428,11 @@ static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr,
 		return -1;
 
 	/*
-	 * Special case for regular (non PI) futexes. The unlock path in
-	 * user space has two race scenarios:
+	 * Special case for regular (non PI) futexes. Ordinarily, we do
+	 * not perform any processing here unless the current thread was
+	 * the owner of the futex (by the TID check below).
+	 *
+	 * However, the unlock path has three race scenarios:
 	 *
 	 * 1. The unlock path releases the user space futex value and
 	 *    before it can execute the futex() syscall to wake up
@@ -3438,41 +3441,68 @@ static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr,
 	 * 2. A woken up waiter is killed before it can acquire the
 	 *    futex in user space.
 	 *
-	 * In the second case, the wake up notification could be generated
-	 * by the unlock path in user space after setting the futex value
-	 * to zero or by the kernel after setting the OWNER_DIED bit below.
+	 * 3. A woken up waiter is killed in user space after another
+	 *    thread has acquired the futex, but before it can set
+	 *    FUTEX_WAITERS.
+	 *
+	 * Note that, if userspace uses the FUTEX_ROBUST_UNLOCK flag, we
+	 * will not see case 1 here.
+	 *
+	 * In the second and third case, the wake up notification could
+	 * be generated from any of:
+	 *
+	 *    i.   An ordinary futex wakeup after unlock (with or
+	 *         without FUTEX_ROBUST_UNLOCK)
+	 *    ii.  A robust wakeup from another thread's death
+	 *    iii. A previous round through this special case
+	 *
+	 * As a result, the futex world will be in one of four states:
 	 *
-	 * In both cases the TID validation below prevents a wakeup of
-	 * potential waiters which can cause these waiters to block
-	 * forever.
+	 *    A. The futex word is 0 (unlocked)
+	 *    B. The futex word is owned by another thread
+	 *       (FUTEX_WAITERS is not set)
+	 *    C. The futex word is owned by another thread
+	 *       (FUTEX_WAITERS set)
+	 *    D. The futex's owner died and OWNER_DIED is set
+	 *       (the owner part of the word is 0)
 	 *
-	 * In both cases the following conditions are met:
+	 * The key issue is that the kernel usually (at least from
+	 * sources ii. and iii. or when so requested by userspace from
+	 * source i.) only ever wakes *one* waiter at a time. If this
+	 * waiter dies before acquiring the futex (or setting the
+	 * FUTEX_WAITERS bit), the kernel *must* still wake the next
+	 * waiter down the line to uphold the futex invariants and
+	 * avoid lost wakeups. Note we do not need to handle state C,
+	 * as it does not matter to us whether *we* successfully set
+	 * the bit or a third thread did so in the meantime.
 	 *
-	 *	1) task->robust_list->list_op_pending != NULL
-	 *	   @pending_op == true
-	 *	2) The owner part of user space futex value == 0
+	 * Therefore, in these cases we must issue an additional
+	 * futex_wake(). Note however that we *must not* set OWNER_DIED
+	 * here. Our thread is *not* the owner of the futex.
+	 *
+	 * Thus to summarize, the conditions for needing the additional
+	 * futex_wake() are:
+	 *
+	 *	1) @pending_op == true (the thread has not finished the
+	 *	   mutex operation)
+	 *	2) The futex word is in one of the states A, B or D
 	 *	3) Regular futex: @pi == false
 	 *
-	 * If these conditions are met, it is safe to attempt waking up a
-	 * potential waiter without touching the user space futex value and
-	 * trying to set the OWNER_DIED bit. If the futex value is zero,
-	 * the rest of the user space mutex state is consistent, so a woken
-	 * waiter will just take over the uncontended futex. Setting the
-	 * OWNER_DIED bit would create inconsistent state and malfunction
-	 * of the user space owner died handling. Otherwise, the OWNER_DIED
-	 * bit is already set, and the woken waiter is expected to deal with
-	 * this.
+	 * Note in particular that in all of the states A-D the owner
+	 * portion of the futex word differs from our thread's TID
+	 * (unless the actual owner has the same TID in another PID
+	 * namespace, but we cannot currently distinguish that
+	 * scenario), so this can be a special-case wakeup in the bail
+	 * path of the ordinary TID check.
 	 */
 	owner = uval & FUTEX_TID_MASK;
 
-	if (pending_op && !pi && !owner) {
-		futex_wake(uaddr, 1, 1, FUTEX_BITSET_MATCH_ANY);
+	if (owner != task_pid_vnr(curr)) {
+		if (pending_op && !pi && (!owner || !(uval & FUTEX_WAITERS)))
+			futex_wake(uaddr, 1, 1, FUTEX_BITSET_MATCH_ANY);
 		return 0;
 	}
 
-	if (owner != task_pid_vnr(curr))
-		return 0;
-
 	/*
 	 * Ok, this dying thread is truly holding a futex
 	 * of interest. Set the OWNER_DIED bit atomically
Signature · 1 line
2.53.0
author maintainer
#361 lore raw

PATCH 361/389 RDMA/rxe: Fix a use-after-free problem in rxe_mmap

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhu Yanjun <[email protected]>

[ Upstream commit 35744ab3d03c5fca8c1752f53fc8fc674e14c561 ]

rxe_mmap() removes a rxe_mmap_info struct from the pending_mmaps list and releases pending_lock while the struct's kref is still at 1:

list_del_init(&ip->pending_mmaps);
spin_unlock_bh(&rxe->pending_lock); /* ref == 1, no lock held */
ret = remap_vmalloc_range(vma, ip->obj, 0); /* walks PTEs */ [...]
rxe_vma_open(vma); /* kref_get, ref → 2 */
remap_vmalloc_range_partial() walks PTEs without any lock.

A concurrent DESTROY_CQ ioctl on another CPU calls:

    kref_put(&q->ip->ref, rxe_mmap_release)   /* ref 1→0 */
    vfree(ip->obj)   /* clears vmalloc PTEs mid-walk */
    kfree(ip)        /* frees rxe_mmap_info */

This yields:

1. Kernel crash, vmalloc_to_page() returns NULL when vfree wins the per-PTE race -> vm_insert_page(NULL) → GPF in validate_page_before_insert

2. Page UAF, vmalloc_to_page() reads a stale PTE before vfree clears it. User VMA holds a PTE to a free'd page which might eventually get reallocated later by vmalloc which allows the attacker to get a clean page-level UAF.

It is worth noting that even though a page-level UAF is possible given the strong primitive, it is statistically very difficult to achieve given the very short time window (after the last insert_page and before the kref_get).

The call trace are as below:

  Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN NOPTI
  KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
  CPU: 0 UID: 1000 PID: 413 Comm: poc Not tainted 7.0.0-rc5-dirty #28 PREEMPT(lazy)
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
  RIP: 0010:validate_page_before_insert+0x32/0x300
  Code: e5 41 57 41 56 49 89 fe 41 55 41 54 53 48 89 f3 e8 93 b5 a3 ff 48 8d 7b 08 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 7b 02 00 00 4c 8b 63 08 31 ff 4d 89 e5 41 83 e5
  RSP: 0018:ffff88811b15f2f0 EFLAGS: 00000202
  RAX: dffffc0000000000 RBX: 0000000000000000 RCX: 0000000000000000
  RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000000008
  RBP: ffff88811b15f318 R08: 0000000000000000 R09: 0000000000000000
  R10: 0000000000000000 R11: 0000000000000000 R12: ffff8881181eee00
  R13: 0000000000000000 R14: ffff8881181eee00 R15: ffff8881181eee20
  FS:  00007b1e000f76c0(0000) GS:ffff8884268e0000(0000) knlGS:0000000000000000
  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  CR2: 00007b1e00a24ac0 CR3: 0000000116eb3000 CR4: 00000000000006f0
  Call Trace:
   <TASK>
   insert_page+0x8f/0x190
   ? __pfx_insert_page+0x10/0x10
   ? kasan_save_alloc_info+0x38/0x60
   vm_insert_page+0x2e7/0x400
   remap_vmalloc_range_partial+0x212/0x3e0
   remap_vmalloc_range+0x6e/0xb0
   ? __kasan_check_write+0x14/0x30
   rxe_mmap+0x2e9/0x5d0
   ib_uverbs_mmap+0x1ad/0x2c0
   __mmap_region+0x12c2/0x2ad0
   ? __pfx___mmap_region+0x10/0x10
   ? __sanitizer_cov_trace_switch+0x58/0xb0
   ? mas_prev_slot+0x360/0x39c0
   ? __sanitizer_cov_trace_switch+0x58/0xb0
   ? mas_next_slot+0x1e5b/0x2f40
   ? __sanitizer_cov_trace_cmp8+0x18/0x30
   ? unmapped_area_topdown+0x4dd/0x610
   ? kfree+0x1b1/0x440
   ? free_cpumask_var+0x16/0x30
   ? __kasan_slab_free+0x7d/0xa0
   ? __sanitizer_cov_trace_cmp8+0x18/0x30
   mmap_region+0x2e6/0x3c0
   do_mmap+0xa3e/0x12a0
   ? __pfx_do_mmap+0x10/0x10
   ? __kasan_check_write+0x14/0x30
   ? down_write_killable+0xba/0x160
   ? __pfx_down_write_killable+0x10/0x10
   ? __sanitizer_cov_trace_cmp4+0x16/0x30
   vm_mmap_pgoff+0x2d4/0x4a0
   ? __pfx_vm_mmap_pgoff+0x10/0x10
   ? fget+0x1bf/0x270
   ksys_mmap_pgoff+0x40c/0x690
   ? __sanitizer_cov_trace_const_cmp4+0x16/0x30
   ? __pfx_ksys_mmap_pgoff+0x10/0x10
   ? __kasan_check_write+0x14/0x30
   ? _raw_spin_trylock+0xbb/0x130
   ? __pfx__raw_spin_trylock+0x10/0x10
   __x64_sys_mmap+0x135/0x1e0
   x64_sys_call+0x1c14/0x2790
   do_syscall_64+0xd2/0x1050
   ? rcu_core+0x352/0x7d0
   ? rcu_core_si+0xe/0x20
   ? handle_softirqs+0x1aa/0x650
   ? __sanitizer_cov_trace_cmp4+0x16/0x30
   ? fpregs_assert_state_consistent+0xe1/0x160
   ? irqentry_exit+0xb1/0x670
   entry_SYSCALL_64_after_hwframe+0x76/0x7e
Reported-and-tested-by nasm <[email protected]>
Fixes 8700e3e7c485 ("Soft RoCE driver")
(cherry picked from commit 35744ab3d03c5fca8c1752f53fc8fc674e14c561)
[Harshit: Minor conflict resolution pr_err() vs rxe_dbg_dev() usage]
---
 drivers/infiniband/sw/rxe/rxe_mmap.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)
drivers/infiniband/sw/rxe/rxe_mmap.c +16 -3
index 035f226af1336..edd9345da295c 100644
@@ -94,18 +94,31 @@ int rxe_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 	goto done;
 
 found_it:
+	/*
+	 * Increment refcount and check whether it is being freed atm while
+	 * holding lock to prevent UAF
+	 */
+	if (!kref_get_unless_zero(&ip->ref)) {
+		spin_unlock_bh(&rxe->pending_lock);
+		ret = -ENXIO;
+		goto done;
+	}
+
 	list_del_init(&ip->pending_mmaps);
 	spin_unlock_bh(&rxe->pending_lock);
 
+	vma->vm_ops = &rxe_vm_ops;
+	vma->vm_private_data = ip;
+
 	ret = remap_vmalloc_range(vma, ip->obj, 0);
 	if (ret) {
+		vma->vm_private_data = NULL;
+		vma->vm_ops = NULL;
+		kref_put(&ip->ref, rxe_mmap_release);
 		pr_err("err %d from remap_vmalloc_range\n", ret);
 		goto done;
 	}
 
-	vma->vm_ops = &rxe_vm_ops;
-	vma->vm_private_data = ip;
-	rxe_vma_open(vma);
 done:
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#362 lore raw

PATCH 362/389 mips: sched: Fix CPUMASK_OFFSTACK memory corruption

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aaron Tomlin <[email protected]>

[ Upstream commit 98e37db4a34d3af3fb2f4648295c25b5e40b20e3 ]

This patch addresses a critical memory management flaw. When CONFIG_CPUMASK_OFFSTACK is enabled, cpumask_var_t is a pointer. Consequently, sizeof(new_mask) evaluates to the pointer size, causing copy_from_user() to clobber the mask pointer. Furthermore, the old logic performed copy_from_user() before allocating the mask.

Fix this by allocating new_mask first. To handle variable-sized user masks correctly, use cpumask_size() to truncate overly large user masks or pad undersized masks with zeros before copying the data directly into the allocated buffer.

Fixes 295cbf6d63165 ("[MIPS] Move FPU affinity code into separate file.")
---
 arch/mips/kernel/mips-mt-fpaff.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)
arch/mips/kernel/mips-mt-fpaff.c +15 -13
index 6c590ef276482..5feffc8708ada 100644
@@ -70,11 +70,16 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
 	struct task_struct *p;
 	int retval;
 
-	if (len < sizeof(new_mask))
-		return -EINVAL;
-
-	if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
-		return -EFAULT;
+	if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
+		return -ENOMEM;
+	if (len < cpumask_size())
+		cpumask_clear(new_mask);
+	else if (len > cpumask_size())
+		len = cpumask_size();
+	if (copy_from_user(new_mask, user_mask_ptr, len)) {
+		retval = -EFAULT;
+		goto out_free_new_mask;
+	}
 
 	get_online_cpus();
 	rcu_read_lock();
@@ -83,7 +88,8 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
 	if (!p) {
 		rcu_read_unlock();
 		put_online_cpus();
-		return -ESRCH;
+		retval = -ESRCH;
+		goto out_free_new_mask;
 	}
 
 	/* Prevent p going away */
@@ -94,13 +100,9 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
 		retval = -ENOMEM;
 		goto out_put_task;
 	}
-	if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
-		retval = -ENOMEM;
-		goto out_free_cpus_allowed;
-	}
 	if (!alloc_cpumask_var(&effective_mask, GFP_KERNEL)) {
 		retval = -ENOMEM;
-		goto out_free_new_mask;
+		goto out_free_cpus_allowed;
 	}
 	if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) {
 		retval = -EPERM;
@@ -141,13 +143,13 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
 	}
 out_unlock:
 	free_cpumask_var(effective_mask);
-out_free_new_mask:
-	free_cpumask_var(new_mask);
 out_free_cpus_allowed:
 	free_cpumask_var(cpus_allowed);
 out_put_task:
 	put_task_struct(p);
 	put_online_cpus();
+out_free_new_mask:
+	free_cpumask_var(new_mask);
 	return retval;
 }
 
Signature · 1 line
2.53.0
author maintainer
#363 lore raw

PATCH 363/389 fscrypt: Replace mk_users keyring with simple list

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Biggers <[email protected]>

commit 696c030e1e3438955aba443b308ee8b6faa3983e upstream.

Change mk_users (the set of user claims to an fscrypt master key) from a 'struct key' keyring to a simple linked list.

It's still a collection of 'struct key' for quota tracking. It was originally thought to be natural that a collection of 'struct key' should be held in a 'struct key' keyring. In reality, it's just been causing problems, similar to how using 'struct key' for the filesystem keyring caused problems and was removed in commit d7e7b9af104c ("fscrypt: stop using keyrings subsystem for fscrypt_master_key").

Commit d3a7bd420076 ("fscrypt: clear keyring before calling key_put()") fixed mk_users cleanup to be synchronous. But that apparently wasn't
enough: the keyring subsystem's redundant locking is still generating lockdep false positives due to the interaction with filesystem reclaim.

With the simple list, the redundant locking and lockdep issue goes away.

Of course, searching a linked list is linear-time whereas the 'struct key' keyring used a fancy constant-time associative array. But that's fine here, since in practice there's just one entry in the list. In fact the new code is much faster in practice, since it's much smaller and doesn't have to convert the kuid_t into a string to search for it.

---
 fs/crypto/fscrypt_private.h |  32 ++++--
 fs/crypto/keyring.c         | 212 ++++++++++++++++--------------------
 2 files changed, 113 insertions(+), 131 deletions(-)
fs/crypto/fscrypt_private.h +22 -10
index b746d7df37582..72db3df9dfad7 100644
@@ -403,6 +403,19 @@ fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
 
 /* keyring.c */
 
+/*
+ * fscrypt_master_key_user - a user's claim to a master key
+ */
+struct fscrypt_master_key_user {
+	struct list_head link;
+	kuid_t uid;
+	/*
+	 * This 'struct key' contains no secret.  It exists solely to charge the
+	 * appropriate user's key quota.
+	 */
+	struct key *quota_key;
+};
+
 /*
  * fscrypt_master_key_secret - secret key material of an in-use master key
  */
@@ -489,19 +502,18 @@ struct fscrypt_master_key {
 	struct fscrypt_key_specifier		mk_spec;
 
 	/*
-	 * Keyring which contains a key of type 'key_type_fscrypt_user' for each
-	 * user who has added this key.  Normally each key will be added by just
-	 * one user, but it's possible that multiple users share a key, and in
-	 * that case we need to keep track of those users so that one user can't
-	 * remove the key before the others want it removed too.
+	 * List of user claims to this key (struct fscrypt_master_key_user).
+	 * Normally each key will be added by just one user, but it's possible
+	 * that multiple users share a key, and in that case we need to keep
+	 * track of those users so that one user can't remove the key before the
+	 * others want it removed too.
 	 *
-	 * This is NULL for v1 policy keys; those can only be added by root.
+	 * Used only for v2 policy keys.  v1 policy keys can be added only by
+	 * root, so user tracking doesn't apply to them.
 	 *
-	 * Locking: protected by ->mk_sem.  (We don't just rely on the keyrings
-	 * subsystem semaphore ->mk_users->sem, as we need support for atomic
-	 * search+insert along with proper synchronization with ->mk_secret.)
+	 * Locking: protected by ->mk_sem.
 	 */
-	struct key		*mk_users;
+	struct list_head	mk_users;
 
 	/*
 	 * List of inodes that were unlocked using this key.  This allows the
fs/crypto/keyring.c +91 -121

331 lines not on this page · raw message

Signature · 1 line
2.53.0
author maintainer
#364 lore raw

PATCH 364/389 ipv4: fix use-after-free in fib_nhc_update_mtu()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chengfeng Ye <[email protected]>

commit bc5bde9ce3cc36502839dfe98e068f7303a50982 upstream.

fib_nhc_update_mtu() walks the nexthop exception table under RTNL, but RTNL does not serialize this walk with PMTU exception updates. The walk uses rcu_dereference_protected() with a constant true condition without holding fnhe_lock.

The following interleaving can therefore occur:

CPU 0 CPU 1
fib_nhc_update_mtu() update_or_create_fnhe()
load fnhe spin_lock_bh(&fnhe_lock)
fnhe_remove_oldest()
unlink fnhe kfree_rcu(fnhe, rcu)
<quiescent state>
access fnhe after grace period

KASAN reported:

  BUG: KASAN: slab-use-after-free in fib_nhc_update_mtu+0x3df/0x410
  Read of size 8 at addr ffff888107d49000 by task poc/90
  Call Trace:
   fib_nhc_update_mtu+0x3df/0x410
   fib_sync_mtu+0x7a/0xd0
   fib_netdev_event+0x229/0x3f0
   netif_set_mtu_ext+0x33a/0x570
   dev_set_mtu+0x88/0x120

The same walk updates fnhe_pmtu and fnhe_mtu_locked. These fields form a pair and other writers serialize them with fnhe_lock. RCU alone prevents reclamation, but would still allow concurrent writers to leave a mixed pair.

Walk the table under RCU and acquire fnhe_lock only while updating each exception. RCU keeps the current entry alive while the short critical section serializes its paired PMTU fields. This avoids holding the global lock while scanning all 2048 buckets for every nexthop.

---
 include/net/route.h      |    2 ++
 net/ipv4/fib_semantics.c |   34 +++++++++++-----------------------
 net/ipv4/route.c         |   29 +++++++++++++++++++++++++++++
 3 files changed, 42 insertions(+), 23 deletions(-)
include/net/route.h +2 -0
@@ -240,6 +240,8 @@ int fib_dump_info_fnhe(struct sk_buff *s
 		       u32 table_id, struct fib_info *fi,
 		       int *fa_index, int fa_start, unsigned int flags);
 
+void fnhe_update_pmtu(struct fib_nh_exception *fnhe, u32 new, u32 orig);
+
 static inline void ip_rt_put(struct rtable *rt)
 {
 	/* dst_release() accepts a NULL parameter.
net/ipv4/fib_semantics.c +11 -23
@@ -1943,42 +1943,30 @@ static int call_fib_nh_notifiers(struct
 	return NOTIFY_DONE;
 }
 
-/* Update the PMTU of exceptions when:
- * - the new MTU of the first hop becomes smaller than the PMTU
- * - the old MTU was the same as the PMTU, and it limited discovery of
- *   larger MTUs on the path. With that limit raised, we can now
- *   discover larger MTUs
- * A special case is locked exceptions, for which the PMTU is smaller
- * than the minimal accepted PMTU:
- * - if the new MTU is greater than the PMTU, don't make any change
- * - otherwise, unlock and set PMTU
+/* Walk the exceptions of a nexthop after its first hop MTU changed. The
+ * chain is RCU protected here, while fnhe_update_pmtu() takes fnhe_lock
+ * for the update of each entry.
  */
 void fib_nhc_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig)
 {
 	struct fnhe_hash_bucket *bucket;
 	int i;
 
-	bucket = rcu_dereference_protected(nhc->nhc_exceptions, 1);
+	rcu_read_lock();
+	bucket = rcu_dereference(nhc->nhc_exceptions);
 	if (!bucket)
-		return;
+		goto out;
 
 	for (i = 0; i < FNHE_HASH_SIZE; i++) {
 		struct fib_nh_exception *fnhe;
 
-		for (fnhe = rcu_dereference_protected(bucket[i].chain, 1);
+		for (fnhe = rcu_dereference(bucket[i].chain);
 		     fnhe;
-		     fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) {
-			if (fnhe->fnhe_mtu_locked) {
-				if (new <= fnhe->fnhe_pmtu) {
-					fnhe->fnhe_pmtu = new;
-					fnhe->fnhe_mtu_locked = false;
-				}
-			} else if (new < fnhe->fnhe_pmtu ||
-				   orig == fnhe->fnhe_pmtu) {
-				fnhe->fnhe_pmtu = new;
-			}
-		}
+		     fnhe = rcu_dereference(fnhe->fnhe_next))
+			fnhe_update_pmtu(fnhe, new, orig);
 	}
+out:
+	rcu_read_unlock();
 }
 
 void fib_sync_mtu(struct net_device *dev, u32 orig_mtu)
net/ipv4/route.c +29 -0
@@ -779,6 +779,35 @@ out_unlock:
 	spin_unlock_bh(&fnhe_lock);
 }
 
+/* Update the PMTU of an exception when:
+ * - the new MTU of the first hop becomes smaller than the PMTU
+ * - the old MTU was the same as the PMTU, and it limited discovery of
+ *   larger MTUs on the path. With that limit raised, we can now
+ *   discover larger MTUs
+ * A special case is locked exceptions, for which the PMTU is smaller
+ * than the minimal accepted PMTU:
+ * - if the new MTU is greater than the PMTU, don't make any change
+ * - otherwise, unlock and set PMTU
+ *
+ * fnhe_lock keeps fnhe_pmtu and fnhe_mtu_locked consistent against
+ * update_or_create_fnhe(), which sets both under the same lock.
+ */
+void fnhe_update_pmtu(struct fib_nh_exception *fnhe, u32 new, u32 orig)
+{
+	spin_lock_bh(&fnhe_lock);
+
+	if (fnhe->fnhe_mtu_locked) {
+		if (new <= fnhe->fnhe_pmtu) {
+			fnhe->fnhe_pmtu = new;
+			fnhe->fnhe_mtu_locked = false;
+		}
+	} else if (new < fnhe->fnhe_pmtu || orig == fnhe->fnhe_pmtu) {
+		fnhe->fnhe_pmtu = new;
+	}
+
+	spin_unlock_bh(&fnhe_lock);
+}
+
 static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flowi4 *fl4,
 			     bool kill_route)
 {
author maintainer
#365 lore raw

PATCH 365/389 serial: 8250_dma: Clear stale RX state on shutdown

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cunhao Lu <[email protected]>

commit e2fe6a0efecbef00e3ecc2db64dd5afa8c212b41 upstream.

serial8250_release_dma() terminates RX DMA and releases the channel, but leaves rx_running set. If the port is closed while an RX transfer is active, the stale state remains while rxchan is NULL until the channel is requested again on the next open.

The DesignWare BUSY workaround added by commit a7b9ce39fbe4 ("serial: 8250_dw: Ensure BUSY is deasserted") calls serial8250_rx_dma_flush() from the LCR write path during startup. This happens before serial8250_request_dma() obtains a new RX channel. On reopen, the stale rx_running state therefore makes the flush path pass a NULL channel to dmaengine_pause(), causing a kernel Oops.

Clear rx_running after terminating RX DMA, matching the TX cleanup. Also make the flush helper return if the DMA object or RX channel is not available so startup and teardown paths cannot pass a NULL channel to the DMAengine API.

Fixes 0fcb7901f9d6 ("tty: serial: 8250_dma: keep own book keeping about RX transfers")
Cc stable <[email protected]>
---
 drivers/tty/serial/8250/8250_dma.c |   12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/tty/serial/8250/8250_dma.c +7 -5
@@ -195,11 +195,12 @@ void serial8250_rx_dma_flush(struct uart
 {
 	struct uart_8250_dma *dma = p->dma;
 
-	if (dma->rx_running) {
-		dmaengine_pause(dma->rxchan);
-		__dma_rx_complete(p);
-		dmaengine_terminate_async(dma->rxchan);
-	}
+	if (!dma || !dma->rxchan || !dma->rx_running)
+		return;
+
+	dmaengine_pause(dma->rxchan);
+	__dma_rx_complete(p);
+	dmaengine_terminate_async(dma->rxchan);
 }
 EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
 
@@ -308,6 +309,7 @@ void serial8250_release_dma(struct uart_
 
 	/* Release RX resources */
 	dmaengine_terminate_sync(dma->rxchan);
+	dma->rx_running = 0;
 	dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
 			  dma->rx_addr);
 	dma_release_channel(dma->rxchan);
author maintainer
#366 lore raw

PATCH 366/389 staging: rtl8723bs: fix OOB read in rtw_get_wpa_ie()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Muhammad Bilal <[email protected]>

commit 1c3e23e78862493e8cf1adad02b10ffcb8b9921c upstream.

rtw_get_wpa_ie() reads bytes at fixed offsets into a vendor-specific information element without checking that the element is long enough, causing an out-of-bounds read for a short trailing IE.

The function locates a vendor-specific IE (EID 221) with rtw_get_ie() and then compares a 4-byte OUI+type at pbuf + 2 and reads a 2-byte version word at pbuf + 6. Those accesses require the IE body to be at least 6 bytes, but rtw_get_ie() only guarantees that the element fits within the buffer; it does not enforce a minimum body length. A vendor-specific IE whose length byte is 0 to 5, placed at the end of the buffer, therefore makes these reads run past the end of the IE and past the end of the buffer itself.

The buffer holds information elements taken from received management frames and from the IE blob passed to rtw_cfg80211_set_wpa_ie(), which is kmemdup'd to its exact length, so the read can run off the end of the allocation.

The sibling helpers rtw_get_sec_ie(), rtw_get_wapi_ie() and rtw_get_wps_ie() in this file already reject too-short vendor-specific IEs before their OUI memcmp(); rtw_get_wpa_ie() was never brought in line with them, and needs a minimum of 6 rather than 4 bytes because of the version word. Add the missing length check.

Fixes 554c0a3abf216 ("staging: Add rtl8723bs sdio wifi driver")
Cc stable <[email protected]>
---
 drivers/staging/rtl8723bs/core/rtw_ieee80211.c |    3 +++
 1 file changed, 3 insertions(+)
drivers/staging/rtl8723bs/core/rtw_ieee80211.c +3 -0
@@ -379,6 +379,9 @@ unsigned char *rtw_get_wpa_ie(unsigned c
 		pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new);
 
 		if (pbuf) {
+			if (len < 6)
+				goto check_next_ie;
+
 			/* check if oui matches... */
 			if (memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type))) {
 				goto check_next_ie;
author maintainer
#367 lore raw

PATCH 367/389 staging: rtl8723bs: validate monitor transmit frame lengths

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mariano Baragiola <[email protected]>

commit 6829665d050983907b560173e49dcc6c11cb2730 upstream.

rtw_cfg80211_monitor_if_xmit_entry() removes the radiotap header and then reads the 802.11 frame control field without checking that a base 802.11 header remains.

The data path also pulls the calculated 802.11, QoS and SNAP header span before confirming that the skb contains it. A truncated frame can therefore cause out-of-bounds reads or leave insufficient data for the Ethernet address writes.

Reject frames that do not contain the base 802.11 header and data frames that do not contain their complete calculated header span.

---
 drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c |    4 ++++
 1 file changed, 4 insertions(+)
drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +4 -0
@@ -2451,6 +2451,8 @@ static netdev_tx_t rtw_cfg80211_monitor_
 
 	/* Skip the ratio tap header */
 	skb_pull(skb, rtap_len);
+	if (skb->len < dot11_hdr_len)
+		goto fail;
 
 	dot11_hdr = (struct ieee80211_hdr *)skb->data;
 	frame_control = le16_to_cpu(dot11_hdr->frame_control);
@@ -2463,6 +2465,8 @@ static netdev_tx_t rtw_cfg80211_monitor_
 			qos_len = 2;
 		if ((frame_control & 0x0300) == 0x0300)
 			dot11_hdr_len += 6;
+		if (skb->len < dot11_hdr_len + qos_len + snap_len)
+			goto fail;
 
 		memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
 		memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
author maintainer
#368 lore raw

PATCH 368/389 misc: fastrpc: fix channel ctx ref leak when session alloc fails

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anandu Krishnan E <[email protected]>

commit 310f7868399668c6d99d88acc9c4cf3462e69d5b upstream.

fastrpc_channel_ctx_get() is called in fastrpc_device_open() before fastrpc_session_alloc(). If session alloc fails, the error path returns -EBUSY without calling fastrpc_channel_ctx_put(), leaking the reference. Fix by adding the missing put.

---
 drivers/misc/fastrpc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/misc/fastrpc.c +1 -1
@@ -1273,7 +1273,7 @@ static int fastrpc_device_open(struct in
 		dev_err(&cctx->rpdev->dev, "No session available\n");
 		mutex_destroy(&fl->mutex);
 		kfree(fl);
-
+		fastrpc_channel_ctx_put(cctx);
 		return -EBUSY;
 	}
 
author maintainer
#369 lore raw

PATCH 369/389 misc: fastrpc: fix memory leak in fastrpc_channel_ctx_free

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eddie Lin <[email protected]>

commit 2fae94ee14f7fea11d3f95e10383a87c01d21518 upstream.

The 'ctx_idr' is initialized but never destroyed when the channel context is freed, leading to a memory leak. Add idr_destroy() to properly clean up the IDR resources.

---
 drivers/misc/fastrpc.c |    1 +
 1 file changed, 1 insertion(+)
drivers/misc/fastrpc.c +1 -0
@@ -342,6 +342,7 @@ static void fastrpc_channel_ctx_free(str
 
 	cctx = container_of(ref, struct fastrpc_channel_ctx, refcount);
 
+	idr_destroy(&cctx->ctx_idr);
 	kfree(cctx);
 }
 
author maintainer
#370 lore raw

PATCH 370/389 fbdev: bitblit: bound-check glyph index in bit_cursor()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Rik van Riel <[email protected]>

commit e033cbf3975a8465f879ebd5989dc35b04423a4d upstream.

bit_cursor() fetches the glyph under the cursor with

	c = scr_readw(vc_pos);
	src = vc_font.data + ((c & charmask) * w * height);

where charmask is 0x1ff when vc_hi_font_mask is set. The screen buffer value comes directly from scr_readw() and may be larger than the current font's glyph count.

Syzkaller triggers this via vcs_write(). The Call Trace shows vcs_write() in vc_screen.c writing an arbitrary 16-bit value with writev() to /dev/vcsa, which vcs_write_buf() in vc_screen.c stores via vcs_scr_writew() without checking charcount. The stored value is later read in bit_cursor() in bitblit.c.

When the font is changed from a font with 512 glyphs to a font with 256 glyphs, the screen buffer can retain characters with the high bit set from the previous mode, which could also produce the same out-of-bounds access.

  BUG: KASAN: global-out-of-bounds in soft_cursor+0x378/0x6bc drivers/video/fbdev/core/softcursor.c:70
  Read of size 16 at addr ffff800086c57970

  Call Trace:
   soft_cursor+0x378/0x6bc drivers/video/fbdev/core/softcursor.c:70
   bit_cursor+0xa90/0x1108 drivers/video/fbdev/core/bitblit.c:365
   fbcon_cursor+0x344/0x498 drivers/video/fbdev/core/fbcon.c:1427
   hide_cursor+0xdc/0x2d0 drivers/tty/vt/vt.c:883
   update_region+0x100/0x18c drivers/tty/vt/vt.c:669
   vcs_write+0x8ec/0xaf0 drivers/tty/vt/vc_screen.c:685

bit_putcs_aligned() and bit_putcs_unaligned() already clamp the glyph index to vc_font.charcount. Apply the same clamp in bit_cursor() after extracting the attribute and masking, before indexing fontdata.

The fix completes the bounds checking started in commit 18c4ef4e765a ("fbdev: bitblit: bound-check glyph index in bit_putcs*"), which missed the cursor path.

This change should be safe because the clamp reuses the existing contract from fbcon: charcount is maintained under console_lock in con_font_set() and fbcon_font_set(), and hi_font_mask is cleared when switching from 512 to 256 glyphs. When stale screen data with high bits remains after a font switch, or when vcs_write() stores an arbitrary value, clamping the index to 0 prevents the out-of-bounds read without changing cursor semantics — the same fallback bit_putcs uses.

Reported-by [email protected]
Fixes 18c4ef4e765a ("fbdev: bitblit: bound-check glyph index in bit_putcs*")
Assisted-by Hermes:muse-spark-1.2 syzkaller
---
 drivers/video/fbdev/core/bitblit.c |    9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/video/fbdev/core/bitblit.c +7 -2
@@ -274,9 +274,14 @@ static void bit_cursor(struct vc_data *v
 	if (!vc->vc_font.data)
 		return;
 
- 	c = scr_readw((u16 *) vc->vc_pos);
+	c = scr_readw((u16 *) vc->vc_pos);
 	attribute = get_attribute(info, c);
-	src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
+	c &= charmask;
+
+	/* Clamp to font size, same as bit_putcs_aligned() */
+	if (c >= vc->vc_font.charcount)
+		c = 0;
+	src = vc->vc_font.data + (c * (w * vc->vc_font.height));
 
 	if (ops->cursor_state.image.data != src ||
 	    ops->cursor_reset) {
author maintainer
#371 lore raw

PATCH 371/389 ipv6: prevent in6_dev_get() from resurrecting inet6_dev

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kyle Zeng <[email protected]>

commit 0e243671bc7b8eaf00f83dd2f4367436dc0cff98 upstream.

in6_dev_get() reads dev->ip6_ptr under RCU and then unconditionally increments its refcount. Device teardown can clear the pointer and drop the last reference between these operations. The increment then resurrects an object whose RCU free has already been queued, so callers can use it after it is freed.

Use refcount_inc_not_zero() and return NULL when the object has already reached zero. RCU keeps the memory accessible through the attempted reference acquisition, and a successful increment pins the object for the caller.

An independent run on the exact unpatched 6f5156d7a31a (v7.2-rc3) kernel reproduced the invalid reference acquisition as UID 1000:

refcount_t: addition on 0; use-after-free.
ip6_mc_source+0xef4/0x17e0

It was followed by the corresponding reference underflow in ip6_mc_source(). The supplied trace from the same unpatched revision additionally shows the access after the RCU read-side section ends:

  BUG: KASAN: slab-use-after-free in mutex_lock+0x76/0xe0
  Write of size 8 at addr ffff888015b50240 by task poc/1219

Bug found and triaged by OpenAI Security Research and validated by Trail of Bits.

---
 include/net/addrconf.h |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
include/net/addrconf.h +2 -2
@@ -368,8 +368,8 @@ static inline struct inet6_dev *in6_dev_
 
 	rcu_read_lock();
 	idev = rcu_dereference(dev->ip6_ptr);
-	if (idev)
-		refcount_inc(&idev->refcnt);
+	if (idev && !refcount_inc_not_zero(&idev->refcnt))
+		idev = NULL;
 	rcu_read_unlock();
 	return idev;
 }
author maintainer
#372 lore raw

PATCH 372/389 netfilter: bridge: release template ct on non-IP path

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhiling Zou <[email protected]>

commit d45cc8020d7c0a9f01dee42ff5c40bc14c9af72f upstream.

A bridge nftables ct zone set rule can attach a conntrack template to an skb before nf_ct_bridge_pre() sees it. For non-IPv4 and non-IPv6 EtherTypes, nf_ct_bridge_pre() currently overwrites skb->_nfct with IP_CT_UNTRACKED without releasing the existing template reference.

That makes the per-cpu template, and any temporary templates allocated for concurrent use, unreachable and leaks memory until the host runs out of slab.

Reset the skb conntrack state before marking the frame untracked so the existing template reference is dropped on the non-IP path.

Fixes 3c171f496ef5 ("netfilter: bridge: add connection tracking system")
---
 net/bridge/netfilter/nf_conntrack_bridge.c |    1 +
 1 file changed, 1 insertion(+)
net/bridge/netfilter/nf_conntrack_bridge.c +1 -0
@@ -280,6 +280,7 @@ static unsigned int nf_ct_bridge_pre(voi
 		ret = nf_ct_br_defrag6(skb, &bridge_state);
 		break;
 	default:
+		nf_reset_ct(skb);
 		nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
 		return NF_ACCEPT;
 	}
author maintainer
#373 lore raw

PATCH 373/389 net: atlantic: free RX pages of consumed but not refilled buffers

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yangyu Chen <[email protected]>

commit e8e7471ef686b6c002218fee9671cc61992ae01a upstream.

aq_ring_rx_deinit() only walks [sw_head, sw_tail), the region posted to hardware. Since the page reuse strategy was added, a cleaned RX buffer keeps its page (and its DMA mapping) in the ring for reuse, and refill is batched: aq_ring_rx_fill() returns early until AQ_CFG_RX_REFILL_THRES slots are free. Slots that were consumed but not yet reposted therefore sit in the complementary [sw_tail, sw_head) gap with a live page, and the deinit walk never visits them: up to a refill batch worth of pages and DMA mappings leak on every interface down.

Walk the whole ring instead and release whatever is still there. Also bail out if the buffer ring is already gone: a partial aq_ptp_ring_alloc() failure frees the ring but leaves aq_nic set, so aq_ptp_ring_deinit() still gets here on the unwind path.

Fixes 46f4c29d9de6 ("net: aquantia: optimize rx performance by page reuse strategy")
---
 drivers/net/ethernet/aquantia/atlantic/aq_ring.c |   22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/net/ethernet/aquantia/atlantic/aq_ring.c +18 -4
@@ -565,15 +565,29 @@ err_exit:
 
 void aq_ring_rx_deinit(struct aq_ring_s *self)
 {
-	if (!self)
+	unsigned int i;
+
+	if (!self || !self->buff_ring)
 		return;
 
-	for (; self->sw_head != self->sw_tail;
-		self->sw_head = aq_ring_next_dx(self, self->sw_head)) {
-		struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
+	/* Release every page still owned by the ring.
+	 *
+	 * Walking [sw_head, sw_tail) is not enough: refill is batched
+	 * (aq_ring_rx_fill() waits for AQ_CFG_RX_REFILL_THRES free slots),
+	 * so slots that were cleaned but not yet reposted accumulate in the
+	 * [sw_tail, sw_head) gap, and they keep their page for reuse. Walk
+	 * the whole ring and release whatever is left.
+	 */
+	for (i = 0; i < self->size; i++) {
+		struct aq_ring_buff_s *buff = &self->buff_ring[i];
+
+		if (!buff->rxdata.page)
+			continue;
 
 		aq_free_rxpage(&buff->rxdata, aq_nic_get_dev(self->aq_nic));
 	}
+
+	self->sw_head = self->sw_tail;
 }
 
 void aq_ring_free(struct aq_ring_s *self)
author maintainer
#374 lore raw

PATCH 374/389 vxlan: do not arm the ageing timer on a device that is down

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Baul Lee <[email protected]>

commit b37971686ec59fb027fa4910ba16805e68fddb97 upstream.

vxlan_changelink() arms vxlan->age_timer whenever the requested ageing interval differs from the configured one:

	if (conf.age_interval != vxlan->cfg.age_interval)
		mod_timer(&vxlan->age_timer, jiffies);

There is no netif_running() test, so the timer is armed even on a device that was never brought up. The only synchronous cancel in the driver is the timer_delete_sync() in vxlan_stop(), which is .ndo_stop. netif_close_many() drops devices without IFF_UP before __dev_close_many() runs, so that cancel is skipped for such a device.

vxlan_setup() sets dev->needs_free_netdev = true and age_timer is a member of struct vxlan_dev, so free_netdev() releases the allocation the timer lives in while it is still queued on a timer_base. expire_timers() unlinks the entry before it loads timer->function, so the timer core writes through the freed object's list pointers:

  BUG: KASAN: slab-use-after-free in __run_timers+0x208/0x654
  Write of size 8 at addr ffff00001adace68 by task true/192
   __asan_store8+0x84/0xac
   __run_timers+0x208/0x654
   run_timer_softirq+0x154/0x18c
  Allocated by task 189:
   alloc_netdev_mqs+0x64/0x720
   rtnl_create_link+0x4ac/0x520
   rtnl_newlink+0x758/0xd00
  Freed by task 191:
   netdev_release+0x40/0x58
   netdev_run_todo+0x4a4/0x8c0
   rtnl_dellink+0x200/0x4e8

The rtnl operations involved are netns-scoped, so an unprivileged user can perform them in a new user and network namespace.

Arming the timer on a down device never had an effect: vxlan_cleanup() returns early on !netif_running(), and vxlan_open() arms the timer for any non-zero interval once the device is brought up. Add the missing test.

Discovered by XBOW, triaged by Baul Lee <[email protected]>

---
 drivers/net/vxlan/vxlan_core.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/vxlan/vxlan_core.c +1 -1
@@ -4315,7 +4315,7 @@ static int vxlan_changelink(struct net_d
 		spin_unlock_bh(&vxlan->hash_lock[hash_index]);
 	}
 
-	if (conf.age_interval != vxlan->cfg.age_interval)
+	if (netif_running(dev) && conf.age_interval != vxlan->cfg.age_interval)
 		mod_timer(&vxlan->age_timer, jiffies);
 
 	netdev_adjacent_change_commit(dst->remote_dev, lowerdev, dev);
author maintainer
#375 lore raw

PATCH 375/389 vsock/virtio: avoid refilling the RX queue after teardown

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Weiming Shi <[email protected]>

commit a31e0ad444698d8aa7534a0f89fda543730f97a5 upstream.

Commit b917507e5ad9 ("vsock/virtio: stop workers during the .remove()") made the RX worker jump to its common exit when rx_run is clear. That exit still refills the RX queue when the buffer count is low, so work queued across virtio_vsock_vqs_del() can add buffers after the virtqueues have been deleted.

BUG: KASAN: slab-use-after-free in virtqueue_add_sgs
Read of size 4 by task kworker/0:1
Workqueue: virtio_vsock virtio_transport_rx_work
Call Trace:
 virtqueue_add_sgs (drivers/virtio/virtio_ring.c:2796)
 virtio_vsock_rx_fill (net/vmw_vsock/virtio_transport.c:332)
 virtio_transport_rx_work (net/vmw_vsock/virtio_transport.c:701)
 process_one_work (kernel/workqueue.c:3314)
 worker_thread (kernel/workqueue.c:3478)
 kthread (kernel/kthread.c:436)
 ret_from_fork (arch/x86/kernel/process.c:158)
 ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
...
Freed by task 141:
 kfree (mm/slub.c:6566)
 vp_del_vq (drivers/virtio/virtio_pci_common.c:259)
 vp_del_vqs (drivers/virtio/virtio_pci_common.c:285)
 virtio_vsock_freeze (net/vmw_vsock/virtio_transport.c:912)
 virtio_device_freeze (drivers/virtio/virtio.c:658)
 virtio_pci_freeze (drivers/virtio/virtio_pci_common.c:601)
 pci_pm_freeze (drivers/pci/pci-driver.c:1098)
 device_suspend (drivers/base/power/main.c:1968)
Kernel panic - not syncing: KASAN: panic_on_warn set ...

Jump to a no-refill exit when rx_run is clear, leaving the normal exit to replenish a running queue.

---
 net/vmw_vsock/virtio_transport.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/vmw_vsock/virtio_transport.c +2 -1
@@ -501,7 +501,7 @@ static void virtio_transport_rx_work(str
 	mutex_lock(&vsock->rx_lock);
 
 	if (!vsock->rx_run)
-		goto out;
+		goto out_nofill;
 
 	do {
 		virtqueue_disable_cb(vq);
@@ -540,6 +540,7 @@ static void virtio_transport_rx_work(str
 out:
 	if (vsock->rx_buf_nr < vsock->rx_buf_max_nr / 2)
 		virtio_vsock_rx_fill(vsock);
+out_nofill:
 	mutex_unlock(&vsock->rx_lock);
 }
 
author maintainer
#376 lore raw

PATCH 376/389 vhost: reset the vring metadata cache on vring reconfiguration

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jun Yang <[email protected]>

commit de845981da67a6b049080c87e605130b0c30adc5 upstream.

vq->meta_iotlb[] caches the vhost_iotlb_map that backs each vring metadata region, and iotlb_access_ok() returns early on a cache hit, taking the hit as proof that the region has already been validated:

	if (vhost_vq_meta_fetch(vq, addr, len, type))
		return true;

The cache is reset on VHOST_IOTLB_UPDATE and VHOST_IOTLB_INVALIDATE, on device IOTLB (re)initialisation and on vq reset, but not when VHOST_SET_VRING_ADDR replaces vq->desc, vq->avail and vq->used, nor when VHOST_SET_VRING_NUM changes the region sizes.

With a device IOTLB attached both ioctls are accepted while the vq is live, and neither validates the addresses at ioctl time: vq_access_ok() and vq_log_used_access_ok() return true early because the addresses are GIOVAs, deferring validation to prefetch time. Once the cache has been populated that deferred validation no longer runs -- vq_meta_prefetch() hits the stale entry and returns true -- and vhost_vq_meta_fetch() keeps translating through the old mapping as

	map->addr + addr - map->start

for an address the mapping no longer covers. vhost_copy_to_user() and vhost_copy_from_user() consume the result with __copy_to_user() and __copy_from_user(), which do not check it either, so a subsequent used ring update or descriptor fetch accesses memory outside the region the IOTLB actually maps.

Reset the metadata cache whenever the vring is reconfigured, so the new addresses are pushed back through iotlb_access_ok()'s slow path.

Fixes f88949138058 ("vhost: introduce O(1) vq metadata cache")
Assisted-by tencentos-corvus-ai:kimi-k3

Message-ID: <[email protected]>

---
 drivers/vhost/vhost.c |    8 ++++++++
 1 file changed, 8 insertions(+)
drivers/vhost/vhost.c +8 -0
@@ -1577,6 +1577,14 @@ static long vhost_vring_set_num_addr(str
 		BUG();
 	}
 
+	/*
+	 * The metadata cache holds the IOTLB mapping that backed the previous
+	 * desc/avail/used addresses and vring size, both of which are being
+	 * replaced here.  iotlb_access_ok() takes a cache hit as proof that the
+	 * region was validated, so the stale entries have to go.
+	 */
+	__vhost_vq_meta_reset(vq);
+
 	mutex_unlock(&vq->mutex);
 
 	return r;
author maintainer
#377 lore raw

PATCH 377/389 tipc: read le->link under the node lock in tipc_node_link_down()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jun Yang <[email protected]>

commit cba9ccb47e9fa4cc77692fb896cc5ab57a667882 upstream.

tipc_node_link_down() caches the link pointer before taking n->lock:

	struct tipc_link *l = le->link;		/* unlocked */

	if (!l)
		return;
	tipc_node_write_lock(n);
	if (!tipc_link_is_establishing(l)) {	/* deref l */
	...
		tipc_link_reset(l);		/* write into l */
	if (delete) {
		kfree(l);
		le->link = NULL;

The delete=true caller frees that very object under n->lock, so the lock does not protect the cached pointer against it:

- CPU A, delete=false: tipc_rcv() on TIPC_LINK_DOWN_EVT, or the link supervision timer via tipc_node_timeout(), reads l unlocked and then dereferences it under n->lock;
- CPU B, delete=true: netlink TIPC_NL_BEARER_DISABLE -> bearer_disable() -> tipc_node_delete_links() -> tipc_node_link_down(n, bearer_id, true) -> kfree(l).

The link is freed with plain kfree(), not kfree_rcu(), and for UDP bearers disable_media() only schedules the asynchronous cleanup_bearer() work, so its synchronize_net() runs after the links are already gone. An in-flight CPU A that has read l therefore dereferences freed memory once B frees it:
a use-after-free read in tipc_link_is_establishing(), and a use-after-free write via tipc_link_reset() on the establishing branch.

The following trace was captured on 7.2.0-rc5-00284-gaf39eb111ce6:

  BUG: KASAN: slab-use-after-free in tipc_link_is_establishing (net/tipc/link.c:285)
  Read of size 4 at addr ffff88802e2aa068 by task swapper/2/0
   tipc_link_is_establishing (net/tipc/link.c:285)
   tipc_node_link_down (net/tipc/node.c:1076)
   tipc_node_timeout (net/tipc/node.c:843)
  Allocated by task 9549:
   tipc_link_create (net/tipc/link.c:490)
   tipc_node_check_dest (net/tipc/node.c:1279)
   tipc_disc_rcv (net/tipc/discover.c:252)
   tipc_udp_recv (net/tipc/udp_media.c:389)
  Freed by task 9549:
   tipc_node_link_down (net/tipc/node.c:1084)
   tipc_node_delete_links (net/tipc/node.c:1320)
   bearer_disable (net/tipc/bearer.c:414)
   __tipc_nl_bearer_disable (net/tipc/bearer.c:992)

Move the le->link read inside tipc_node_write_lock(), so it is serialised against the kfree() in the delete path. A racing teardown now either has not run yet, and we see a valid link, or has already run, and we see NULL.

Fixes 73f646cec354 ("tipc: delay ESTABLISH state event when link is established")
Assisted-by tencentos-corvus-ai:kimi-k3
---
 net/tipc/node.c |   15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)
net/tipc/node.c +10 -5
@@ -1036,18 +1036,23 @@ static void __tipc_node_link_down(struct
 
 static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete)
 {
-	struct tipc_link_entry *le = &n->links[bearer_id];
 	struct tipc_media_addr *maddr = NULL;
-	struct tipc_link *l = le->link;
 	int old_bearer_id = bearer_id;
+	struct tipc_link_entry *le;
 	struct sk_buff_head xmitq;
-
-	if (!l)
-		return;
+	struct tipc_link *l;
 
 	__skb_queue_head_init(&xmitq);
 
+	/* Synchronize the link lookup with bearer teardown. */
 	tipc_node_write_lock(n);
+	le = &n->links[bearer_id];
+	l = le->link;
+	if (!l) {
+		tipc_node_write_unlock_fast(n);
+		return;
+	}
+
 	if (!tipc_link_is_establishing(l)) {
 		__tipc_node_link_down(n, &bearer_id, &xmitq, &maddr);
 	} else {
author maintainer
#378 lore raw

PATCH 378/389 ring-buffer: Use current_context for safe per-CPU buffer swap

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Tengda Wu <[email protected]>

commit f27bdc43077e4fcb5557dfc315ee8d91e741f483 upstream.

The ring_buffer_swap_cpu() function currently checks the per-CPU committing counter to determine if a buffer is actively being written to before performing the swap. However, there exists a race window where this check can be bypassed:

    ring_buffer_lock_reserve
        cpu_buffer = buffer->buffers[cpu];       // cpu_buffer_a
        rb_reserve_next_event
            rb_start_commit // inc committing
            if (unlikely(READ_ONCE(cpu_buffer->buffer) != buffer)) {...}
            __rb_reserve_next
                rb_move_tail
                    rb_end_commit(cpu_buffer);   // dec committing => 0
                    /* interrupt hits here, successfully swaps! */
                    local_inc(&cpu_buffer->committing);

    ring_buffer_unlock_commit
        cpu_buffer = buffer->buffers[cpu];      // cpu_buffer_b
        rb_commit
            rb_end_commit
            RB_WARN_ON(cpu_buffer, !local_read(&cpu_buffer->committing))
                                                // triggers warning

The committing counter can temporarily drop to 0 during a single write operation (within rb_move_tail), creating a window where swap can succeed even though the write is still in progress. This leads to inconsistent buffer state and triggers the RB_WARN_ON in rb_commit().

Replace the committing counter check with current_context checks, which are set at the entry of ring_buffer_lock_reserve() and remain valid throughout the entire write operation, providing a reliable indicator of buffer busy state during swap.

Fixes 4239c38fe0b3 ("ring-buffer: Process commits whenever moving to a new page.")
---
 kernel/trace/ring_buffer.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
kernel/trace/ring_buffer.c +4 -4
@@ -5234,7 +5234,7 @@ int ring_buffer_swap_cpu(struct trace_bu
 {
 	struct ring_buffer_per_cpu *cpu_buffer_a;
 	struct ring_buffer_per_cpu *cpu_buffer_b;
-	int ret = -EINVAL;
+	int ret = -EBUSY;
 
 	if (!cpumask_test_cpu(cpu, buffer_a->cpumask) ||
 	    !cpumask_test_cpu(cpu, buffer_b->cpumask))
@@ -5270,10 +5270,10 @@ int ring_buffer_swap_cpu(struct trace_bu
 	atomic_inc(&cpu_buffer_a->record_disabled);
 	atomic_inc(&cpu_buffer_b->record_disabled);
 
-	ret = -EBUSY;
-	if (local_read(&cpu_buffer_a->committing))
+	/* Do not swap if either buffer is in the process of writing */
+	if (cpu_buffer_a->current_context)
 		goto out_dec;
-	if (local_read(&cpu_buffer_b->committing))
+	if (cpu_buffer_b->current_context)
 		goto out_dec;
 
 	/*
author maintainer
#379 lore raw

PATCH 379/389 ipv6: fix Route Information option length validation

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yuejie Shi <[email protected]>

commit d1ad8fb2ac6a1afb71dc22d9ae8efb4dda96c824 upstream.

rt6_route_rcv() validates the Route Information option (RFC 4191) length against the prefix length, but both checks are off by one.

rinfo->length is the ND option length in units of 8 octets and it *includes* the 8-byte option header, so an option carrying N bytes of prefix has length == 1 + N/8. RFC 4191 section 2.3 requires length 3 when Prefix Length is greater than 64, and 2 or 3 when it is greater than 0. The code accepts length >= 2 and length >= 1 respectively.

ipv6_addr_prefix() then copies prefix_len/8 bytes out of rinfo->prefix, so a Router Advertisement with (prefix_len=128, length=2) or (prefix_len=64, length=1) makes the kernel read up to 8 bytes past the end of the option. Those bytes end up in the prefix of the route that gets installed, so they are visible to userspace:

# RA with a Route Information option (prefix_len=128, length=2)

  # followed by a source link-layer address option, 01 01 de ad be ef ca fe
  $ ip -6 route show
  2001:db8:dead:beef:101:dead:beef:cafe via fe80::1234 dev veth0 proto ra
                     ^^^^^^^^^^^^^^^^^^ the next option, read out of bounds

When the Route Information option is the last one in the packet, those eight bytes come from the skb tail room instead.

Reject the option lengths RFC 4191 does not allow.

Fixes 70ceb4f53929 ("[IPV6]: ROUTE: Add experimental support for Route Information Option in RA (RFC4191).")
---
 net/ipv6/route.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
net/ipv6/route.c +4 -4
@@ -942,13 +942,13 @@ int rt6_route_rcv(struct net_device *dev
 	} else if (rinfo->prefix_len > 128) {
 		return -EINVAL;
 	} else if (rinfo->prefix_len > 64) {
-		if (rinfo->length < 2) {
+		/* RFC 4191: Length MUST be 3 when Prefix Length > 64 */
+		if (rinfo->length < 3)
 			return -EINVAL;
-		}
 	} else if (rinfo->prefix_len > 0) {
-		if (rinfo->length < 1) {
+		/* RFC 4191: Length MUST be 2 or 3 when Prefix Length > 0 */
+		if (rinfo->length < 2)
 			return -EINVAL;
-		}
 	}
 
 	pref = rinfo->route_pref;
author maintainer
#380 lore raw

PATCH 380/389 ip6_tunnel: clear skb2->cb[] in ip6ip6_err()

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhiling Zou <[email protected]>

commit f803c086399da277b5d0ff36a107d0f162751800 upstream.

ip6ip6_err() clones an outer IPv6 ICMP error skb, pulls it to the quoted inner IPv6 packet, and then passes the clone to icmpv6_send(). The clone still carries the outer packet's inet6_skb_parm in skb->cb.

If the outer packet had a Home Address Option, IP6CB(skb2)->dsthao remains non-zero after skb_pull(). icmpv6_send() later calls mip6_addr_swap(), which uses that stale dsthao offset against the quoted inner packet. A malformed inner destination-options header can then make the HAO lookup and address swap run past the end of the quoted packet and corrupt skb_shared_info.

Clear skb2->cb[] before pulling the quoted inner IPv6 packet so the reply path does not reuse metadata left by the outer IPv6 stack.

---
 net/ipv6/ip6_tunnel.c |    3 +++
 1 file changed, 3 insertions(+)
net/ipv6/ip6_tunnel.c +3 -0
@@ -708,6 +708,9 @@ ip6ip6_err(struct sk_buff *skb, struct i
 		if (!skb2)
 			return 0;
 
+		/* Remove debris left by outer IPv6 stack. */
+		memset(IP6CB(skb2), 0, sizeof(*IP6CB(skb2)));
+
 		skb_dst_drop(skb2);
 		skb_pull(skb2, offset);
 		skb_reset_network_header(skb2);
author maintainer
#381 lore raw

PATCH 381/389 bpf, sockmap: Fix sk_redir use-after-free in send verdict

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chengfeng Ye <[email protected]>

commit a76624733730e541e4955fdecf506af2f6b20558 upstream.

sk_psock_msg_verdict() takes a socket reference for psock->sk_redir. tcp_bpf_send_verdict() copies that pointer while holding the source socket lock, but does not take a reference for the local copy before dropping the lock around tcp_bpf_sendmsg_redir().

When apply_bytes keeps the cached verdict active, another sendmsg() on the same source socket can consume the remaining bytes and release the cached reference while the first thread still holds only the raw local pointer:

CPU 0 CPU 1
sk_redir = psock->sk_redir
apply_bytes remains nonzero
release_sock(sk)
lock_sock(sk) apply_bytes reaches zero psock->sk_redir = NULL release_sock(sk) tcp_bpf_sendmsg_redir(sk_redir) sock_put(sk_redir)
tcp_bpf_sendmsg_redir(sk_redir)

The final sock_put() can free sk_redir before CPU 0 dereferences it.

KASAN reported:

  BUG: KASAN: slab-use-after-free in tcp_bpf_sendmsg_redir+0xf39/0x1020
  Read of size 8 at addr ffff888108537090 by task poc/87
  Call Trace:
   tcp_bpf_sendmsg_redir+0xf39/0x1020
   tcp_bpf_sendmsg+0x977/0x1a50
   __sys_sendto+0x32c/0x3a0
   __x64_sys_sendto+0xdb/0x1b0
  Allocated by task 85:
   sk_prot_alloc+0x56/0x210
   sk_clone+0x6f/0x14b0
   inet_csk_clone_lock+0x24/0x740
   tcp_create_openreq_child+0x25/0x2710
   tcp_v4_syn_recv_sock+0x10a/0xe00
  Freed by task 0:
   __kasan_slab_free+0x43/0x70
   slab_free_after_rcu_debug+0xa6/0x1e0
   rcu_core+0x50a/0x1850
  Last potentially related work creation:
   __sk_destruct+0x3da/0x540
   sk_psock_destroy+0x81e/0xab0
   process_one_work+0x63a/0x1070

Take a temporary socket reference while the source socket lock still protects psock->sk_redir, and drop it after tcp_bpf_sendmsg_redir() returns. This keeps each unlocked use independent of cached-verdict ownership.

---
 net/ipv4/tcp_bpf.c |    2 ++
 1 file changed, 2 insertions(+)
net/ipv4/tcp_bpf.c +2 -0
@@ -370,6 +370,7 @@ more_data:
 		break;
 	case __SK_REDIRECT:
 		sk_redir = psock->sk_redir;
+		sock_hold(sk_redir);
 		sk_msg_apply_bytes(psock, tosend);
 		if (!psock->apply_bytes) {
 			/* Clean up before releasing the sock lock. */
@@ -389,6 +390,7 @@ more_data:
 
 		if (eval == __SK_REDIRECT)
 			sock_put(sk_redir);
+		sock_put(sk_redir);
 
 		lock_sock(sk);
 		sk_mem_uncharge(sk, sent);
author maintainer
#382 lore raw

PATCH 382/389 scsi: scsi_debug: Negate wrapped memcmp() result

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Xu Rao <[email protected]>

commit c4f6916a99cf105c3ff340b6210fcbba3fa66b35 upstream.

comp_write_worker() returns true when the compared data matches. memcmp() returns zero for equal data and non-zero for different data, so its result must be negated before it is stored in a bool.

The first segment already uses !memcmp(), but the wrapped segment uses memcmp() directly, reversing the match result. Use !memcmp() there as well.

Fixes 38d5c8336e60 ("scsi_debug: add Report supported opcodes+tmfs; Compare and write")
---
 drivers/scsi/scsi_debug.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/scsi_debug.c +2 -2
@@ -3004,8 +3004,8 @@ static bool comp_write_worker(struct sde
 	if (!res)
 		return res;
 	if (rest)
-		res = memcmp(fsp, arr + ((num - rest) * lb_size),
-			     rest * lb_size);
+		res = !memcmp(fsp, arr + ((num - rest) * lb_size),
+			      rest * lb_size);
 	if (!res)
 		return res;
 	if (compare_only)
author maintainer
#383 lore raw

PATCH 383/389 sctp: keep chunk->transport in step with the list it is queued on

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Baul Lee <[email protected]>

commit 9f2cf069a9a72a2d6b97ca8b4c70e714aac99749 upstream.

__sctp_outq_flush_rtx() moves a gap-acked chunk onto another transport's transmitted list without updating chunk->transport:

	if (chunk->tsn_gap_acked) {
		list_move_tail(&chunk->transmitted_list,
			       &transport->transmitted);
		continue;
	}

The chunk then sits on a live transport's list while chunk->transport still names a different one. If that transport is removed - sctp_assoc_rm_peer() from an ASCONF Delete-IP - sctp_transport_free() RCU-frees it and the chunk is left with a dangling pointer. sctp_assoc_rm_peer() scrubs peer->transmitted and asoc->outqueue.out_chunk_list, but the chunk is on neither.

The pointer is not followed while tsn_gap_acked is set. A SACK that reneges on the TSN clears the flag, and the next SACK reaches

	tchunk->transport->flight_size -= sctp_data_size(tchunk);

inside the freed transport. KASAN reports a slab-use-after-free read in sctp_check_transmitted(), freed from sctp_assoc_rm_peer(). Both the removal and the SACKs come from the association peer.

Set chunk->transport at the move. The ordinary resend path needs nothing:
it reaches its list_move_tail() only after sctp_packet_append_chunk() returned SCTP_XMIT_OK, and __sctp_packet_append_chunk() has rebound the chunk by then.

Discovered by XBOW, triaged by Baul Lee <[email protected]>

---
 net/sctp/outqueue.c |    1 +
 1 file changed, 1 insertion(+)
net/sctp/outqueue.c +1 -0
@@ -647,6 +647,7 @@ static int __sctp_outq_flush_rtx(struct
 		if (chunk->tsn_gap_acked) {
 			list_move_tail(&chunk->transmitted_list,
 				       &transport->transmitted);
+			chunk->transport = transport;
 			continue;
 		}
 
author maintainer
#384 lore raw

PATCH 384/389 sctp: fix use-after-free of cached ASCONF chunk

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yuxiang Yang <[email protected]>

commit 8c283e7b56adce00193837f3311b06662466fb21 upstream.

addip_last_asconf caches the outstanding outbound ASCONF chunk. The normal ASCONF-ACK completion path releases the chunk and clears the pointer.

However, sctp_asconf_queue_teardown() releases the cached chunk without clearing addip_last_asconf. During peer restart handling, sctp_sf_do_dupcook_a() queues SCTP_CMD_PURGE_ASCONF_QUEUE, which invokes sctp_asconf_queue_teardown() while the association remains alive and leaves the pointer dangling.

A delayed authenticated ASCONF-ACK can then reach sctp_sf_do_asconf_ack(), which accesses the stale chunk and passes it to sctp_process_asconf_ack(), causing a use-after-free and a second release.

Clearing the pointer exposes a race with T4 expiry. Peer restart handling queues the timer stop before the purge, but SCTP_CMD_TIMER_STOP uses timer_delete(), which does not wait for a callback already running on another CPU. Such a callback can reach sctp_sf_t4_timer_expire() after the purge and dereference NULL.

Clear addip_last_asconf after releasing the cached chunk, and make sctp_sf_t4_timer_expire() consume a stale T4 expiry if no outstanding ASCONF remains.

Fixes a000c01e60e4 ("sctp: stop pending timers and purge queues when peer restart asoc")
---
 net/sctp/associola.c    |    4 +++-
 net/sctp/sm_statefuns.c |    6 +++++-
 2 files changed, 8 insertions(+), 2 deletions(-)
net/sctp/associola.c +3 -1
@@ -1722,6 +1722,8 @@ void sctp_asconf_queue_teardown(struct s
 	sctp_assoc_free_asconf_queue(asoc);
 
 	/* Free any cached ASCONF chunk. */
-	if (asoc->addip_last_asconf)
+	if (asoc->addip_last_asconf) {
 		sctp_chunk_free(asoc->addip_last_asconf);
+		asoc->addip_last_asconf = NULL;
+	}
 }
net/sctp/sm_statefuns.c +5 -1
@@ -5999,8 +5999,12 @@ enum sctp_disposition sctp_sf_t4_timer_e
 					struct sctp_cmd_seq *commands)
 {
 	struct sctp_chunk *chunk = asoc->addip_last_asconf;
-	struct sctp_transport *transport = chunk->transport;
+	struct sctp_transport *transport;
 
+	if (!chunk)
+		return SCTP_DISPOSITION_CONSUME;
+
+	transport = chunk->transport;
 	SCTP_INC_STATS(net, SCTP_MIB_T4_RTO_EXPIREDS);
 
 	/* ADDIP 4.1 B1) Increment the error counters and perform path failure
author maintainer
#385 lore raw

PATCH 385/389 sctp: clear new_transport when removing a peer

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Qing Ming <[email protected]>

commit beb33f8ee1ca83acddb2a5ae80f3d22ec550b4c3 upstream.

sctp_process_asconf_param() stores a newly added peer transport in asoc->new_transport. After all parameters in the ASCONF chunk have been processed, sctp_sf_do_asconf() uses this pointer to send a HEARTBEAT to the new transport.

An authenticated ASCONF from a remote SCTP peer can add a transport and remove it again with a wildcard DEL-IP parameter in the same chunk. The wildcard deletion preserves the transport on which the ASCONF arrived, but removes the newly added transport through sctp_assoc_del_nonprimary_peers(). The removal does not clear asoc->new_transport, leaving it pointing to the removed transport.

sctp_sf_do_asconf() then creates a HEARTBEAT whose chunk->transport points to the removed transport without holding a transport reference. During local address replacement, src_out_of_asoc_ok keeps this HEARTBEAT on control_chunk_list. After the transport is freed by RCU, a successful ASCONF_ACK for the replacement address releases the queued HEARTBEAT and sctp_outq_select_transport() reads the freed transport's state.

The issue was found during a static audit of SCTP objects. With an authenticated peer, the reproducer triggered the same KASAN report in 2 of 2 unpatched runs on a KASAN-enabled netdev/main kernel:

  BUG: KASAN: slab-use-after-free in sctp_outq_select_transport
  Read of size 4 at addr ffff88800b9bd95c by task python3/197

  Call Trace:
   sctp_outq_select_transport+0x549/0x8b0 [sctp]
   sctp_outq_flush+0x306/0x2c60 [sctp]
   sctp_transport_immediate_rtx+0xaf/0x260 [sctp]
   sctp_process_asconf_ack+0xa48/0xf70 [sctp]

  Allocated by task 197:
   sctp_transport_new+0x68/0x650 [sctp]
   sctp_assoc_add_peer+0x258/0x12a0 [sctp]
   sctp_process_asconf+0x5e9/0x1090 [sctp]

  Last potentially related work creation:
   __call_rcu_common.constprop.0+0x77/0xb70
   sctp_assoc_del_nonprimary_peers+0x7c/0xd0 [sctp]
   sctp_process_asconf+0xd9c/0x1090 [sctp]

The first invalid access was a four-byte read of transport->state at net/sctp/outqueue.c:833. The same reproducer completed the full authenticated ASCONF and local-address replacement sequence with this change without a KASAN report or oops.

Clear new_transport when its peer is removed, before it can be used to create the HEARTBEAT.

---
 net/sctp/associola.c |    3 +++
 1 file changed, 3 insertions(+)
net/sctp/associola.c +3 -0
@@ -542,6 +542,9 @@ void sctp_assoc_rm_peer(struct sctp_asso
 	    asoc->addip_last_asconf->transport == peer)
 		asoc->addip_last_asconf->transport = NULL;
 
+	if (asoc->new_transport == peer)
+		asoc->new_transport = NULL;
+
 	/* If we have something on the transmitted list, we have to
 	 * save it off.  The best place is the active path.
 	 */
author maintainer
#386 lore raw

PATCH 386/389 thunderbolt: Bound the DROM dual link port number before indexing sw->ports

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Bryam Vargas <[email protected]>

commit d6764992f17b23d91ff93ce905ab53c2aa7191f0 upstream.

tb_drom_parse_entry_port() validates the device-supplied header->index against sw->config.max_port_number before indexing sw->ports[], but the sibling field entry->dual_link_port_nr -- a 6-bit value also read from the DROM -- indexes the same array with no such check. A malicious or malformed Thunderbolt device can set dual_link_port_nr beyond the allocated sw->ports[] (max_port_number + 1 entries), producing an out-of-bounds tb_port pointer that is stored and later dereferenced.

Reject a port entry whose dual_link_port_nr exceeds max_port_number, the same bound already applied to header->index.

Fixes cd22e73bdf5e ("thunderbolt: Read port configuration from eeprom.")
---
 drivers/thunderbolt/eeprom.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/thunderbolt/eeprom.c +8 -1
@@ -367,9 +367,16 @@ static int tb_drom_parse_entry_port(stru
 			return -EIO;
 		}
 		port->link_nr = entry->link_nr;
-		if (entry->has_dual_link_port)
+		if (entry->has_dual_link_port) {
+			if (entry->dual_link_port_nr > sw->config.max_port_number) {
+				tb_sw_warn(sw,
+					"port entry has invalid dual link port number %u\n",
+					entry->dual_link_port_nr);
+				return -EIO;
+			}
 			port->dual_link_port =
 				&port->sw->ports[entry->dual_link_port_nr];
+		}
 	}
 	return 0;
 }
author maintainer
#387 lore raw

PATCH 387/389 prestera: fix fallback to previous version on same major version

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jonas Gorski <[email protected]>

commit b755c25fbcd568821a3bb0e0d5c2daa5fcb00bba upstream.

When both supported and previous version have the same major version, and the firmwares are missing, the driver ends in a loop requesting the same (previous) version over and over again:

    [   76.327413] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.1.img firmware, fall-back to previous 4.0 version
    [   76.339802] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version
    [   76.352162] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version
    [   76.364502] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version
    [   76.376848] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version
    [   76.389183] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version
    [   76.401522] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version
    [   76.413860] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version
    [   76.426199] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.0.img firmware, fall-back to previous 4.0 version
    ...

Fix this by inverting the check to that we aren't yet at the previous version, and also check the minor version.

This also catches the case where both versions are the same, as it was after commit bb5dbf2cc64d ("net: marvell: prestera: add firmware v4.0 support").

With this fix applied:

    [   88.499622] Prestera DX 0000:01:00.0: missing latest mrvl/prestera/mvsw_prestera_fw-v4.1.img firmware, fall-back to previous 4.0 version
    [   88.511995] Prestera DX 0000:01:00.0: failed to request previous firmware: mrvl/prestera/mvsw_prestera_fw-v4.0.img
    [   88.522403] Prestera DX: probe of 0000:01:00.0 failed with error -2
---
 drivers/net/ethernet/marvell/prestera/prestera_pci.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/marvell/prestera/prestera_pci.c +2 -1
@@ -629,7 +629,8 @@ pick_fw_ver:
 
 	err = request_firmware_direct(&fw->bin, fw_path, fw->dev.dev);
 	if (err) {
-		if (ver_maj == PRESTERA_SUPP_FW_MAJ_VER) {
+		if (ver_maj != PRESTERA_PREV_FW_MAJ_VER ||
+		    ver_min != PRESTERA_PREV_FW_MIN_VER) {
 			ver_maj = PRESTERA_PREV_FW_MAJ_VER;
 			ver_min = PRESTERA_PREV_FW_MIN_VER;
 
author maintainer
#388 lore raw

PATCH 388/389 hwmon: (adt7470) Add missing dependency on REGMAP_I2C

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Javier Carrasco <[email protected]>

commit b6abcc19566509ab4812bd5ae5df46515d0c1d70 upstream.

This driver requires REGMAP_I2C to be selected in order to get access to regmap_config and devm_regmap_init_i2c. Add the missing dependency.

Fixes ef67959c4253 ("hwmon: (adt7470) Convert to use regmap")

Message-ID: <[email protected]>

---
 drivers/hwmon/Kconfig |    1 +
 1 file changed, 1 insertion(+)
drivers/hwmon/Kconfig +1 -0
@@ -239,6 +239,7 @@ config SENSORS_ADT7462
 config SENSORS_ADT7470
 	tristate "Analog Devices ADT7470"
 	depends on I2C
+	select REGMAP_I2C
 	help
 	  If you say yes here you get support for the Analog Devices
 	  ADT7470 temperature monitoring chips.
author maintainer
#389 lore raw

PATCH 389/389 hwmon: (adt7470) Fix fans stuck in manual mode on I2C errors

In reply to Greg Kroah-Hartman

5.10-stable review patch. If anyone has any objections, please let me know.

------------------

From: Luiz Angelo Daros de Luca <[email protected]>

commit 625a2c02a1c04571232a746fe188b4d9a8d63edd upstream.

During adt7470_read_temperatures(), the driver temporarily switches the PWM channels to manual mode, performs the temperature collection, and then restores the original configuration registers.

However, if an I2C transaction fails at any point after entering manual mode, the function aborts and returns immediately. This leaves the configuration registers un-restored, permanently trapping the fans in manual mode.

Introduce a recovery path to ensure that the original PWM configuration registers are always restored, even when intermediate I2C operations fail.

---
 drivers/hwmon/adt7470.c |   40 +++++++++++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 11 deletions(-)
drivers/hwmon/adt7470.c +29 -11
@@ -205,11 +205,12 @@ static inline int adt7470_write_word_dat
 /* Probe for temperature sensors.  Assumes lock is held */
 static int adt7470_read_temperatures(struct adt7470_data *data)
 {
-	unsigned long res;
+	struct device *dev = regmap_get_device(data->regmap);
+	u8 pwm[ADT7470_FAN_COUNT];
 	unsigned int pwm_cfg[2];
-	int err;
+	unsigned long res;
+	int err, err2;
 	int i;
-	u8 pwm[ADT7470_FAN_COUNT];
 
 	/* save pwm[1-4] config register */
 	err = regmap_read(data->regmap, ADT7470_REG_PWM_CFG(0), &pwm_cfg[0]);
@@ -233,19 +234,19 @@ static int adt7470_read_temperatures(str
 	err = regmap_update_bits(data->regmap, ADT7470_REG_PWM_CFG(2),
 				 ADT7470_PWM_AUTO_MASK, 0);
 	if (err < 0)
-		return err;
+		goto out_restore;
 
 	/* write pwm control to whatever it was */
 	err = regmap_bulk_write(data->regmap, ADT7470_REG_PWM(0), &pwm[0],
 				ADT7470_PWM_COUNT);
 	if (err < 0)
-		return err;
+		goto out_restore;
 
 	/* start reading temperature sensors */
 	err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
 				 ADT7470_T05_STB_MASK, ADT7470_T05_STB_MASK);
 	if (err < 0)
-		return err;
+		goto out_restore;
 
 	/* Delay is 200ms * number of temp sensors. */
 	res = msleep_interruptible((data->num_temp_sensors >= 0 ?
@@ -256,13 +257,30 @@ static int adt7470_read_temperatures(str
 	err = regmap_update_bits(data->regmap, ADT7470_REG_CFG,
 				 ADT7470_T05_STB_MASK, 0);
 	if (err < 0)
-		return err;
+		goto out_restore;
 
+out_restore:
 	/* restore pwm[1-4] config registers */
-	err = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]);
-	if (err < 0)
-		return err;
-	err = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
+	err2 = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]);
+	if (err2 < 0) {
+		dev_warn_ratelimited(dev,
+				     "failed to restore PWM{1,2} config (%d)\n",
+				     err2);
+
+		if (!err)
+			err = err2;
+	}
+
+	err2 = regmap_write(data->regmap, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]);
+	if (err2 < 0) {
+		dev_warn_ratelimited(dev,
+				     "failed to restore PWM{3,4} config (%d)\n",
+				     err2);
+
+		if (!err)
+			err = err2;
+	}
+
 	if (err < 0)
 		return err;
 
Tested-by on the v1 series
#390 lore raw
In reply to Greg Kroah-Hartman

Hi!

Quoted 4 lines

This is the start of the stable review cycle for the 5.10.265 release. There are 389 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.

I'll likely have comments about some of the patches in near future.

CIP testing did not find any problems here:

https://gitlab.com/cip-project/cip-testing/linux-stable-rc-ci/-/tree/linux-5.10.y

Best regards,
Pavel

Tested-by on the v1 series
#391 lore raw
In reply to Greg Kroah-Hartman
Quoted 9 lines · Greg Kroah-Hartman

This is the start of the stable review cycle for the 5.10.265 release. There are 389 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.

Responses should be made by Wed, 19 Aug 2026 13:23:44 +0000. Anything received after that time might be too late.

The whole patch series can be found in one patch at:

Quoted 8 lines
	https://www.kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.10.265-rc1.gz

or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-5.10.y
and the diffstat can be found below.

thanks,

greg k-h

On ARCH_BRCMSTB using 32-bit and 64-bit ARM kernels, build tested on BMIPS_GENERIC:

Signature · 1 line
Florian
Tested-by on the v1 series
#392 lore raw
In reply to Greg Kroah-Hartman

Greg Kroah-Hartman wrote on Mon, Aug 17, 2026 at 03:27:19PM +0200:

Quoted 5 lines

This is the start of the stable review cycle for the 5.10.265 release. There are 389 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.

Quoted 8 lines

Responses should be made by Wed, 19 Aug 2026 13:23:44 +0000. Anything received after that time might be too late.

The whole patch series can be found in one patch at:

	https://www.kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.10.265-rc1.gz

or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-5.10.y
and the diffstat can be found below.

Tested d2f1aa5b909d ("Linux 5.10.265-rc1") on:
- arm i.MX6ULL (Armadillo 640)
- arm64 i.MX8MP (Armadillo G4)
- arm64 i.MX8ULP (Armadillo IoT A9E)

No obvious regression in dmesg or basic tests:

Signature · 1 line
Dominique Martinet
Tested-by on the v1 series
#393 lore raw
In reply to Greg Kroah-Hartman
Quoted 9 lines · Greg Kroah-Hartman

This is the start of the stable review cycle for the 5.10.265 release. There are 389 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.

Responses should be made by Wed, 19 Aug 2026 13:23:44 +0000. Anything received after that time might be too late.

The whole patch series can be found in one patch at:

Quoted 8 lines
	https://www.kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.10.265-rc1.gz

or in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-5.10.y
and the diffstat can be found below.

thanks,

greg k-h

Tested on an amd64 laptop (Lenovo ThinkPad T14 Gen 1). Working well, no regressions observed.

Signature · 1 line
-Barry K. Nathan  <[email protected]>
Tested-by on the v1 series
#394 lore raw
In reply to Greg Kroah-Hartman
Quoted 6 lines · Greg Kroah-Hartman

This is the start of the stable review cycle for the 5.10.265 release. There are 389 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.

Built OK on i386, rested boot, no new issues noticed on 23-bit EeePC