Skip to contentSkip to conversation

6.1.178-rc1 review

PATCH In review Greg Kroah-Hartman 10 participants 1,078 messages Jul 21 – Jul 22 Page 4 of 9

Subsystems (6)
lore
Share & tools
lore
author maintainer
#383 lore raw

PATCH 379/1067 ocfs2/dlm: require a ref for locking_state debugfs open

In reply to Greg Kroah-Hartman

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

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

From: Zhang Cen <[email protected]>

[ Upstream commit 03ad858ce8064861ea580021976dc19b7aabb549 ]

debug_lockres_open() copies inode->i_private into struct debug_lockres and debug_lockres_release() later drops that pointer with dlm_put(). That only works if open successfully pins the struct dlm_ctxt.

Today open calls dlm_grab(dlm) but ignores its return value. Once the last domain unregister has removed the context from dlm_domains, dlm_grab() returns NULL, yet open still stores the raw pointer and returns success. The later release path is outside the debugfs removal barrier, so it can call dlm_put() after dlm_free_ctxt_mem() has freed the context. KASAN reports this as a slab-use-after-free in dlm_put() called from debug_lockres_release().

Fail the open when dlm_grab() cannot acquire the reference and unwind the seq_file private state before returning. That keeps locking_state from handing out a file descriptor whose release path does not own the dlm_ctxt.

The buggy scenario involves two paths, with each column showing the order within that path:

locking_state debugfs open: last domain unregister:
1. debug_lockres_open() reads 1. dlm_unregister_domain() calls
inode->i_private. dlm_complete_dlm_shutdown().
2. debug_lockres_open() calls 2. shutdown removes the dlm_ctxt from
dlm_grab(dlm) and gets NULL. dlm_domains.
3. open still stores the raw dlm 3. final teardown reaches
pointer in dl->dl_ctxt and dlm_free_ctxt_mem() and frees it.
returns success.
4. debug_lockres_release() later
calls dlm_put(dl->dl_ctxt).

Validation reproduced this kernel report:
KASAN slab-use-after-free in dlm_put+0x82/0x200

RIP: 0033:0x7f4d349bc9e0
The buggy address belongs to the object at ffff888103a3c000 which belongs
to the cache kmalloc-2k of size 2048
The buggy address is located 816 bytes inside of freed 2048-byte region
[ffff888103a3c000, ffff888103a3c800)
Write of size 4
Call trace:
  dump_stack_lvl+0x66/0xa0 (?:?)
  print_report+0xd0/0x630 (?:?)
  dlm_put+0x82/0x200 (?:?)
  srso_alias_return_thunk+0x5/0xfbef5 (?:?)
  __virt_addr_valid+0x188/0x2f0 (?:?)
  kasan_report+0xe4/0x120 (?:?)
  kasan_check_range+0x105/0x1b0 (?:?)
  debug_lockres_release+0x53/0x80 (fs/ocfs2/dlm/dlmdebug.c:587)
  dlm_put+0x9/0x200 (?:?)
  debug_lockres_release+0x5c/0x80 (fs/ocfs2/dlm/dlmdebug.c:587)
  full_proxy_release+0x67/0x90 (?:?)
  __fput+0x1df/0x4b0 (?:?)
  do_raw_spin_lock+0x10f/0x1b0 (?:?)
  fput_close_sync+0xd2/0x170 (?:?)
  __x64_sys_close+0x55/0x90 (?:?)
  do_syscall_64+0x10c/0x640 (arch/x86/entry/syscall_64.c:87)
  irqentry_exit+0xac/0x6e0 (?:?)
  entry_SYSCALL_64_after_hwframe+0x77/0x7f (?:?)
Freed by task stack:
  kasan_save_stack+0x33/0x60 (?:?)
  kasan_save_track+0x14/0x30 (?:?)
  kasan_save_free_info+0x3b/0x60 (?:?)
  __kasan_slab_free+0x5f/0x80 (?:?)
  kfree+0x30f/0x580 (?:?)
  dlm_put+0x1ce/0x200 (?:?)
  dlm_unregister_domain+0xf6/0xb30 (?:?)
  o2cb_cluster_disconnect+0x6b/0x90 (?:?)
  ocfs2_cluster_disconnect+0x41/0x70 (?:?)
  ocfs2_dlm_shutdown+0x1c4/0x220 (?:?)
  ocfs2_dismount_volume+0x38a/0x550 (?:?)
  generic_shutdown_super+0xc3/0x220 (?:?)
  kill_block_super+0x29/0x60 (?:?)
  deactivate_locked_super+0x66/0xe0 (?:?)
  cleanup_mnt+0x13d/0x210 (?:?)
  task_work_run+0xfa/0x170 (?:?)
  exit_to_user_mode_loop+0xd6/0x430 (?:?)
  do_syscall_64+0x3cb/0x640 (arch/x86/entry/syscall_64.c:87)
  entry_SYSCALL_64_after_hwframe+0x77/0x7f (?:?)
Fixes 4e3d24ed1a12 ("ocfs2/dlm: Dumps the lockres' into a debugfs file")
Assisted-by Codex:gpt-5.5
Cc Mark Fasheh <[email protected]>
Cc Joel Becker <[email protected]>
Cc Junxiao Bi <[email protected]>
Cc Changwei Ge <[email protected]>
Cc Jun Piao <[email protected]>
Cc Heming Zhao <[email protected]>
---
 fs/ocfs2/dlm/dlmdebug.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)
fs/ocfs2/dlm/dlmdebug.c +12 -4
index be5e9ed7da8d94..e62ed98df7de4b 100644
@@ -612,6 +612,7 @@ static int debug_lockres_open(struct inode *inode, struct file *file)
 	struct dlm_ctxt *dlm = inode->i_private;
 	struct debug_lockres *dl;
 	void *buf;
+	int status = -ENOMEM;
 
 	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 	if (!buf)
@@ -624,16 +625,23 @@ static int debug_lockres_open(struct inode *inode, struct file *file)
 	dl->dl_len = PAGE_SIZE;
 	dl->dl_buf = buf;
 
-	dlm_grab(dlm);
-	dl->dl_ctxt = dlm;
+	/* ->release uses dl_ctxt after open, so it needs a real pin. */
+	dl->dl_ctxt = dlm_grab(dlm);
+	if (!dl->dl_ctxt) {
+		status = -ENOENT;
+		goto bailseq;
+	}
 
 	return 0;
 
+bailseq:
+	seq_release_private(inode, file);
 bailfree:
 	kfree(buf);
 bail:
-	mlog_errno(-ENOMEM);
-	return -ENOMEM;
+	if (status != -ENOENT)
+		mlog_errno(status);
+	return status;
 }
 
 static int debug_lockres_release(struct inode *inode, struct file *file)
Signature · 1 line
2.53.0
author maintainer
#384 lore raw

PATCH 380/1067 ocfs2: fix race between ocfs2_control_install_private() and ocfs2_control_release()

In reply to Greg Kroah-Hartman

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

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

From: Joseph Qi <[email protected]>

[ Upstream commit 57dcfd9049d497c31151787a0696d59f0a98f8e6 ]

Move atomic_inc(&ocfs2_control_opened) and the handshake state update inside ocfs2_control_lock to close a race window where ocfs2_control_release() can observe ocfs2_control_opened dropping to zero (resetting ocfs2_control_this_node and running_proto) while ocfs2_control_install_private() is about to bump the counter and mark the connection valid.

Fixes 3cfd4ab6b6b4 ("ocfs2: Add the local node id to the handshake.")
Cc Mark Fasheh <[email protected]>
Cc Joel Becker <[email protected]>
Cc Junxiao Bi <[email protected]>
Cc Changwei Ge <[email protected]>
Cc Jun Piao <[email protected]>
Cc Heming Zhao <[email protected]>
---
 fs/ocfs2/stack_user.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)
fs/ocfs2/stack_user.c +3 -7
index e28905e58bd6a0..895ab1222fc3e0 100644
@@ -326,18 +326,14 @@ static int ocfs2_control_install_private(struct file *file)
 		ocfs2_control_this_node = p->op_this_node;
 		running_proto.pv_major = p->op_proto.pv_major;
 		running_proto.pv_minor = p->op_proto.pv_minor;
-	}
-
-out_unlock:
-	mutex_unlock(&ocfs2_control_lock);
-
-	if (!rc && set_p) {
-		/* We set the global values successfully */
 		atomic_inc(&ocfs2_control_opened);
 		ocfs2_control_set_handshake_state(file,
 					OCFS2_CONTROL_HANDSHAKE_VALID);
 	}
 
+out_unlock:
+	mutex_unlock(&ocfs2_control_lock);
+
 	return rc;
 }
 
Signature · 1 line
2.53.0
author maintainer
#385 lore raw

PATCH 381/1067 netfilter: nfnetlink_osf: fix mss parsing on big-endian architectures

In reply to Greg Kroah-Hartman

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

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

From: Fernando Fernandez Mancera <[email protected]>

[ Upstream commit a625c94144c9b66d32e1f374f909f38db46161c1 ]

The MSS calculation in nf_osf_match_one() manually shifts bytes to construct a 16-bit value before passing it to ntohs().

This works on little-endian hosts but it does not work on big-endian as the bytes are being always shifted and set in the same way for all architectures.

Use get_unaligned_be16() to fix this on big-endian systems. It also simplifies the code.

Fixes 11eeef41d5f6 ("netfilter: passive OS fingerprint xtables match")
---
 net/netfilter/nfnetlink_osf.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
net/netfilter/nfnetlink_osf.c +1 -5
index 6d3dfbeb398cb4..b61656cb0f3eb5 100644
@@ -95,11 +95,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb,
 
 			switch (*optp) {
 			case OSFOPT_MSS:
-				mss = optp[3];
-				mss <<= 8;
-				mss |= optp[2];
-
-				mss = ntohs((__force __be16)mss);
+				mss = get_unaligned_be16(&optp[2]);
 				break;
 			case OSFOPT_TS:
 				break;
Signature · 1 line
2.53.0
author maintainer
#386 lore raw

PATCH 382/1067 netfilter: synproxy: protect nf_ct_seqadj_init() with conntrack lock

In reply to Greg Kroah-Hartman

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

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

From: Fernando Fernandez Mancera <[email protected]>

[ Upstream commit 9e37388b8070afe73d4ab2d973b28593ed65f3ad ]

nf_ct_seqadj_init() is called without holding the ct lock. This can race with nf_ct_seq_adjust() when a connection is in CLOSE state due to an RST or connection reopening. In addition for SYN_RECV state, concurrent processing of packets can trigger nf_ct_seq_adjust() too. These situations create a read/write data race.

As synproxy is the only user of nf_ct_seqadj_init() at the moment, fix this by holding ct->lock inside nf_ct_seqadj_init() until all is done.

Fixes 48b1de4c110a ("netfilter: add SYNPROXY core/target")
---
 net/netfilter/nf_conntrack_seqadj.c | 2 ++
 1 file changed, 2 insertions(+)
net/netfilter/nf_conntrack_seqadj.c +2 -0
index 7ab2b25b57bcc0..b7e99f34dfce86 100644
@@ -17,12 +17,14 @@ int nf_ct_seqadj_init(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
 	if (off == 0)
 		return 0;
 
+	spin_lock_bh(&ct->lock);
 	set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
 
 	seqadj = nfct_seqadj(ct);
 	this_way = &seqadj->seq[dir];
 	this_way->offset_before	 = off;
 	this_way->offset_after	 = off;
+	spin_unlock_bh(&ct->lock);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(nf_ct_seqadj_init);
Signature · 1 line
2.53.0
author maintainer
#387 lore raw

PATCH 383/1067 netfilter: conntrack: call nf_ct_gre_keymap_destroy() if master helper is pptp

In reply to Greg Kroah-Hartman

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

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

From: Pablo Neira Ayuso <[email protected]>

[ Upstream commit b0f02608fbcd607b5131cceb91fc0a035264e61c ]

For GRE flows, validate that the ct master helper (if any) is pptp before calling nf_ct_gre_keymap_destroy(), so the helper data area can be accessed safely. Note that only the pptp helper provides a .destroy callback.

Fixes e56894356f60 ("netfilter: conntrack: remove l4proto destroy hook")
---
 net/netfilter/nf_conntrack_core.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)
net/netfilter/nf_conntrack_core.c +16 -2
index 002d53ded404ec..f5c466ea1e7df7 100644
@@ -576,9 +576,23 @@ static void destroy_gre_conntrack(struct nf_conn *ct)
 {
 #ifdef CONFIG_NF_CT_PROTO_GRE
 	struct nf_conn *master = ct->master;
+	struct nf_conn_help *help;
+
+	if (!master)
+		return;
+
+	help = nfct_help(master);
+	if (help) {
+		struct nf_conntrack_helper *helper;
 
-	if (master)
-		nf_ct_gre_keymap_destroy(master);
+		rcu_read_lock();
+		helper = rcu_dereference(help->helper);
+		/* Only pptp helper has a destroy callback. */
+		if (helper && helper->destroy)
+			nf_ct_gre_keymap_destroy(master);
+
+		rcu_read_unlock();
+	}
 #endif
 }
 
Signature · 1 line
2.53.0
author maintainer
#388 lore raw

PATCH 384/1067 IB/cm: Fix av cm device leak on an error path in cm_init_av_by_path()

In reply to Greg Kroah-Hartman

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

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

From: Jason Gunthorpe <[email protected]>

[ Upstream commit 9b2207bc5cdb955bdae34b3eec80f04979e17081 ]

Codex pointed out that cm_init_av_by_path() can call cm_set_av_port() which takes a reference on the cm device, but then can immediately return error if ib_init_ah_attr_from_path() fails.

Since callers like ib_send_cm_req() put the av on the stack this leaks that cm device reference.

Re-order cm_init_av_by_path() so it doesn't touch the av until it has done all its failable work, and then update the av in one shot so it is either left alone or fully init'd.

Sashiko also pointed out that the cm_destroy_av() prior to cm_init_av_by_path() is harmful as it leaves the AV broken in the error case and thus the REJ won't send. Since cm_init_av_by_path() is now atomic it is safe to delete the cm_destroy_av(). On succees the av from cm_init_av_for_response() is cleaned up by cm_init_av_by_path(), on failure the 'goto rejected' guarentees the av is destroyed during ib_destroy_cm_id().

Fixes 76039ac9095f ("IB/cm: Protect cm_dev, cm_ports and mad_agent with kref and lock")
---
 drivers/infiniband/core/cm.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)
drivers/infiniband/core/cm.c +8 -5
index 5c336ab12ee1dc..6b277d2fa91a63 100644
@@ -514,6 +514,7 @@ static int cm_init_av_by_path(struct sa_path_rec *path,
 	struct rdma_ah_attr new_ah_attr;
 	struct cm_device *cm_dev;
 	struct cm_port *port;
+	u16 pkey_index;
 	int ret;
 
 	port = get_cm_port_from_path(path, sgid_attr);
@@ -522,12 +523,10 @@ static int cm_init_av_by_path(struct sa_path_rec *path,
 	cm_dev = port->cm_dev;
 
 	ret = ib_find_cached_pkey(cm_dev->ib_device, port->port_num,
-				  be16_to_cpu(path->pkey), &av->pkey_index);
+				  be16_to_cpu(path->pkey), &pkey_index);
 	if (ret)
 		return ret;
 
-	cm_set_av_port(av, port);
-
 	/*
 	 * av->ah_attr might be initialized based on wc or during
 	 * request processing time which might have reference to sgid_attr.
@@ -542,6 +541,8 @@ static int cm_init_av_by_path(struct sa_path_rec *path,
 	if (ret)
 		return ret;
 
+	av->pkey_index = pkey_index;
+	cm_set_av_port(av, port);
 	av->timeout = path->packet_life_time + 1;
 	rdma_move_ah_attr(&av->ah_attr, &new_ah_attr);
 	return 0;
@@ -2169,8 +2170,10 @@ static int cm_req_handler(struct cm_work *work)
 				 cm_id_priv->av.ah_attr.roce.dmac);
 	work->path[0].hop_limit = grh->hop_limit;
 
-	/* This destroy call is needed to pair with cm_init_av_for_response */
-	cm_destroy_av(&cm_id_priv->av);
+	/*
+	 * cm_init_av_by_path() will internally pair with the above
+	 * cm_init_av_for_response() if it succeeds.
+	 */
 	ret = cm_init_av_by_path(&work->path[0], gid_attr, &cm_id_priv->av);
 	if (ret) {
 		int err;
Signature · 1 line
2.53.0
author maintainer
#389 lore raw

PATCH 385/1067 RDMA/irdma: Fix OOB read during CQ MR registration

In reply to Greg Kroah-Hartman

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

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

From: Jacob Moroni <[email protected]>

[ Upstream commit 4385ddd654d90245eeb83b3cb539670ab5c85ba4 ]

Sashiko pointed out an unrelated bug during a previous patch:
https://sashiko.dev/#/patchset/20260512183852.614045-1-jmoroni%40google.com

This change fixes the bug by eliminating the cqmr->split field which was not being set properly and instead just checks the CQ resize feature flag directly.

The cqmr->split field essentially tracks whether IRDMA_FEATURE_CQ_RESIZE is set, but it was not being set until CQ creation time, which is _after_ CQ memory registration (the only other place where it is referenced).

As a result, it would always be false during MR registration and would therefore cause irdma_handle_q_mem to populate cqmr->shadow even for GEN_2 HW and beyond:

    cqmr->shadow = (dma_addr_t)arr[req->cq_pages];

The issue is that for GEN_2 and beyond, req->cq_pages may be exactly equal to iwmr->page_cnt and therefore equal to the size of arr, which would cause an OOB read by one.

Fixes b48c24c2d710 ("RDMA/irdma: Implement device supported verb APIs")
---
 drivers/infiniband/hw/irdma/verbs.c | 4 ++--
 drivers/infiniband/hw/irdma/verbs.h | 1 -
 2 files changed, 2 insertions(+), 3 deletions(-)
drivers/infiniband/hw/irdma/verbs.c +2 -2
index 8258bb2218df6f..b43ce455050c66 100644
@@ -2106,7 +2106,6 @@ static int irdma_create_cq(struct ib_cq *ibcq,
 			}
 			cqmr_shadow = &iwpbl_shadow->cq_mr;
 			info.shadow_area_pa = cqmr_shadow->cq_pbl.addr;
-			cqmr->split = true;
 		} else {
 			info.shadow_area_pa = cqmr->shadow;
 		}
@@ -2480,7 +2479,8 @@ static int irdma_handle_q_mem(struct irdma_device *iwdev,
 	case IRDMA_MEMREG_TYPE_CQ:
 		hmc_p = &cqmr->cq_pbl;
 
-		if (!cqmr->split)
+		if (!(iwdev->rf->sc_dev.hw_attrs.uk_attrs.feature_flags &
+		      IRDMA_FEATURE_CQ_RESIZE))
 			cqmr->shadow = (dma_addr_t)arr[req->cq_pages];
 
 		if (use_pbles)
drivers/infiniband/hw/irdma/verbs.h +0 -1
index 8809465020e135..ece2d66fd077af 100644
@@ -62,7 +62,6 @@ struct irdma_hmc_pble {
 struct irdma_cq_mr {
 	struct irdma_hmc_pble cq_pbl;
 	dma_addr_t shadow;
-	bool split;
 };
 
 struct irdma_qp_mr {
Signature · 1 line
2.53.0
author maintainer
#390 lore raw

PATCH 386/1067 bpf: Check tail zero of bpf_prog_info

In reply to Greg Kroah-Hartman

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

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

From: Leon Hwang <[email protected]>

[ Upstream commit 786be2b05980a5828e67fc564ad7517e2adbe9bd ]

Since there're 4 bytes padding at the end of struct bpf_prog_info, they won't be checked by bpf_check_uarg_tail_zero().

pahole -C bpf_prog_info ./vmlinux

struct bpf_prog_info {
	...
	__u32                      attach_btf_obj_id;    /*   220     4 */
	__u32                      attach_btf_id;        /*   224     4 */

	/* size: 232, cachelines: 4, members: 38 */
	/* sum members: 224 */
	/* sum bitfield members: 1 bits, bit holes: 1, sum bit holes: 31 bits */
	/* padding: 4 */
	/* forced alignments: 9 */
	/* last cacheline: 40 bytes */
} __attribute__((__aligned__(8)));

If a future kernel extension adds a new 4-byte field, older userspace programs allocating this structure on the stack might inadvertently pass uninitialized stack garbage into the new field, permanently breaking backward compatibility. -- sashiko [1]

Fix it by changing sizeof(info) to
offsetofend(struct bpf_prog_info, attach_btf_id).

And, add "__u32 :32" to the tail of struct bpf_prog_info.

[1] https://lore.kernel.org/bpf/[email protected]/

Fixes aba64c7da983 ("bpf: Add verified_insns to bpf_prog_info and fdinfo")
---
 include/uapi/linux/bpf.h       | 1 +
 kernel/bpf/syscall.c           | 5 +++--
 tools/include/uapi/linux/bpf.h | 1 +
 3 files changed, 5 insertions(+), 2 deletions(-)
include/uapi/linux/bpf.h +1 -0
index 600b10c50fdd9c..a87ca626ab1d24 100644
@@ -6239,6 +6239,7 @@ struct bpf_prog_info {
 	__u32 verified_insns;
 	__u32 attach_btf_obj_id;
 	__u32 attach_btf_id;
+	__u32 :32;
 } __attribute__((aligned(8)));
 
 struct bpf_map_info {
kernel/bpf/syscall.c +3 -2
index ed8f55bdc13703..19f7c9e17be14a 100644
@@ -3966,10 +3966,11 @@ static int bpf_prog_get_info_by_fd(struct file *file,
 	u32 info_len = attr->info.info_len;
 	struct bpf_prog_kstats stats;
 	char __user *uinsns;
-	u32 ulen;
+	u32 ulen, len;
 	int err;
 
-	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
+	len = offsetofend(struct bpf_prog_info, attach_btf_id);
+	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), len, info_len);
 	if (err)
 		return err;
 	info_len = min_t(u32, sizeof(info), info_len);
tools/include/uapi/linux/bpf.h +1 -0
index cbdc5299f6bf79..35c23bd813a125 100644
@@ -6242,6 +6242,7 @@ struct bpf_prog_info {
 	__u32 verified_insns;
 	__u32 attach_btf_obj_id;
 	__u32 attach_btf_id;
+	__u32 :32;
 } __attribute__((aligned(8)));
 
 struct bpf_map_info {
Signature · 1 line
2.53.0
author maintainer
#391 lore raw

PATCH 387/1067 bpf: Update transport_header when encapsulating UDP tunnel in lwt

In reply to Greg Kroah-Hartman

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

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

From: Leon Hwang <[email protected]>

[ Upstream commit 82d7d0adbc678064543e9d254864f6b4ea4a388c ]

Currently, bpf_lwt_push_ip_encap() does not update skb->transport_header. When a driver, e.g. ice, reuses the stale skb->transport_header to offload checksum computation to NIC hardware, VxLAN packets encapsulated by bpf_lwt_push_encap() helper may be dropped due to incorrect checksum.

Update skb->transport_header in bpf_lwt_push_ip_encap() whenever the encapsulated packet uses UDP, so checksum offload works correctly.

Fixes 52f278774e79 ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_encap")
Cc Leon Hwang <[email protected]>
---
 net/core/lwt_bpf.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
net/core/lwt_bpf.c +12 -0
index 4a0797f0a154b2..efbd9eecb00d17 100644
@@ -590,6 +590,7 @@ static int handle_gso_encap(struct sk_buff *skb, bool ipv4, int encap_len)
 
 int bpf_lwt_push_ip_encap(struct sk_buff *skb, void *hdr, u32 len, bool ingress)
 {
+	bool is_udp_tunnel;
 	struct iphdr *iph;
 	bool ipv4;
 	int err;
@@ -603,10 +604,16 @@ int bpf_lwt_push_ip_encap(struct sk_buff *skb, void *hdr, u32 len, bool ingress)
 		ipv4 = true;
 		if (unlikely(len < iph->ihl * 4))
 			return -EINVAL;
+		is_udp_tunnel = iph->protocol == IPPROTO_UDP;
+		if (unlikely(is_udp_tunnel && len < iph->ihl * 4 + sizeof(struct udphdr)))
+			return -EINVAL;
 	} else if (iph->version == 6) {
 		ipv4 = false;
 		if (unlikely(len < sizeof(struct ipv6hdr)))
 			return -EINVAL;
+		is_udp_tunnel = ((struct ipv6hdr *)iph)->nexthdr == NEXTHDR_UDP;
+		if (unlikely(is_udp_tunnel && len < sizeof(struct ipv6hdr) + sizeof(struct udphdr)))
+			return -EINVAL;
 	} else {
 		return -EINVAL;
 	}
@@ -628,6 +635,11 @@ int bpf_lwt_push_ip_encap(struct sk_buff *skb, void *hdr, u32 len, bool ingress)
 	if (ingress)
 		skb_postpush_rcsum(skb, iph, len);
 	skb_reset_network_header(skb);
+	if (is_udp_tunnel) {
+		size_t iph_sz = ipv4 ? iph->ihl * 4 : sizeof(struct ipv6hdr);
+
+		skb_set_transport_header(skb, skb_network_offset(skb) + iph_sz);
+	}
 	memcpy(skb_network_header(skb), hdr, len);
 	bpf_compute_data_pointers(skb);
 	skb_clear_hash(skb);
Signature · 1 line
2.53.0
author maintainer
#392 lore raw

PATCH 388/1067 wifi: wcn36xx: fix heap overflow from oversized firmware HAL response

In reply to Greg Kroah-Hartman

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

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

From: Tristan Madani <[email protected]>

[ Upstream commit 88a240d86d3d64521f9194abe185ac71cc74d0bd ]

The firmware response dispatcher copies all synchronous HAL responses into the 4096-byte hal_buf without validating the response length. A response exceeding WCN36XX_HAL_BUF_SIZE causes a heap buffer overflow with firmware-controlled content.

Add a bounds check on the response length.

Fixes 8e84c2582169 ("wcn36xx: mac80211 driver for Qualcomm WCN3660/WCN3680 hardware")
---
 drivers/net/wireless/ath/wcn36xx/smd.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/net/wireless/ath/wcn36xx/smd.c +4 -0
index 566f0b9c15841e..bd51abef3a5be7 100644
@@ -3353,6 +3353,10 @@ int wcn36xx_smd_rsp_process(struct rpmsg_device *rpdev,
 	case WCN36XX_HAL_EXIT_IMPS_RSP:
 	case WCN36XX_HAL_UPDATE_CHANNEL_LIST_RSP:
 	case WCN36XX_HAL_ADD_BCN_FILTER_RSP:
+		if (len > WCN36XX_HAL_BUF_SIZE) {
+			wcn36xx_warn("HAL response too large: %d\n", len);
+			break;
+		}
 		memcpy(wcn->hal_buf, buf, len);
 		wcn->hal_rsp_len = len;
 		complete(&wcn->hal_rsp_compl);
Signature · 1 line
2.53.0
author maintainer
#393 lore raw

PATCH 389/1067 wifi: wcn36xx: fix OOB read from firmware count in PRINT_REG_INFO indication

In reply to Greg Kroah-Hartman

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

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

From: Tristan Madani <[email protected]>

[ Upstream commit df2187acfca6c6cca372c5d35f42394d9c270b09 ]

The firmware-controlled rsp->count field is used as the loop bound for indexing into the flexible rsp->regs[] array without validation against the message length. A count exceeding the actual data causes out-of- bounds reads from the heap-allocated message buffer.

Add a check that count fits within the received message.

---
 drivers/net/wireless/ath/wcn36xx/smd.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/net/wireless/ath/wcn36xx/smd.c +6 -0
index bd51abef3a5be7..ad329252a7ceb8 100644
@@ -2865,6 +2865,12 @@ static int wcn36xx_smd_print_reg_info_ind(struct wcn36xx *wcn,
 		return -EIO;
 	}
 
+	if (rsp->count > (len - sizeof(*rsp)) / sizeof(rsp->regs[0])) {
+		wcn36xx_warn("Truncated print reg info indication: count %u, len %zu\n",
+			     rsp->count, len);
+		return -EIO;
+	}
+
 	wcn36xx_dbg(WCN36XX_DBG_HAL,
 		    "reginfo indication, scenario: 0x%x reason: 0x%x\n",
 		    rsp->scenario, rsp->reason);
Signature · 1 line
2.53.0
author maintainer
#394 lore raw

PATCH 390/1067 wifi: wcn36xx: fix OOB read from short trigger BA firmware response

In reply to Greg Kroah-Hartman

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

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

From: Tristan Madani <[email protected]>

[ Upstream commit b5e6f21923ca89d90256e7346301056f6502691e ]

The firmware response length is only checked against sizeof(*rsp) (20 bytes), but when candidate_cnt >= 1, a 22-byte candidate struct is read at buf + 20 without verifying the response contains it. This causes an out-of-bounds read of stale heap data, corrupting the BA session state.

Add validation that the response includes the candidate data.

Fixes 16be1ac55944 ("wcn36xx: Parse trigger_ba response properly")
---
 drivers/net/wireless/ath/wcn36xx/smd.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/wireless/ath/wcn36xx/smd.c +3 -0
index ad329252a7ceb8..79f0ed675a838b 100644
@@ -2659,6 +2659,9 @@ static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len, struct add_ba_info *ba
 	if (rsp->candidate_cnt < 1)
 		return rsp->status ? rsp->status : -EINVAL;
 
+	if (len < sizeof(*rsp) + sizeof(*candidate))
+		return -EINVAL;
+
 	candidate = (struct wcn36xx_hal_trigger_ba_rsp_candidate *)(buf + sizeof(*rsp));
 
 	for (i = 0; i < STACFG_MAX_TC; i++) {
Signature · 1 line
2.53.0
author maintainer
#395 lore raw

PATCH 391/1067 riscv: stacktrace: Remove bogus -0x4 offset in non-FP walk_stackframe

In reply to Greg Kroah-Hartman

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

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

From: Rui Qi <[email protected]>

[ Upstream commit 8ac35bac70e7e581d673b76878f7691cdadc33b8 ]

In the non-frame-pointer version of walk_stackframe, each value read from the stack is treated as a potential return address and has 0x4 subtracted before being used as the program counter. This was intended to convert the return address (the instruction after a call) back to the call site, but it is incorrect:

1. RISC-V has variable-length instructions due to the RVC (compressed instruction) extension. A call instruction can be either 4 bytes (regular) or 2 bytes (compressed, e.g. c.jal). Subtracting a fixed 0x4 assumes all call instructions are 4 bytes, which is wrong for compressed instructions.

2. Stack traces conventionally report return addresses, not call sites. Other architectures (ARM64, x86, ARM) do not subtract instruction size from return addresses in their stack unwinding code.

3. The frame-pointer version of walk_stackframe already dropped the -0x4 offset. Commit b785ec129bd9 ("riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support") replaced "pc = frame->ra - 0x4" with ftrace_graph_ret_addr(), and the commit message explicitly noted that "the original calculation, pc = frame->ra - 4, is buggy when the instruction at the return address happened to be a compressed inst." The non-FP version was simply overlooked.

Remove the bogus -0x4 offset to match the FP version and the conventions used by other architectures.

Fixes 5d8544e2d007 ("RISC-V: Generic library routines and assembly")
---
 arch/riscv/kernel/stacktrace.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/riscv/kernel/stacktrace.c +1 -1
index 4f78b79626513d..04313f203cb086 100644
@@ -127,7 +127,7 @@ void notrace walk_stackframe(struct task_struct *task,
 	while (!kstack_end(ksp)) {
 		if (__kernel_text_address(pc) && unlikely(!fn(arg, pc)))
 			break;
-		pc = READ_ONCE_NOCHECK(*ksp++) - 0x4;
+		pc = READ_ONCE_NOCHECK(*ksp++);
 	}
 }
 
Signature · 1 line
2.53.0
author maintainer
#396 lore raw

PATCH 392/1067 ALSA: seq: Introduce SNDRV_SEQ_IOCTL_USER_PVERSION ioctl

In reply to Greg Kroah-Hartman

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

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

From: Takashi Iwai <[email protected]>

[ Upstream commit afb72505e4614a2ccefe3440d37dec3a2273c330 ]

For the future extension of ALSA sequencer ABI, introduce a new ioctl SNDRV_SEQ_IOCTL_USER_PVERSION. This is similar like the ioctls used in PCM and other interfaces, for an application to specify its supporting ABI version.

The use of this ioctl will be mandatory for the upcoming UMP support.

Stable-dep-of: 705dd6dcbc0e ("ALSA: seq: Clear variable event pointer on read")

---
 include/uapi/sound/asequencer.h | 1 +
 sound/core/seq/seq_clientmgr.c  | 8 ++++++++
 sound/core/seq/seq_clientmgr.h  | 1 +
 sound/core/seq/seq_compat.c     | 1 +
 4 files changed, 11 insertions(+)
include/uapi/sound/asequencer.h +1 -0
index 00d2703e8fca5e..4a3c5a718baeb4 100644
@@ -561,6 +561,7 @@ struct snd_seq_query_subs {
 #define SNDRV_SEQ_IOCTL_CLIENT_ID	_IOR ('S', 0x01, int)
 #define SNDRV_SEQ_IOCTL_SYSTEM_INFO	_IOWR('S', 0x02, struct snd_seq_system_info)
 #define SNDRV_SEQ_IOCTL_RUNNING_MODE	_IOWR('S', 0x03, struct snd_seq_running_info)
+#define SNDRV_SEQ_IOCTL_USER_PVERSION	_IOW('S', 0x04, int)
 
 #define SNDRV_SEQ_IOCTL_GET_CLIENT_INFO	_IOWR('S', 0x10, struct snd_seq_client_info)
 #define SNDRV_SEQ_IOCTL_SET_CLIENT_INFO	_IOW ('S', 0x11, struct snd_seq_client_info)
sound/core/seq/seq_clientmgr.c +8 -0
index 1252ea7ad55eab..00c798b83d4fa8 100644
@@ -1158,6 +1158,12 @@ static int snd_seq_ioctl_pversion(struct snd_seq_client *client, void *arg)
 	return 0;
 }
 
+static int snd_seq_ioctl_user_pversion(struct snd_seq_client *client, void *arg)
+{
+	client->user_pversion = *(unsigned int *)arg;
+	return 0;
+}
+
 static int snd_seq_ioctl_client_id(struct snd_seq_client *client, void *arg)
 {
 	int *client_id = arg;
@@ -2085,6 +2091,7 @@ static const struct ioctl_handler {
 	int (*func)(struct snd_seq_client *client, void *arg);
 } ioctl_handlers[] = {
 	{ SNDRV_SEQ_IOCTL_PVERSION, snd_seq_ioctl_pversion },
+	{ SNDRV_SEQ_IOCTL_USER_PVERSION, snd_seq_ioctl_user_pversion },
 	{ SNDRV_SEQ_IOCTL_CLIENT_ID, snd_seq_ioctl_client_id },
 	{ SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info },
 	{ SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode },
@@ -2225,6 +2232,7 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
 	client->accept_input = 1;
 	client->accept_output = 1;
 	client->data.kernel.card = card;
+	client->user_pversion = SNDRV_SEQ_VERSION;
 		
 	va_start(args, name_fmt);
 	vsnprintf(client->name, sizeof(client->name), name_fmt, args);
sound/core/seq/seq_clientmgr.h +1 -0
index 8cdd0ee53fb1f6..31b988785ca23c 100644
@@ -35,6 +35,7 @@ struct snd_seq_client {
 	snd_seq_client_type_t type;
 	unsigned int accept_input: 1,
 		accept_output: 1;
+	unsigned int user_pversion;
 	char name[64];		/* client name */
 	int number;		/* client number */
 	unsigned int filter;	/* filter flags */
sound/core/seq/seq_compat.c +1 -0
index 54723566ce2428..c0ce6236dc7f1d 100644
@@ -81,6 +81,7 @@ static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
 
 	switch (cmd) {
 	case SNDRV_SEQ_IOCTL_PVERSION:
+	case SNDRV_SEQ_IOCTL_USER_PVERSION:
 	case SNDRV_SEQ_IOCTL_CLIENT_ID:
 	case SNDRV_SEQ_IOCTL_SYSTEM_INFO:
 	case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO:
Signature · 1 line
2.53.0
author maintainer
#397 lore raw

PATCH 393/1067 ALSA: seq: Add UMP support

In reply to Greg Kroah-Hartman

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

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

From: Takashi Iwai <[email protected]>

[ Upstream commit 46397622a3fa8372b8fda0f04b33d16923b03b1b ]

Starting from this commit, we add the basic support of UMP (Universal MIDI Packet) events on ALSA sequencer infrastructure. The biggest change here is that, for transferring UMP packets that are up to 128 bits, we extend the data payload of ALSA sequencer event record when the client is declared to support for the new UMP events.

A new event flag bit, SNDRV_SEQ_EVENT_UMP, is defined and it shall be set for the UMP packet events that have the larger payload of 128 bits, defined as struct snd_seq_ump_event.

For controlling the UMP feature enablement in kernel, a new Kconfig, CONFIG_SND_SEQ_UMP is introduced. The extended event for UMP is available only when this Kconfig item is set. Similarly, the size of the internal snd_seq_event_cell also increases (in 4 bytes) when the Kconfig item is set. (But the size increase is effective only for 32bit architectures; 64bit archs already have padding there.) Overall, when CONFIG_SND_SEQ_UMP isn't set, there is no change in the event and cell, keeping the old sizes.

For applications that want to access the UMP packets, first of all, a sequencer client has to declare the user-protocol to match with the latest one via the new SNDRV_SEQ_IOCTL_USER_PVERSION; otherwise it's treated as if a legacy client without UMP support.

Then the client can switch to the new UMP mode (MIDI 1.0 or MIDI 2.0) with a new field, midi_version, in snd_seq_client_info. When switched to UMP mode (midi_version = 1 or 2), the client can write the UMP events with SNDRV_SEQ_EVENT_UMP flag. For reads, the alignment size is changed from snd_seq_event (28 bytes) to snd_seq_ump_event (32 bytes). When a UMP sequencer event is delivered to a legacy sequencer client, it's ignored or handled as an error.

Conceptually, ALSA sequencer client and port correspond to the UMP Endpoint and Group, respectively; each client may have multiple ports and each port has the fixed number (16) of channels, total up to 256 channels.

As of this commit, ALSA sequencer core just sends and receives the UMP events as-is from/to clients. The automatic conversions between the legacy events and the new UMP events will be implemented in a later patch.

Along with this commit, bump the sequencer protocol version to 1.0.3.

Stable-dep-of: 705dd6dcbc0e ("ALSA: seq: Clear variable event pointer on read")

---
 include/sound/asequencer.h      |   4 +
 include/sound/seq_kernel.h      |   8 ++
 include/uapi/sound/asequencer.h |  53 +++++++----
 sound/core/seq/Kconfig          |   7 ++
 sound/core/seq/seq_clientmgr.c  | 154 +++++++++++++++++++++++---------
 sound/core/seq/seq_clientmgr.h  |   1 +
 sound/core/seq/seq_memory.c     |  10 ++-
 sound/core/seq/seq_memory.h     |  19 +++-
 8 files changed, 193 insertions(+), 63 deletions(-)
include/sound/asequencer.h +4 -0
index 18d4bc3ee0b7f6..ddbb6bf801bbda 100644
@@ -65,6 +65,10 @@
 #define snd_seq_ev_is_abstime(ev)	(snd_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_ABS)
 #define snd_seq_ev_is_reltime(ev)	(snd_seq_ev_timemode_type(ev) == SNDRV_SEQ_TIME_MODE_REL)
 
+/* check whether the given event is a UMP event */
+#define snd_seq_ev_is_ump(ev) \
+	(IS_ENABLED(CONFIG_SND_SEQ_UMP) && ((ev)->flags & SNDRV_SEQ_EVENT_UMP))
+
 /* queue sync port */
 #define snd_seq_queue_sync_port(q)	((q) + 16)
 
include/sound/seq_kernel.h +8 -0
index 658911926f3ab8..b9b197db3c8f99 100644
@@ -73,6 +73,14 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
 int snd_seq_dump_var_event(const struct snd_seq_event *event,
 			   snd_seq_dump_func_t func, void *private_data);
 
+/* size of the event packet; it can be greater than snd_seq_event size */
+static inline size_t snd_seq_event_packet_size(struct snd_seq_event *ev)
+{
+	if (snd_seq_ev_is_ump(ev))
+		return sizeof(struct snd_seq_ump_event);
+	return sizeof(struct snd_seq_event);
+}
+
 /* interface for OSS emulation */
 int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo);
 
include/uapi/sound/asequencer.h +37 -16

90 lines not on this page · raw message

sound/core/seq/Kconfig +7 -0
index f84718a44980b2..c69d8beb09faec 100644
@@ -60,4 +60,11 @@ config SND_SEQ_MIDI_EMUL
 config SND_SEQ_VIRMIDI
 	tristate
 
+config SND_SEQ_UMP
+	bool "Support for UMP events"
+	help
+	  Say Y here to enable the support for handling UMP (Universal MIDI
+	  Packet) events via ALSA sequencer infrastructure, which is an
+	  essential feature for enabling MIDI 2.0 support.
+
 endif # SND_SEQUENCER
sound/core/seq/seq_clientmgr.c +110 -44

314 lines not on this page · raw message

sound/core/seq/seq_clientmgr.h +1 -0
index 31b988785ca23c..97ae9fdc164e14 100644
@@ -35,6 +35,7 @@ struct snd_seq_client {
 	snd_seq_client_type_t type;
 	unsigned int accept_input: 1,
 		accept_output: 1;
+	unsigned int midi_version;
 	unsigned int user_pversion;
 	char name[64];		/* client name */
 	int number;		/* client number */
sound/core/seq/seq_memory.c +8 -2
index e30b92d85079b8..082cc410689a2b 100644
@@ -288,6 +288,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
 	int ncells, err;
 	unsigned int extlen;
 	struct snd_seq_event_cell *cell;
+	int size;
 
 	*cellp = NULL;
 
@@ -305,7 +306,12 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
 		return err;
 
 	/* copy the event */
-	cell->event = *event;
+	size = snd_seq_event_packet_size(event);
+	memcpy(&cell->ump, event, size);
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+	if (size < sizeof(cell->event))
+		cell->ump.raw.extra = 0;
+#endif
 
 	/* decompose */
 	if (snd_seq_ev_is_variable(event)) {
@@ -323,7 +329,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
 		tail = NULL;
 
 		while (ncells-- > 0) {
-			int size = sizeof(struct snd_seq_event);
+			size = sizeof(struct snd_seq_event);
 			if (len < size)
 				size = len;
 			err = snd_seq_cell_alloc(pool, &tmp, nonblock, file,
sound/core/seq/seq_memory.h +18 -1
index 7d7ff80f915e79..7f7a2c0b187df9 100644
@@ -11,9 +11,26 @@
 
 struct snd_info_buffer;
 
+/* aliasing for legacy and UMP event packet handling */
+union __snd_seq_event {
+	struct snd_seq_event legacy;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+	struct snd_seq_ump_event ump;
+#endif
+	struct {
+		struct snd_seq_event event;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+		u32 extra;
+#endif
+	} __packed raw;
+};
+
 /* container for sequencer event (internal use) */
 struct snd_seq_event_cell {
-	struct snd_seq_event event;
+	union {
+		struct snd_seq_event event;
+		union __snd_seq_event ump;
+	};
 	struct snd_seq_pool *pool;				/* used pool */
 	struct snd_seq_event_cell *next;	/* next cell */
 };
Signature · 1 line
2.53.0
author maintainer
#398 lore raw

PATCH 394/1067 ALSA: seq: Clear variable event pointer on read

In reply to Greg Kroah-Hartman

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

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

From: Kyle Zeng <[email protected]>

[ Upstream commit 705dd6dcbc0ea87351c660c1a6443f85f1001c76 ]

snd_seq_read() copies a queued variable-length event header to userspace before expanding the payload. Queued variable-length events use SNDRV_SEQ_EXT_CHAINED internally, and data.ext.ptr points at the first extension cell.

The read side strips SNDRV_SEQ_EXT_* bits from data.ext.len before the copy, but it leaves data.ext.ptr untouched. A userspace sequencer client can therefore write a direct variable event to itself and read back the extension-cell kernel address from the returned header.

Clear the temporary header pointer before copy_to_user(). The original queued event remains unchanged and is still passed to snd_seq_expand_var_event(), so payload expansion keeps using the internal chain.

---
 sound/core/seq/seq_clientmgr.c | 1 +
 1 file changed, 1 insertion(+)
sound/core/seq/seq_clientmgr.c +1 -0
index bd05f14b6804bf..1efc407e7784b0 100644
@@ -464,6 +464,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
 
 			memcpy(&tmpev, &cell->event, aligned_size);
 			tmpev.data.ext.len &= ~SNDRV_SEQ_EXT_MASK;
+			tmpev.data.ext.ptr = NULL;
 			if (copy_to_user(buf, &tmpev, aligned_size)) {
 				err = -EFAULT;
 				break;
Signature · 1 line
2.53.0
author maintainer
#399 lore raw

PATCH 395/1067 ACPI: IPMI: Fix message kref handling on dead device

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit 63320db6a5d84ec3fed8b3d36ba5244d07ddd108 ]

acpi_ipmi_space_handler() takes an extra reference on tx_msg before checking whether the selected IPMI device is dead. The reference belongs to the tx_msg_list entry and is normally dropped by ipmi_cancel_tx_msg() or ipmi_flush_tx_msg() after the message is removed from the list.

On the dead-device path, the message has not been queued yet, but the error path still calls ipmi_msg_release() directly. That bypasses kref_put() and frees tx_msg while the queued-message reference is still recorded in the kref count.

Take the queued-message reference only after the dead-device check succeeds, immediately before adding tx_msg to the list.

Fixes 7b9844772237 ("ACPI / IPMI: Add reference counting for ACPI IPMI transfers")
---
 drivers/acpi/acpi_ipmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/acpi/acpi_ipmi.c +1 -1
index 0555f68c2dfd68..148d9486106cad 100644
@@ -545,7 +545,6 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
 		return AE_TYPE;
 	}
 
-	acpi_ipmi_msg_get(tx_msg);
 	mutex_lock(&driver_data.ipmi_lock);
 	/* Do not add a tx_msg that can not be flushed. */
 	if (ipmi_device->dead) {
@@ -553,6 +552,7 @@ acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
 		ipmi_msg_release(tx_msg);
 		return AE_NOT_EXIST;
 	}
+	acpi_ipmi_msg_get(tx_msg);
 	spin_lock_irqsave(&ipmi_device->tx_msg_lock, flags);
 	list_add_tail(&tx_msg->head, &ipmi_device->tx_msg_list);
 	spin_unlock_irqrestore(&ipmi_device->tx_msg_lock, flags);
Signature · 1 line
2.53.0
author maintainer
#400 lore raw

PATCH 396/1067 cpufreq: Documentation: fix conservative governor freq_step description

In reply to Greg Kroah-Hartman

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

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

From: Pengjie Zhang <[email protected]>

[ Upstream commit 03120e1425262c7d11f93362a88e579a1720390b ]

The conservative governor documentation incorrectly states that setting freq_step to 0 will use the default 5% frequency step. In reality, since at least commit 8e677ce83bf4 ("[CPUFREQ] conservative: fixup governor to function more like ondemand logic"), freq_step=0 has always caused the governor to skip frequency updates entirely.

Correct the documentation to reflect the actual behavior: freq_step=0 disables frequency changes by the governor entirely.

Fixes 2a0e49279850 ("cpufreq: User/admin documentation update and consolidation")
[ rjw: Subject adjustment ]
---
 Documentation/admin-guide/pm/cpufreq.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Documentation/admin-guide/pm/cpufreq.rst +2 -2
index d2f37309cca3b3..5247eabb92065a 100644
@@ -569,8 +569,8 @@ This governor exposes the following tunables:
 	100 (5 by default).
 
 	This is how much the frequency is allowed to change in one go.  Setting
-	it to 0 will cause the default frequency step (5 percent) to be used
-	and setting it to 100 effectively causes the governor to periodically
+	it to 0 disables frequency changes by the governor entirely and setting
+	it to 100 effectively causes the governor to periodically
 	switch the frequency between the ``scaling_min_freq`` and
 	``scaling_max_freq`` policy limits.
 
Signature · 1 line
2.53.0
author maintainer
#401 lore raw

PATCH 397/1067 IB/mlx5: Dont take the rereg_mr fallback without a new translation

In reply to Greg Kroah-Hartman

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

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

From: Jason Gunthorpe <[email protected]>

[ Upstream commit 55d339d200c908de83a408d023cfb7be779b0dd7 ]

Jumping to mlx5_ib_reg_user_mr() without IB_MR_REREG_TRANS set will use garbage values for start, length, and iova. Recovering the original mr parameters for ODP and DMABUF to properly recreate it is too hard in this flow, so just fail it.

Fixes ef3642c4f54d ("RDMA/mlx5: Fix error unwinds for rereg_mr")
---
 drivers/infiniband/hw/mlx5/mr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/mr.c +1 -1
index b81b03aa2a629e..ca8ebe5cdeebf2 100644
@@ -1463,7 +1463,7 @@ struct ib_mr *mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
 		}
 		/* DM or ODP MR's don't have a normal umem so we can't re-use it */
 		if (!mr->umem || is_odp_mr(mr) || is_dmabuf_mr(mr))
-			goto recreate;
+			return ERR_PTR(-EOPNOTSUPP);
 
 		/*
 		 * Only one active MR can refer to a umem at one time, revoke
Signature · 1 line
2.53.0
author maintainer
#402 lore raw

PATCH 398/1067 IB/mlx5: Properly support implicit ODP rereg_mr

In reply to Greg Kroah-Hartman

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

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

From: Jason Gunthorpe <[email protected]>

[ Upstream commit ee7a8335069150c3f1893a697ab30bbeca00d796 ]

Due to all the child mkeys in the implicit ODP configuration we cannot change anything in place for the parent mkey. Instead the whole thing needs to be rebuilt if any change is requested. If the user does not specify a translation then force the implicit values which will then fall through the logic into mlx5_ib_reg_user_mr() to allocate a completely new MR.

Since implicit children were also touching the mr->pd, this removes another case where the access was racy.

---
 drivers/infiniband/hw/mlx5/mr.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
drivers/infiniband/hw/mlx5/mr.c +15 -0
index ca8ebe5cdeebf2..2cb4310cc3d685 100644
@@ -1449,6 +1449,21 @@ struct ib_mr *mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
 	if (!(flags & IB_MR_REREG_PD))
 		new_pd = ib_mr->pd;
 
+	if (mr->is_odp_implicit && !(flags & IB_MR_REREG_TRANS)) {
+		if (!(new_access_flags & IB_ACCESS_ON_DEMAND))
+			return ERR_PTR(-EOPNOTSUPP);
+
+		/*
+		 * Due to all the child mkeys we cannot actually change an
+		 * implicit MR in place. If the user did not specify a new
+		 * translation then force the fixed implicit MR values.
+		 */
+		start = 0;
+		iova = 0;
+		length = U64_MAX;
+		flags |= IB_MR_REREG_TRANS;
+	}
+
 	if (!(flags & IB_MR_REREG_TRANS)) {
 		struct ib_umem *umem;
 
Signature · 1 line
2.53.0
author maintainer
#403 lore raw

PATCH 399/1067 spi: ep93xx: fix double-free of zeropage on DMA setup failure

In reply to Greg Kroah-Hartman

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

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

From: Felix Gu <[email protected]>

[ Upstream commit 7886054b06f762f62054957a8f6de0f14e6b7541 ]

If DMA setup fails after allocating the zeropage, the error path frees the page but leaves espi->zeropage dangling. A subsequent call to ep93xx_spi_release_dma() sees the non-NULL pointer and frees the page again.

Clear the pointer after freeing in the error path of ep93xx_spi_setup_dma().

Fixes 626a96db1169 ("spi/ep93xx: add DMA support")
---
 drivers/spi/spi-ep93xx.c | 1 +
 1 file changed, 1 insertion(+)
drivers/spi/spi-ep93xx.c +1 -0
index 5896a7b2fade0c..9b694cd5361d93 100644
@@ -625,6 +625,7 @@ static int ep93xx_spi_setup_dma(struct ep93xx_spi *espi)
 	espi->dma_rx = NULL;
 fail_free_page:
 	free_page((unsigned long)espi->zeropage);
+	espi->zeropage = NULL;
 
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#404 lore raw

PATCH 400/1067 firmware_loader: Fix recursive lock in device_cache_fw_images()

In reply to Greg Kroah-Hartman

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

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

From: Dmitry Vyukov <[email protected]>

[ Upstream commit d3ec78f8f8d48a04a9fac38d47275c34645e5103 ]

A recursive locking deadlock can occur in the firmware loader's power management notification handler.

During system suspend or hibernation preparation, fw_pm_notify() calls device_cache_fw_images(). This function acquires fw_lock to set the firmware cache state to FW_LOADER_START_CACHE and then iterates over all devices using dpm_for_each_dev() while still holding the lock.

For each device, dev_cache_fw_image() schedules asynchronous work to cache the firmware. If memory allocation for the async work entry fails (e.g., in out-of-memory conditions), async_schedule_node_domain() falls back to executing the work function synchronously in the current thread.

The synchronous execution path (__async_dev_cache_fw_image() -> cache_firmware() -> request_firmware() -> assign_fw()) attempts to acquire fw_lock again. Since the current thread already holds fw_lock, this results in a recursive locking deadlock.

Fix this by releasing fw_lock immediately after updating the cache state and before calling dpm_for_each_dev(). The lock is only needed to protect the state update. Concurrent firmware requests will correctly see the FW_LOADER_START_CACHE state and use the piggyback mechanism, which is independently protected by its own fwc->name_lock.

Fixes ac39b3ea73aa ("firmware loader: let caching firmware piggyback on loading firmware")
Assisted-by Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview syzbot
Reported-by [email protected]
---
 drivers/base/firmware_loader/main.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/base/firmware_loader/main.c +2 -1
index cfface4f4c1e61..9c04a734a83e15 100644
@@ -1452,9 +1452,10 @@ static void device_cache_fw_images(void)
 
 	mutex_lock(&fw_lock);
 	fwc->state = FW_LOADER_START_CACHE;
-	dpm_for_each_dev(NULL, dev_cache_fw_image);
 	mutex_unlock(&fw_lock);
 
+	dpm_for_each_dev(NULL, dev_cache_fw_image);
+
 	/* wait for completion of caching firmware for all devices */
 	async_synchronize_full_domain(&fw_cache_domain);
 
Signature · 1 line
2.53.0
author maintainer
#405 lore raw

PATCH 401/1067 configfs: fix lockless traversals of ->s_children

In reply to Greg Kroah-Hartman

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

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

From: Al Viro <[email protected]>

[ Upstream commit 9b9e8bb81c41fd27e7b57a1c936fde140548535f ]

Having the parent directory locked protects entries from removal by another thread, but it does *not* protect cursors from being moved around by lseek() - or freed, for that matter.

Fixes 6f6107640625 ("configfs: Introduce configfs_dirent_lock")
---
 fs/configfs/dir.c | 54 +++++++++++++++++++++++++++++++++++------------
 1 file changed, 41 insertions(+), 13 deletions(-)
fs/configfs/dir.c +41 -13
index afe2b802eb3193..01c9d54833b300 100644
@@ -225,15 +225,16 @@ static int configfs_dirent_exists(struct configfs_dirent *parent_sd,
 {
 	struct configfs_dirent * sd;
 
+	spin_lock(&configfs_dirent_lock);
 	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
 		if (sd->s_element) {
-			const unsigned char *existing = configfs_get_name(sd);
-			if (strcmp(existing, new))
-				continue;
-			else
+			if (strcmp(configfs_get_name(sd), new) == 0) {
+				spin_unlock(&configfs_dirent_lock);
 				return -EEXIST;
+			}
 		}
 	}
+	spin_unlock(&configfs_dirent_lock);
 
 	return 0;
 }
@@ -551,11 +552,28 @@ static void configfs_detach_rollback(struct dentry *dentry)
 			configfs_detach_rollback(sd->s_dentry);
 }
 
+/*
+ * Find the next non-cursor.  configfs_dirent_lock held by caller.
+ */
+static struct configfs_dirent *next_dirent(struct configfs_dirent *parent,
+					   struct configfs_dirent *last)
+{
+	struct configfs_dirent *s;
+
+	s = list_prepare_entry(last, &parent->s_children, s_sibling);
+
+	list_for_each_entry_continue(s, &parent->s_children, s_sibling) {
+		if (s->s_element)
+			return s;
+	}
+	return NULL;
+}
+
 static void detach_attrs(struct config_item * item)
 {
 	struct dentry * dentry = dget(item->ci_dentry);
-	struct configfs_dirent * parent_sd;
-	struct configfs_dirent * sd, * tmp;
+	struct configfs_dirent *parent_sd;
+	struct configfs_dirent *sd, *next;
 
 	if (!dentry)
 		return;
@@ -564,15 +582,19 @@ static void detach_attrs(struct config_item * item)
 		 dentry->d_name.name);
 
 	parent_sd = dentry->d_fsdata;
-	list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
-		if (!sd->s_element || !(sd->s_type & CONFIGFS_NOT_PINNED))
+
+	spin_lock(&configfs_dirent_lock);
+	for (sd = next_dirent(parent_sd, NULL); sd; sd = next) {
+		next = next_dirent(parent_sd, sd);
+		if (!(sd->s_type & CONFIGFS_NOT_PINNED))
 			continue;
-		spin_lock(&configfs_dirent_lock);
 		list_del_init(&sd->s_sibling);
 		spin_unlock(&configfs_dirent_lock);
 		configfs_drop_dentry(sd, dentry);
 		configfs_put(sd);
+		spin_lock(&configfs_dirent_lock);
 	}
+	spin_unlock(&configfs_dirent_lock);
 
 	/**
 	 * Drop reference from dget() on entrance.
@@ -621,18 +643,20 @@ static void detach_groups(struct config_group *group)
 	struct dentry * dentry = dget(group->cg_item.ci_dentry);
 	struct dentry *child;
 	struct configfs_dirent *parent_sd;
-	struct configfs_dirent *sd, *tmp;
+	struct configfs_dirent *sd, *next;
 
 	if (!dentry)
 		return;
 
 	parent_sd = dentry->d_fsdata;
-	list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
-		if (!sd->s_element ||
-		    !(sd->s_type & CONFIGFS_USET_DEFAULT))
+	spin_lock(&configfs_dirent_lock);
+	for (sd = next_dirent(parent_sd, NULL); sd; sd = next) {
+		next = next_dirent(parent_sd, sd);
+		if (!(sd->s_type & CONFIGFS_USET_DEFAULT))
 			continue;
 
 		child = sd->s_dentry;
+		spin_unlock(&configfs_dirent_lock);
 
 		inode_lock(d_inode(child));
 
@@ -644,7 +668,9 @@ static void detach_groups(struct config_group *group)
 
 		d_delete(child);
 		dput(child);
+		spin_lock(&configfs_dirent_lock);
 	}
+	spin_unlock(&configfs_dirent_lock);
 
 	/**
 	 * Drop reference from dget() on entrance.
@@ -1096,6 +1122,7 @@ configfs_find_subsys_dentry(struct configfs_dirent *root_sd,
 	struct configfs_dirent *p;
 	struct configfs_dirent *ret = NULL;
 
+	spin_lock(&configfs_dirent_lock);
 	list_for_each_entry(p, &root_sd->s_children, s_sibling) {
 		if (p->s_type & CONFIGFS_DIR &&
 		    p->s_element == subsys_item) {
@@ -1103,6 +1130,7 @@ configfs_find_subsys_dentry(struct configfs_dirent *root_sd,
 			break;
 		}
 	}
+	spin_unlock(&configfs_dirent_lock);
 
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#406 lore raw

PATCH 402/1067 watchdog: unregister PM notifier on watchdog unregister

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit a298c7302ee9584a7a1ac1e8acbede8d98ab51a4 ]

watchdog_register_device() registers wdd->pm_nb when WDOG_NO_PING_ON_SUSPEND is set, but watchdog_unregister_device() does not remove it. This leaves an embedded notifier block on the PM notifier chain after the watchdog device has been unregistered.

A later suspend/resume notification can then call watchdog_pm_notifier() with a stale watchdog_device pointer, or at minimum after wdd->wd_data has been cleared by watchdog_dev_unregister().

Unregister the PM notifier before tearing down the watchdog device.

Fixes 60bcd91aafd2 ("watchdog: introduce watchdog_dev_suspend/resume")
---
 drivers/watchdog/watchdog_core.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/watchdog/watchdog_core.c +3 -0
index c777a612d932dd..6c2599e040b84a 100644
@@ -381,6 +381,9 @@ static void __watchdog_unregister_device(struct watchdog_device *wdd)
 	if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status))
 		unregister_reboot_notifier(&wdd->reboot_nb);
 
+	if (test_bit(WDOG_NO_PING_ON_SUSPEND, &wdd->status))
+		unregister_pm_notifier(&wdd->pm_nb);
+
 	watchdog_dev_unregister(wdd);
 	ida_simple_remove(&watchdog_ida, wdd->id);
 }
Signature · 1 line
2.53.0
author maintainer
#407 lore raw

PATCH 403/1067 scsi: target: Fix hexadecimal CHAP_I handling

In reply to Greg Kroah-Hartman

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

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

From: David Disseldorp <[email protected]>

[ Upstream commit 7e161211f1dd5288b4ea802b30e70ef919ebc3da ]

A mutual CHAP handshake requires target processing of an initiator-sent CHAP_I identifier. The RFC 3720 specification states:

11.1.4. Challenge Handshake Authentication Protocol (CHAP)
...
CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
...
Where N, (A,A1,A2), I, C, and R are (correspondingly) the Name, Algorithm, Identifier, Challenge, and Response as defined in [RFC1994], N is a text string, A,A1,A2, and I are numbers

CHAP_I parsing currently calls extract_param(), which returns the @identifier string (stripped of any 0b/0B or 0x/0X prefix) and a @type which indicates DECIMAL, HEX, or BASE64 encoding (based on any stripped prefix).

Any HEX encoded CHAP_I string is further processed via:

  ret = kstrtoul(&identifier[2], 0, &id);

This is incorrect for two reasons:

* The @identifier string has already been stripped of the 0x/0X prefix, so skipping the first two bytes omits part of the number.

* The kstrtoul() call specifies a base of 0, which will see &identifier[2] parsed as a decimal, unless a '0x' or (octal) '0' is erroneously present at that offset.

Fix this by passing the (zero-offset) identifier string to kstrtoul() along with a base=16 parameter. Also add an explicit error handler for BASE64 encoding.

Hex-encoded CHAP_I handling can be testing using the libiscsi EncodedI test linked below.

---
 drivers/target/iscsi/iscsi_target_auth.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/target/iscsi/iscsi_target_auth.c +4 -2
index 02a4c9aff98d51..41e4def46ede69 100644
@@ -437,9 +437,11 @@ static int chap_server_compute_hash(
 	}
 
 	if (type == HEX)
-		ret = kstrtoul(&identifier[2], 0, &id);
+		ret = kstrtoul(identifier, 16, &id);
+	else if (type == DECIMAL)
+		ret = kstrtoul(identifier, 10, &id);
 	else
-		ret = kstrtoul(identifier, 0, &id);
+		ret = -EINVAL;
 
 	if (ret < 0) {
 		pr_err("kstrtoul() failed for CHAP identifier: %d\n", ret);
Signature · 1 line
2.53.0
author maintainer
#408 lore raw

PATCH 404/1067 pinctrl: mediatek: mt8516: Fix Schmitt trigger register offset of pins 34-39

In reply to Greg Kroah-Hartman

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

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

From: Luca Leonardo Scorcia <[email protected]>

[ Upstream commit 1c3044cab23a056ea28da47da1cdd667a39df0b8 ]

The correct Schmitt trigger register offset for pins 34-39 is 0xA00.

Fixes 264667112ef0 ("pinctrl: mediatek: Add MT8516 Pinctrl driver")
---
 drivers/pinctrl/mediatek/pinctrl-mt8516.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pinctrl/mediatek/pinctrl-mt8516.c +1 -1
index e929339dd2cb3d..46686b61002dae 100644
@@ -245,7 +245,7 @@ static const struct mtk_pin_ies_smt_set mt8516_smt_set[] = {
 	MTK_PIN_IES_SMT_SPEC(24, 25, 0xA00, 12),
 	MTK_PIN_IES_SMT_SPEC(26, 30, 0xA00, 0),
 	MTK_PIN_IES_SMT_SPEC(31, 33, 0xA00, 1),
-	MTK_PIN_IES_SMT_SPEC(34, 39, 0xA900, 2),
+	MTK_PIN_IES_SMT_SPEC(34, 39, 0xA00, 2),
 	MTK_PIN_IES_SMT_SPEC(40, 40, 0xA10, 11),
 	MTK_PIN_IES_SMT_SPEC(41, 43, 0xA00, 10),
 	MTK_PIN_IES_SMT_SPEC(44, 47, 0xA00, 11),
Signature · 1 line
2.53.0
author maintainer
#409 lore raw

PATCH 405/1067 pinctrl: mediatek: mt8167: Fix Schmitt trigger register offset of pins 34-39

In reply to Greg Kroah-Hartman

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

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

From: Luca Leonardo Scorcia <[email protected]>

[ Upstream commit 439bc91d20188901dac698bed4921caac76d9074 ]

The correct Schmitt trigger register offset for pins 34-39 is 0xA00. Value was verified with SoC data sheet.

Fixes 82d70627e94a ("pinctrl: mediatek: Add MT8167 Pinctrl driver")
---
 drivers/pinctrl/mediatek/pinctrl-mt8167.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pinctrl/mediatek/pinctrl-mt8167.c +1 -1
index 866da2c4a890cd..37b270757de7cf 100644
@@ -245,7 +245,7 @@ static const struct mtk_pin_ies_smt_set mt8167_smt_set[] = {
 	MTK_PIN_IES_SMT_SPEC(24, 25, 0xA00, 12),
 	MTK_PIN_IES_SMT_SPEC(26, 30, 0xA00, 0),
 	MTK_PIN_IES_SMT_SPEC(31, 33, 0xA00, 1),
-	MTK_PIN_IES_SMT_SPEC(34, 39, 0xA900, 2),
+	MTK_PIN_IES_SMT_SPEC(34, 39, 0xA00, 2),
 	MTK_PIN_IES_SMT_SPEC(40, 40, 0xA10, 11),
 	MTK_PIN_IES_SMT_SPEC(41, 43, 0xA00, 10),
 	MTK_PIN_IES_SMT_SPEC(44, 47, 0xA00, 11),
Signature · 1 line
2.53.0
author maintainer
#410 lore raw

PATCH 406/1067 vmalloc: fix NULL pointer dereference in is_vm_area_hugepages()

In reply to Greg Kroah-Hartman

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

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

From: Hui Zhu <[email protected]>

[ Upstream commit c55dd3b46c1208d6d2ea737a8aefef4aa4c70cb8 ]

find_vm_area() can return NULL if the given address is not a valid vmalloc area. Check the return value before dereferencing it to avoid a kernel crash.

---
 include/linux/vmalloc.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
include/linux/vmalloc.h +3 -1
index 07843967bc52f7..0a14c117c0fdb8 100644
@@ -211,7 +211,9 @@ static inline bool is_vm_area_hugepages(const void *addr)
 	 * allocated in the vmalloc layer.
 	 */
 #ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC
-	return find_vm_area(addr)->page_order > 0;
+	struct vm_struct *area = find_vm_area(addr);
+
+	return area && area->page_order > 0;
 #else
 	return false;
 #endif
Signature · 1 line
2.53.0
author maintainer
#411 lore raw

PATCH 407/1067 hwspinlock: qcom: avoid uninitialized struct members

In reply to Greg Kroah-Hartman

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

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

From: Wolfram Sang <[email protected]>

[ Upstream commit 8752c396ce3b2136b3d4c906fe103f6efb6782d9 ]

The reg_field is allocated on stack, so using the REG_FIELD macro will ensure that unused members do not have uninitialized values.

---
 drivers/hwspinlock/qcom_hwspinlock.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
drivers/hwspinlock/qcom_hwspinlock.c +1 -4
index 3f08cd4a5c2801..319959b11ef4f0 100644
@@ -178,7 +178,6 @@ static struct regmap *qcom_hwspinlock_probe_mmio(struct platform_device *pdev,
 static int qcom_hwspinlock_probe(struct platform_device *pdev)
 {
 	struct hwspinlock_device *bank;
-	struct reg_field field;
 	struct regmap *regmap;
 	size_t array_size;
 	u32 stride;
@@ -200,9 +199,7 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, bank);
 
 	for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) {
-		field.reg = base + i * stride;
-		field.lsb = 0;
-		field.msb = 31;
+		struct reg_field field = REG_FIELD(base + i * stride, 0, 31);
 
 		bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev,
 							     regmap, field);
Signature · 1 line
2.53.0
author maintainer
#412 lore raw

PATCH 408/1067 wifi: mt76: fix argument to ieee80211_is_first_frag()

In reply to Greg Kroah-Hartman

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

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

From: Bjoern A. Zeeb <[email protected]>

[ Upstream commit 5832743279da8c6ae72f715bad2f7141eca6f4b8 ]

ieee80211_is_first_frag() operates on the seq_ctrl not the frame_control header field. Pass the correct one in; otherwise the results may vary.

Sponsored by: The FreeBSD Foundation

---
 drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mac80211.c +1 -1
index 82fce4b1d581be..5bcb2837efaa98 100644
@@ -1060,7 +1060,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
 		 * All further fragments will be validated by mac80211 only.
 		 */
 		if (ieee80211_is_frag(hdr) &&
-		    !ieee80211_is_first_frag(hdr->frame_control))
+		    !ieee80211_is_first_frag(hdr->seq_ctrl))
 			return;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#413 lore raw

PATCH 409/1067 btrfs: fix invalid pointer dereference in __btrfs_run_delayed_refs()

In reply to Greg Kroah-Hartman

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

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

From: Filipe Manana <[email protected]>

[ Upstream commit 486f8298b6188ff11ef1f4be7f1d5d2e4d1b1fae ]

In the beginning of the loop, we try to obtain a locked delayed ref head, if 'locked_ref' is currently NULL, by calling btrfs_select_ref_head(), which can return an error pointer. If the error pointer is -EAGAIN we do a continue and go back to the beginning of the loop, which will not try again to call btrfs_select_ref_head() since 'locked_ref' is no longer NULL but it's ERR_PTR(-EAGAIN), and then we do:

   spin_lock(&locked_ref->lock);

against a ERR_PTR(-EAGAIN) value, generating an invalid pointer dereference.

Fix this by ensuring that 'locked_ref' is set to NULL when btrfs_select_ref_head() returns ERR_PTR(-EAGAIN) and incrementing 'count' as well, to prevent infinite looping. We do this by doing a goto to the bottom of the loop that already sets 'locked_ref' to NULL and does a cond_resched(), with an increment to 'count' right before the goto. These measures were in place before the refactoring in commit 0110a4c43451 ("btrfs: refactor __btrfs_run_delayed_refs loop") but were unintentionally lost afterwards.

---
 fs/btrfs/extent-tree.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
fs/btrfs/extent-tree.c +3 -2
index 61c162e5245241..9a3c304d76b400 100644
@@ -2007,7 +2007,8 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
 			locked_ref = btrfs_obtain_ref_head(trans);
 			if (IS_ERR_OR_NULL(locked_ref)) {
 				if (PTR_ERR(locked_ref) == -EAGAIN) {
-					continue;
+					count++;
+					goto again;
 				} else {
 					break;
 				}
@@ -2056,7 +2057,7 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
 		 * Either success case or btrfs_run_delayed_refs_for_head
 		 * returned -EAGAIN, meaning we need to select another head
 		 */
-
+again:
 		locked_ref = NULL;
 		cond_resched();
 	} while ((nr != -1 && count < nr) || locked_ref);
Signature · 1 line
2.53.0
author maintainer
#414 lore raw

PATCH 410/1067 fbdev: sm501fb: Fix buffer errors in OF binding code

In reply to Greg Kroah-Hartman

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

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

From: David Laight <[email protected]>

[ Upstream commit d8421e09382cfe0bd2a044c8b0a822f64855dd4e ]

The code that gets the frame buffer mode from OF has 'use after free', 'buffer overrun' and memory leaks.

info->edid_data isn't free if the probe functions fail or if pd->def_mode is set.

If both the CRT and PANEL are enabled info->edid_data is used after being freed and is freed twice.

The string returned by of_get_property(np, "mode", &len) is just written over either the static "640x480-16@60" or the module parameter string without any regard for the length (which is most likely longer).

Use kstrump() for the OF mode and free everything before freeing 'info.

Fixes 4295f9bf74a88 ("video, sm501: add OF binding to support SM501")
---
 drivers/video/fbdev/sm501fb.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)
drivers/video/fbdev/sm501fb.c +12 -4
index bbbc9de06a81b4..1decdf51cee8bb 100644
@@ -95,6 +95,7 @@ struct sm501fb_info {
 	void __iomem		*fbmem;		/* remapped framebuffer */
 	size_t			 fbmem_len;	/* length of remapped region */
 	u8 *edid_data;
+	char *fb_mode;
 };
 
 /* per-framebuffer private data */
@@ -1788,12 +1789,11 @@ static int sm501fb_init_fb(struct fb_info *fb, enum sm501_controller head,
 			fb->var.yres_virtual = fb->var.yres;
 		} else {
 			if (info->edid_data) {
-				ret = fb_find_mode(&fb->var, fb, fb_mode,
+				ret = fb_find_mode(&fb->var, fb,
+					info->fb_mode ?: fb_mode,
 					fb->monspecs.modedb,
 					fb->monspecs.modedb_len,
 					&sm501_default_mode, default_bpp);
-				/* edid_data is no longer needed, free it */
-				kfree(info->edid_data);
 			} else {
 				ret = fb_find_mode(&fb->var, fb,
 					   NULL, NULL, 0, NULL, 8);
@@ -1969,7 +1969,7 @@ static int sm501fb_probe(struct platform_device *pdev)
 			/* Get EDID */
 			cp = of_get_property(np, "mode", &len);
 			if (cp)
-				strcpy(fb_mode, cp);
+				info->fb_mode = kstrdup(cp, GFP_KERNEL);
 			prop = of_get_property(np, "edid", &len);
 			if (prop && len == EDID_LENGTH) {
 				info->edid_data = kmemdup(prop, EDID_LENGTH,
@@ -2026,6 +2026,12 @@ static int sm501fb_probe(struct platform_device *pdev)
 		goto err_started_crt;
 	}
 
+	/* These aren't needed any more */
+	kfree(info->edid_data);
+	kfree(info->fb_mode);
+	info->edid_data = NULL;
+	info->fb_mode = NULL;
+
 	/* we registered, return ok */
 	return 0;
 
@@ -2043,6 +2049,8 @@ static int sm501fb_probe(struct platform_device *pdev)
 	framebuffer_release(info->fb[HEAD_CRT]);
 
 err_alloc:
+	kfree(info->edid_data);
+	kfree(info->fb_mode);
 	kfree(info);
 
 	return ret;
Signature · 1 line
2.53.0
author maintainer
#415 lore raw

PATCH 411/1067 btrfs: zoned: dont account data relocation space-info in statfs free space

In reply to Greg Kroah-Hartman

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

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

From: Johannes Thumshirn <[email protected]>

[ Upstream commit 52416a27aabc43eab3792fd0ca9f5dabeab58f31 ]

Don't account the free space in a data relocation space-info sub-group as usable free space in statfs.

This is misleading as no user allocations can be made in this space-info sub-group. It is only a target for relocation.

Fixes f92ee31e031c ("btrfs: introduce btrfs_space_info sub-group")
---
 fs/btrfs/super.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
fs/btrfs/super.c +2 -1
index 91b19d66449bc1..3b8afd05e37480 100644
@@ -2350,7 +2350,8 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	int mixed = 0;
 
 	list_for_each_entry(found, &fs_info->space_info, list) {
-		if (found->flags & BTRFS_BLOCK_GROUP_DATA) {
+		if (found->flags & BTRFS_BLOCK_GROUP_DATA &&
+		    found->subgroup_id != BTRFS_SUB_GROUP_DATA_RELOC) {
 			int i;
 
 			total_free_data += found->disk_total - found->disk_used;
Signature · 1 line
2.53.0
author maintainer
#416 lore raw

PATCH 412/1067 IB/mlx4: Fill in the access_flags if IB_MR_REREG_ACCESS is not specified

In reply to Greg Kroah-Hartman

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

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

From: Jason Gunthorpe <[email protected]>

[ Upstream commit bade9a3150d44ed20b8c6484c4c8a943b7289abb ]

Sashiko noticed mlx4 was using whatever random access flags were provided when IB_MR_REREG_ACCESS is not used. Since IB_MR_REREG_TRANS needs access_flags it used the random ones which means it doesn't work sensibly if userspace provides only IB_MR_REREG_TRANS.

Keep track of the current access_flag of the MR and use it if the user does not specify one.

Also fixup a little confusion around mmr.access, it is the HW access flags so the convert_access() was missing. But nothing reads this by the time rereg_mr can happen.

Fixes 9376932d0c26 ("IB/mlx4_ib: Add support for user MR re-registration")
---
 drivers/infiniband/hw/mlx4/mlx4_ib.h | 1 +
 drivers/infiniband/hw/mlx4/mr.c      | 9 +++++++--
 2 files changed, 8 insertions(+), 2 deletions(-)
drivers/infiniband/hw/mlx4/mlx4_ib.h +1 -0
index 6a3b0f121045e1..110083471f4dc4 100644
@@ -136,6 +136,7 @@ struct mlx4_ib_mr {
 	dma_addr_t		page_map;
 	u32			npages;
 	u32			max_pages;
+	int			access_flags;
 	struct mlx4_mr		mmr;
 	struct ib_umem	       *umem;
 	size_t			page_map_size;
drivers/infiniband/hw/mlx4/mr.c +7 -2
index 004311925dbf9b..db3cd0a9c7ec87 100644
@@ -439,6 +439,7 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
 	if (err)
 		goto err_mr;
 
+	mr->access_flags = access_flags;
 	mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key;
 	mr->ibmr.page_size = 1U << shift;
 
@@ -495,6 +496,8 @@ struct ib_mr *mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags, u64 start,
 
 		if (err)
 			goto release_mpt_entry;
+	} else {
+		mr_access_flags = mmr->access_flags;
 	}
 
 	if (flags & IB_MR_REREG_TRANS) {
@@ -536,8 +539,10 @@ struct ib_mr *mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags, u64 start,
 	 * return a failure. But dereg_mr will free the resources.
 	 */
 	err = mlx4_mr_hw_write_mpt(dev->dev, &mmr->mmr, pmpt_entry);
-	if (!err && flags & IB_MR_REREG_ACCESS)
-		mmr->mmr.access = mr_access_flags;
+	if (!err && flags & IB_MR_REREG_ACCESS) {
+		mmr->access_flags = mr_access_flags;
+		mmr->mmr.access = convert_access(mr_access_flags);
+	}
 
 release_mpt_entry:
 	mlx4_mr_hw_put_mpt(dev->dev, pmpt_entry);
Signature · 1 line
2.53.0
author maintainer
#417 lore raw

PATCH 413/1067 vduse: hold vduse_lock across IDR lookup in open path

In reply to Greg Kroah-Hartman

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

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

From: Qihang Tang <[email protected]>

[ Upstream commit e440e077748939839d9f76e24383b76b785f80ce ]

vduse_dev_open() looks up struct vduse_dev through the IDR and then acquires dev->lock only after vduse_lock has been dropped.

This leaves a window where a concurrent VDUSE_DESTROY_DEV can remove the same object from the IDR and free it before the open path locks the device, leading to a use-after-free.

Close this race by keeping vduse_lock held until dev->lock has been acquired in the open path, matching the lock ordering already used by the destroy path.

Fixes c8a6153b6c59 ("vduse: Introduce VDUSE - vDPA Device in Userspace")

Message-ID: <[email protected]>

---
 drivers/vdpa/vdpa_user/vduse_dev.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)
drivers/vdpa/vdpa_user/vduse_dev.c +7 -14
index 0ccece3f4f7da8..abc35be6e0df9e 100644
@@ -1296,26 +1296,18 @@ static int vduse_dev_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static struct vduse_dev *vduse_dev_get_from_minor(int minor)
+static int vduse_dev_open(struct inode *inode, struct file *file)
 {
+	int ret = -EBUSY;
 	struct vduse_dev *dev;
 
 	mutex_lock(&vduse_lock);
-	dev = idr_find(&vduse_idr, minor);
-	mutex_unlock(&vduse_lock);
-
-	return dev;
-}
-
-static int vduse_dev_open(struct inode *inode, struct file *file)
-{
-	int ret;
-	struct vduse_dev *dev = vduse_dev_get_from_minor(iminor(inode));
-
-	if (!dev)
+	dev = idr_find(&vduse_idr, iminor(inode));
+	if (!dev) {
+		mutex_unlock(&vduse_lock);
 		return -ENODEV;
+	}
 
-	ret = -EBUSY;
 	mutex_lock(&dev->lock);
 	if (dev->connected)
 		goto unlock;
@@ -1325,6 +1317,7 @@ static int vduse_dev_open(struct inode *inode, struct file *file)
 	file->private_data = dev;
 unlock:
 	mutex_unlock(&dev->lock);
+	mutex_unlock(&vduse_lock);
 
 	return ret;
 }
Signature · 1 line
2.53.0
author maintainer
#418 lore raw

PATCH 414/1067 vhost/vdpa: validate virtqueue index in mmap and fault paths

In reply to Greg Kroah-Hartman

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

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

From: Qihang Tang <[email protected]>

[ Upstream commit 929e4f044621c8cc30b612fb74e1410bef09e41b ]

vhost_vdpa_mmap() and vhost_vdpa_fault() use vma->vm_pgoff as a virtqueue index for get_vq_notification(), but they do not validate that the index is smaller than v->nvqs.

The ioctl path already performs both a bounds check and array_index_nospec(), but the mmap/fault path only checks that the index fits in u16. This allows an out-of-range queue index to reach driver-specific get_vq_notification() callbacks.

Fix this by extracting a unified vhost_vdpa_get_vq_notification() helper that validates the queue index against v->nvqs and applies array_index_nospec() before calling the driver callback. Both the mmap and fault paths use this helper, and the bounds checking is consolidated into a single location.

Quoted 1 line

From source inspection, the most defensible impact is out-of-bounds

access in the callback path, potentially leading to invalid PFN remaps and crash/DoS.

Fixes ddd89d0a059d ("vhost_vdpa: support doorbell mapping via mmap")

Message-ID: <[email protected]>

---
 drivers/vhost/vdpa.c | 29 ++++++++++++++++++++++-------
 1 file changed, 22 insertions(+), 7 deletions(-)
drivers/vhost/vdpa.c +22 -7
index 59587f9880d3c7..7684c16e9e07a2 100644
@@ -1295,16 +1295,32 @@ static int vhost_vdpa_release(struct inode *inode, struct file *filep)
 }
 
 #ifdef CONFIG_MMU
-static vm_fault_t vhost_vdpa_fault(struct vm_fault *vmf)
+static int
+vhost_vdpa_get_vq_notification(struct vhost_vdpa *v, unsigned long index,
+			       struct vdpa_notification_area *notify)
 {
-	struct vhost_vdpa *v = vmf->vma->vm_file->private_data;
 	struct vdpa_device *vdpa = v->vdpa;
 	const struct vdpa_config_ops *ops = vdpa->config;
+
+	if (index > 65535 || index >= v->nvqs)
+		return -EINVAL;
+
+	index = array_index_nospec(index, v->nvqs);
+
+	*notify = ops->get_vq_notification(vdpa, index);
+
+	return 0;
+}
+
+static vm_fault_t vhost_vdpa_fault(struct vm_fault *vmf)
+{
+	struct vhost_vdpa *v = vmf->vma->vm_file->private_data;
 	struct vdpa_notification_area notify;
 	struct vm_area_struct *vma = vmf->vma;
-	u16 index = vma->vm_pgoff;
+	unsigned long index = vma->vm_pgoff;
 
-	notify = ops->get_vq_notification(vdpa, index);
+	if (vhost_vdpa_get_vq_notification(v, index, &notify))
+		return VM_FAULT_SIGBUS;
 
 	return vmf_insert_pfn(vma, vmf->address & PAGE_MASK, PFN_DOWN(notify.addr));
 }
@@ -1327,8 +1343,6 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma)
 		return -EINVAL;
 	if (vma->vm_flags & VM_READ)
 		return -EINVAL;
-	if (index > 65535)
-		return -EINVAL;
 	if (!ops->get_vq_notification)
 		return -ENOTSUPP;
 
@@ -1336,7 +1350,8 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma)
 	 * support the doorbell which sits on the page boundary and
 	 * does not share the page with other registers.
 	 */
-	notify = ops->get_vq_notification(vdpa, index);
+	if (vhost_vdpa_get_vq_notification(v, index, &notify))
+		return -EINVAL;
 	if (notify.addr & (PAGE_SIZE - 1))
 		return -EINVAL;
 	if (vma->vm_end - vma->vm_start != notify.size)
Signature · 1 line
2.53.0
author maintainer
#419 lore raw

PATCH 415/1067 vduse: Requeue failed read to send_list head

In reply to Greg Kroah-Hartman

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

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

From: Zhang Tianci <[email protected]>

[ Upstream commit 373ec43ded742b2f3aecf14731ffe1a57f438f38 ]

When copy_to_iter() fails in vduse_dev_read_iter(), put the message back at the head of send_list to preserve FIFO ordering and retry the oldest pending request first.

Message-ID: <[email protected]>

---
 drivers/vdpa/vdpa_user/vduse_dev.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/vdpa/vdpa_user/vduse_dev.c +7 -1
index abc35be6e0df9e..075f5853bb4d7d 100644
@@ -182,6 +182,12 @@ static void vduse_enqueue_msg(struct list_head *head,
 	list_add_tail(&msg->list, head);
 }
 
+static void vduse_enqueue_msg_head(struct list_head *head,
+				   struct vduse_dev_msg *msg)
+{
+	list_add(&msg->list, head);
+}
+
 static void vduse_dev_broken(struct vduse_dev *dev)
 {
 	struct vduse_dev_msg *msg, *tmp;
@@ -342,7 +348,7 @@ static ssize_t vduse_dev_read_iter(struct kiocb *iocb, struct iov_iter *to)
 	spin_lock(&dev->msg_lock);
 	if (ret != size) {
 		ret = -EFAULT;
-		vduse_enqueue_msg(&dev->send_list, msg);
+		vduse_enqueue_msg_head(&dev->send_list, msg);
 		goto unlock;
 	}
 	vduse_enqueue_msg(&dev->recv_list, msg);
Signature · 1 line
2.53.0
author maintainer
#420 lore raw

PATCH 416/1067 vhost/net: complete zerocopy ubufs only once

In reply to Greg Kroah-Hartman

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

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

From: Qing Ming <[email protected]>

[ Upstream commit 8f6898fe80794f2d7c3d38c1158c806e4074a1c4 ]

vhost-net initializes one ubuf_info per outstanding zerocopy TX descriptor and hands it to the backend socket. The networking stack may then clone a zerocopy skb before all skb references are released. For example, batman-adv fragmentation reaches skb_split(), which calls skb_zerocopy_clone() and increments the same ubuf_info refcount.

vhost_zerocopy_complete() currently treats every ubuf callback as a completed vhost descriptor. It dereferences ubuf->ctx, writes the descriptor completion state, and drops the vhost_net_ubuf_ref even when the callback only releases a cloned skb reference. A backend reset can therefore wait for and free the vhost_net_ubuf_ref while another cloned skb still carries the same ubuf_info. A later completion then dereferences the freed ubufs pointer.

KASAN reports the stale completion as:

  BUG: KASAN: slab-use-after-free in vhost_zerocopy_complete+0x1d7/0x1f0
  BUG: KASAN: slab-use-after-free in vhost_zerocopy_complete+0x101/0x1f0
  vhost_zerocopy_complete
  skb_copy_ubufs
  __dev_forward_skb2
  veth_xmit

The freed object was allocated from vhost_net_ioctl() while setting the backend and freed through kfree_rcu()/kvfree_rcu_bulk after backend removal, while delayed skb completion still reached vhost_zerocopy_complete().

Honor the generic ubuf_info refcount before touching vhost state, and run the vhost descriptor completion only for the final ubuf reference. This matches the msg_zerocopy_complete() ownership rule for cloned zerocopy skbs.

Fixes bab632d69ee4 ("vhost: vhost TX zero-copy support")

Message-ID: <[email protected]>

---
 drivers/vhost/net.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)
drivers/vhost/net.c +11 -4
index 3ae572df07960e..a6f966864252a4 100644
@@ -389,13 +389,20 @@ static void vhost_zerocopy_signal_used(struct vhost_net *net,
 static void vhost_zerocopy_callback(struct sk_buff *skb,
 				    struct ubuf_info *ubuf_base, bool success)
 {
-	struct ubuf_info_msgzc *ubuf = uarg_to_msgzc(ubuf_base);
-	struct vhost_net_ubuf_ref *ubufs = ubuf->ctx;
-	struct vhost_virtqueue *vq = ubufs->vq;
+	struct ubuf_info_msgzc *ubuf;
+	struct vhost_net_ubuf_ref *ubufs;
+	struct vhost_virtqueue *vq;
 	int cnt;
 
-	rcu_read_lock_bh();
+	/* Only the final cloned skb reference completes the vhost descriptor. */
+	if (!refcount_dec_and_test(&ubuf_base->refcnt))
+		return;
+
+	ubuf = uarg_to_msgzc(ubuf_base);
+	ubufs = ubuf->ctx;
+	vq = ubufs->vq;
 
+	rcu_read_lock_bh();
 	/* set len to mark this desc buffers done DMA */
 	vq->heads[ubuf->desc].len = success ?
 		VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN;
Signature · 1 line
2.53.0
author maintainer
#421 lore raw

PATCH 417/1067 tools/virtio: check mmap return value in vringh_test

In reply to Greg Kroah-Hartman

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

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

From: longlong yan <[email protected]>

[ Upstream commit ec6177dfe98b9be1c3ede6c0dfe4394ea2a76959 ]

In parallel_test(), the return values of mmap() for both host_map and guest_map are not checked against MAP_FAILED. If mmap() fails, the subsequent code will dereference the invalid pointer, leading to a segmentation fault.

Add MAP_FAILED checks after both mmap() calls, using err() to report the error and exit, consistent with the existing error handling style in this file (e.g., the open() call on line 149).

Fixes 1515c5ce26ae ("tools/virtio: add vring_test.")

Message-ID: <[email protected]>

---
 tools/virtio/vringh_test.c | 5 +++++
 1 file changed, 5 insertions(+)
tools/virtio/vringh_test.c +5 -0
index 98ff808d6f0c2d..16f3723b467129 100644
@@ -159,7 +159,12 @@ static int parallel_test(u64 features,
 
 	/* Parent and child use separate addresses, to check our mapping logic! */
 	host_map = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+	if (host_map == MAP_FAILED)
+		err(1, "mmap host_map");
+
 	guest_map = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+	if (guest_map == MAP_FAILED)
+		err(1, "mmap guest_map");
 
 	pipe(to_guest);
 	pipe(to_host);
Signature · 1 line
2.53.0
author maintainer
#422 lore raw

PATCH 418/1067 bonding: 3ad: fix mux port state on oper down

In reply to Greg Kroah-Hartman

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

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

From: Louis Scalbert <[email protected]>

[ Upstream commit 807afc7544b865d4d09068a415fd5b71bf5665cc ]

When the bonding interface has carrier down due to the absence of usable slaves and a slave transitions from down to up, the bonding interface briefly goes carrier up, then down again, and finally up once LACP negotiates collecting and distributing on the port.

When lacp_strict mode is on, the interface should not transition to carrier up until LACP negotiation is complete.

This happens because the actor and partner port states remain in Collecting_Distributing when the port goes down. When the port comes back up, it temporarily remains in this state until LACP renegotiation occurs.

Previously this was mostly cosmetic, but since the bonding carrier state may depend on the LACP negotiation state, it causes the interface to flap.

According to IEEE 802.3ad-2000 and IEEE 802.1ax-2014, Collecting and Distributing should be reset when a port goes down:
- In the Receive state machine, port_enabled == FALSE causes a transition to the PORT_DISABLED state, which is expected to clear Partner_Oper_Port_State.Synchronization.
- In the Mux state machine, Partner_Oper_Port_State.Synchronization == FALSE causes a transition to the ATTACHED state, which disables Collecting and Distributing.

However, Partner_Oper_Port_State.Synchronization is not cleared in the PORT_DISABLED state.

Clear Partner_Oper_Port_State.Synchronization in the Receive PORT_DISABLED state.

---
 drivers/net/bonding/bond_3ad.c | 1 +
 1 file changed, 1 insertion(+)
drivers/net/bonding/bond_3ad.c +1 -0
index 2849c2e6a89515..dedb1a86a6eaab 100644
@@ -1275,6 +1275,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
 			fallthrough;
 		case AD_RX_PORT_DISABLED:
 			port->sm_vars &= ~AD_PORT_MATCHED;
+			port->partner_oper.port_state &= ~LACP_STATE_SYNCHRONIZATION;
 			break;
 		case AD_RX_LACP_DISABLED:
 			port->sm_vars &= ~AD_PORT_SELECTED;
Signature · 1 line
2.53.0
author maintainer
#423 lore raw

PATCH 419/1067 selftests/bpf: Fix bpf_iter/task_vma test

In reply to Greg Kroah-Hartman

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

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

From: Yonghong Song <[email protected]>

[ Upstream commit 2e8ad1ff712d2a397e407c9fde60901f68d077dc ]

For selftest bpf_iter/task_vma, I got a failure like below on my qemu run:

test_task_vma_common:FAIL:compare_output unexpected compare_output:

    actual
    '561593546000-561593585000r--p0000000000:241256579534/root/devshare/bpf-next/tools/testing/selftests/bpf/test_progs'
    != expected
    '561593546000-561593585000r--p0000000000:245551546830/root/devshare/bpf-next/tools/testing/selftests/bpf/test_progs'

Further debugging found out file->f_inode->i_ino value may exceed 32bit, e.g., i_ino = 0x14c2eae35, but the format string is '%u'. This caused inode mismatch between bpf iter and proc result.

Fix the issue by using format string '%llu' to accommodate 64bit i_ino.

---
 tools/testing/selftests/bpf/progs/bpf_iter_task_vma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/bpf/progs/bpf_iter_task_vma.c +1 -1
index dd923dc637d5c6..97f7e8d5b6c9d5 100644
@@ -52,7 +52,7 @@ SEC("iter/task_vma") int proc_maps(struct bpf_iter__task_vma *ctx)
 		bpf_d_path(&file->f_path, d_path_buf, D_PATH_BUF_SIZE);
 
 		BPF_SEQ_PRINTF(seq, "%08llx ", vma->vm_pgoff << 12);
-		BPF_SEQ_PRINTF(seq, "%02x:%02x %u", MAJOR(dev), MINOR(dev),
+		BPF_SEQ_PRINTF(seq, "%02x:%02x %llu", MAJOR(dev), MINOR(dev),
 			       file->f_inode->i_ino);
 		BPF_SEQ_PRINTF(seq, "\t%s\n", d_path_buf);
 	} else {
Signature · 1 line
2.53.0
author maintainer
#424 lore raw

PATCH 420/1067 cxl/test: Fix integer overflow in mock LSA bounds checks

In reply to Greg Kroah-Hartman

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

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

From: Dave Jiang <[email protected]>

[ Upstream commit 81eafcada109b653977c4dfbd2b6a72470025a01 ]

Pre-existing issue discovered by sashiko-bot.

mock_get_lsa() and mock_set_lsa() validate the requested LSA range with "offset + length > LSA_SIZE". Both offset and length are u32 and, in mock_get_lsa(), both are taken directly from the user-supplied payload. The addition is evaluated modulo 2^32, so a large offset combined with a small length wraps around and passes the check.

Rewrite the checks to first bound offset, then compare length against the remaining LSA size.

Suggested-by sashiko-bot
Fixes 7d3eb23c4ccf ("tools/testing/cxl: Introduce a mock memory device + driver")
Assisted-by Claude:claude-opus-4-8
---
 tools/testing/cxl/test/mem.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
tools/testing/cxl/test/mem.c +2 -2
index 6e9a89f54d94f5..e171a2f48719a5 100644
@@ -148,7 +148,7 @@ static int mock_get_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
 		return -EINVAL;
 	offset = le32_to_cpu(get_lsa->offset);
 	length = le32_to_cpu(get_lsa->length);
-	if (offset + length > LSA_SIZE)
+	if (offset > LSA_SIZE || length > LSA_SIZE - offset)
 		return -EINVAL;
 	if (length > cmd->size_out)
 		return -EINVAL;
@@ -167,7 +167,7 @@ static int mock_set_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
 		return -EINVAL;
 	offset = le32_to_cpu(set_lsa->offset);
 	length = cmd->size_in - sizeof(*set_lsa);
-	if (offset + length > LSA_SIZE)
+	if (offset > LSA_SIZE || length > LSA_SIZE - offset)
 		return -EINVAL;
 
 	memcpy(lsa + offset, &set_lsa->data[0], length);
Signature · 1 line
2.53.0
author maintainer
#425 lore raw

PATCH 421/1067 bpf: Tighten cgroup storage cookie checks for prog arrays

In reply to Greg Kroah-Hartman

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

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

From: Daniel Borkmann <[email protected]>

[ Upstream commit 10627ddc0167aab5c1c390a10ef461e9937aba08 ]

The fix in commit abad3d0bad72 ("bpf: Fix oob access in cgroup local storage") is still incomplete. The prog-array compatibility check treats a program with no cgroup storage as compatible with any stored storage cookie. This allows a storage-less program to bridge a tail call chain between an entry program and a storage-using callee even though cgroup local storage at runtime still follows the caller's context, that is, A -> B(no storage) -> C(storage) path.

Requiring exact cookie equality would break the legitimate case of a storage-less leaf program being tail called from a storage-using one. Instead, only accept a zero storage cookie if the program cannot perform tail calls itself. This keeps A -> B(no storage) working while rejecting the A -> B(no storage) -> C(storage) bridge.

---
 kernel/bpf/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/core.c +1 -1
index 6924f86a8a3ff1..77044d4a80cc16 100644
@@ -2159,7 +2159,7 @@ bool bpf_prog_map_compatible(struct bpf_map *map,
 			cookie = aux->cgroup_storage[i] ?
 				 aux->cgroup_storage[i]->cookie : 0;
 			ret = map->owner->storage_cookie[i] == cookie ||
-			      !cookie;
+			      (!cookie && !aux->tail_call_reachable);
 		}
 		if (ret &&
 		    map->owner->attach_func_proto != aux->attach_func_proto) {
Signature · 1 line
2.53.0
author maintainer
#426 lore raw

PATCH 422/1067 s390/process: Fix kernel thread function pointer type

In reply to Greg Kroah-Hartman

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

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

From: Heiko Carstens <[email protected]>

[ Upstream commit d0478f5d3cba1095bfdeb43a9b063c10cdebef14 ]

In case of a kernel thread __ret_from_fork() calls the specified function indirectly. Fix the kernel thread function pointer, since kernel threads return an int instead of void.

Fixes 56e62a737028 ("s390: convert to generic entry")
---
 arch/s390/kernel/process.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kernel/process.c +1 -1
index 42af4b3aa02b85..407500eca5328e 100644
@@ -48,7 +48,7 @@ void ret_from_fork(void) asm("ret_from_fork");
 
 void __ret_from_fork(struct task_struct *prev, struct pt_regs *regs)
 {
-	void (*func)(void *arg);
+	int (*func)(void *arg);
 
 	schedule_tail(prev);
 
Signature · 1 line
2.53.0
author maintainer
#427 lore raw

PATCH 423/1067 Bluetooth: eir: Fix stack OOB write when prepending the Flags AD

In reply to Greg Kroah-Hartman

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

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

From: Weiming Shi <[email protected]>

[ Upstream commit 6f5fb689fdf80bdd143f22a502f9eb1f3c85e286 ]

eir_create_adv_data() builds the advertising data into a fixed-size buffer ("size", 31 for the legacy path). It may prepend a 3-byte "Flags" AD structure (LE_AD_NO_BREDR on an LE-only controller) and then copies the per-instance data without checking that it still fits:

	memcpy(ptr, adv->adv_data, adv->adv_data_len);

tlv_data_max_len() only reserves those 3 bytes when the user-supplied flags carry a managed-flags bit, so an instance added with flags == 0 is accepted with adv_data_len up to the full buffer. At advertise time the flags are still prepended, and the memcpy() writes 3 + adv_data_len bytes into the size-byte buffer:

  BUG: KASAN: stack-out-of-bounds in eir_create_adv_data (net/bluetooth/eir.c:301)
  Write of size 31 at addr ffff88800a547bdc by task kworker/u9:0/65
  Workqueue: hci0 hci_cmd_sync_work
   __asan_memcpy (mm/kasan/shadow.c:106)
   eir_create_adv_data (net/bluetooth/eir.c:301)
   hci_update_adv_data_sync (net/bluetooth/hci_sync.c:1310)
   hci_schedule_adv_instance_sync (net/bluetooth/hci_sync.c:1817)
   hci_cmd_sync_work (net/bluetooth/hci_sync.c:332)
  This frame has 1 object:
   [32, 64) 'cp'

The "Flags" structure is added by the kernel, not requested by userspace, so only prepend it when it fits together with the instance advertising data; when there is no room for both, drop the flags rather than the user-provided data.

Reachable by a local user with CAP_NET_ADMIN owning an LE-only controller on the legacy advertising path.

Fixes b44133ff03be ("Bluetooth: Support the "discoverable" adv flag")
Assisted-by Claude:claude-opus-4-8
---
 net/bluetooth/eir.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
net/bluetooth/eir.c +5 -3
index 3f72111ba651f9..1de5f9df6eec00 100644
@@ -283,10 +283,12 @@ u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size)
 		if (!flags)
 			flags |= mgmt_get_adv_discov_flags(hdev);
 
-		/* If flags would still be empty, then there is no need to
-		 * include the "Flags" AD field".
+		/* Only add the "Flags" if it fits together with the instance
+		 * advertising data; drop it rather than overflow the buffer.
 		 */
-		if (flags && (ad_len + eir_precalc_len(1) <= size)) {
+		if (flags &&
+		    (ad_len + eir_precalc_len(1) +
+		     (adv ? adv->adv_data_len : 0) <= size)) {
 			ptr[0] = 0x02;
 			ptr[1] = EIR_FLAGS;
 			ptr[2] = flags;
Signature · 1 line
2.53.0
author maintainer
#428 lore raw

PATCH 424/1067 Bluetooth: hci: validate codec capability element length

In reply to Greg Kroah-Hartman

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

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

From: Samuel Moelius <[email protected]>

[ Upstream commit c38fbcdc407925c7088f7e5f11c1fff73d2d35a2 ]

Read Local Codec Capabilities returns a sequence of capability elements. Each element starts with a one-byte length followed by that many payload bytes.

hci_read_codec_capabilities() checks that the skb contains the length byte, but then validates only caps->len against the remaining skb length. A malformed controller response with one remaining byte and caps->len set to one passes that check even though the element needs two bytes. The parser then records a two-byte capability and copies one byte beyond the advertised response payload into the codec list.

Validate the full element size, including the length byte, before adding it to the accumulated capability length. This preserves all well-formed capability elements and drops only truncated controller responses.

Fixes 8961987f3f5f ("Bluetooth: Enumerate local supported codec and cache details")
Assisted-by Codex:gpt-5.5-cyber-preview
---
 net/bluetooth/hci_codec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/hci_codec.c +1 -1
index 3cc135bb1d30ca..5bc5003c387c66 100644
@@ -100,7 +100,7 @@ static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport,
 				caps = (void *)skb->data;
 				if (skb->len < sizeof(*caps))
 					goto error;
-				if (skb->len < caps->len)
+				if (skb->len < sizeof(caps->len) + caps->len)
 					goto error;
 				len += sizeof(caps->len) + caps->len;
 				skb_pull(skb,  sizeof(caps->len) + caps->len);
Signature · 1 line
2.53.0
author maintainer
#429 lore raw

PATCH 425/1067 fs: efs: remove unneeded debug prints

In reply to Greg Kroah-Hartman

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

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

From: Maxwell Doose <[email protected]>

[ Upstream commit 89009392c80da5da00876c8334ff20028e6e3eb6 ]

The current code uses debug prints conditionally compiled with #ifdef DEBUG. However, that code, when compiled, causes compiler errors due to incompatible formatters and undefined variables, notably:

fs/efs/file.c: In function `efs_get_block':
fs/efs/file.c:26:35: error: block' undeclared (first use in this function); did you mean iblock'?
26 | __func__, block, inode->i_blocks, inode->i_size);
| ^~~~~

and:

fs/efs/file.c: In function `efs_bmap':
./include/linux/kern_levels.h:5:25: error: format %ld' expects argument of type long int', but argument 4 has type blkcnt_t' {aka long long unsigned int'} [-Werror=format=]

   5 | #define KERN_SOH        "\001"          /* ASCII Start Of Header */
     |                         ^~~~~~

which also extends to the other formatters. As this part of the code has been dead for just about 14 years now, it has not been modernized to stay compatible with the most recent gcc compilers. Fix these issues by removing the debug prints.

Fixes f403d1dbac6d ("fs/efs: add pr_fmt / use __func__")
Cc Fabian Frederick <[email protected]>
Cc Christian Brauner <[email protected]>
---
 fs/efs/file.c | 21 +++------------------
 1 file changed, 3 insertions(+), 18 deletions(-)
fs/efs/file.c +3 -18
index 9e641da6fab276..9153dfe79bbcc9 100644
@@ -18,16 +18,9 @@ int efs_get_block(struct inode *inode, sector_t iblock,
 
 	if (create)
 		return error;
-	if (iblock >= inode->i_blocks) {
-#ifdef DEBUG
-		/*
-		 * i have no idea why this happens as often as it does
-		 */
-		pr_warn("%s(): block %d >= %ld (filesize %ld)\n",
-			__func__, block, inode->i_blocks, inode->i_size);
-#endif
+	if (iblock >= inode->i_blocks)
 		return 0;
-	}
+
 	phys = efs_map_block(inode, iblock);
 	if (phys)
 		map_bh(bh_result, inode->i_sb, phys);
@@ -42,16 +35,8 @@ int efs_bmap(struct inode *inode, efs_block_t block) {
 	}
 
 	/* are we about to read past the end of a file ? */
-	if (!(block < inode->i_blocks)) {
-#ifdef DEBUG
-		/*
-		 * i have no idea why this happens as often as it does
-		 */
-		pr_warn("%s(): block %d >= %ld (filesize %ld)\n",
-			__func__, block, inode->i_blocks, inode->i_size);
-#endif
+	if (!(block < inode->i_blocks))
 		return 0;
-	}
 
 	return efs_map_block(inode, block);
 }
Signature · 1 line
2.53.0
author maintainer
#430 lore raw

PATCH 426/1067 RDMA/mlx5: Remove raw RSS QP restrack tracking

In reply to Greg Kroah-Hartman

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

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

From: Patrisious Haddad <[email protected]>

[ Upstream commit 666031fed8f0fdfc29b20d125a628c1b0a04cdaf ]

Raw RSS QP restrack tracking wasn't working to begin with as it was only tracking the first raw RSS QP which was added, since at creation the raw RSS QP number is reserved so the QP number for this qp type was always zero.
The following raw RSS QP additions were always failing silently.

Since the fix isn't trivial and there were no users that required or complained about this issue we are dropping this for now instead of fixing.

Fixes 968f0b6f9c01 ("RDMA/mlx5: Consolidate into special function all create QP calls")
---
 drivers/infiniband/hw/mlx5/qp.c | 1 +
 1 file changed, 1 insertion(+)
drivers/infiniband/hw/mlx5/qp.c +1 -0
index d782a494abcda6..25d3d657889f46 100644
@@ -3005,6 +3005,7 @@ static int create_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,
 	int err;
 
 	if (params->is_rss_raw) {
+		rdma_restrack_no_track(&qp->ibqp.res);
 		err = create_rss_raw_qp_tir(dev, pd, qp, params);
 		goto out;
 	}
Signature · 1 line
2.53.0
author maintainer
#431 lore raw

PATCH 427/1067 RDMA/mlx5: Fix undefined shift of user RQ WQE size

In reply to Greg Kroah-Hartman

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

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

From: Maher Sanalla <[email protected]>

[ Upstream commit d881d60223aac8fdc12b227d89c76e131e92a9cd ]

set_rq_size() computes the RQ WQE size as "1 << rq_wqe_shift" based on the user-provided rq_wqe_shift, which is only checked to be greater than 32, so shifts of 32 are still accepted. A shift of 31 also overflows a signed integer, leading to undefined behavior.

Use check_shl_overflow() to compute the RQ WQE size and reject any invalid values.

Fixes e126ba97dba9 ("mlx5: Add driver for Mellanox Connect-IB adapters")
---
 drivers/infiniband/hw/mlx5/qp.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)
drivers/infiniband/hw/mlx5/qp.c +4 -7
index 25d3d657889f46..a431f9665b7202 100644
@@ -370,16 +370,13 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
 
 		if (ucmd) {
 			qp->rq.wqe_cnt = ucmd->rq_wqe_count;
-			if (ucmd->rq_wqe_shift > BITS_PER_BYTE * sizeof(ucmd->rq_wqe_shift))
-				return -EINVAL;
 			qp->rq.wqe_shift = ucmd->rq_wqe_shift;
-			if ((1 << qp->rq.wqe_shift) /
-				    sizeof(struct mlx5_wqe_data_seg) <
-			    wq_sig)
+			if (check_shl_overflow(1, qp->rq.wqe_shift, &wqe_size))
+				return -EINVAL;
+			if (wqe_size / sizeof(struct mlx5_wqe_data_seg) < wq_sig)
 				return -EINVAL;
 			qp->rq.max_gs =
-				(1 << qp->rq.wqe_shift) /
-					sizeof(struct mlx5_wqe_data_seg) -
+				wqe_size / sizeof(struct mlx5_wqe_data_seg) -
 				wq_sig;
 			qp->rq.max_post = qp->rq.wqe_cnt;
 		} else {
Signature · 1 line
2.53.0
author maintainer
#432 lore raw

PATCH 428/1067 RDMA/mlx5: Release the HW‑provided UAR index rather than the SW one

In reply to Greg Kroah-Hartman

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

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

From: Leon Romanovsky <[email protected]>

[ Upstream commit 449ae7927152e46acbe5f19f97eafdae6d3a96b1 ]

Free the UAR index returned by the hardware.

Fixes 4ed131d0bb15 ("IB/mlx5: Expose dynamic mmap allocation")
---
 drivers/infiniband/hw/mlx5/main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/main.c +1 -1
index 45a414e8d35faf..7102c3a78ee9d3 100644
@@ -2229,7 +2229,7 @@ static int uar_mmap(struct mlx5_ib_dev *dev, enum mlx5_ib_mmap_cmd cmd,
 	if (!dyn_uar)
 		return err;
 
-	mlx5_cmd_uar_dealloc(dev->mdev, idx, context->devx_uid);
+	mlx5_cmd_uar_dealloc(dev->mdev, uar_index, context->devx_uid);
 
 free_bfreg:
 	mlx5_ib_free_bfreg(dev, bfregi, bfreg_dyn_idx);
Signature · 1 line
2.53.0
author maintainer
#433 lore raw

PATCH 429/1067 ASoC: codecs: hdac_hdmi: Validate written enum value

In reply to Greg Kroah-Hartman

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

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

From: HyeongJun An <[email protected]>

[ Upstream commit 0b08baeccdcf52fad328ad645f5b4fbee04eea34 ]

hdac_hdmi_set_pin_port_mux() uses the written enum value to index the texts array before calling snd_soc_dapm_put_enum_double(), which validates that the value is within the enum item range.

An out-of-range value can therefore make the driver read past the texts array before the helper rejects the write. Move the lookup after the helper has accepted the value.

Fixes 4a3478debf36 ("ASoC: hdac_hdmi: Add jack reporting")
Assisted-by Claude:claude-opus-4-8
---
 sound/soc/codecs/hdac_hdmi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
sound/soc/codecs/hdac_hdmi.c +3 -1
index 90baca4c2b4dbc..b9e2e5a9601396 100644
@@ -906,12 +906,14 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
 	struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
 	struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
 	struct hdac_hdmi_pcm *pcm;
-	const char *cvt_name =  e->texts[ucontrol->value.enumerated.item[0]];
+	const char *cvt_name;
 
 	ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
 	if (ret < 0)
 		return ret;
 
+	cvt_name = e->texts[ucontrol->value.enumerated.item[0]];
+
 	if (port == NULL)
 		return -EINVAL;
 
Signature · 1 line
2.53.0
author maintainer
#434 lore raw

PATCH 430/1067 ASoC: fsl: fsl_audmix: Validate written enum values

In reply to Greg Kroah-Hartman

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

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

From: HyeongJun An <[email protected]>

[ Upstream commit 3cd17e4e2871114d5579fa7bc8da66faf7fc1930 ]

fsl_audmix_put_mix_clk_src() and fsl_audmix_put_out_src() convert the user-provided enum item with snd_soc_enum_item_to_val() before checking whether the item is within the enum's item count.

The generic snd_soc_put_enum_double() helper performs that validation, but these callbacks use the converted value first: the clock-source path tests it with BIT(), and the output-source path indexes the prms transition table with it.

Reject out-of-range enum items before converting them.

Fixes be1df61cf06e ("ASoC: fsl: Add Audio Mixer CPU DAI driver")
Assisted-by Claude:claude-opus-4-8
---
 sound/soc/fsl/fsl_audmix.c | 6 ++++++
 1 file changed, 6 insertions(+)
sound/soc/fsl/fsl_audmix.c +6 -0
index acb499a5043c83..f391fc95daa7fe 100644
@@ -117,6 +117,9 @@ static int fsl_audmix_put_mix_clk_src(struct snd_kcontrol *kcontrol,
 	unsigned int *item = ucontrol->value.enumerated.item;
 	unsigned int reg_val, val, mix_clk;
 
+	if (item[0] >= e->items)
+		return -EINVAL;
+
 	/* Get current state */
 	reg_val = snd_soc_component_read(comp, FSL_AUDMIX_CTR);
 	mix_clk = ((reg_val & FSL_AUDMIX_CTR_MIXCLK_MASK)
@@ -157,6 +160,9 @@ static int fsl_audmix_put_out_src(struct snd_kcontrol *kcontrol,
 	unsigned int reg_val, val, mask = 0, ctr = 0;
 	int ret;
 
+	if (item[0] >= e->items)
+		return -EINVAL;
+
 	/* Get current state */
 	reg_val = snd_soc_component_read(comp, FSL_AUDMIX_CTR);
 
Signature · 1 line
2.53.0
author maintainer
#435 lore raw

PATCH 431/1067 ASoC: tegra: tegra210_ahub: Validate written enum value

In reply to Greg Kroah-Hartman

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

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

From: HyeongJun An <[email protected]>

[ Upstream commit 1d8aabb413b5638670dfd1162169edc0ba276a2e ]

tegra_ahub_put_value_enum() reads e->values[item[0]] before checking whether item[0] is within the enum item range. The existing check therefore happens too late to prevent an out-of-range read of the values array.

Move the check before the array access.

Fixes 16e1bcc2caf4 ("ASoC: tegra: Add Tegra210 based AHUB driver")
Assisted-by Claude:claude-opus-4-8
---
 sound/soc/tegra/tegra210_ahub.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
sound/soc/tegra/tegra210_ahub.c +3 -1
index 4be56835041546..6dcd7efe0802e9 100644
@@ -60,13 +60,15 @@ static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
 	struct soc_enum *e = (struct soc_enum *)kctl->private_value;
 	struct snd_soc_dapm_update update[TEGRA_XBAR_UPDATE_MAX_REG] = { };
 	unsigned int *item = uctl->value.enumerated.item;
-	unsigned int value = e->values[item[0]];
+	unsigned int value;
 	unsigned int i, bit_pos, reg_idx = 0, reg_val = 0;
 	int change = 0;
 
 	if (item[0] >= e->items)
 		return -EINVAL;
 
+	value = e->values[item[0]];
+
 	if (value) {
 		/* Get the register index and value to set */
 		reg_idx = (value - 1) / (8 * cmpnt->val_bytes);
Signature · 1 line
2.53.0
author maintainer
#436 lore raw

PATCH 432/1067 net/sched: cls_flow: Dont expose folded kernel pointers

In reply to Greg Kroah-Hartman

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

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

From: Jamal Hadi Salim <[email protected]>

[ Upstream commit f294fc71c4a0fa4964f6428a1b4e7929c1d83125 ]

The flow classifier falls back to addr_fold() for fields that are missing from packet headers. In map mode, userspace controls mask, xor, rshift, addend and divisor, and can observe the resulting classid through class statistics. This allows a tc classifier in a user/network namespace to recover the 32-bit folded value of skb->sk, skb_dst() or skb_nfct().

Align with standard kernel practices for pointer hashing and replace the XOR folding with a keyed siphash (which is cryptographically secure)

---
 net/sched/cls_flow.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
net/sched/cls_flow.c +9 -3
index 64b281cca6ae73..315d689adf651f 100644
@@ -21,6 +21,7 @@
 #include <net/inet_sock.h>
 
 #include <net/pkt_cls.h>
+#include <linux/siphash.h>
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/flow_dissector.h>
@@ -56,11 +57,15 @@ struct flow_filter {
 	struct rcu_work		rwork;
 };
 
+static siphash_aligned_key_t flow_keys_secret __read_mostly;
+
 static inline u32 addr_fold(void *addr)
 {
-	unsigned long a = (unsigned long)addr;
-
-	return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0);
+#ifdef CONFIG_64BIT
+	return (u32)siphash_1u64((u64)addr, &flow_keys_secret);
+#else
+	return (u32)siphash_1u32((u32)addr, &flow_keys_secret);
+#endif
 }
 
 static u32 flow_get_src(const struct sk_buff *skb, const struct flow_keys *flow)
@@ -594,6 +599,7 @@ static int flow_init(struct tcf_proto *tp)
 		return -ENOBUFS;
 	INIT_LIST_HEAD(&head->filters);
 	rcu_assign_pointer(tp->root, head);
+	net_get_random_once(&flow_keys_secret, sizeof(flow_keys_secret));
 	return 0;
 }
 
Signature · 1 line
2.53.0
author maintainer
#437 lore raw

PATCH 433/1067 net: fib_rules: Dont dump dying fib_rule in fib_rules_dump().

In reply to Greg Kroah-Hartman

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

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

From: Kuniyuki Iwashima <[email protected]>

[ Upstream commit 2821e85c058f81c9948a2fb1a634f7b47457d51c ]

rocker_router_fib_event() calls fib_rule_get() during RCU dump.

If the fib_rule is dying, refcount_inc() will complain about it.

Let's call refcount_inc_not_zero() in fib_rules_dump().

Fixes 5d7bfd141924 ("ipv4: fib_rules: Dump FIB rules when registering FIB notifier")
---
 include/net/fib_rules.h | 5 +++++
 net/core/fib_rules.c    | 6 +++++-
 2 files changed, 10 insertions(+), 1 deletion(-)
include/net/fib_rules.h +5 -0
index 82da359bca035d..c47f6f6d3cada6 100644
@@ -107,6 +107,11 @@ static inline void fib_rule_get(struct fib_rule *rule)
 	refcount_inc(&rule->refcnt);
 }
 
+static inline bool fib_rule_get_safe(struct fib_rule *rule)
+{
+	return refcount_inc_not_zero(&rule->refcnt);
+}
+
 static inline void fib_rule_put(struct fib_rule *rule)
 {
 	if (refcount_dec_and_test(&rule->refcnt))
net/core/fib_rules.c +5 -1
index 75282222e0b456..e31873c87c0a36 100644
@@ -328,7 +328,7 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,
 
 		if (err != -EAGAIN) {
 			if ((arg->flags & FIB_LOOKUP_NOREF) ||
-			    likely(refcount_inc_not_zero(&rule->refcnt))) {
+			    likely(fib_rule_get_safe(rule))) {
 				arg->rule = rule;
 				goto out;
 			}
@@ -386,8 +386,12 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family,
 	if (!ops)
 		return -EAFNOSUPPORT;
 	list_for_each_entry_rcu(rule, &ops->rules_list, list) {
+		if (!fib_rule_get_safe(rule))
+			continue;
+
 		err = call_fib_rule_notifier(nb, FIB_EVENT_RULE_ADD,
 					     rule, family, extack);
+		fib_rule_put(rule);
 		if (err)
 			break;
 	}
Signature · 1 line
2.53.0
author maintainer
#438 lore raw

PATCH 434/1067 bridge: cfm: reject invalid CCM interval at configuration time

In reply to Greg Kroah-Hartman

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

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

From: Xiang Mei <[email protected]>

[ Upstream commit f3e02edd8322b31b8e6517faa6ba053bf29d1e26 ]

ccm_tx_work_expired() re-arms itself via queue_delayed_work() using the configured exp_interval converted by interval_to_us(). When exp_interval is BR_CFM_CCM_INTERVAL_NONE or out of range, interval_to_us() returns 0, causing the worker to fire immediately in a tight loop that allocates skbs until OOM.

Fix this by validating exp_interval at configuration time:

- Constrain IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL to the valid range [BR_CFM_CCM_INTERVAL_3_3_MS, BR_CFM_CCM_INTERVAL_10_MIN] in the netlink policy so userspace cannot set an invalid value.

- Reject starting CCM TX in br_cfm_cc_ccm_tx() when exp_interval has not yet been configured (defaults to 0 from kzalloc).

---
 net/bridge/br_cfm.c         | 6 ++++++
 net/bridge/br_cfm_netlink.c | 4 +++-
 2 files changed, 9 insertions(+), 1 deletion(-)
net/bridge/br_cfm.c +6 -0
index a3c755d0a09de9..a89aec83141648 100644
@@ -805,6 +805,12 @@ int br_cfm_cc_ccm_tx(struct net_bridge *br, const u32 instance,
 		goto save;
 	}
 
+	if (!interval_to_us(mep->cc_config.exp_interval)) {
+		NL_SET_ERR_MSG_MOD(extack,
+				   "Invalid CCM interval");
+		return -EINVAL;
+	}
+
 	/* Start delayed work to transmit CCM frames. It is done with zero delay
 	 * to send first frame immediately
 	 */
net/bridge/br_cfm_netlink.c +3 -1
index 2faab44652e7c0..91b9922dc3f25e 100644
@@ -34,7 +34,9 @@ br_cfm_cc_config_policy[IFLA_BRIDGE_CFM_CC_CONFIG_MAX + 1] = {
 	[IFLA_BRIDGE_CFM_CC_CONFIG_UNSPEC]	 = { .type = NLA_REJECT },
 	[IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE]	 = { .type = NLA_U32 },
 	[IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE]	 = { .type = NLA_U32 },
-	[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL] = { .type = NLA_U32 },
+	[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL] =
+		NLA_POLICY_RANGE(NLA_U32, BR_CFM_CCM_INTERVAL_3_3_MS,
+				 BR_CFM_CCM_INTERVAL_10_MIN),
 	[IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID]	 = {
 	.type = NLA_BINARY, .len = CFM_MAID_LENGTH },
 };
Signature · 1 line
2.53.0
author maintainer
#439 lore raw

PATCH 435/1067 sctp: validate embedded address parameter length

In reply to Greg Kroah-Hartman

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

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

From: Xin Long <[email protected]>

[ Upstream commit e9361d0ca55c4af12aac09e2572852fa91046229 ]

sctp_verify_asconf() and sctp_verify_param() only validate ADD_IP, DEL_IP, and SET_PRIMARY parameters against a fixed minimum size of sizeof(struct sctp_addip_param) + sizeof(struct sctp_paramhdr). This ensures the outer parameter is large enough to contain an embedded address parameter header, but does not verify that the embedded address parameter's declared length fits within the bounds of the outer parameter.

Later, sctp_process_param() and sctp_process_asconf_param() extract the embedded address parameter and pass it to af->from_addr_param(), which uses the address parameter length to parse the variable-length address payload. A malformed peer can therefore advertise an embedded address parameter length that exceeds the remaining bytes in the enclosing parameter.

Validate that addr_param->p.length does not exceed the space available after the sctp_addip_param header before processing the embedded address parameter. Reject malformed parameters when the embedded address length extends beyond the enclosing parameter bounds.

This prevents out-of-bounds reads when parsing malformed parameters carried in INIT or ASCONF processing paths.

---
 net/sctp/sm_make_chunk.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
net/sctp/sm_make_chunk.c +8 -2
index 088764ba47a173..3089d5e577584f 100644
@@ -2670,6 +2670,9 @@ static int sctp_process_param(struct sctp_association *asoc,
 			goto fall_through;
 
 		addr_param = param.v + sizeof(struct sctp_addip_param);
+		if (ntohs(addr_param->p.length) >
+		    ntohs(param.p->length) - sizeof(struct sctp_addip_param))
+			break;
 
 		af = sctp_get_af_specific(param_type2af(addr_param->p.type));
 		if (!af)
@@ -3068,13 +3071,16 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
 	union sctp_addr	addr;
 	struct sctp_af *af;
 
-	addr_param = (void *)asconf_param + sizeof(*asconf_param);
-
 	if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP &&
 	    asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP &&
 	    asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY)
 		return SCTP_ERROR_UNKNOWN_PARAM;
 
+	addr_param = (void *)asconf_param + sizeof(*asconf_param);
+	if (ntohs(addr_param->p.length) >
+	    ntohs(asconf_param->param_hdr.length) - sizeof(*asconf_param))
+		return SCTP_ERROR_PROTO_VIOLATION;
+
 	switch (addr_param->p.type) {
 	case SCTP_PARAM_IPV6_ADDRESS:
 		if (!asoc->peer.ipv6_address)
Signature · 1 line
2.53.0
author maintainer
#440 lore raw

PATCH 436/1067 net/sched: sch_hfsc: Dont make class passive twice

In reply to Greg Kroah-Hartman

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

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

From: Victor Nogueira <[email protected]>

[ Upstream commit 90b662ea25f5e83bb3b8ccec5b93ced810b92fb8 ]

update_vf() is called from two places for the same class during a single dequeue when the class's child qdisc (e.g. codel/fq_codel) drops its last packets while dequeuing:

1. The child calls qdisc_tree_reduce_backlog(), which, now that the child is empty, invokes hfsc_qlen_notify() -> update_vf(cl, 0, 0) and turns the class passive (cl_nactive is decremented up the hierarchy).

2. hfsc_dequeue() then calls update_vf(cl, qdisc_pkt_len(skb), cur_time) to charge the dequeued bytes.

On the second call the class is already passive, but its child qdisc is still empty, so update_vf() arms go_passive again:

      if (cl->qdisc->q.qlen == 0 && cl->cl_flags & HFSC_FSC)
              go_passive = 1;

The leaf is then skipped by the cl_nactive == 0 check inside the loop, which does not clear go_passive, so the stale go_passive propagates to the parent and decrements its cl_nactive a second time. A parent that still has other active children is driven to cl_nactive == 0 and removed from the vttree, even though those siblings are still backlogged. They are never dequeued again and the qdisc stalls.

Fix this by only arming go_passive when the class is actually active, so an already-passive class no longer triggers a second passive transition. The byte accounting (cl->cl_total += len) still runs for every ancestor, so dequeued bytes continue to be counted exactly once.

---
 net/sched/sch_hfsc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/sch_hfsc.c +1 -1
index 80acdec16d2f67..2d6baf7d7b0366 100644
@@ -754,7 +754,7 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
 	u64 f; /* , myf_bound, delta; */
 	int go_passive = 0;
 
-	if (cl->qdisc->q.qlen == 0 && cl->cl_flags & HFSC_FSC)
+	if (cl->qdisc->q.qlen == 0 && cl->cl_flags & HFSC_FSC && cl->cl_nactive)
 		go_passive = 1;
 
 	for (; cl->cl_parent != NULL; cl = cl->cl_parent) {
Signature · 1 line
2.53.0
author maintainer
#441 lore raw

PATCH 437/1067 tipc: require net admin for TIPCv2 netlink mutators

In reply to Greg Kroah-Hartman

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

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

From: Michael Bommarito <[email protected]>

[ Upstream commit 86b0c540e2ea397cde021eecd24145f7c16a3d4e ]

TIPCv2 registers mutating generic-netlink operations without admin permission flags. Generic netlink only checks CAP_NET_ADMIN when an operation sets GENL_ADMIN_PERM or GENL_UNS_ADMIN_PERM, so a local unprivileged process can currently change TIPC state through commands such as TIPC_NL_NET_SET, TIPC_NL_KEY_SET, TIPC_NL_KEY_FLUSH, and bearer enable/disable.

The legacy TIPC netlink API already checks netlink_net_capable(..., CAP_NET_ADMIN) for administrative commands. Give the TIPCv2 mutators the equivalent generic-netlink gate. Use GENL_UNS_ADMIN_PERM, which maps to the same namespace-aware CAP_NET_ADMIN check that netlink_net_capable() performs, so the behaviour matches the legacy path and keeps working for CAP_NET_ADMIN holders in a non-initial user namespace (containers).

A QEMU/KASAN repro run as uid/gid 65534 with zero effective capabilities previously succeeded in changing the network id and node identity, setting and flushing key material, and enabling/disabling a UDP bearer. With this patch applied the same operations fail with -EPERM.

---
 net/tipc/netlink.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
net/tipc/netlink.c +12 -0
index 1a9a5bdaccf4fc..8336a9664703fe 100644
@@ -152,11 +152,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_BEARER_DISABLE,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_bearer_disable,
 	},
 	{
 		.cmd	= TIPC_NL_BEARER_ENABLE,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_bearer_enable,
 	},
 	{
@@ -168,11 +170,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_BEARER_ADD,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_bearer_add,
 	},
 	{
 		.cmd	= TIPC_NL_BEARER_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_bearer_set,
 	},
 	{
@@ -197,11 +201,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_LINK_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_node_set_link,
 	},
 	{
 		.cmd	= TIPC_NL_LINK_RESET_STATS,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit   = tipc_nl_node_reset_link_stats,
 	},
 	{
@@ -213,6 +219,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_MEDIA_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_media_set,
 	},
 	{
@@ -228,6 +235,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_NET_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_net_set,
 	},
 	{
@@ -238,6 +246,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_MON_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_node_set_monitor,
 	},
 	{
@@ -255,6 +264,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_PEER_REMOVE,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_peer_rm,
 	},
 #ifdef CONFIG_TIPC_MEDIA_UDP
@@ -269,11 +279,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
 	{
 		.cmd	= TIPC_NL_KEY_SET,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_node_set_key,
 	},
 	{
 		.cmd	= TIPC_NL_KEY_FLUSH,
 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+		.flags	= GENL_UNS_ADMIN_PERM,
 		.doit	= tipc_nl_node_flush_key,
 	},
 #endif
Signature · 1 line
2.53.0
author maintainer
#442 lore raw

PATCH 438/1067 tipc: prevent snt_unacked underflow on CONN_ACK

In reply to Greg Kroah-Hartman

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

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

From: Michael Bommarito <[email protected]>

[ Upstream commit ab3e10b44ba5411779aac7afd2477917dd77750f ]

tipc_sk_conn_proto_rcv() subtracts the peer-supplied connection ack count from the unsigned 16-bit send counter snt_unacked without checking that it does not exceed the number of messages actually outstanding:

	tsk->snt_unacked -= msg_conn_ack(hdr);

msg_conn_ack() is read straight from a received CONN_MANAGER/CONN_ACK message. If the ack count is larger than snt_unacked, the subtraction wraps to a near-maximum value, leaving tsk_conn_cong() permanently true and starving the connection of further transmits.

Validate the ACK count at the start of the CONN_ACK block and drop the message if it acknowledges more messages than are outstanding. A peer (or, for a local connection, the connected peer socket) can otherwise wedge a TIPC connection's send side by sending an oversized connection ack.

Fixes 10724cc7bb78 ("tipc: redesign connection-level flow control")
---
 net/tipc/socket.c | 3 +++
 1 file changed, 3 insertions(+)
net/tipc/socket.c +3 -0
index 1d828ae769fd67..c981bca5af5947 100644
@@ -1366,6 +1366,9 @@ static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
 			__skb_queue_tail(xmitq, skb);
 		return;
 	} else if (mtyp == CONN_ACK) {
+		if (tsk->snt_unacked < msg_conn_ack(hdr))
+			goto exit;
+
 		was_cong = tsk_conn_cong(tsk);
 		tipc_sk_push_backlog(tsk, msg_nagle_ack(hdr));
 		tsk->snt_unacked -= msg_conn_ack(hdr);
Signature · 1 line
2.53.0
author maintainer
#443 lore raw

PATCH 439/1067 tipc: reject inverted service ranges from peer bindings

In reply to Greg Kroah-Hartman

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

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

From: Michael Bommarito <[email protected]>

[ Upstream commit 2afb648f7b99216c687db1f89739c995e1144153 ]

tipc_update_nametbl() inserts a binding advertised by a peer node using the lower and upper service-range bounds taken directly from the wire, without checking that lower <= upper. The local bind path validates the ordering (tipc_uaddr_valid()), but the name-distribution path does not.

A binding with lower > upper is inserted at the far end of the service-range rbtree (keyed on lower) where no lookup or withdrawal can ever match it (service_range_foreach_match() requires sr->lower <= end). The publication, its service_range node and the augmented rbtree entry are then leaked for the lifetime of the namespace, and there is no per-peer cap equivalent to TIPC_MAX_PUBL on locally created bindings.

Reject inverted ranges in the network path as well. A peer node can otherwise leak unbounded binding-table memory by sending PUBLICATION items with lower > upper.

Fixes 37922ea4a310 ("tipc: permit overlapping service ranges in name table")
---
 net/tipc/name_distr.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)
net/tipc/name_distr.c +11 -2
index 190b49c5cbc3ec..ba4f4906e13b70 100644
@@ -280,12 +280,21 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
 				u32 node, u32 dtype)
 {
 	struct publication *p = NULL;
+	u32 lower = ntohl(i->lower);
+	u32 upper = ntohl(i->upper);
 	struct tipc_socket_addr sk;
-	struct tipc_uaddr ua;
 	u32 key = ntohl(i->key);
+	struct tipc_uaddr ua;
+
+	/* A peer-advertised binding with lower > upper can never be matched
+	 * or withdrawn and would leak the publication; the local bind path
+	 * rejects such ranges, so reject ranges learned from the network too.
+	 */
+	if (lower > upper)
+		return false;
 
 	tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,
-		   ntohl(i->type), ntohl(i->lower), ntohl(i->upper));
+		   ntohl(i->type), lower, upper);
 	sk.ref = ntohl(i->port);
 	sk.node = node;
 
Signature · 1 line
2.53.0
author maintainer
#444 lore raw

PATCH 440/1067 cxl/test: Add check after kzalloc() memory in alloc_mock_res()

In reply to Greg Kroah-Hartman

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

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

From: Dave Jiang <[email protected]>

[ Upstream commit dfe28c8592538152e9611341dae6f7be1735b3f1 ]

alloc_mock_res() calls kzalloc() without checking the return value. Add scope based resource management to deal with the allocated memory cleanly.

Reported-by sashiko-bot
Fixes 67dcdd4d3b83 ("tools/testing/cxl: Introduce a mocked-up CXL port hierarchy")
---
 tools/testing/cxl/test/cxl.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
tools/testing/cxl/test/cxl.c +6 -2
index 339b31a3319bfe..7be8bc4e4500ec 100644
@@ -264,12 +264,16 @@ static void depopulate_all_mock_resources(void)
 
 static struct cxl_mock_res *alloc_mock_res(resource_size_t size)
 {
-	struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL);
 	struct genpool_data_align data = {
 		.align = SZ_256M,
 	};
 	unsigned long phys;
 
+	struct cxl_mock_res *res __free(kfree) = kzalloc(sizeof(*res),
+							 GFP_KERNEL);
+	if (!res)
+		return NULL;
+
 	INIT_LIST_HEAD(&res->list);
 	phys = gen_pool_alloc_algo(cxl_mock_pool, size,
 				   gen_pool_first_fit_align, &data);
@@ -284,7 +288,7 @@ static struct cxl_mock_res *alloc_mock_res(resource_size_t size)
 	list_add(&res->list, &mock_res);
 	mutex_unlock(&mock_res_lock);
 
-	return res;
+	return no_free_ptr(res);
 }
 
 static int populate_cedt(void)
Signature · 1 line
2.53.0
author maintainer
#445 lore raw

PATCH 441/1067 crypto: marvell/octeontx - fix DMA cleanup using wrong loop index

In reply to Greg Kroah-Hartman

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

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

From: Felix Gu <[email protected]>

[ Upstream commit 7891c64c0520519782470ba29bac8a5761e295d8 ]

The sg_cleanup path used list[i] instead of list[j] when unmapping DMA buffers, leaking successfully mapped entries and repeatedly unmapping the failed one.

Fixes 10b4f09491bf ("crypto: marvell - add the Virtual Function driver for CPT")
---
 drivers/crypto/marvell/octeontx/otx_cptvf_reqmgr.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/marvell/octeontx/otx_cptvf_reqmgr.c +2 -2
index c80baf1ad90b2f..89030e2711ce41 100644
@@ -157,8 +157,8 @@ static inline int setup_sgio_components(struct pci_dev *pdev,
 sg_cleanup:
 	for (j = 0; j < i; j++) {
 		if (list[j].dma_addr) {
-			dma_unmap_single(&pdev->dev, list[i].dma_addr,
-					 list[i].size, DMA_BIDIRECTIONAL);
+			dma_unmap_single(&pdev->dev, list[j].dma_addr,
+					 list[j].size, DMA_BIDIRECTIONAL);
 		}
 
 		list[j].dma_addr = 0;
Signature · 1 line
2.53.0
author maintainer
#446 lore raw

PATCH 442/1067 crypto: cavium/cpt - fix DMA cleanup using wrong loop index

In reply to Greg Kroah-Hartman

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

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

From: Felix Gu <[email protected]>

[ Upstream commit 9dbf173bd32d5f81b005008b682bfb50aa093455 ]

The sg_cleanup error path used list[i] instead of list[j] when unmapping DMA buffers, leaking successfully mapped entries and repeatedly unmapping the failed one.

Fixes c694b233295b ("crypto: cavium - Add the Virtual Function driver for CPT")
---
 drivers/crypto/cavium/cpt/cptvf_reqmanager.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/cavium/cpt/cptvf_reqmanager.c +2 -2
index 153004bdfb5cde..753bdb2ae33f8d 100644
@@ -108,8 +108,8 @@ static int setup_sgio_components(struct cpt_vf *cptvf, struct buf_ptr *list,
 sg_cleanup:
 	for (j = 0; j < i; j++) {
 		if (list[j].dma_addr) {
-			dma_unmap_single(&pdev->dev, list[i].dma_addr,
-					 list[i].size, DMA_BIDIRECTIONAL);
+			dma_unmap_single(&pdev->dev, list[j].dma_addr,
+					 list[j].size, DMA_BIDIRECTIONAL);
 		}
 
 		list[j].dma_addr = 0;
Signature · 1 line
2.53.0
author maintainer
#447 lore raw

PATCH 443/1067 crypto: rng - Free default RNG on module exit

In reply to Greg Kroah-Hartman

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

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

From: Herbert Xu <[email protected]>

[ Upstream commit 606ba888b98e0d26a2c4e5c8dc0542e3ad8f0f3a ]

When the rng module is removed the default RNG will be leaked. Call crypto_del_default_rng to free it if possible.

Fixes 7cecadb7cca8 ("crypto: rng - Do not free default RNG when it becomes unused")
---
 crypto/rng.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
crypto/rng.c +11 -0
index a2bf2efb7937f9..5992cdb392c50a 100644
@@ -232,5 +232,16 @@ void crypto_unregister_rngs(struct rng_alg *algs, int count)
 }
 EXPORT_SYMBOL_GPL(crypto_unregister_rngs);
 
+static void __exit rng_exit(void)
+{
+	int err;
+
+	err = crypto_del_default_rng();
+	if (err)
+		pr_err("Failed delete default RNG: %d\n", err);
+}
+
+module_exit(rng_exit);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Random Number Generator");
Signature · 1 line
2.53.0
author maintainer
#448 lore raw

PATCH 444/1067 spi: xilinx: use FIFO occupancy register to determine buffer size

In reply to Greg Kroah-Hartman

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

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

From: Lars Pöschel <[email protected]>

[ Upstream commit 47f3b5365536e8c38f264824ab15fdb74454e066 ]

The method the driver uses to determine the size of the FIFO has a problem. What it currently does is this:
It stops the SPI hardware and writes to the TX FIFO register until TX FIFO FULL asserts in the status register. But the hardware does not only have the FIFO, it also has a shift register which can hold a byte. This can be seen, when writing a byte to the FIFO (while the SPI hardware is stopped,) the TX FIFO EMPTY is still empty. So, if we have a FIFO size of 16 for example, the current method returns a 17.
This is a problem, at least when using the driver in irq mode. The same size determined for the TX FIFO is also assumed for the RX FIFO. When a SPI transaction wants to write the amount of the FIFO size or more bytes, the following happens, for example with 16 bytes FIFO size:
The driver stops the SPI hardware and writes 17 bytes to the TX FIFO and starts the SPI hardware and goes sleep.
The hardware then shifts out 17 bytes (FIFO + shift register) and simultaneously reads bytes into the RX FIFO, but it only has 16 places, so it looses one byte. Then TX FIFO empty asserts, wakes the driver again, which has a fast path and reads 16 bytes from the RX FIFO, but before reading the last 17th byte (which is lost) it does this:

	sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
	if (!(sr & XSPI_SR_RX_EMPTY_MASK)) {
		xilinx_spi_rx(xspi);
		rx_words--;
	}

It reads the status register and checks if the RX FIFO is not empty. But it is empty in our case. So this check spins in a while loop forever locking the driver.

This patch fixes the logic to determine the FIFO size.

---
 drivers/spi/spi-xilinx.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/spi/spi-xilinx.c +9 -2
index 8e2ed8a068ca2c..65516289989265 100644
@@ -369,11 +369,18 @@ static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi)
 		xspi->regs + XIPIF_V123B_RESETR_OFFSET);
 
 	/* Fill the Tx FIFO with as many words as possible */
-	do {
+	while (1) {
 		xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
 		sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
+		if (sr & XSPI_SR_TX_FULL_MASK)
+			break;
+
 		n_words++;
-	} while (!(sr & XSPI_SR_TX_FULL_MASK));
+	}
+
+	/* Handle the NO FIFO case separately */
+	if (!n_words)
+		return 1;
 
 	return n_words;
 }
Signature · 1 line
2.53.0
author maintainer
#449 lore raw

PATCH 445/1067 ASoC: adau1372: Clear PLL_EN on failed PLL lock without reset GPIO

In reply to Greg Kroah-Hartman

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

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

From: Guangshuo Li <[email protected]>

[ Upstream commit 69b4141b428bcf2cf7a863950c0d6e5c5ae89ac1 ]

The PLL lock failure path in adau1372_set_power() unwinds by putting the regmap back in cache-only mode, asserting the optional power-down GPIO and disabling mclk.

adau1372_enable_pll() enables CLK_CTRL.PLL_EN before polling the PLL lock bit. If the lock fails on a board without a power-down GPIO, the error path disables mclk and returns an error, but leaves PLL_EN set in the hardware register. The normal power-off path already handles the no-GPIO case by explicitly clearing PLL_EN.

Mirror that cleanup in the PLL lock failure path and clear PLL_EN while the regmap is still live, before switching it back to cache-only mode.

Fixes bfe6a264effc ("ASoC: adau1372: Fix clock leak on PLL lock failure")
---
 sound/soc/codecs/adau1372.c | 5 +++++
 1 file changed, 5 insertions(+)
sound/soc/codecs/adau1372.c +5 -0
index 1a4ab7c993d28c..3e3b8955036d94 100644
@@ -812,6 +812,11 @@ static int adau1372_set_power(struct adau1372 *adau1372, bool enable)
 		if (adau1372->use_pll) {
 			ret = adau1372_enable_pll(adau1372);
 			if (ret) {
+				if (!adau1372->pd_gpio)
+					regmap_update_bits(adau1372->regmap,
+							   ADAU1372_REG_CLK_CTRL,
+							   ADAU1372_CLK_CTRL_PLL_EN,
+							   0);
 				regcache_cache_only(adau1372->regmap, true);
 				if (adau1372->pd_gpio)
 					gpiod_set_value(adau1372->pd_gpio, 1);
Signature · 1 line
2.53.0
author maintainer
#450 lore raw

PATCH 446/1067 power: supply: core: fix supplied_from allocations

In reply to Greg Kroah-Hartman

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

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

From: Lucas Tsai <[email protected]>

[ Upstream commit ba61aed9a34671222d1149acfc2f0179a9ce7e80 ]

If dts property power-supplies has multiple values, then accessing to psy->supplied_from[i-1] in __power_supply_populate_supplied_from will overrun supplied_from array.

Fixes f6e0b081fb30 ("power_supply: Populate supplied_from hierarchy from the device tree")
---
 drivers/power/supply/power_supply_core.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)
drivers/power/supply/power_supply_core.c +3 -8
index 13801dfa5c3857..54a1d8dee95ddd 100644
@@ -262,18 +262,13 @@ static int power_supply_check_supplies(struct power_supply *psy)
 	if (cnt == 1)
 		return 0;
 
-	/* All supplies found, allocate char ** array for filling */
-	psy->supplied_from = devm_kzalloc(&psy->dev, sizeof(*psy->supplied_from),
+	/* All supplies found, allocate char * array for filling */
+	psy->supplied_from = devm_kcalloc(&psy->dev,
+					  cnt - 1, sizeof(*psy->supplied_from),
 					  GFP_KERNEL);
 	if (!psy->supplied_from)
 		return -ENOMEM;
 
-	*psy->supplied_from = devm_kcalloc(&psy->dev,
-					   cnt - 1, sizeof(**psy->supplied_from),
-					   GFP_KERNEL);
-	if (!*psy->supplied_from)
-		return -ENOMEM;
-
 	return power_supply_populate_supplied_from(psy);
 }
 #else
Signature · 1 line
2.53.0
author maintainer
#451 lore raw

PATCH 447/1067 net/sched: sch_fq_codel: Do not call qdisc_tree_reduce_backlog during peek before restoring qlen

In reply to Greg Kroah-Hartman

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

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

From: Victor Nogueira <[email protected]>

[ Upstream commit 097f6fc7b1ae362dd7a9444b2572162fda73b284 ]

Whenever fq_codel drops packets during peek, it calls qdisc_tree_reduce_backlog. An issue arises because it calls qdisc_tree_reduce_backlog before it reincrements the qlen. If qlen drops to zero, but peek returns an skb, the parent's qlen_notify callback will be executed even though fq_codel still has 1 packet on the queue and, thus, will mistakenly deactivate the parent's class causing issues like a recent report [1] and a wild memory access in qfq:

[   29.371146][  T360] Oops: general protection fault, probably for non-canonical address 0xfbd59c0000000024: 0000 [#1] SMP KASAN NOPTI
[   29.371666][  T360] KASAN: maybe wild-memory-access in range [0xdead000000000120-0xdead000000000127]
[   29.371987][  T360] CPU: 6 UID: 0 PID: 360 Comm: tc Not tainted 7.1.0-rc5-00285-gc530e5b2dbc6-dirty #82 PREEMPT(full)
[   29.372384][  T360] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[   29.372620][  T360] RIP: 0010:qfq_deactivate_agg (include/linux/list.h:1029 (discriminator 2) include/linux/list.h:1043 (discriminator 2) net/sched/sch_qfq.c:1369 (discriminator 2) net/sched/sch_qfq.c:1395 (discriminator 2)) sch_qfq
[   29.373544][  T360] RSP: 0018:ffff888102417370 EFLAGS: 00010216
[   29.373800][  T360] RAX: 0000000000000000 RBX: ffff88811224d568 RCX: dffffc0000000000
[   29.374079][  T360] RDX: 1ffff11021fe1543 RSI: ffff88810ff0aa00 RDI: dffffc0000000000
[   29.374368][  T360] RBP: ffff88811224c280 R08: dead000000000122 R09: 1bd5a00000000024
[   29.374649][  T360] R10: fffffbfff7940329 R11: fffffbfff7940329 R12: 0000000000000000
[   29.374926][  T360] R13: dead000000000100 R14: ffff88811224d580 R15: ffff88811224d578
[   29.375207][  T360] FS:  00007f5b794e5780(0000) GS:ffff88815d1e9000(0000) knlGS:0000000000000000
[   29.375545][  T360] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   29.375823][  T360] CR2: 000055ffb091f000 CR3: 000000010a305000 CR4: 0000000000750ef0
[   29.376103][  T360] PKRU: 55555554
[   29.376258][  T360] Call Trace:
[   29.376401][  T360]  <TASK>
...
[   29.376885][  T360] qfq_reset_qdisc (net/sched/sch_qfq.c:357 net/sched/sch_qfq.c:1487) sch_qfq
[   29.377074][  T360]  qdisc_reset (net/sched/sch_generic.c:1057)
[   29.377414][  T360]  __qdisc_destroy (net/sched/sch_generic.c:1096)
[   29.377600][  T360]  qdisc_graft (net/sched/sch_api.c:1062 net/sched/sch_api.c:1053 net/sched/sch_api.c:1159)
[   29.378593][  T360]  tc_get_qdisc (net/sched/sch_api.c:1528 net/sched/sch_api.c:1556)

Fix this by only calling qdisc_tree_reduce_backlog in peek after the qlen is restored.

[1] http://lore.kernel.org/netdev/CAN2cbVe79oj0O9==m4+4x3v+O+qzRagA=2=wkrp9i9=CqYvyZA@mail.gmail.com/

---
 net/sched/sch_fq_codel.c | 41 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 39 insertions(+), 2 deletions(-)
net/sched/sch_fq_codel.c +39 -2
index 056895df178541..e059d6c145741b 100644
@@ -278,7 +278,7 @@ static void drop_func(struct sk_buff *skb, void *ctx)
 	qdisc_qstats_drop(sch);
 }
 
-static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
+static struct sk_buff *__fq_codel_dequeue(struct Qdisc *sch)
 {
 	struct fq_codel_sched_data *q = qdisc_priv(sch);
 	struct sk_buff *skb;
@@ -315,12 +315,49 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
 	qdisc_bstats_update(sch, skb);
 	flow->deficit -= qdisc_pkt_len(skb);
 
+	return skb;
+}
+
+static void fq_codel_dequeue_drop(struct Qdisc *sch)
+{
+	struct fq_codel_sched_data *q = qdisc_priv(sch);
+
 	if (q->cstats.drop_count) {
 		qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
 					  q->cstats.drop_len);
 		q->cstats.drop_count = 0;
 		q->cstats.drop_len = 0;
 	}
+}
+
+static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
+{
+	struct sk_buff *skb;
+
+	skb =  __fq_codel_dequeue(sch);
+
+	fq_codel_dequeue_drop(sch);
+
+	return skb;
+}
+
+static struct sk_buff *fq_codel_peek(struct Qdisc *sch)
+{
+	struct sk_buff *skb = skb_peek(&sch->gso_skb);
+
+	if (!skb) {
+		skb = __fq_codel_dequeue(sch);
+
+		if (skb) {
+			__skb_queue_head(&sch->gso_skb, skb);
+			/* it's still part of the queue */
+			qdisc_qstats_backlog_inc(sch, skb);
+			sch->q.qlen++;
+		}
+
+		fq_codel_dequeue_drop(sch);
+	}
+
 	return skb;
 }
 
@@ -707,7 +744,7 @@ static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
 	.priv_size	=	sizeof(struct fq_codel_sched_data),
 	.enqueue	=	fq_codel_enqueue,
 	.dequeue	=	fq_codel_dequeue,
-	.peek		=	qdisc_peek_dequeued,
+	.peek		=	fq_codel_peek,
 	.init		=	fq_codel_init,
 	.reset		=	fq_codel_reset,
 	.destroy	=	fq_codel_destroy,
Signature · 1 line
2.53.0
author maintainer
#452 lore raw

PATCH 448/1067 net/sched: sch_codel: Do not call qdisc_tree_reduce_backlog during peek before restoring qlen

In reply to Greg Kroah-Hartman

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

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

From: Victor Nogueira <[email protected]>

[ Upstream commit 52f1da34c9f4d5bdc1e8b44242da5c7ba8db85f3 ]

Whenever codel drops packets during peek, it calls qdisc_tree_reduce_backlog. An issue arises because it calls qdisc_tree_reduce_backlog before it reincrements the qlen. If qlen drops to zero, but peek returns an skb, the parent's qlen_notify callback will be executed even though codel still has 1 packet on the queue and, thus, will mistakenly deactivate the parent's class causing issues like a wild memory access when qfq has codel as a child:

[   36.339843][  T370] Oops: general protection fault, probably for non-canonical address 0xfbd59c0000000024: 0000 [#1] SMP KASAN NOPTI
[   36.340408][  T370] KASAN: maybe wild-memory-access in range [0xdead000000000120-0xdead000000000127]
[   36.340737][  T370] CPU: 2 UID: 0 PID: 370 Comm: tc Not tainted 7.1.0-rc5-00287-g66e13b626592 #87 PREEMPT(full)
[   36.341113][  T370] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[   36.341357][  T370] RIP: 0010:qfq_deactivate_agg (include/linux/list.h:1029 (discriminator 2) include/linux/list.h:1043 (discriminator 2) net/sched/sch_qfq.c:1369 (discriminator 2) net/sched/sch_qfq.c:1395 (discriminator 2)) sch_qfq
[   36.342221][  T370] RSP: 0018:ffff8881100ef370 EFLAGS: 00010216
[   36.342422][  T370] RAX: 0000000000000000 RBX: ffff8881058a9568 RCX: dffffc0000000000
[   36.342664][  T370] RDX: 1ffff11021064dc3 RSI: ffff888108326e00 RDI: dffffc0000000000
[   36.342905][  T370] RBP: ffff8881058a8280 R08: dead000000000122 R09: 1bd5a00000000024
[   36.343140][  T370] R10: fffffbfff2940329 R11: fffffbfff2940329 R12: 0000000000000000
[   36.343383][  T370] R13: dead000000000100 R14: ffff8881058a9580 R15: ffff8881058a9578
[   36.343631][  T370] FS:  00007fc04b0ca780(0000) GS:ffff888184fef000(0000) knlGS:0000000000000000
[   36.343911][  T370] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   36.344116][  T370] CR2: 0000557c02c02000 CR3: 000000010e0ba000 CR4: 0000000000750ef0
[   36.344359][  T370] PKRU: 55555554
[   36.344481][  T370] Call Trace:
...
[   36.345054][  T370] qfq_reset_qdisc (net/sched/sch_qfq.c:357 net/sched/sch_qfq.c:1487) sch_qfq
[   36.345222][  T370]  qdisc_reset (net/sched/sch_generic.c:1057)
[   36.345503][  T370]  __qdisc_destroy (net/sched/sch_generic.c:1096)
[   36.345677][  T370]  qdisc_graft (net/sched/sch_api.c:1062 net/sched/sch_api.c:1053 net/sched/sch_api.c:1159)
[   36.346335][  T370]  tc_get_qdisc (net/sched/sch_api.c:1528 net/sched/sch_api.c:1556)

Fix this by only calling qdisc_tree_reduce_backlog in peek after the qlen is restored.

Fixes 342debc12183 ("codel: remove sch->q.qlen check before qdisc_tree_reduce_backlog()")
---
 net/sched/sch_codel.c | 48 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 43 insertions(+), 5 deletions(-)
net/sched/sch_codel.c +43 -5
index 63c02040b426ae..0dfdc8b6569955 100644
@@ -86,7 +86,7 @@ static void drop_func(struct sk_buff *skb, void *ctx)
 	qdisc_qstats_drop(sch);
 }
 
-static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
+static struct sk_buff *__codel_qdisc_dequeue(struct Qdisc *sch)
 {
 	struct codel_sched_data *q = qdisc_priv(sch);
 	struct sk_buff *skb;
@@ -95,13 +95,51 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
 			    &q->stats, qdisc_pkt_len, codel_get_enqueue_time,
 			    drop_func, dequeue_func);
 
+	if (skb)
+		qdisc_bstats_update(sch, skb);
+	return skb;
+}
+
+static void codel_dequeue_drop(struct Qdisc *sch)
+{
+	struct codel_sched_data *q = qdisc_priv(sch);
+
 	if (q->stats.drop_count) {
-		qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len);
+		qdisc_tree_reduce_backlog(sch, q->stats.drop_count,
+					  q->stats.drop_len);
 		q->stats.drop_count = 0;
 		q->stats.drop_len = 0;
 	}
-	if (skb)
-		qdisc_bstats_update(sch, skb);
+}
+
+static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
+{
+	struct sk_buff *skb;
+
+	skb = __codel_qdisc_dequeue(sch);
+
+	codel_dequeue_drop(sch);
+
+	return skb;
+}
+
+static struct sk_buff *codel_peek(struct Qdisc *sch)
+{
+	struct sk_buff *skb = skb_peek(&sch->gso_skb);
+
+	if (!skb) {
+		skb = __codel_qdisc_dequeue(sch);
+
+		if (skb) {
+			__skb_queue_head(&sch->gso_skb, skb);
+			/* it's still part of the queue */
+			qdisc_qstats_backlog_inc(sch, skb);
+			sch->q.qlen++;
+		}
+
+		codel_dequeue_drop(sch);
+	}
+
 	return skb;
 }
 
@@ -276,7 +314,7 @@ static struct Qdisc_ops codel_qdisc_ops __read_mostly = {
 
 	.enqueue	=	codel_qdisc_enqueue,
 	.dequeue	=	codel_qdisc_dequeue,
-	.peek		=	qdisc_peek_dequeued,
+	.peek		=	codel_peek,
 	.init		=	codel_init,
 	.reset		=	codel_reset,
 	.change 	=	codel_change,
Signature · 1 line
2.53.0
author maintainer
#453 lore raw

PATCH 449/1067 net: mana: initialize gdma queue id to INVALID_QUEUE_ID

In reply to Greg Kroah-Hartman

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

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

From: Aditya Garg <[email protected]>

[ Upstream commit 5985474e1cb4034680fac2145497a94b0860be50 ]

mana_gd_create_mana_wq_cq() leaves queue->id as 0 (from kzalloc_obj()) until mana_create_wq_obj() assigns the firmware-returned id. If creation fails before that, cleanup calls mana_gd_destroy_cq() with id 0, NULLing gc->cq_table[0] and silently breaking whichever real CQ owns that slot.

Initialize queue->id to INVALID_QUEUE_ID right after allocation, matching mana_gd_create_eq(). The existing (id >= max_num_cqs) guard then short-circuits cleanly.

Fixes ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
---
 drivers/net/ethernet/microsoft/mana/gdma_main.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/net/ethernet/microsoft/mana/gdma_main.c +2 -0
index 9e55679796d938..014deff90a6c43 100644
@@ -805,6 +805,8 @@ int mana_gd_create_mana_wq_cq(struct gdma_dev *gd,
 	if (!queue)
 		return -ENOMEM;
 
+	queue->id = INVALID_QUEUE_ID;
+
 	gmi = &queue->mem_info;
 	err = mana_gd_alloc_memory(gc, spec->queue_size, gmi);
 	if (err)
Signature · 1 line
2.53.0
author maintainer
#454 lore raw

PATCH 450/1067 net: mana: guard TX wq object destroy with INVALID_MANA_HANDLE check

In reply to Greg Kroah-Hartman

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

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

From: Aditya Garg <[email protected]>

[ Upstream commit f8fd56977eeea3d6939b1a9cd8bd36f1779b3ad0 ]

mana_create_txq() has several error paths (after mana_alloc_queues() or mana_create_wq_obj() failure) where tx_qp[i].tx_object stays as the INVALID_MANA_HANDLE sentinel set at allocation. mana_destroy_txq() then unconditionally calls mana_destroy_wq_obj() with (u64)-1, which firmware rejects and logs an error.

Mirror the RX-side pattern in mana_destroy_rxq() and skip the destroy when the handle is still INVALID_MANA_HANDLE.

Fixes ca9c54d2d6a5 ("net: mana: Add a driver for Microsoft Azure Network Adapter (MANA)")
---
 drivers/net/ethernet/microsoft/mana/mana_en.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +2 -1
index 0f84cc4586f02e..db1b8f965eeca4 100644
@@ -1413,7 +1413,8 @@ static void mana_destroy_txq(struct mana_port_context *apc)
 			netif_napi_del(napi);
 			apc->tx_qp[i].txq.napi_initialized = false;
 		}
-		mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i].tx_object);
+		if (apc->tx_qp[i].tx_object != INVALID_MANA_HANDLE)
+			mana_destroy_wq_obj(apc, GDMA_SQ, apc->tx_qp[i].tx_object);
 
 		mana_deinit_cq(apc, &apc->tx_qp[i].tx_cq);
 
Signature · 1 line
2.53.0
author maintainer
#455 lore raw

PATCH 451/1067 bpf: Run generic devmap egress prog on private skb

In reply to Greg Kroah-Hartman

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

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

From: Sun Jian <[email protected]>

[ Upstream commit 6001896f00984d317fb75160ba05c4a885fbe2a0 ]

Generic XDP devmap multi redirect uses skb_clone() for intermediate destinations and sends the last destination with the original skb. This can leave multiple destinations sharing the same packet data.

This becomes visible after generic devmap egress-program support was
added: a devmap egress program may mutate packet data, and another destination sharing the same data can observe that mutation.

Native XDP broadcast redirect does not have this issue because xdpf_clone() copies the frame data for each destination. Generic XDP should provide the same per-destination isolation before running a devmap egress program.

Fix this by making cloned skbs private before running the generic devmap egress program. Use skb_copy() instead of skb_unshare() so allocation failure does not consume the skb and the existing caller error paths keep their ownership semantics.

---
 kernel/bpf/devmap.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
kernel/bpf/devmap.c +12 -0
index fac0773fe9a0c4..f4e28ad6c920dd 100644
@@ -681,6 +681,18 @@ int dev_map_generic_redirect(struct bpf_dtab_netdev *dst, struct sk_buff *skb,
 	if (unlikely(err))
 		return err;
 
+	if (dst->xdp_prog && skb_cloned(skb)) {
+		struct sk_buff *nskb;
+
+		nskb = skb_copy(skb, GFP_ATOMIC);
+		if (!nskb)
+			return -ENOMEM;
+
+		nskb->mac_len = skb->mac_len;
+		consume_skb(skb);
+		skb = nskb;
+	}
+
 	/* Redirect has already succeeded semantically at this point, so we just
 	 * return 0 even if packet is dropped. Helper below takes care of
 	 * freeing skb.
Signature · 1 line
2.53.0
author maintainer
#456 lore raw

PATCH 452/1067 net/mlx5: Check max_macs devlink param value against max capability

In reply to Greg Kroah-Hartman

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

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

From: Dragos Tatulea <[email protected]>

[ Upstream commit d7b0413b35715d7b32cb12d4d424613eff85ed2b ]

The max_macs devlink param is checked against the FW max value only at param register time (driver load) and inside the validate callback (devlink param set). The stored DRIVERINIT value persists across FW resets and devlink reloads without any further checks against the max.

If the FW link type changes from Ethernet to IB and a FW reset happens, the MAX cap for log_max_current_uc_list will become zero, but the previously stored max_macs value remains and is unconditionally programmed into the HCA caps in handle_hca_cap(). FW will then return a syndrome during SET_HCA_CAP:

mlx5_cmd_out_err:839:(pid 3831): SET_HCA_CAP(0x109) op_mod(0x0) failed, status bad parameter(0x3), syndrome (0x537801), err(-22) set_hca_cap:907:(pid 3831): handle_hca_cap failed

This results in a failure to register the RDMA device.

This patch skips programming log_max_current_uc_list when the MAX capability is 0 (in case of IB).

---
 drivers/net/ethernet/mellanox/mlx5/core/main.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/main.c +7 -5
index 72af9827157d8e..ef406e8d5fc4e9 100644
@@ -550,7 +550,6 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx)
 {
 	struct mlx5_profile *prof = &dev->profile;
 	void *set_hca_cap;
-	int max_uc_list;
 	int err;
 
 	err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL);
@@ -627,10 +626,13 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx)
 		MLX5_SET(cmd_hca_cap, set_hca_cap, roce,
 			 mlx5_is_roce_on(dev));
 
-	max_uc_list = max_uc_list_get_devlink_param(dev);
-	if (max_uc_list > 0)
-		MLX5_SET(cmd_hca_cap, set_hca_cap, log_max_current_uc_list,
-			 ilog2(max_uc_list));
+	if (MLX5_CAP_GEN_MAX(dev, log_max_current_uc_list)) {
+		int max_uc_list = max_uc_list_get_devlink_param(dev);
+
+		if (max_uc_list > 0)
+			MLX5_SET(cmd_hca_cap, set_hca_cap,
+				 log_max_current_uc_list, ilog2(max_uc_list));
+	}
 
 	return set_caps(dev, set_ctx, MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE);
 }
Signature · 1 line
2.53.0
author maintainer
#457 lore raw

PATCH 453/1067 net: bcmgenet: Use weighted round-robin TX DMA arbitration

In reply to Greg Kroah-Hartman

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

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

From: Ovidiu Panait <[email protected]>

[ Upstream commit fd615abd53110f0f815984e99e7cc51ca6b7d979 ]

Under heavy network traffic, we observed sporadic TX queue timeouts on the Raspberry Pi 4. The timeouts can be reproduced by stress testing the TX path with multiple concurrent iperf UDP streams:

iperf3 -c <ip> -u -b0 -P16 -t60
NETDEV WATCHDOG: CPU: 0: transmit queue 0 timed out 2044 ms NETDEV WATCHDOG: CPU: 3: transmit queue 0 timed out 2004 ms

Investigation showed that the timeouts are caused by the priority-based arbiter. Under heavy load the highest priority queue starves the lower priority ones, causing timeouts. The TX strict priority arbiter is not suitable for the default use case where all the traffic gets spread across all the TX queues.

Therefore, to fix this, switch the TX DMA arbiter to Weighted Round-Robin, which services all queues, so they do not stall. The weights were chosen to follow the existing priority scheme: q0 gets the smallest weight, while q1-4 get the bulk of the TX bandwidth.

Fixes 1c1008c793fa ("net: bcmgenet: add main driver file")
---
 .../net/ethernet/broadcom/genet/bcmgenet.c    | 23 +++++++------------
 1 file changed, 8 insertions(+), 15 deletions(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +8 -15
index ab06c676e2cbaa..a22f569987c6f8 100644
@@ -41,9 +41,8 @@
 
 #include "bcmgenet.h"
 
-/* Default highest priority queue for multi queue support */
-#define GENET_Q1_PRIORITY	0
-#define GENET_Q0_PRIORITY	1
+#define GENET_Q0_WEIGHT		1
+#define GENET_Q1_WEIGHT		4
 
 #define GENET_Q0_RX_BD_CNT	\
 	(TOTAL_DESC - priv->hw_params->rx_queues * priv->hw_params->rx_bds_per_q)
@@ -2081,13 +2080,6 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
 	int i;
 
 	index = skb_get_queue_mapping(skb);
-	/* Mapping strategy:
-	 * queue_mapping = 0, unclassified, packet xmited through ring 0
-	 * queue_mapping = 1, goes to ring 1. (highest priority queue)
-	 * queue_mapping = 2, goes to ring 2.
-	 * queue_mapping = 3, goes to ring 3.
-	 * queue_mapping = 4, goes to ring 4.
-	 */
 	ring = &priv->tx_rings[index];
 	txq = netdev_get_tx_queue(dev, index);
 
@@ -2787,8 +2779,9 @@ static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv)
 
 /* Initialize Tx queues
  *
- * Queues 1-4 are priority-based, each one has 32 descriptors,
- * with queue 1 being the highest priority queue.
+ * Queues 1-4 are the priority queues, each one has 32 descriptors.
+ * The weighted round-robin arbiter gives them a larger share of TX
+ * bandwidth than the default queue 0.
  *
  * Queue 0 is the default Tx queue with
  * GENET_Q0_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors.
@@ -2816,8 +2809,8 @@ static void bcmgenet_init_tx_queues(struct net_device *dev)
 	dma_ctrl = 0;
 	ring_cfg = 0;
 
-	/* Enable strict priority arbiter mode */
-	bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL);
+	/* Enable Weighted Round-Robin arbiter mode */
+	bcmgenet_tdma_writel(priv, DMA_ARBITER_WRR, DMA_ARB_CTRL);
 
 	/* Initialize Tx priority queues */
 	for (i = 0; i <= priv->hw_params->tx_queues; i++) {
@@ -2827,7 +2820,7 @@ static void bcmgenet_init_tx_queues(struct net_device *dev)
 		ring_cfg |= (1 << i);
 		dma_ctrl |= (1 << (i + DMA_RING_BUF_EN_SHIFT));
 		dma_priority[DMA_PRIO_REG_INDEX(i)] |=
-			(i ? GENET_Q1_PRIORITY : GENET_Q0_PRIORITY)
+			(i ? GENET_Q1_WEIGHT : GENET_Q0_WEIGHT)
 			<< DMA_PRIO_REG_SHIFT(i);
 	}
 
Signature · 1 line
2.53.0
author maintainer
#458 lore raw

PATCH 454/1067 kcm: use WRITE_ONCE() when changing lower socket callbacks

In reply to Greg Kroah-Hartman

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

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

From: Runyu Xiao <[email protected]>

[ Upstream commit 47186409c092cd7dd70350999186c700233e854d ]

kcm_attach() replaces a live lower TCP socket's sk_data_ready and sk_write_space callbacks with KCM handlers, and kcm_unattach() restores them later. Those callback-pointer updates are still plain stores even though the same fields can be read and invoked concurrently on other CPUs.

If another CPU observes an older callback snapshot after the live field has already been restored, callback execution can run with a mismatched target and sk_user_data state, leading to stale or misdirected wakeups.

Use WRITE_ONCE() for the callback replacement and restore operations so these shared callback fields follow the same visibility contract already established by the earlier 4022 fixes.

Fixes ab7ac4eb9832 ("kcm: Kernel Connection Multiplexor module")
---
 net/kcm/kcmsock.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
net/kcm/kcmsock.c +4 -4
index 462bdb6bfa4d85..ba221c6a8cbd71 100644
@@ -1403,8 +1403,8 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
 	psock->save_write_space = csk->sk_write_space;
 	psock->save_state_change = csk->sk_state_change;
 	csk->sk_user_data = psock;
-	csk->sk_data_ready = psock_data_ready;
-	csk->sk_write_space = psock_write_space;
+	WRITE_ONCE(csk->sk_data_ready, psock_data_ready);
+	WRITE_ONCE(csk->sk_write_space, psock_write_space);
 	csk->sk_state_change = psock_state_change;
 
 	write_unlock_bh(&csk->sk_callback_lock);
@@ -1480,8 +1480,8 @@ static void kcm_unattach(struct kcm_psock *psock)
 	 */
 	write_lock_bh(&csk->sk_callback_lock);
 	csk->sk_user_data = NULL;
-	csk->sk_data_ready = psock->save_data_ready;
-	csk->sk_write_space = psock->save_write_space;
+	WRITE_ONCE(csk->sk_data_ready, psock->save_data_ready);
+	WRITE_ONCE(csk->sk_write_space, psock->save_write_space);
 	csk->sk_state_change = psock->save_state_change;
 	strp_stop(&psock->strp);
 
Signature · 1 line
2.53.0
author maintainer
#459 lore raw

PATCH 455/1067 netfilter: nf_conncount: callers must hold rcu read lock

In reply to Greg Kroah-Hartman

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

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

From: Florian Westphal <[email protected]>

[ Upstream commit 64d7d5abe2160bba369b4a8f06bdf5630573bab0 ]

rcu_derefence_raw() should not have been used here, it concealed this bug. Its used because struct rb_node lacks __rcu annotated pointers, so plain rcu_derefence causes sparse warnings.

The major tradeoff is that rcu_derefence_raw() doesn't warn when the caller isn't in a rcu read section.

Extend the rcu read lock scope accordingly and cause sparse warnings, those warnings are the lesser evil.

---
 net/netfilter/nf_conncount.c | 6 +++---
 net/openvswitch/conntrack.c  | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)
net/netfilter/nf_conncount.c +3 -3
index ae9ad439449fa5..b9265a8cdb2bc4 100644
@@ -499,7 +499,7 @@ count_tree(struct net *net,
 	hash = jhash2(key, data->keylen, conncount_rnd) % CONNCOUNT_SLOTS;
 	root = &data->root[hash];
 
-	parent = rcu_dereference_raw(root->rb_node);
+	parent = rcu_dereference(root->rb_node);
 	while (parent) {
 		int diff;
 
@@ -507,9 +507,9 @@ count_tree(struct net *net,
 
 		diff = key_diff(key, rbconn->key, data->keylen);
 		if (diff < 0) {
-			parent = rcu_dereference_raw(parent->rb_left);
+			parent = rcu_dereference(parent->rb_left);
 		} else if (diff > 0) {
-			parent = rcu_dereference_raw(parent->rb_right);
+			parent = rcu_dereference(parent->rb_right);
 		} else {
 			int ret;
 
net/openvswitch/conntrack.c +1 -1
index b6ec5497b930fd..e0ff87aaf979ff 100644
@@ -2096,10 +2096,10 @@ static int ovs_ct_limit_get_zone_limit(struct net *net,
 		} else {
 			rcu_read_lock();
 			limit = ct_limit_get(info, zone);
-			rcu_read_unlock();
 
 			err = __ovs_ct_limit_get_zone_limit(
 				net, info->data, zone, limit, reply);
+			rcu_read_unlock();
 			if (err)
 				return err;
 		}
Signature · 1 line
2.53.0
author maintainer
#460 lore raw

PATCH 456/1067 ALSA: core: Fix unintuitive behavior of snd_power_ref_and_wait()

In reply to Greg Kroah-Hartman

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

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

From: Takashi Iwai <[email protected]>

[ Upstream commit b113a891252c3fa4fab11ec8c2894a22ecaf278c ]

snd_power_ref_and_wait() takes the power refcount and doesn't leave it no matter whether it returns an error or not. However, the majority of callers don't expect but just returns without unreferencing in the caller side upon errors.

For addressing the potential refcount unbalance, rather correct the behavior of snd_power_ref_wait() to unreference upon returning an error.

Note that the problem above is likely negligible; the function returns an error only when the sound card is being shutdown, hence it doesn't matter about the power refcount any longer at such a state.

Fixes e94fdbd7b25d ("ALSA: control: Track in-flight control read/write/tlv accesses")
---
 sound/core/init.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
sound/core/init.c +8 -3
index f142e73e2e3fd0..4b95d885a7dcf2 100644
@@ -1161,7 +1161,7 @@ EXPORT_SYMBOL(snd_card_file_remove);
  * typically around calling control ops.
  *
  * The caller needs to pull down the refcount via snd_power_unref() later
- * no matter whether the error is returned from this function or not.
+ * when this function returns 0.
  *
  * Return: Zero if successful, or a negative error code.
  */
@@ -1174,7 +1174,11 @@ int snd_power_ref_and_wait(struct snd_card *card)
 		       card->shutdown ||
 		       snd_power_get_state(card) == SNDRV_CTL_POWER_D0,
 		       snd_power_unref(card), snd_power_ref(card));
-	return card->shutdown ? -ENODEV : 0;
+	if (card->shutdown) {
+		snd_power_unref(card);
+		return  -ENODEV;
+	}
+	return 0;
 }
 EXPORT_SYMBOL_GPL(snd_power_ref_and_wait);
 
@@ -1191,7 +1195,8 @@ int snd_power_wait(struct snd_card *card)
 	int ret;
 
 	ret = snd_power_ref_and_wait(card);
-	snd_power_unref(card);
+	if (!ret)
+		snd_power_unref(card);
 	return ret;
 }
 EXPORT_SYMBOL(snd_power_wait);
Signature · 1 line
2.53.0
author maintainer
#461 lore raw

PATCH 457/1067 cifs: remove all cifs files before kill super

In reply to Greg Kroah-Hartman

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

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

From: Jian Zhang <[email protected]>

[ Upstream commit 6d9a4aaaa8b2612b5ef9d581e2f286a458b71ee1 ]

Cifs files may be put into fileinfo_put_wq during umounting cifs. After umount done, cifsFileInfo_put_final is called, which cause following BUG:

BUG: kernel NULL pointer dereference, address: 0000000000000000
...
[  134.222152]  list_lru_add+0x64/0x1a0
[  134.222399]  ? cifs_put_tcon+0x171/0x340 [cifs]
[  134.222772]  d_lru_add+0x44/0x60
[  134.222997]  dput+0x1fc/0x210
[  134.223213]  cifsFileInfo_put_final+0x11a/0x140 [cifs]
[  134.223576]  process_one_work+0x17c/0x320
[  134.223843]  worker_thread+0x188/0x280
[  134.224084]  ? __pfx_worker_thread+0x10/0x10
[  134.224366]  kthread+0xcc/0x100
[  134.224576]  ? __pfx_kthread+0x10/0x10
[  134.224827]  ret_from_fork+0x30/0x50
[  134.225063]  ? __pfx_kthread+0x10/0x10
[  134.225328]  ret_from_fork_asm+0x1b/0x30

This can be reproduce by following:
unshare -n bash -c "
mkdir -p ${CIFS_MNT}
ip netns attach root 1
ip link add eth0 type veth peer veth0 netns root
ip link set eth0 up
ip -n root link set veth0 up
ip addr add 192.168.0.2/24 dev eth0
ip -n root addr add 192.168.0.1/24 dev veth0
ip route add default via 192.168.0.1 dev eth0
ip netns exec root sysctl net.ipv4.ip_forward=1
ip netns exec root iptables -t nat -A POSTROUTING -s 192.168.0.2 -o
${DEV} -j MASQUERADE
mount -t cifs ${CIFS_PATH} ${CIFS_MNT} -o vers=3.0,sec=ntlmssp,credentials=${CIFS_CRED},rsize=65536,wsize=65536,cache=none,echo_interval=1 touch ${CIFS_MNT}/a.txt
ip netns exec root iptables -t nat -D POSTROUTING -s 192.168.0.2 -o
${DEV} -j MASQUERADE
"
umount ${CIFS_MNT}

Fixes 340cea84f691 ("cifs: open files should not hold ref on superblock")
---
 fs/smb/client/connect.c | 3 +++
 1 file changed, 3 insertions(+)
fs/smb/client/connect.c +3 -0
index a8f16cd8dca692..5b3e7fa242afa9 100644
@@ -4187,6 +4187,9 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
 	}
 	spin_unlock(&cifs_sb->tlink_tree_lock);
 
+	flush_workqueue(serverclose_wq);
+	flush_workqueue(fileinfo_put_wq);
+
 	kfree(cifs_sb->prepath);
 #ifdef CONFIG_CIFS_DFS_UPCALL
 	dfs_cache_put_refsrv_sessions(&cifs_sb->dfs_mount_id);
Signature · 1 line
2.53.0
author maintainer
#462 lore raw

PATCH 458/1067 smb/client: always return a value for FS_IOC_GETFLAGS

In reply to Greg Kroah-Hartman

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

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

From: Huiwen He <[email protected]>

[ Upstream commit 7acbaa16b99edaf8ef432229d4b7a6f3b666767d ]

Currently, repeated lsattr calls on a regular CIFS file without the compressed attribute may show random flags:

	$ touch test.bin
	$ lsattr test.bin
	s-S-ia-A-EjI---------m test.bin
	$ lsattr test.bin
	------d-cEjI---------m test.bin

The lsattr reproducer depends on the previous contents of its userspace buffer, so it may not reproduce on every setup. A deterministic reproducer is to initialize the ioctl argument before FS_IOC_GETFLAGS on a file without the compressed attribute:

        int flags = 0x7fffffff;
        ioctl(fd, FS_IOC_GETFLAGS, &flags);

On an affected kernel, flags remains 0x7fffffff. With the fix, it is set to 0.

This happens because when the cached inode does not have the compressed bit set, the CIFS fallback path in FS_IOC_GETFLAGS returns success without calling put_user() to write the zero flags value into the user buffer. As a result, the caller observes stale contents from its own buffer.

Fix this by always writing the visible flags value back to the user buffer before returning success, even when the value is zero.

Fixes 64a5cfa6db94 ("Allow setting per-file compression via SMB2/3")
---
 fs/smb/client/ioctl.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)
fs/smb/client/ioctl.c +5 -7
index 367ac363e21123..0a3948c714cbc2 100644
@@ -366,13 +366,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 			}
 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
 #endif /* CONFIG_CIFS_POSIX */
-			rc = 0;
-			if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) {
-				/* add in the compressed bit */
-				ExtAttrBits = FS_COMPR_FL;
-				rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE,
-					      (int __user *)arg);
-			}
+			if (CIFS_I(inode)->cifsAttrs & FILE_ATTRIBUTE_COMPRESSED)
+				ExtAttrBits |= FS_COMPR_FL;
+
+			rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE,
+				      (int __user *)arg);
 			break;
 		case FS_IOC_SETFLAGS:
 			if (pSMBFile == NULL)
Signature · 1 line
2.53.0
author maintainer
#463 lore raw

PATCH 459/1067 bpf: Fix bpf_get/setsockopt to tos for ipv4-mapped ipv6 socket

In reply to Greg Kroah-Hartman

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

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

From: Leon Hwang <[email protected]>

[ Upstream commit ca0f587c029afa66227f7b932450b1c417403394 ]

When TCP over IPv4 via INET6 API, bpf_get/setsockopt with ipv4 will fail, because sk->sk_family is AF_INET6. With ipv6 will success, not take effect, because inet_csk(sk)->icsk_af_ops is ipv6_mapped and use ip_queue_xmit, inet_sk(sk)->tos.

To relax this restriction, allow getting/setting tos for those possible ipv4-mapped ipv6 sockets.

Fixes ee7f1e1302f5 ("bpf: Change bpf_setsockopt(SOL_IP) to reuse do_ip_setsockopt()")
---
 net/core/filter.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
net/core/filter.c +14 -1
index 7f65131e24894e..26762c3825a3dd 100644
@@ -5374,11 +5374,24 @@ static int sol_tcp_sockopt(struct sock *sk, int optname,
 				 KERNEL_SOCKPTR(optval), *optlen);
 }
 
+static bool sk_allows_sol_ip_sockopt(struct sock *sk)
+{
+	switch (sk->sk_family) {
+	case AF_INET:
+		return true;
+	case AF_INET6:
+		/* Allow getting/setting sockopt for possible ipv4-mapped ipv6 socket. */
+		return sk->sk_type != SOCK_RAW && !ipv6_only_sock(sk);
+	default:
+		return false;
+	}
+}
+
 static int sol_ip_sockopt(struct sock *sk, int optname,
 			  char *optval, int *optlen,
 			  bool getopt)
 {
-	if (sk->sk_family != AF_INET)
+	if (!sk_allows_sol_ip_sockopt(sk))
 		return -EINVAL;
 
 	switch (optname) {
Signature · 1 line
2.53.0
author maintainer
#464 lore raw

PATCH 460/1067 bpf, sockmap: reject overflowing copy + len in bpf_msg_push_data()

In reply to Greg Kroah-Hartman

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

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

From: Weiming Shi <[email protected]>

[ Upstream commit 0c0a8ed85349dae298712d79cb276acfeb794d82 ]

When the scatterlist ring is full or nearly full, bpf_msg_push_data() enters a copy fallback path and computes copy + len for the page allocation size. Since len comes from BPF with arg3_type = ARG_ANYTHING and both are u32, a crafted len can wrap the sum to a small value, causing an undersized allocation followed by an out-of-bounds memcpy.

 BUG: unable to handle page fault for address: ffffed104089a402
 Oops: Oops: 0000 [#1] SMP KASAN NOPTI
 Call Trace:
  __asan_memcpy (mm/kasan/shadow.c:105)
  bpf_msg_push_data (net/core/filter.c:2852 net/core/filter.c:2788)
  bpf_prog_9ed8b5711920a7d7+0x2e/0x36
  sk_psock_msg_verdict (net/core/skmsg.c:934)
  tcp_bpf_sendmsg (net/ipv4/tcp_bpf.c:421 net/ipv4/tcp_bpf.c:584)
  __sys_sendto (net/socket.c:2206)
  do_syscall_64 (arch/x86/entry/syscall_64.c:94)
  entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)

Add an overflow check before the allocation.

---
 net/core/filter.c | 3 +++
 1 file changed, 3 insertions(+)
net/core/filter.c +3 -0
index 26762c3825a3dd..2e64f8e85631ef 100644
@@ -2815,6 +2815,9 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,
 	if (!space || (space == 1 && start != offset))
 		copy = msg->sg.data[i].length;
 
+	if (unlikely(copy + len < copy))
+		return -EINVAL;
+
 	page = alloc_pages(__GFP_NOWARN | GFP_ATOMIC | __GFP_COMP,
 			   get_order(copy + len));
 	if (unlikely(!page))
Signature · 1 line
2.53.0
author maintainer
#465 lore raw

PATCH 461/1067 bpf, sockmap: fix integer overflow in bpf_msg_pop_data() bounds check

In reply to Greg Kroah-Hartman

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

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

From: Sechang Lim <[email protected]>

[ Upstream commit a48802fb2cd2d1e23651989f8ff4d15e9d5dad54 ]

start and len are u32, so

	u64 last = start + len;

evaluates start + len in 32-bit and wraps before storing it in last. The bounds check

	if (start >= offset + l || last > msg->sg.size)
		return -EINVAL;

can then be passed with an out-of-range start/len, after which the pop loop runs off the end of the scatterlist and sk_msg_shift_left() calls put_page() on the empty msg->sg.end slot:

  Oops: general protection fault, probably for non-canonical address
  0xdffffc0000000001: 0000 [#1] SMP KASAN PTI
  KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
  RIP: 0010:sk_msg_shift_left net/core/filter.c:2957 [inline]
  RIP: 0010:____bpf_msg_pop_data net/core/filter.c:3103 [inline]
  RIP: 0010:bpf_msg_pop_data+0x753/0x1a10 net/core/filter.c:2984
  Call Trace:
   <TASK>
   bpf_prog_4cc92c278f4d5d56+0x1b1/0x1e8
   bpf_prog_run_pin_on_cpu+0x107/0x320 include/linux/filter.h:746
   sk_psock_msg_verdict+0x357/0x7f0 net/core/skmsg.c:934
   tcp_bpf_send_verdict net/ipv4/tcp_bpf.c:420 [inline]
   tcp_bpf_sendmsg+0x766/0x1ae0 net/ipv4/tcp_bpf.c:583
   __sock_sendmsg+0x153/0x1c0 net/socket.c:802
   __sys_sendto+0x326/0x430 net/socket.c:2265
   __x64_sys_sendto+0xe3/0x100 net/socket.c:2268
   do_syscall_64+0x14c/0x480
   entry_SYSCALL_64_after_hwframe+0x77/0x7f
   </TASK>

Widen the addition with a (u64) cast so the bound is evaluated in 64-bit and a len near U32_MAX no longer wraps below msg->sg.size.

While here, change pop from int to u32. It counts bytes against the unsigned scatterlist lengths and can never be negative, so the signed type only invites sign-confusion in the pop loop.

---
 net/core/filter.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/core/filter.c +2 -2
index 2e64f8e85631ef..94a2dcf3aa08e3 100644
@@ -2981,8 +2981,8 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start,
 	   u32, len, u64, flags)
 {
 	u32 i = 0, l = 0, space, offset = 0;
-	u64 last = start + len;
-	int pop;
+	u64 last = (u64)start + len;
+	u32 pop;
 
 	if (unlikely(flags))
 		return -EINVAL;
Signature · 1 line
2.53.0
author maintainer
#466 lore raw

PATCH 462/1067 MIPS: mm: Fix out-of-bounds write in maar_res_walk()

In reply to Greg Kroah-Hartman

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

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

From: Yadan Fan <[email protected]>

[ Upstream commit 1b001b16bc88f3f7817e228acfd91ee01bdcfcce ]

maar_res_walk() uses wi->num_cfg as the index into the fixed-size wi->cfg array, but checks whether the array is full only after it has filled the selected entry. If walk_system_ram_range() reports more than 16 memory ranges, the overflow call writes one struct maar_config past the end of the array before WARN_ON() prevents num_cfg from advancing.

Move the full-array check before taking the array slot and return non-zero when the scratch array is full, so walk_system_ram_range() terminates the walk instead of invoking the callback for further ranges.

Fixes a5718fe8f70f ("MIPS: mm: Drop boot_mem_map")
---
 arch/mips/mm/init.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
arch/mips/mm/init.c +8 -4
index e8660d06f663fb..45f209a37e08be 100644
@@ -276,9 +276,15 @@ static int maar_res_walk(unsigned long start_pfn, unsigned long nr_pages,
 			 void *data)
 {
 	struct maar_walk_info *wi = data;
-	struct maar_config *cfg = &wi->cfg[wi->num_cfg];
+	struct maar_config *cfg;
 	unsigned int maar_align;
 
+	/* Ensure we don't overflow the cfg array */
+	if (WARN_ON(wi->num_cfg >= ARRAY_SIZE(wi->cfg)))
+		return -1;
+
+	cfg = &wi->cfg[wi->num_cfg];
+
 	/* MAAR registers hold physical addresses right shifted by 4 bits */
 	maar_align = BIT(MIPS_MAAR_ADDR_SHIFT + 4);
 
@@ -287,9 +293,7 @@ static int maar_res_walk(unsigned long start_pfn, unsigned long nr_pages,
 	cfg->upper = ALIGN_DOWN(PFN_PHYS(start_pfn + nr_pages), maar_align) - 1;
 	cfg->attrs = MIPS_MAAR_S;
 
-	/* Ensure we don't overflow the cfg array */
-	if (!WARN_ON(wi->num_cfg >= ARRAY_SIZE(wi->cfg)))
-		wi->num_cfg++;
+	wi->num_cfg++;
 
 	return 0;
 }
Signature · 1 line
2.53.0
author maintainer
#467 lore raw

PATCH 463/1067 powerpc/perf: fix preempt count underflow in fsl_emb_pmu_del

In reply to Greg Kroah-Hartman

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

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

From: Aboorva Devarajan <[email protected]>

[ Upstream commit 81e3a86030462824a67d697739cf3f387f4ba350 ]

fsl_emb_pmu_del() unconditionally calls put_cpu_var(cpu_hw_events) at the 'out:' label, but only calls the matching get_cpu_var() after the 'i < 0' early-return check. When event->hw.idx is negative the function jumps to 'out:' without having taken get_cpu_var(), and the trailing put_cpu_var() then issues an unmatched preempt_enable(), underflowing preempt_count.

On a CONFIG_PREEMPT=y kernel preempt_count would underflow and eventually present as a 'scheduling while atomic' BUG.

Move put_cpu_var() to pair with get_cpu_var() so the percpu access is correctly bracketed and the 'out:' label only handles perf_pmu_enable.

---
 arch/powerpc/perf/core-fsl-emb.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/powerpc/perf/core-fsl-emb.c +2 -1
index 1a53ab08447cbe..31037df4178ca2 100644
@@ -366,9 +366,10 @@ static void fsl_emb_pmu_del(struct perf_event *event, int flags)
 
 	cpuhw->n_events--;
 
+	put_cpu_var(cpu_hw_events);
+
  out:
 	perf_pmu_enable(event->pmu);
-	put_cpu_var(cpu_hw_events);
 }
 
 static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags)
Signature · 1 line
2.53.0
author maintainer
#468 lore raw

PATCH 464/1067 powerpc/powernv: fix preempt count leak in pnv_kexec_wait_secondaries_down

In reply to Greg Kroah-Hartman

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

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

From: Aboorva Devarajan <[email protected]>

[ Upstream commit 0ecd26e93e698c8327521910fc6296f5b84a4b92 ]

pnv_kexec_wait_secondaries_down() calls get_cpu() to obtain the current CPU id but never calls the matching put_cpu(), leaking one preempt_disable() nesting level on every invocation.

In practice the imbalance does not trigger a visible splat because the kexec teardown path is a one-way trip: IRQs are already disabled, no schedule() occurs after the leak, and default_machine_kexec() overwrites preempt_count with HARDIRQ_OFFSET before jumping into kexec_sequence() which never returns. However the bookkeeping is still wrong.

The function only needs the current CPU id, and this path runs with interrupts disabled and the CPU pinned, so the preempt_disable() side-effect of get_cpu() is unnecessary. Replace it with raw_smp_processor_id().

Fixes 298b34d7d578 ("powerpc/powernv: Fix kexec races going back to OPAL")
---
 arch/powerpc/platforms/powernv/setup.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/powerpc/platforms/powernv/setup.c +2 -1
index 61ab2d38ff4be9..8d71e7d3a1122b 100644
@@ -396,7 +396,8 @@ static void pnv_kexec_wait_secondaries_down(void)
 {
 	int my_cpu, i, notified = -1;
 
-	my_cpu = get_cpu();
+	/* Called with interrupts disabled, so the CPU is pinned. */
+	my_cpu = raw_smp_processor_id();
 
 	for_each_online_cpu(i) {
 		uint8_t status;
Signature · 1 line
2.53.0
author maintainer
#469 lore raw

PATCH 465/1067 powerpc/kexec: fix double get_cpu() imbalance in kexec_prepare_cpus

In reply to Greg Kroah-Hartman

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

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

From: Aboorva Devarajan <[email protected]>

[ Upstream commit 5c86f1c1f972761a04bf22f4c0618d1aa714185b ]

kexec_prepare_cpus_wait() calls get_cpu() internally to obtain the current CPU id. kexec_prepare_cpus() calls kexec_prepare_cpus_wait() twice -- once for KEXEC_STATE_IRQS_OFF and once for KEXEC_STATE_REAL_MODE -- but only issues a single put_cpu() at the end, leaving preempt_count elevated by one extra nesting level.

In practice the imbalance does not trigger a 'scheduling while atomic' splat because the kexec path is a one-way trip: IRQs are already disabled, no schedule() occurs after the leak, and default_machine_kexec() overwrites preempt_count with HARDIRQ_OFFSET before jumping into kexec_sequence() which never returns. However the bookkeeping is still wrong.

kexec_prepare_cpus() calls local_irq_disable()/hard_irq_disable() before invoking kexec_prepare_cpus_wait(), so the CPU is already pinned and the get_cpu()/put_cpu() preempt_disable() bracketing is unnecessary. Only the current CPU id is needed, so replace get_cpu() with raw_smp_processor_id() and drop the now-unneeded put_cpu().

---
 arch/powerpc/kexec/core_64.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
arch/powerpc/kexec/core_64.c +1 -3
index cda688bc5c9a8f..1d43ea88ff3d92 100644
@@ -169,7 +169,7 @@ static void kexec_prepare_cpus_wait(int wait_state)
 	int my_cpu, i, notified=-1;
 
 	hw_breakpoint_disable();
-	my_cpu = get_cpu();
+	my_cpu = raw_smp_processor_id();
 	/* Make sure each CPU has at least made it to the state we need.
 	 *
 	 * FIXME: There is a (slim) chance of a problem if not all of the CPUs
@@ -267,8 +267,6 @@ static void kexec_prepare_cpus(void)
 	/* after we tell the others to go down */
 	if (ppc_md.kexec_cpu_down)
 		ppc_md.kexec_cpu_down(0, 0);
-
-	put_cpu();
 }
 
 #else /* ! SMP */
Signature · 1 line
2.53.0
author maintainer
#470 lore raw

PATCH 466/1067 KEYS: Use acquire when reading state in keyring search

In reply to Greg Kroah-Hartman

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

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

From: Gui-Dong Han <[email protected]>

[ Upstream commit c1201b37f666f6466ab1fd3a381c2b7a4b7e9fee ]

The negative-key race fix added release/acquire ordering for key use.

Publish payload before state; read state before payload.

keyring_search_iterator() still uses READ_ONCE() before match callbacks. An asymmetric match callback calls asymmetric_key_ids(), which reads key->payload.data[asym_key_ids].

Use key_read_state() there to complete that ordering.

Fixes 363b02dab09b ("KEYS: Fix race between updating and finding a negative key")
---
 security/keys/keyring.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
security/keys/keyring.c +1 -1
index df2580072cfe16..e105349794f23e 100644
@@ -576,7 +576,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
 	struct keyring_search_context *ctx = iterator_data;
 	const struct key *key = keyring_ptr_to_key(object);
 	unsigned long kflags = READ_ONCE(key->flags);
-	short state = READ_ONCE(key->state);
+	short state = key_read_state(key);
 
 	kenter("{%d}", key->serial);
 
Signature · 1 line
2.53.0
author maintainer
#471 lore raw

PATCH 467/1067 tipc: fix UAF in tipc_l2_send_msg()

In reply to Greg Kroah-Hartman

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

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

From: Eric Dumazet <[email protected]>

[ Upstream commit f4c3d89fc986b0da196ddfc6cfe0ea5d5d08bec6 ]

Syzbot reported a slab-use-after-free in ipvlan_hard_header() when called from tipc_l2_send_msg().

The root cause is that tipc_disable_l2_media() calls synchronize_net() while b->media_ptr is still valid. This allows concurrent RCU readers to obtain the device pointer after synchronize_net() has finished. The pointer is cleared later in bearer_disable(), but without any subsequent synchronization, allowing the device to be freed while still in use by readers.

Fix this by clearing b->media_ptr in tipc_disable_l2_media() before calling synchronize_net().

This is safe to do now because the call order in bearer_disable() was reversed in 0d051bf93c06 ("tipc: make bearer packet filtering generic") to call tipc_node_delete_links() (which needs the pointer) before disable_media().

Fixes 282b3a056225 ("tipc: send out RESET immediately when link goes down")

https: //lore.kernel.org/netdev/[email protected]/T/#u

---
 net/tipc/bearer.c | 1 +
 1 file changed, 1 insertion(+)
net/tipc/bearer.c +1 -0
index 538bb63e07d503..61b611450f208a 100644
@@ -484,6 +484,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b)
 	dev = (struct net_device *)rtnl_dereference(b->media_ptr);
 	dev_remove_pack(&b->pt);
 	RCU_INIT_POINTER(dev->tipc_ptr, NULL);
+	RCU_INIT_POINTER(b->media_ptr, NULL);
 	synchronize_net();
 	dev_put(dev);
 }
Signature · 1 line
2.53.0
author maintainer
#472 lore raw

PATCH 468/1067 tcp: ipv6: clamp default adverting MSS to avoid GSO_BY_FRAGS (0xFFFF)

In reply to Greg Kroah-Hartman

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

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

From: Eric Dumazet <[email protected]>

[ Upstream commit 2bf43d0e2e6a27d52a7d624e2d6b9116972e8a22 ]

When MTU is large, ip6_default_advmss() can return IPV6_MAXPLEN (65535). This is interpreted by TCP as mss_clamp, allowing the MSS to reach 65535.

However, 0xFFFF is also used as a magic value GSO_BY_FRAGS in the kernel. If a TCP packet with gso_size=0xFFFF is passed to skb_segment(), it will be mistakenly treated as GSO_BY_FRAGS, leading to a NULL pointer dereference because local TCP packets do not use frag_list.

Fix this by returning min(IPV6_MAXPLEN, GSO_BY_FRAGS - 1) (65534) from ip6_default_advmss() when MTU is large.

Also update the stale comment in ip6_default_advmss() which suggested that IPV6_MAXPLEN is returned to mean "any MSS".

---
 net/ipv6/route.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
net/ipv6/route.c +3 -3
index 2b861eacee30e4..dde86722cc0399 100644
@@ -3243,11 +3243,11 @@ static unsigned int ip6_default_advmss(const struct dst_entry *dst)
 	/*
 	 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
 	 * corresponding MSS is IPV6_MAXPLEN - tcp_header_size.
-	 * IPV6_MAXPLEN is also valid and means: "any MSS,
-	 * rely only on pmtu discovery"
+	 * Limit the default MSS to GSO_BY_FRAGS - 1 to avoid
+	 * collision with the GSO_BY_FRAGS magic value (0xFFFF).
 	 */
 	if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr))
-		mtu = IPV6_MAXPLEN;
+		mtu = min_t(unsigned int, IPV6_MAXPLEN, GSO_BY_FRAGS - 1);
 	return mtu;
 }
 
Signature · 1 line
2.53.0
author maintainer
#473 lore raw

PATCH 469/1067 ksmbd: fix use-after-free in same_client_has_lease()

In reply to Greg Kroah-Hartman

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

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

From: Guangshuo Li <[email protected]>

[ Upstream commit 65b655f65c3ca1ab5d598d3832bb0ff531725858 ]

same_client_has_lease() returns an opinfo pointer from ci->m_op_list after dropping ci->m_lock without taking a reference.

smb_grant_oplock() then dereferences that pointer in copy_lease() and when checking breaking_cnt. A concurrent close can remove the old lease from ci->m_op_list and drop the last reference before the caller uses the returned pointer, leading to a use-after-free.

Take a reference when same_client_has_lease() selects an existing lease, drop any previous match while scanning, and release the returned reference in smb_grant_oplock() after copying the lease state.

Fixes e2f34481b24d ("cifsd: add server-side procedures for SMB3")
---
 fs/smb/server/oplock.c | 6 ++++++
 1 file changed, 6 insertions(+)
fs/smb/server/oplock.c +6 -0
index 258ed9978b90e7..df3cc4d457f9ac 100644
@@ -534,7 +534,12 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
 
 		ret = compare_guid_key(opinfo, client_guid, lctx->lease_key);
 		if (ret) {
+			if (!atomic_inc_not_zero(&opinfo->refcount))
+				continue;
+			if (m_opinfo)
+				opinfo_put(m_opinfo);
 			m_opinfo = opinfo;
+
 			/* skip upgrading lease about breaking lease */
 			if (atomic_read(&opinfo->breaking_cnt)) {
 				read_lock(&ci->m_lock);
@@ -1253,6 +1258,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
 			if (atomic_read(&m_opinfo->breaking_cnt))
 				opinfo->o_lease->flags =
 					SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE;
+			opinfo_put(m_opinfo);
 			goto out;
 		}
 	}
Signature · 1 line
2.53.0
author maintainer
#474 lore raw

PATCH 470/1067 ocfs2: fix circular locking dependency in ocfs2_dio_end_io_write

In reply to Greg Kroah-Hartman

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

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

From: Aleksandr Nogikh <[email protected]>

[ Upstream commit ff6f26c58421614b02694ac9d219ac61d924bc68 ]

A circular locking dependency involves INODE_ALLOC_SYSTEM_INODE, EXTENT_ALLOC_SYSTEM_INODE, and ORPHAN_DIR_SYSTEM_INODE.

1. ocfs2_mknod() acquires INODE_ALLOC then EXTENT_ALLOC.

2. ocfs2_dio_end_io_write() acquires EXTENT_ALLOC for unwritten extents, then ORPHAN_DIR via ocfs2_del_inode_from_orphan() while still holding EXTENT_ALLOC.

3. ocfs2_wipe_inode() acquires ORPHAN_DIR then INODE_ALLOC via ocfs2_remove_inode.

Break the cycle in ocfs2_dio_end_io_write() by freeing the allocation contexts (releasing EXTENT_ALLOC) before acquiring ORPHAN_DIR.

WARNING: possible circular locking dependency detected
------------------------------------------------------
is trying to acquire lock:
ffff8881e78b33a0 (&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}, at:
ocfs2_evict_inode+0x1539/0x43b0 fs/ocfs2/inode.c:1299

but task is already holding lock:
ffff8881e78b4fa0 (&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]){+.+.}-{4:4}, at:
ocfs2_evict_inode+0xe97/0x43b0 fs/ocfs2/inode.c:1299

the existing dependency chain (in reverse order) is:

-> #2 (&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]){+.+.}-{4:4}:

       inode_lock include/linux/fs.h:1029 [inline]
       ocfs2_del_inode_from_orphan+0x12e/0x7a0 fs/ocfs2/namei.c:2728
       ocfs2_dio_end_io+0xf9c/0x1370 fs/ocfs2/aops.c:2418
       dio_complete+0x25b/0x790 fs/direct-io.c:281

-> #1 (&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}:

       inode_lock include/linux/fs.h:1029 [inline]
       ocfs2_reserve_suballoc_bits+0x16d/0x4840 fs/ocfs2/suballoc.c:882
       ocfs2_reserve_new_metadata_blocks+0x415/0x9a0
       fs/ocfs2/suballoc.c:1078
       ocfs2_mknod+0x10f3/0x2260 fs/ocfs2/namei.c:351

-> #0 (&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}:

       __lock_acquire+0x15a5/0x2cf0 kernel/locking/lockdep.c:5237
       lock_acquire+0x106/0x350 kernel/locking/lockdep.c:5868
       down_write+0x96/0x200 kernel/locking/rwsem.c:1625
       inode_lock include/linux/fs.h:1029 [inline]
       ocfs2_remove_inode fs/ocfs2/inode.c:733 [inline]
       ocfs2_wipe_inode fs/ocfs2/inode.c:896 [inline]
       ocfs2_delete_inode fs/ocfs2/inode.c:1157 [inline]
       ocfs2_evict_inode+0x1539/0x43b0 fs/ocfs2/inode.c:1299

Chain exists of:
  &ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE] -->
  &ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE] -->
  &ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]

 Possible unsafe locking scenario:
       CPU0                    CPU1
       ----                    ----
  lock(&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]);
                               lock(&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]);
                               lock(&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]);

lock(&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]);

*** DEADLOCK ***

Fixes d647c5b2fbf8 ("ocfs2: split transactions in dio completion to avoid credit exhaustion")
Assisted-by Gemini:gemini-3.1-pro-preview Gemini:gemini-3-flash-preview syzbot
Reported-by [email protected]
Cc Mark Fasheh <[email protected]>
Cc Joel Becker <[email protected]>
Cc Junxiao Bi <[email protected]>
Cc Joseph Qi <[email protected]>
Cc Changwei Ge <[email protected]>
Cc Jun Piao <[email protected]>
---
 fs/ocfs2/aops.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
fs/ocfs2/aops.c +9 -4
index 9c4ca8c71998c6..4faa11d961e1a0 100644
@@ -2400,6 +2400,15 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
 unlock:
 	up_write(&oi->ip_alloc_sem);
 
+	if (data_ac) {
+		ocfs2_free_alloc_context(data_ac);
+		data_ac = NULL;
+	}
+	if (meta_ac) {
+		ocfs2_free_alloc_context(meta_ac);
+		meta_ac = NULL;
+	}
+
 	/* everything looks good, let's start the cleanup */
 	if (!ret && dwc->dw_orphaned) {
 		BUG_ON(dwc->dw_writer_pid != task_pid_nr(current));
@@ -2411,10 +2420,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,
 	ocfs2_inode_unlock(inode, 1);
 	brelse(di_bh);
 out:
-	if (data_ac)
-		ocfs2_free_alloc_context(data_ac);
-	if (meta_ac)
-		ocfs2_free_alloc_context(meta_ac);
 	ocfs2_run_deallocs(osb, &dealloc);
 	ocfs2_dio_free_write_ctx(inode, dwc);
 
Signature · 1 line
2.53.0
author maintainer
#475 lore raw

PATCH 471/1067 net/9p: fix race condition on rdma->state in trans_rdma.c

In reply to Greg Kroah-Hartman

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

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

From: Yizhou Zhao <[email protected]>

[ Upstream commit 7d54894a1ee265a72d70f7cae1da6cc774cccc71 ]

The rdma->state field is modified without holding req_lock in both recv_done() and p9_cm_event_handler(), while rdma_request() accesses the same field under the req_lock spinlock. This inconsistent locking creates a race condition:

- recv_done() running in softirq completion context sets rdma->state = P9_RDMA_FLUSHING without acquiring req_lock

- p9_cm_event_handler() modifies rdma->state at multiple points (ADDR_RESOLVED, ROUTE_RESOLVED, ESTABLISHED, CLOSED) without req_lock

- rdma_request() uses spin_lock_irqsave(&rdma->req_lock, flags) to protect the read-modify-write of rdma->state

The race can cause lost state transitions: recv_done() or the CM event handler could set state to FLUSHING/CLOSED while rdma_request() is concurrently checking or modifying state under the lock, leading to the FLUSHING transition being silently overwritten by CLOSING. This corrupts the connection state machine and can cause use-after-free on RDMA request objects during teardown.

Fix by adding req_lock protection to all rdma->state modifications in recv_done() and p9_cm_event_handler(), matching the pattern already used in rdma_request(). Use spin_lock_irqsave/spin_unlock_irqrestore in the CM event handler since it can race with recv_done() which runs in softirq context.

Tested with a kernel module that races two threads (simulating rdma_request and recv_done/CM handler) on rdma->state with proper
locking: 5.5M+ FLUSHING writes over 27M iterations with 0 lost transitions.

Fixes 473c7dd1d7b5 ("9p/rdma: remove useless check in cm_event_handler")
Assisted-by GLM:GLM-5.1

Message-ID: <[email protected]>

---
 net/9p/trans_rdma.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
net/9p/trans_rdma.c +17 -2
index 29a9292303ea30..e3ee21bbe389a5 100644
@@ -241,25 +241,36 @@ p9_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
 {
 	struct p9_client *c = id->context;
 	struct p9_trans_rdma *rdma = c->trans;
+	unsigned long flags;
+
 	switch (event->event) {
 	case RDMA_CM_EVENT_ADDR_RESOLVED:
+		spin_lock_irqsave(&rdma->req_lock, flags);
 		BUG_ON(rdma->state != P9_RDMA_INIT);
 		rdma->state = P9_RDMA_ADDR_RESOLVED;
+		spin_unlock_irqrestore(&rdma->req_lock, flags);
 		break;
 
 	case RDMA_CM_EVENT_ROUTE_RESOLVED:
+		spin_lock_irqsave(&rdma->req_lock, flags);
 		BUG_ON(rdma->state != P9_RDMA_ADDR_RESOLVED);
 		rdma->state = P9_RDMA_ROUTE_RESOLVED;
+		spin_unlock_irqrestore(&rdma->req_lock, flags);
 		break;
 
 	case RDMA_CM_EVENT_ESTABLISHED:
+		spin_lock_irqsave(&rdma->req_lock, flags);
 		BUG_ON(rdma->state != P9_RDMA_ROUTE_RESOLVED);
 		rdma->state = P9_RDMA_CONNECTED;
+		spin_unlock_irqrestore(&rdma->req_lock, flags);
 		break;
 
 	case RDMA_CM_EVENT_DISCONNECTED:
-		if (rdma)
+		if (rdma) {
+			spin_lock_irqsave(&rdma->req_lock, flags);
 			rdma->state = P9_RDMA_CLOSED;
+			spin_unlock_irqrestore(&rdma->req_lock, flags);
+		}
 		c->status = Disconnected;
 		break;
 
@@ -297,6 +308,7 @@ recv_done(struct ib_cq *cq, struct ib_wc *wc)
 	struct p9_req_t *req;
 	int err = 0;
 	int16_t tag;
+	unsigned long flags;
 
 	req = NULL;
 	ib_dma_unmap_single(rdma->cm_id->device, c->busa, client->msize,
@@ -333,7 +345,10 @@ recv_done(struct ib_cq *cq, struct ib_wc *wc)
  err_out:
 	p9_debug(P9_DEBUG_ERROR, "req %p err %d status %d\n",
 			req, err, wc->status);
-	rdma->state = P9_RDMA_FLUSHING;
+	spin_lock_irqsave(&rdma->req_lock, flags);
+	if (rdma->state < P9_RDMA_FLUSHING)
+		rdma->state = P9_RDMA_FLUSHING;
+	spin_unlock_irqrestore(&rdma->req_lock, flags);
 	client->status = Disconnected;
 	goto out;
 }
Signature · 1 line
2.53.0
author maintainer
#476 lore raw

PATCH 472/1067 staging: nvec: fix use-after-free in nvec_rx_completed()

In reply to Greg Kroah-Hartman

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

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

From: Alexandru Hossu <[email protected]>

[ Upstream commit 26813881181deb3a32fbb59eadb2599cbe8423f6 ]

In nvec_rx_completed(), when an incomplete RX transfer is detected, nvec_msg_free() is called to return the message back to the pool by clearing its 'used' atomic flag. Immediately after this, the code accesses nvec->rx->data[0] to check the message type.

Since nvec_msg_free() marks the pool slot as available via atomic_set(), any concurrent or subsequent call to nvec_msg_alloc() could claim that same slot and overwrite its data[] array. Reading nvec->rx->data[0] after freeing the message is therefore a use-after-free.

Fix this by saving the message type byte before calling nvec_msg_free(), then using the saved value for the battery quirk check.

Fixes d6bdcf2e1019 ("staging: nvec: Add battery quirk to ignore incomplete responses")
---
 drivers/staging/nvec/nvec.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/staging/nvec/nvec.c +3 -1
index b3f114cb00dc86..46d26e3870d3de 100644
@@ -489,6 +489,8 @@ static void nvec_tx_completed(struct nvec_chip *nvec)
 static void nvec_rx_completed(struct nvec_chip *nvec)
 {
 	if (nvec->rx->pos != nvec_msg_size(nvec->rx)) {
+		unsigned char msg_type = nvec->rx->data[0];
+
 		dev_err(nvec->dev, "RX incomplete: Expected %u bytes, got %u\n",
 			(uint)nvec_msg_size(nvec->rx),
 			(uint)nvec->rx->pos);
@@ -497,7 +499,7 @@ static void nvec_rx_completed(struct nvec_chip *nvec)
 		nvec->state = 0;
 
 		/* Battery quirk - Often incomplete, and likes to crash */
-		if (nvec->rx->data[0] == NVEC_BAT)
+		if (msg_type == NVEC_BAT)
 			complete(&nvec->ec_transfer);
 
 		return;
Signature · 1 line
2.53.0
author maintainer
#477 lore raw

PATCH 473/1067 coresight: cti: Fix DT filter signals silently ignored

In reply to Greg Kroah-Hartman

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

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

From: Yingchao Deng <[email protected]>

[ Upstream commit 551bb2fd5e4ed63d33aa11f07102cce5179b7595 ]

In cti_plat_process_filter_sigs(), after allocating a temporary cti_trig_grp struct via kzalloc_obj(), the code never assigns tg->nr_sigs = nr_filter_sigs. Since kzalloc zero-initialises the struct, tg->nr_sigs remains 0. cti_plat_read_trig_group() guards with:

    if (!tgrp->nr_sigs)
        return 0;

so it returns immediately without reading any signal indices from DT.

Fix by assigning tg->nr_sigs before calling cti_plat_read_trig_group().

Fixes a5614770ab97 ("coresight: cti: Add device tree support for custom CTI")
---
 drivers/hwtracing/coresight/coresight-cti-platform.c | 1 +
 1 file changed, 1 insertion(+)
drivers/hwtracing/coresight/coresight-cti-platform.c +1 -0
index ccef04f27f12fa..438f9c7ddccdc3 100644
@@ -329,6 +329,7 @@ static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata,
 	if (!tg)
 		return -ENOMEM;
 
+	tg->nr_sigs = nr_filter_sigs;
 	err = cti_plat_read_trig_group(tg, fwnode, CTI_DT_FILTER_OUT_SIGS);
 	if (!err)
 		drvdata->config.trig_out_filter |= tg->used_mask;
Signature · 1 line
2.53.0
author maintainer
#478 lore raw

PATCH 474/1067 coresight: etm4x: Correct TRCVMIDCCTLR1 save and restore

In reply to Greg Kroah-Hartman

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

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

From: Leo Yan <[email protected]>

[ Upstream commit 0ec0a8785d21f63db520bd9d2a67c55e855d36a8 ]

It is a typo to use trcvmidcctlr0 to save and restore TRCVMIDCCTLR1. Use trcvmidcctlr1 instead.

Fixes f5bd523690d2 ("coresight: etm4x: Convert all register accesses")
---
 drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +2 -2
index 0616efc7cb198f..b2c55cc45a11f7 100644
@@ -1758,7 +1758,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
 
 	state->trcvmidcctlr0 = etm4x_read32(csa, TRCVMIDCCTLR0);
 	if (drvdata->numvmidc > 4)
-		state->trcvmidcctlr0 = etm4x_read32(csa, TRCVMIDCCTLR1);
+		state->trcvmidcctlr1 = etm4x_read32(csa, TRCVMIDCCTLR1);
 
 	state->trcclaimset = etm4x_read32(csa, TRCCLAIMCLR);
 
@@ -1884,7 +1884,7 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
 
 	etm4x_relaxed_write32(csa, state->trcvmidcctlr0, TRCVMIDCCTLR0);
 	if (drvdata->numvmidc > 4)
-		etm4x_relaxed_write32(csa, state->trcvmidcctlr0, TRCVMIDCCTLR1);
+		etm4x_relaxed_write32(csa, state->trcvmidcctlr1, TRCVMIDCCTLR1);
 
 	etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
 
Signature · 1 line
2.53.0
author maintainer
#479 lore raw

PATCH 475/1067 PCI/ASPM: Dont reconfigure ASPM entering low-power state

In reply to Greg Kroah-Hartman

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

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

From: Carlos Bilbao <[email protected]>

[ Upstream commit c855c9921da72e535c24737c748f603a52d03f7e ]

Reconfiguring ASPM when a device transitions to low-power state can enable L1.1/L1.2 substates on the PCIe link at a time when the device is sleeping and may be unable to exit them. ASPM should be reconfigured on D0 entry (resume), not on the way down.

pci_set_low_power_state() calls pcie_aspm_pm_state_change() after writing D3hot to PCI_PM_CTRL. pcie_aspm_pm_state_change() resets link->aspm_capable to link->aspm_support and then calls pcie_config_aspm_path(), which can enable ASPM L1.1/L1.2 substates on the PCIe link. If the device cannot recover the link from L1.2 while in D3hot, subsequent config space reads return 0xFFFF ("device inaccessible") and pci_power_up() fails with messages like:

vfio-pci 0000:5d:00.0: Unable to change power state from D3hot to D0, device inaccessible

This was observed on NVIDIA H100 SXM5 GPUs bound to vfio-pci when Linux runtime PM suspends them to D3hot: the GPU becomes permanently inaccessible and disappears from the PCIe bus.

The call to pcie_aspm_pm_state_change() in pci_set_low_power_state() was restored by f93e71aea6c6 ("Revert "PCI/ASPM: Remove pcie_aspm_pm_state_change()""), which reverted 08d0cc5f3426 ("PCI/ASPM:
Remove pcie_aspm_pm_state_change()"). The revert was necessary because the removal broke suspend/resume on certain platforms that required ASPM to be reconfigured on D0 entry. However, the revert restored the call in both pci_set_full_power_state() (D0 entry) and pci_set_low_power_state() (low-power entry).

Only the D0-entry call is needed to fix the suspend/resume regression. The low-power-entry call is harmful: reconfiguring ASPM immediately after putting a device into D3hot can enable link substates that the device or platform cannot exit while the device is sleeping.

Remove the pcie_aspm_pm_state_change() call from pci_set_low_power_state(). ASPM will still be reconfigured correctly when the device returns to D0 via pci_set_full_power_state().

Fixes f93e71aea6c6 ("Revert "PCI/ASPM: Remove pcie_aspm_pm_state_change()"")
---
 drivers/pci/pci.c | 3 ---
 1 file changed, 3 deletions(-)
drivers/pci/pci.c +0 -3
index 953646cd759b03..92fa1e9444a99f 100644
@@ -1488,9 +1488,6 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool
 				     pci_power_name(dev->current_state),
 				     pci_power_name(state));
 
-	if (dev->bus->self)
-		pcie_aspm_pm_state_change(dev->bus->self, locked);
-
 	return 0;
 }
 
Signature · 1 line
2.53.0
author maintainer
#480 lore raw

PATCH 476/1067 PCI: Introduce named defines for PCI ROM

In reply to Greg Kroah-Hartman

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

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

From: Guixin Liu <[email protected]>

[ Upstream commit 113e86bc58a918f85d250723436a4d541a873358 ]

Convert the magic numbers associated with PCI ROM into named definitions. Some of these definitions will be used in the second fix patch.

Stable-dep-of: 538796b807fc ("PCI: Check ROM header and data structure addr before accessing")

---
 drivers/pci/rom.c | 40 ++++++++++++++++++++++++++++------------
 1 file changed, 28 insertions(+), 12 deletions(-)
drivers/pci/rom.c +28 -12
index e18d3a4383ba6b..d4a141bd148b4b 100644
@@ -5,13 +5,28 @@
  * (C) Copyright 2004 Jon Smirl <[email protected]>
  * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <[email protected]>
  */
+
+#include <linux/bits.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <linux/pci.h>
+#include <linux/sizes.h>
 #include <linux/slab.h>
 
 #include "pci.h"
 
+#define PCI_ROM_HEADER_SIZE			0x1A
+#define PCI_ROM_POINTER_TO_DATA_STRUCT		0x18
+#define PCI_ROM_LAST_IMAGE_INDICATOR		0x15
+#define PCI_ROM_LAST_IMAGE_INDICATOR_BIT	BIT(7)
+#define PCI_ROM_IMAGE_LEN			0x10
+#define PCI_ROM_IMAGE_SECTOR_SIZE		SZ_512
+#define PCI_ROM_IMAGE_SIGNATURE			0xAA55
+
+/* Data structure signature is "PCIR" in ASCII representation */
+#define PCI_ROM_DATA_STRUCT_SIGNATURE		0x52494350
+#define PCI_ROM_DATA_STRUCT_LEN			0x0A
+
 /**
  * pci_enable_rom - enable ROM decoding for a PCI device
  * @pdev: PCI device to enable
@@ -91,26 +106,27 @@ static size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom,
 	do {
 		void __iomem *pds;
 		/* Standard PCI ROMs start out with these bytes 55 AA */
-		if (readw(image) != 0xAA55) {
-			pci_info(pdev, "Invalid PCI ROM header signature: expecting 0xaa55, got %#06x\n",
-				 readw(image));
+		if (readw(image) != PCI_ROM_IMAGE_SIGNATURE) {
+			pci_info(pdev, "Invalid PCI ROM header signature: expecting %#06x, got %#06x\n",
+				 PCI_ROM_IMAGE_SIGNATURE, readw(image));
 			break;
 		}
-		/* get the PCI data structure and check its "PCIR" signature */
-		pds = image + readw(image + 24);
-		if (readl(pds) != 0x52494350) {
-			pci_info(pdev, "Invalid PCI ROM data signature: expecting 0x52494350, got %#010x\n",
-				 readl(pds));
+		/* Get the PCI data structure and check its "PCIR" signature */
+		pds = image + readw(image + PCI_ROM_POINTER_TO_DATA_STRUCT);
+		if (readl(pds) != PCI_ROM_DATA_STRUCT_SIGNATURE) {
+			pci_info(pdev, "Invalid PCI ROM data signature: expecting %#010x, got %#010x\n",
+				 PCI_ROM_DATA_STRUCT_SIGNATURE, readl(pds));
 			break;
 		}
-		last_image = readb(pds + 21) & 0x80;
-		length = readw(pds + 16);
-		image += length * 512;
+		last_image = readb(pds + PCI_ROM_LAST_IMAGE_INDICATOR) &
+				   PCI_ROM_LAST_IMAGE_INDICATOR_BIT;
+		length = readw(pds + PCI_ROM_IMAGE_LEN);
+		image += length * PCI_ROM_IMAGE_SECTOR_SIZE;
 		/* Avoid iterating through memory outside the resource window */
 		if (image >= rom + size)
 			break;
 		if (!last_image) {
-			if (readw(image) != 0xAA55) {
+			if (readw(image) != PCI_ROM_IMAGE_SIGNATURE) {
 				pci_info(pdev, "No more image in the PCI ROM\n");
 				break;
 			}
Signature · 1 line
2.53.0
author maintainer
#481 lore raw

PATCH 477/1067 PCI: Check ROM header and data structure addr before accessing

In reply to Greg Kroah-Hartman

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

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

From: Guixin Liu <[email protected]>

[ Upstream commit 538796b807fcfb81b2ce40cc97a614fd8588feb5 ]

We meet a crash when running stress-ng on x86_64 machine:

  BUG: unable to handle page fault for address: ffa0000007f40000
  RIP: 0010:pci_get_rom_size+0x52/0x220
  Call Trace:
  <TASK>
    pci_map_rom+0x80/0x130
    pci_read_rom+0x4b/0xe0
    kernfs_file_read_iter+0x96/0x180
    vfs_read+0x1b1/0x300

Our analysis reveals that the ROM space's start address is 0xffa0000007f30000, and size is 0x10000. Because of broken ROM space, before calling readl(pds), the pds's value is 0xffa0000007f3ffff, which is already pointed to the ROM space end, invoking readl() would read 4 bytes therefore cause an out-of-bounds access and trigger a crash. Fix this by adding image header and data structure checking.

We also found another crash on arm64 machine:

  Unable to handle kernel paging request at virtual address ffff8000dd1393ff
  Mem abort info:
  ESR = 0x0000000096000021
  EC = 0x25: DABT (current EL), IL = 32 bits
  SET = 0, FnV = 0
  EA = 0, S1PTW = 0
  FSC = 0x21: alignment fault

The call trace is the same with x86_64, but the crash reason is that the data structure addr is not aligned with 4, and arm64 machine report "alignment fault". Fix this by adding alignment checking.

Fixes 47b975d234ea ("PCI: Avoid iterating through memory outside the resource window")
[bhelgaas: shorten function names, wrap comments]
---
 drivers/pci/rom.c | 123 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 105 insertions(+), 18 deletions(-)
drivers/pci/rom.c +105 -18
index d4a141bd148b4b..f2105c6ceef524 100644
@@ -6,9 +6,12 @@
  * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <[email protected]>
  */
 
+#include <linux/align.h>
 #include <linux/bits.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
+#include <linux/io.h>
+#include <linux/overflow.h>
 #include <linux/pci.h>
 #include <linux/sizes.h>
 #include <linux/slab.h>
@@ -27,6 +30,15 @@
 #define PCI_ROM_DATA_STRUCT_SIGNATURE		0x52494350
 #define PCI_ROM_DATA_STRUCT_LEN			0x0A
 
+/*
+ * Per PCI Firmware r3.3, sec 5.1.3, a conformant PCI Data Structure is at
+ * least 24 bytes (0x18), large enough to cover every fixed field this
+ * driver reads (up to the Indicator byte at offset 0x15).  Reject smaller
+ * device-claimed lengths so the follow-up readers in pci_get_rom_size()
+ * cannot escape the mapped ROM window.
+ */
+#define PCI_ROM_DATA_STRUCT_MIN_LEN		0x18
+
 /**
  * pci_enable_rom - enable ROM decoding for a PCI device
  * @pdev: PCI device to enable
@@ -84,6 +96,91 @@ void pci_disable_rom(struct pci_dev *pdev)
 }
 EXPORT_SYMBOL_GPL(pci_disable_rom);
 
+static bool pci_rom_header_valid(struct pci_dev *pdev, void __iomem *image,
+				 void __iomem *rom, size_t size,
+				 bool expect_valid)
+{
+	unsigned long rom_end = (unsigned long)rom + size - 1;
+	unsigned long header_end;
+	u16 signature;
+
+	/*
+	 * Per PCI Firmware r3.3, sec 5.1, each image must start on a
+	 * 512-byte boundary and must contain the PCI Expansion ROM header.
+	 * Because @rom is page-aligned (returned by ioremap()), checking
+	 * 512-byte alignment of @image is equivalent to enforcing the
+	 * spec's sector-aligned layout within the ROM.  This also
+	 * satisfies the natural-alignment requirement of readw() on archs
+	 * such as arm64 that disallow unaligned IOMEM access.
+	 */
+	if (!IS_ALIGNED((unsigned long)image, PCI_ROM_IMAGE_SECTOR_SIZE))
+		return false;
+
+	if (check_add_overflow((unsigned long)image, PCI_ROM_HEADER_SIZE - 1,
+				&header_end))
+		return false;
+
+	if (image < rom || header_end > rom_end)
+		return false;
+
+	/* Standard PCI ROMs start out with these bytes 55 AA */
+	signature = readw(image);
+	if (signature != PCI_ROM_IMAGE_SIGNATURE) {
+		if (expect_valid) {
+			pci_info(pdev, "Invalid PCI ROM header signature: expecting %#06x, got %#06x\n",
+				 PCI_ROM_IMAGE_SIGNATURE, signature);
+		} else {
+			pci_info(pdev, "No more images in PCI ROM\n");
+		}
+		return false;
+	}
+
+	return true;
+}
+
+static bool pci_rom_data_struct_valid(struct pci_dev *pdev, void __iomem *pds,
+				      void __iomem *rom, size_t size)
+{
+	unsigned long rom_end = (unsigned long)rom + size - 1;
+	unsigned long end;
+	u32 signature;
+	u16 data_len;
+
+	/*
+	 * Some CPU architectures require IOMEM access addresses to be
+	 * aligned, for example arm64, so since we're about to call
+	 * readl(), check here for 4-byte alignment.
+	 */
+	if (!IS_ALIGNED((unsigned long)pds, 4))
+		return false;
+
+	if (check_add_overflow((unsigned long)pds, PCI_ROM_DATA_STRUCT_LEN + 1,
+				&end))
+		return false;
+
+	if (pds < rom || end > rom_end)
+		return false;
+
+	signature = readl(pds);
+	if (signature != PCI_ROM_DATA_STRUCT_SIGNATURE) {
+		pci_info(pdev, "Invalid PCI ROM data signature: expecting %#010x, got %#010x\n",
+			 PCI_ROM_DATA_STRUCT_SIGNATURE, signature);
+		return false;
+	}
+
+	data_len = readw(pds + PCI_ROM_DATA_STRUCT_LEN);
+	if (data_len < PCI_ROM_DATA_STRUCT_MIN_LEN || data_len == U16_MAX)
+		return false;
+
+	if (check_add_overflow((unsigned long)pds, data_len - 1, &end))
+		return false;
+
+	if (end > rom_end)
+		return false;
+
+	return true;
+}
+
 /**
  * pci_get_rom_size - obtain the actual size of the ROM image
  * @pdev: target PCI device
@@ -99,38 +196,28 @@ static size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom,
 			       size_t size)
 {
 	void __iomem *image;
-	int last_image;
 	unsigned int length;
+	bool last_image;
 
 	image = rom;
 	do {
 		void __iomem *pds;
-		/* Standard PCI ROMs start out with these bytes 55 AA */
-		if (readw(image) != PCI_ROM_IMAGE_SIGNATURE) {
-			pci_info(pdev, "Invalid PCI ROM header signature: expecting %#06x, got %#06x\n",
-				 PCI_ROM_IMAGE_SIGNATURE, readw(image));
+		if (!pci_rom_header_valid(pdev, image, rom, size, true))
 			break;
-		}
+
 		/* Get the PCI data structure and check its "PCIR" signature */
 		pds = image + readw(image + PCI_ROM_POINTER_TO_DATA_STRUCT);
-		if (readl(pds) != PCI_ROM_DATA_STRUCT_SIGNATURE) {
-			pci_info(pdev, "Invalid PCI ROM data signature: expecting %#010x, got %#010x\n",
-				 PCI_ROM_DATA_STRUCT_SIGNATURE, readl(pds));
+		if (!pci_rom_data_struct_valid(pdev, pds, rom, size))
 			break;
-		}
+
 		last_image = readb(pds + PCI_ROM_LAST_IMAGE_INDICATOR) &
 				   PCI_ROM_LAST_IMAGE_INDICATOR_BIT;
 		length = readw(pds + PCI_ROM_IMAGE_LEN);
 		image += length * PCI_ROM_IMAGE_SECTOR_SIZE;
-		/* Avoid iterating through memory outside the resource window */
-		if (image >= rom + size)
+
+		if (!last_image &&
+		    !pci_rom_header_valid(pdev, image, rom, size, false))
 			break;
-		if (!last_image) {
-			if (readw(image) != PCI_ROM_IMAGE_SIGNATURE) {
-				pci_info(pdev, "No more image in the PCI ROM\n");
-				break;
-			}
-		}
 	} while (length && !last_image);
 
 	/* never return a size larger than the PCI resource window */
Signature · 1 line
2.53.0
author maintainer
#482 lore raw

PATCH 478/1067 x86/platform/olpc: xo15: Drop wakeup source on driver removal

In reply to Greg Kroah-Hartman

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

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

From: Rafael J. Wysocki <[email protected]>

[ Upstream commit cc966553e6ff0849978b5754531b768b0ff54985 ]

Prevent leaking a wakeup source object after removing the driver by adding appropriate cleanup code to its remove callback function.

---
 arch/x86/platform/olpc/olpc-xo15-sci.c | 1 +
 1 file changed, 1 insertion(+)
arch/x86/platform/olpc/olpc-xo15-sci.c +1 -0
index 994a229cb79fe1..76ba025a545c79 100644
@@ -185,6 +185,7 @@ static int xo15_sci_add(struct acpi_device *device)
 
 static int xo15_sci_remove(struct acpi_device *device)
 {
+	device_init_wakeup(&device->dev, false);
 	acpi_disable_gpe(NULL, xo15_sci_gpe);
 	acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
 	cancel_work_sync(&sci_work);
Signature · 1 line
2.53.0
author maintainer
#483 lore raw

PATCH 479/1067 platform/x86: xo15-ebook: Fix wakeup source and GPE handling

In reply to Greg Kroah-Hartman

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

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

From: Rafael J. Wysocki <[email protected]>

[ Upstream commit b2fc2c6ebbd2d49935c8960755d8170faead2159 ]

The device_set_wakeup_enable() call in ebook_switch_add() doesn't actually do anything because power.can_wakeup is not set for ACPI device objects. Moreover, had it done anything, it would have registered a wakeup source object that wouldn't have been used going forward and that wakeup source would have been leaked after driver removal because ebook_switch_remove() doesn't clean it up. Accordingly, remove that call from ebook_switch_add().

Also prevent leaking an enabled ACPI GPE after removing the driver by adding appropriate cleanup code to ebook_switch_remove().

---
 drivers/platform/x86/xo15-ebook.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/platform/x86/xo15-ebook.c +6 -1
index 97440462aa258a..6413bb8fe26df9 100644
@@ -38,6 +38,7 @@ MODULE_DEVICE_TABLE(acpi, ebook_device_ids);
 struct ebook_switch {
 	struct input_dev *input;
 	char phys[32];			/* for input device */
+	bool gpe_enabled;
 };
 
 static int ebook_send_state(struct acpi_device *device)
@@ -131,7 +132,7 @@ static int ebook_switch_add(struct acpi_device *device)
 		/* Button's GPE is run-wake GPE */
 		acpi_enable_gpe(device->wakeup.gpe_device,
 				device->wakeup.gpe_number);
-		device_set_wakeup_enable(&device->dev, true);
+		button->gpe_enabled = true;
 	}
 
 	return 0;
@@ -147,6 +148,10 @@ static int ebook_switch_remove(struct acpi_device *device)
 {
 	struct ebook_switch *button = acpi_driver_data(device);
 
+	if (button->gpe_enabled)
+		acpi_disable_gpe(device->wakeup.gpe_device,
+				 device->wakeup.gpe_number);
+
 	input_unregister_device(button->input);
 	kfree(button);
 	return 0;
Signature · 1 line
2.53.0
author maintainer
#484 lore raw

PATCH 480/1067 perf sched: Add missing mmap2 handler in timehist

In reply to Greg Kroah-Hartman

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

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

From: Ian Rogers <[email protected]>

[ Upstream commit 91182741369b261c441e63e6678893032a6d7e4c ]

perf_sched__timehist() registers event handlers for options using the sched->tool struct. It registers handlers for MMAP, COMM, EXIT, FORK, etc. but completely omits registering a handler for MMAP2 events.

Failing to register both MMAP and MMAP2 handlers causes modern systems (which primarily output MMAP2 records) to silently drop VMA map mappings. This results in uninitialized machine/thread mapping structures, making it impossible to resolve shared library instruction pointers (IPs) to dynamic symbols/DSOs during timehist callchain analysis.

Fix this by correctly registering perf_event__process_mmap2 in sched->tool inside perf_sched__timehist().

Fixes 49394a2a24c78ce0 ("perf sched timehist: Introduce timehist command")
Assisted-by Gemini-CLI:Google Gemini 3
Cc Adrian Hunter <[email protected]>
Cc David Ahern <[email protected]>
Cc Gabriel Marin <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc James Clark <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Peter Zijlstra <[email protected]>
---
 tools/perf/builtin-sched.c | 1 +
 1 file changed, 1 insertion(+)
tools/perf/builtin-sched.c +1 -0
index 3ffb41fa82b814..6584e39b2a8d48 100644
@@ -3055,6 +3055,7 @@ static int perf_sched__timehist(struct perf_sched *sched)
 	 */
 	sched->tool.sample	 = perf_timehist__process_sample;
 	sched->tool.mmap	 = perf_event__process_mmap;
+	sched->tool.mmap2	 = perf_event__process_mmap2;
 	sched->tool.comm	 = perf_event__process_comm;
 	sched->tool.exit	 = perf_event__process_exit;
 	sched->tool.fork	 = perf_event__process_fork;
Signature · 1 line
2.53.0
author maintainer
#485 lore raw

PATCH 481/1067 PCI: loongson: Do not ignore downstream devices on external bridges

In reply to Greg Kroah-Hartman

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

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

From: Rong Zhang <[email protected]>

[ Upstream commit 1389ab9bf9f627d4daed86f492091b00f110aa86 ]

Loongson PCI host controllers have a hardware quirk that requires software to ignore downstream devices with device number > 0 on the internal bridges. The current implementation applies the workaround to all non-root buses, which breaks external bridges (e.g., PCIe switches) with multiple downstream devices.

Fix it by only applying the workaround to internal bridges.

Tested on Loongson-LS3A4000-7A1000-NUC-SE, using AMD Promontory 21 chipset add-in card [1].

  $ lspci -tnnnvvv
  -[0000:00]-+-00.0  Loongson Technology LLC 7A1000 Chipset Hyper Transport Bridge Controller [0014:7a00]
             +-00.1  Loongson Technology LLC 7A2000 Chipset Hyper Transport Bridge Controller [0014:7a10]
             +-03.0  Loongson Technology LLC 2K1000/2000 / 7A1000 Chipset Gigabit Ethernet Controller [0014:7a03]
             +-04.0  Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB OHCI Controller [0014:7a24]
             +-04.1  Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB EHCI Controller [0014:7a14]
             +-05.0  Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB OHCI Controller [0014:7a24]
             +-05.1  Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB EHCI Controller [0014:7a14]
             +-06.0  Loongson Technology LLC 7A1000 Chipset Vivante GC1000 GPU [0014:7a15]
             +-06.1  Loongson Technology LLC 2K1000 / 7A1000 Chipset Display Controller [0014:7a06]
             +-07.0  Loongson Technology LLC 2K1000/2000/3000 / 3B6000M / 7A1000/2000 Chipset HD Audio Controller [0014:7a07]
             +-08.0  Loongson Technology LLC 2K1000 / 7A1000 Chipset 3Gb/s SATA AHCI Controller [0014:7a08]
             +-08.1  Loongson Technology LLC 2K1000 / 7A1000 Chipset 3Gb/s SATA AHCI Controller [0014:7a08]
             +-08.2  Loongson Technology LLC 2K1000 / 7A1000 Chipset 3Gb/s SATA AHCI Controller [0014:7a08]
             +-09.0-[01]----00.0  Qualcomm Technologies, Inc QCNFA765 Wireless Network Adapter [17cb:1103]
             +-0a.0-[02]----00.0  Etron Technology, Inc. EJ188/EJ198 USB 3.0 Host Controller [1b6f:7052]
             +-0f.0-[03-08]----00.0-[04-08]--+-00.0-[05]----00.0  Shenzhen Longsys Electronics Co., Ltd. FORESEE XP1000 / Lexar Professional CFexpress Type B Gold series, NM620 PCIe NVME SSD (DRAM-less) [1d97:5216]
             |                               +-08.0-[06]----00.0  MAXIO Technology (Hangzhou) Ltd. NVMe SSD Controller MAP1202 (DRAM-less) [1e4b:1202]
             |                               +-0c.0-[07]----00.0  Advanced Micro Devices, Inc. [AMD] 600 Series Chipset USB 3.2 Controller [1022:43f7]
             |                               \-0d.0-[08]----00.0  Advanced Micro Devices, Inc. [AMD] 600 Series Chipset SATA Controller [1022:43f6]
             \-16.0  Loongson Technology LLC 7A1000 Chipset SPI Controller [0014:7a0b]
---
 drivers/pci/controller/pci-loongson.c | 31 ++++++++++++++-------------
 1 file changed, 16 insertions(+), 15 deletions(-)
drivers/pci/controller/pci-loongson.c +16 -15
index 76f125d556ebb1..5b744f1288959e 100644
@@ -80,6 +80,18 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
 			DEV_LS7A_LPC, system_bus_quirk);
 
+static const struct pci_device_id loongson_internal_bridge_devids[] = {
+	{ PCI_VDEVICE(LOONGSON, DEV_LS2K_PCIE_PORT0) },
+	{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT0) },
+	{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT1) },
+	{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT2) },
+	{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT3) },
+	{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT4) },
+	{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT5) },
+	{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT6) },
+	{ 0, },
+};
+
 /*
  * Some Loongson PCIe ports have hardware limitations on their Maximum Read
  * Request Size. They can't handle anything larger than this.  Sane
@@ -92,24 +104,13 @@ static void loongson_set_min_mrrs_quirk(struct pci_dev *pdev)
 {
 	struct pci_bus *bus = pdev->bus;
 	struct pci_dev *bridge;
-	static const struct pci_device_id bridge_devids[] = {
-		{ PCI_VDEVICE(LOONGSON, DEV_LS2K_PCIE_PORT0) },
-		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT0) },
-		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT1) },
-		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT2) },
-		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT3) },
-		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT4) },
-		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT5) },
-		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT6) },
-		{ 0, },
-	};
 
 	/* look for the matching bridge */
 	while (!pci_is_root_bus(bus)) {
 		bridge = bus->self;
 		bus = bus->parent;
 
-		if (pci_match_id(bridge_devids, bridge)) {
+		if (pci_match_id(loongson_internal_bridge_devids, bridge)) {
 			if (pcie_get_readrq(pdev) > 256) {
 				pci_info(pdev, "limiting MRRS to 256\n");
 				pcie_set_readrq(pdev, 256);
@@ -230,11 +231,11 @@ static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,
 	struct loongson_pci *priv = pci_bus_to_loongson_pci(bus);
 
 	/*
-	 * Do not read more than one device on the bus other than
-	 * the host bus.
+	 * Do not read more than one device on the internal bridges.
 	 */
 	if ((priv->data->flags & FLAG_DEV_FIX) && bus->self) {
-		if (!pci_is_root_bus(bus) && (device > 0))
+		if (!pci_is_root_bus(bus) && (device > 0) &&
+		    pci_match_id(loongson_internal_bridge_devids, bus->self))
 			return NULL;
 	}
 
Signature · 1 line
2.53.0
author maintainer
#486 lore raw

PATCH 482/1067 bus: mhi: ep: Fix potential deadlock in mhi_ep_reset_worker()

In reply to Greg Kroah-Hartman

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

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

From: Sumit Kumar <[email protected]>

[ Upstream commit 9dece4435d396e9877e27483552b910ba8654169 ]

There is a potential deadlock scenario in mhi_ep_reset_worker() where the state_lock mutex is acquired twice in the same call chain:

mhi_ep_reset_worker()
mutex_lock(&mhi_cntrl->state_lock)

    mhi_ep_power_up()
      mhi_ep_set_ready_state()
        mutex_lock(&mhi_cntrl->state_lock)  <- Deadlock

Fix this by releasing the state_lock before calling mhi_ep_power_up(). The lock is only needed to protect current MHI state read operation. The lock can be safely released before proceeding with the power up sequence.

---
 drivers/bus/mhi/ep/main.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/bus/mhi/ep/main.c +3 -4
index 34e0ba6f52d059..4b9c7043a07a80 100644
@@ -1026,11 +1026,12 @@ static void mhi_ep_reset_worker(struct work_struct *work)
 
 	mhi_ep_power_down(mhi_cntrl);
 
-	mutex_lock(&mhi_cntrl->state_lock);
-
 	/* Reset MMIO to signal host that the MHI_RESET is completed in endpoint */
 	mhi_ep_mmio_reset(mhi_cntrl);
+
+	mutex_lock(&mhi_cntrl->state_lock);
 	cur_state = mhi_cntrl->mhi_state;
+	mutex_unlock(&mhi_cntrl->state_lock);
 
 	/*
 	 * Only proceed further if the reset is due to SYS_ERR. The host will
@@ -1039,8 +1040,6 @@ static void mhi_ep_reset_worker(struct work_struct *work)
 	 */
 	if (cur_state == MHI_STATE_SYS_ERR)
 		mhi_ep_power_up(mhi_cntrl);
-
-	mutex_unlock(&mhi_cntrl->state_lock);
 }
 
 /*
Signature · 1 line
2.53.0
author maintainer
#487 lore raw

PATCH 483/1067 phy: phy-can-transceiver: Check driver match and driver data against NULL

In reply to Greg Kroah-Hartman

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

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

From: Andy Shevchenko <[email protected]>

[ Upstream commit ebee9004cc0200b2b708ebf7ac625d35c71c049f ]

Every platform driver can be forced to match a device that doesn't match its list of device IDs because of device_match_driver_override() so platform drivers that rely on the existence of a device's driver data need to verify its presence.

Accordingly, add requisite match and driver data checks against NULL to the driver where they are missing.

Fixes a4a86d273ff1 ("phy: phy-can-transceiver: Add support for generic CAN transceiver driver")
---
 drivers/phy/phy-can-transceiver.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/phy/phy-can-transceiver.c +3 -0
index ce511ad5d36907..2852661d398603 100644
@@ -106,6 +106,9 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
+	if (!match || !match->data)
+		return -ENODEV;
+
 	drvdata = match->data;
 
 	if (of_property_read_bool(dev->of_node, "mux-states")) {
Signature · 1 line
2.53.0
author maintainer
#488 lore raw

PATCH 484/1067 mailbox: mtk-adsp: fix UAF during device teardown

In reply to Greg Kroah-Hartman

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

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

From: Sergey Senozhatsky <[email protected]>

[ Upstream commit b57d1a40bc43258372fa1f4d39305e093947a262 ]

When the SOF audio driver fails to initialize (e.g. firmware boot timeout), its devres unwind frees the snd_sof_dev object that the mailbox client (mtk-adsp-ipc) reaches via chan->cl->rx_callback. The mtk-adsp-mailbox shutdown clears the mailbox command registers but leaves the IRQ line unmasked, so a late interrupt can still queue a threaded handler after mbox_free_channel() had cleared chan->cl, and mbox_chan_received_data() would then trigger UAF:

  BUG: KASAN: slab-use-after-free in sof_ipc3_validate_fw_version
   sof_ipc3_validate_fw_version
   sof_ipc3_do_rx_work
   sof_ipc3_rx_msg
   mt8196_dsp_handle_request
   mtk_adsp_ipc_recv
   mbox_chan_received_data
   mtk_adsp_mbox_isr
   irq_thread_fn
  Freed by task ...:
   kfree
   devres_release_all
   really_probe
   ... (sof-audio-of-mt8196 probe failure)

The crash was observed roughly three seconds after the failed probe.

disable_irq() in shutdown and enable_irq() in startup. disable_irq() also waits for any in-flight interrupts, so by the time mbox_free_channel() proceeds to clear chan->cl no rx_callback can run.

In addition, request the IRQ with IRQF_NO_AUTOEN so it stays masked between probe and the first client bind — otherwise an early interrupt can crash on chan->cl == NULL in mbox_chan_received_data().

Fixes af2dfa96c52d ("mailbox: mediatek: add support for adsp mailbox controller")
---
 drivers/mailbox/mtk-adsp-mailbox.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/mailbox/mtk-adsp-mailbox.c +8 -1
index 14bc0057de814c..182045dd90df94 100644
@@ -18,6 +18,7 @@ struct mtk_adsp_mbox_priv {
 	struct mbox_controller mbox;
 	void __iomem *va_mboxreg;
 	const struct mtk_adsp_mbox_cfg *cfg;
+	int irq;
 };
 
 struct mtk_adsp_mbox_cfg {
@@ -66,6 +67,8 @@ static int mtk_adsp_mbox_startup(struct mbox_chan *chan)
 	writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in);
 	writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out);
 
+	enable_irq(priv->irq);
+
 	return 0;
 }
 
@@ -73,6 +76,8 @@ static void mtk_adsp_mbox_shutdown(struct mbox_chan *chan)
 {
 	struct mtk_adsp_mbox_priv *priv = get_mtk_adsp_mbox_priv(chan->mbox);
 
+	disable_irq(priv->irq);
+
 	/* Clear ADSP mbox command */
 	writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_in);
 	writel(0xFFFFFFFF, priv->va_mboxreg + priv->cfg->clr_out);
@@ -138,8 +143,10 @@ static int mtk_adsp_mbox_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return irq;
 
+	priv->irq = irq;
 	ret = devm_request_threaded_irq(dev, irq, mtk_adsp_mbox_irq,
-					mtk_adsp_mbox_isr, IRQF_TRIGGER_NONE,
+					mtk_adsp_mbox_isr,
+					IRQF_TRIGGER_NONE | IRQF_NO_AUTOEN,
 					dev_name(dev), mbox->chans);
 	if (ret < 0)
 		return ret;
Signature · 1 line
2.53.0
author maintainer
#489 lore raw

PATCH 485/1067 staging: most: video: avoid double free on video register failure

In reply to Greg Kroah-Hartman

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

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

From: Guangshuo Li <[email protected]>

[ Upstream commit 7cb1c5b32a2bfde961fff8d5204526b609bcb30a ]

comp_register_videodev() allocates a video_device with video_device_alloc() and releases it if video_register_device() fails.

This can double free the video_device when __video_register_device() reaches device_register() and that call fails:

video_register_device()

    -> __video_register_device()
       -> device_register() fails
          -> put_device(&vdev->dev)
             -> v4l2_device_release()
                -> vdev->release(vdev)
                   -> video_device_release(vdev)

comp_register_videodev()

    -> video_device_release(mdev->vdev)

Use video_device_release_empty() while registering the device so that registration failure paths do not free mdev->vdev through vdev->release(). comp_register_videodev() then releases mdev->vdev exactly once on failure. Restore video_device_release() after successful registration so the registered device keeps its normal lifetime handling.

This issue was found by a static analysis tool I am developing.

Fixes eab231c0398a ("staging: most: v4l2-aim: remove unnecessary label err_vbi_dev")
---
 drivers/staging/most/video/video.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/staging/most/video/video.c +6 -1
index ffa97ef21ea500..f09d634af8d3bc 100644
@@ -416,6 +416,7 @@ static int comp_register_videodev(struct most_video_dev *mdev)
 
 	/* Fill the video capture device struct */
 	*mdev->vdev = comp_videodev_template;
+	mdev->vdev->release = video_device_release_empty;
 	mdev->vdev->v4l2_dev = &mdev->v4l2_dev;
 	mdev->vdev->lock = &mdev->lock;
 	snprintf(mdev->vdev->name, sizeof(mdev->vdev->name), "MOST: %s",
@@ -428,9 +429,13 @@ static int comp_register_videodev(struct most_video_dev *mdev)
 		v4l2_err(&mdev->v4l2_dev, "video_register_device failed (%d)\n",
 			 ret);
 		video_device_release(mdev->vdev);
+		return ret;
 	}
 
-	return ret;
+	mdev->vdev->release = video_device_release;
+
+	return 0;
+
 }
 
 static void comp_unregister_videodev(struct most_video_dev *mdev)
Signature · 1 line
2.53.0
author maintainer
#490 lore raw

PATCH 486/1067 usb: host: max3421: Fix shift-out-of-bounds in max3421_hub_control()

In reply to Greg Kroah-Hartman

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

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

From: Seungjin Bae <[email protected]>

[ Upstream commit cff06b03b530ae1fe8a13e93a7848f2130e00fb4 ]

The max3421_hub_control() function handles USB hub class requests to the virtual root hub. In the default branches of both the ClearPortFeature and SetPortFeature switch statements, it modifies max3421_hcd->port_status by left shifting 1 by the request's value parameter. However, it does not validate whether this shift will exceed the width of port_status.

So if a malicious userspace task with access to the root hub via /dev/bus/usb/.../001 issues a USBDEVFS_CONTROL ioctl with wValue greater than or equal to 32, the left shift operation invokes shift-out-of-bounds undefined behavior. This results in arbitrary bit corruption of port_status, including the normally-immutable change bits, which can bypass internal state checks and confuse the hub status.

Fix this by rejecting requests whose value exceeds the shift width before performing the shift.

This issue was found using a KLEE-based symbolic execution tool for kernel drivers that I'm currently developing.

Fixes 2d53139f3162 ("Add support for using a MAX3421E chip as a host driver.")
---
 drivers/usb/host/max3421-hcd.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/usb/host/max3421-hcd.c +4 -0
index f170741206e1df..7f948ec94305ef 100644
@@ -1703,6 +1703,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
 						!pdata->vbus_active_level);
 			fallthrough;
 		default:
+			if (value >= 32)
+				goto error;
 			max3421_hcd->port_status &= ~(1 << value);
 		}
 		break;
@@ -1756,6 +1758,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
 			max3421_reset_port(hcd);
 			fallthrough;
 		default:
+			if (value >= 32)
+				goto error;
 			if ((max3421_hcd->port_status & USB_PORT_STAT_POWER)
 			    != 0)
 				max3421_hcd->port_status |= (1 << value);
Signature · 1 line
2.53.0
author maintainer
#491 lore raw

PATCH 487/1067 usb: host: max3421: Reject hub port requests for non-existent ports

In reply to Greg Kroah-Hartman

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

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

From: Seungjin Bae <[email protected]>

[ Upstream commit 11b5c101e2fd206104b05bc92554d356989423a8 ]

The max3421_hub_control() function handles USB hub class requests to the virtual root hub. The GetPortStatus case correctly rejects requests with index != 1, since the virtual root hub has only a single port. However, the ClearPortFeature and SetPortFeature cases lack the same check.

Fix this by extending the index != 1 rejection to both cases, matching the existing behavior of GetPortStatus.

Fixes 2d53139f3162 ("Add support for using a MAX3421E chip as a host driver.")
---
 drivers/usb/host/max3421-hcd.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/usb/host/max3421-hcd.c +4 -0
index 7f948ec94305ef..24611352efd1c3 100644
@@ -1694,6 +1694,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
 	case ClearHubFeature:
 		break;
 	case ClearPortFeature:
+		if (index != 1)
+			goto error;
 		switch (value) {
 		case USB_PORT_FEAT_SUSPEND:
 			break;
@@ -1737,6 +1739,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,
 		break;
 
 	case SetPortFeature:
+		if (index != 1)
+			goto error;
 		switch (value) {
 		case USB_PORT_FEAT_LINK_STATE:
 		case USB_PORT_FEAT_U1_TIMEOUT:
Signature · 1 line
2.53.0
author maintainer
#492 lore raw

PATCH 488/1067 char: tlclk: fix use-after-free in tlclk_cleanup()

In reply to Greg Kroah-Hartman

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

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

From: James Kim <[email protected]>

[ Upstream commit bbf003b7794d6ad6f939fdd29f1f1bde8ac554c1 ]

This patch improves the module cleanup process in the tlclk driver to prevent potential use-after-free and race conditions.

Currently, the file_operations structure does not specify the .owner field, which could allow the module to be unloaded while user-space processes are still interacting with the device. Additionally, the tlclk_cleanup() function frees the alarm_events memory before ensuring that blocked processes in the waitqueue are fully awakened and that the switchover_timer has completed.

To address these cases, this patch:
- Sets '.owner = THIS_MODULE' in tlclk_fops to safely defer module unloading while the device is in use.
- Updates tlclk_cleanup() to explicitly wake up all blocked readers (wake_up_all), properly release hardware I/O regions, and safely delete the timer (timer_delete_sync) prior to freeing memory.

Fixes 1a80ba882730 ("[PATCH] Telecom Clock Driver for MPCBL0010 ATCA computer blade")
---
 drivers/char/tlclk.c | 4 ++++
 1 file changed, 4 insertions(+)
drivers/char/tlclk.c +4 -0
index 896a3550fba9f3..6b993744f2d781 100644
@@ -263,6 +263,7 @@ static ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count,
 }
 
 static const struct file_operations tlclk_fops = {
+	.owner = THIS_MODULE,
 	.read = tlclk_read,
 	.open = tlclk_open,
 	.release = tlclk_release,
@@ -852,6 +853,9 @@ static void __exit tlclk_cleanup(void)
 	misc_deregister(&tlclk_miscdev);
 	unregister_chrdev(tlclk_major, "telco_clock");
 
+	got_event = 1;
+	wake_up_all(&wq);
+
 	release_region(TLCLK_BASE, 8);
 	del_timer_sync(&switchover_timer);
 	kfree(alarm_events);
Signature · 1 line
2.53.0
author maintainer
#493 lore raw

PATCH 489/1067 perf header: Sanity check HEADER_EVENT_DESC attr.size before swap

In reply to Greg Kroah-Hartman

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

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

From: Arnaldo Carvalho de Melo <[email protected]>

[ Upstream commit 944f65c8b8231d26d4db6be67bcb641142603cb4 ]

read_event_desc() reads nre (event count), sz (attr size), and nr (IDs per event) from the file and uses them to control allocations and loops without validating them against the section size.

A crafted perf.data could trigger large allocations or many loop iterations before __do_read() eventually rejects the reads.

Add bounds checks in read_event_desc():
- Reject sz smaller than PERF_ATTR_SIZE_VER0.
- Require at least one event (nre > 0).
- Check that nre events fit in the remaining section, using the minimum per-event footprint of sz + sizeof(u32).
- Pre-swap attr->size to native byte order, then reject values below PERF_ATTR_SIZE_VER0 or above sz before calling perf_event__attr_swap() to prevent heap out-of-bounds access.
- Handle ABI0 (attr.size == 0): substitute PERF_ATTR_SIZE_VER0, and on native-endian files write the value back so free_event_desc() does not treat the zero as its end-of-array sentinel (it iterates while attr.size != 0). The swap path skips the write-back — perf_event__attr_swap() has its own ABI0 fallback that sets VER0 after swapping.
- Check that nr IDs fit in the remaining section before allocating.

Fixes b30b61729246 ("perf tools: Fix a problem when opening old perf.data with different byte order")
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Wang Nan <[email protected]>
Assisted-by Claude:claude-opus-4.6-1m
---
 tools/perf/util/header.c | 54 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
tools/perf/util/header.c +54 -0
index b2b0293567f07a..085994cba3895f 100644
@@ -1900,9 +1900,28 @@ static struct evsel *read_event_desc(struct feat_fd *ff)
 	if (do_read_u32(ff, &nre))
 		goto error;
 
+	/* Size of each of the nre attributes. */
 	if (do_read_u32(ff, &sz))
 		goto error;
 
+	/*
+	 * Require at least one event with an attr no smaller than the
+	 * first published struct, and reject sz values where
+	 * sz + sizeof(u32) would overflow size_t (possible on 32-bit)
+	 * or nre == UINT32_MAX where nre + 1 wraps to 0 in the calloc.
+	 *
+	 * The minimum section footprint per event is sz bytes for the
+	 * attr plus a u32 for the id count, check that nre events fit.
+	 */
+	if (!nre || sz < PERF_ATTR_SIZE_VER0 ||
+	    sz > ff->size || (size_t)sz > SIZE_MAX - sizeof(u32) ||
+	    nre == UINT32_MAX ||
+	    nre > (ff->size - ff->offset) / (sz + sizeof(u32))) {
+		pr_err("Invalid HEADER_EVENT_DESC: nre=%u sz=%u (min %d)\n",
+		       nre, sz, PERF_ATTR_SIZE_VER0);
+		goto error;
+	}
+
 	/* buffer to hold on file attr struct */
 	buf = malloc(sz);
 	if (!buf)
@@ -1918,6 +1937,9 @@ static struct evsel *read_event_desc(struct feat_fd *ff)
 		msz = sz;
 
 	for (i = 0, evsel = events; i < nre; evsel++, i++) {
+		struct perf_event_attr *attr = buf;
+		u32 attr_size;
+
 		evsel->core.idx = i;
 
 		/*
@@ -1927,6 +1949,32 @@ static struct evsel *read_event_desc(struct feat_fd *ff)
 		if (__do_read(ff, buf, sz))
 			goto error;
 
+		/* Reject before attr_swap to prevent OOB via bswap_safe() */
+		attr_size = ff->ph->needs_swap ? bswap_32(attr->size) : attr->size;
+		/* ABI0: size == 0 means the producer didn't set it */
+		if (!attr_size) {
+			attr_size = PERF_ATTR_SIZE_VER0;
+			/*
+			 * Write back so free_event_desc() doesn't
+			 * treat this event as the end-of-array sentinel
+			 * (it iterates while attr.size != 0).
+			 *
+			 * Only for native — the swap path must NOT
+			 * write native-endian VER0 here because
+			 * perf_event__attr_swap() would re-swap it
+			 * to 0x40000000, defeating bswap_safe() bounds.
+			 * perf_event__attr_swap() has its own ABI0
+			 * fallback that sets VER0 after swapping.
+			 */
+			if (!ff->ph->needs_swap)
+				attr->size = attr_size;
+		}
+		if (attr_size < PERF_ATTR_SIZE_VER0 || attr_size > sz) {
+			pr_err("Event %d attr.size (%u) invalid (min: %d, max: %u)\n",
+			       i, attr_size, PERF_ATTR_SIZE_VER0, sz);
+			goto error;
+		}
+
 		if (ff->ph->needs_swap)
 			perf_event__attr_swap(buf);
 
@@ -1948,6 +1996,12 @@ static struct evsel *read_event_desc(struct feat_fd *ff)
 		if (!nr)
 			continue;
 
+		/* Prevent oversized allocation from crafted nr */
+		if (nr > (ff->size - ff->offset) / sizeof(*id)) {
+			pr_err("Event %d: id count %u exceeds remaining section\n", i, nr);
+			goto error;
+		}
+
 		id = calloc(nr, sizeof(*id));
 		if (!id)
 			goto error;
Signature · 1 line
2.53.0
author maintainer
#494 lore raw

PATCH 490/1067 iio: light: si1133: reset counter to prevent race condition

In reply to Greg Kroah-Hartman

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

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

From: Joshua Crofts <[email protected]>

[ Upstream commit 0a5f45ed2342aabae1e32c72558d15be28940a95 ]

Sashiko reported a potential race condition happening when the driver returns an errno after a timeout in the si1133_command() function. The premature exit causes the hardware and software counters to become out of sync by not updating data->rsp_seq, therefore the internal hardware counter keeps incrementing.

Fix this by adding a call to si1133_cmd_reset_counter() before returning from timeout.

Fixes e01e7eaf37d8 ("iio: light: introduce si1133")
Assisted-by gemini:gemini-3.1-pro-preview
---
 drivers/iio/light/si1133.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/iio/light/si1133.c +5 -0
index f8c9b2cc322e8d..17ee203d16a274 100644
@@ -427,6 +427,11 @@ static int si1133_command(struct si1133_data *data, u8 cmd)
 			dev_warn(dev,
 				 "Failed to read command 0x%02x, ret=%d\n",
 				 cmd, err);
+			/*
+			 * Reset counter on err to prevent software and hardware
+			 * counters being out of sync.
+			 */
+			si1133_cmd_reset_counter(data);
 			goto out;
 		}
 	}
Signature · 1 line
2.53.0
author maintainer
#495 lore raw

PATCH 491/1067 iio: light: si1133: prevent race condition on timeout

In reply to Greg Kroah-Hartman

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

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

From: Joshua Crofts <[email protected]>

[ Upstream commit 8c50a95ceb230d17801758a9e41ffbbbe46f8b4d ]

Sashiko reported a bug where the si1133_command exits on timeout without halting the sensor or masking the interrupt. If the sensor completes the command later, any subsequent command to the sensor will cause the IRQ handler to complete immediately, returning stale data to the driver all while the command hasn't finished yet, shifting all potential reads in the future.

Fix this by masking the IRQ if wait_for_completion_timeout() fails. When initiating a new command, do a dummy read of the IRQ_STATUS register and turn the IRQ back on.

Fixes e01e7eaf37d8 ("iio: light: introduce si1133")
Assisted-by gemini:gemini-3.1-pro-preview
---
 drivers/iio/light/si1133.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/iio/light/si1133.c +8 -1
index 17ee203d16a274..d207a928b1f823 100644
@@ -395,8 +395,14 @@ static int si1133_command(struct si1133_data *data, u8 cmd)
 
 	expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR;
 
-	if (cmd == SI1133_CMD_FORCE)
+	if (cmd == SI1133_CMD_FORCE) {
+		/* Flush pending IRQs from a previous timeout. */
+		regmap_read(data->regmap, SI1133_REG_IRQ_STATUS, &resp);
+		regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE,
+			     SI1133_IRQ_CHANNEL_ENABLE);
+
 		reinit_completion(&data->completion);
+	}
 
 	err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd);
 	if (err) {
@@ -409,6 +415,7 @@ static int si1133_command(struct si1133_data *data, u8 cmd)
 		/* wait for irq */
 		if (!wait_for_completion_timeout(&data->completion,
 			msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) {
+			regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE, 0);
 			err = -ETIMEDOUT;
 			goto out;
 		}
Signature · 1 line
2.53.0
author maintainer
#496 lore raw

PATCH 492/1067 iio: magnetometer: ak8975: fix potential kernel stack memory leak

In reply to Greg Kroah-Hartman

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

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

From: Joshua Crofts <[email protected]>

[ Upstream commit a9a00d727b7bbc5e913a919530a9dd468935bf95 ]

Currently in the AK8975 driver there are four instances where potential uninitialized kernel stack memory leaks can occur. If i2c_smbus_read_i2c_block_data_or_emulated() returns a value less than the size of the buffer, uninitialized bytes are retained in the buffer and later the buffer is passed on to IIO buffers, potentially leaking memory to userspace.

Fix this by adding checks whether the return value of the function is equal to the size of the buffer and subsequently if the value is lesser than zero to distinguish from a returned error code.

---
 drivers/iio/magnetometer/ak8975.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
drivers/iio/magnetometer/ak8975.c +14 -0
index 44f3ab2bb1b330..ac7541e1b7da54 100644
@@ -464,6 +464,10 @@ static int ak8975_who_i_am(struct i2c_client *client,
 		dev_err(&client->dev, "Error reading WIA\n");
 		return ret;
 	}
+	if (ret != sizeof(wia_val)) {
+		dev_err(&client->dev, "Error reading WIA\n");
+		return -EIO;
+	}
 
 	if (wia_val[0] != AK8975_DEVICE_ID)
 		return -ENODEV;
@@ -580,6 +584,10 @@ static int ak8975_setup(struct i2c_client *client)
 		dev_err(&client->dev, "Not able to read asa data\n");
 		return ret;
 	}
+	if (ret != sizeof(data->asa)) {
+		dev_err(&client->dev, "Error reading asa data\n");
+		return -EIO;
+	}
 
 	/* After reading fuse ROM data set power-down mode */
 	ret = ak8975_set_mode(data, POWER_DOWN);
@@ -719,6 +727,10 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
 			sizeof(rval), (u8*)&rval);
 	if (ret < 0)
 		goto exit;
+	if (ret != sizeof(rval)) {
+		ret = -EIO;
+		goto exit;
+	}
 
 	/* Read out ST2 for release lock on measurment data. */
 	ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST2]);
@@ -848,6 +860,8 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev)
 							(u8 *)fval);
 	if (ret < 0)
 		goto unlock;
+	if (ret != sizeof(fval))
+		goto unlock;
 
 	mutex_unlock(&data->lock);
 
Signature · 1 line
2.53.0
author maintainer
#497 lore raw

PATCH 493/1067 iio: adc: xilinx-ams: fix out-of-bounds channel lookup in event handling

In reply to Greg Kroah-Hartman

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

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

From: Guilherme Ivo Bozi <[email protected]>

[ Upstream commit 947eb6f0a274f8b15a0248051a65b069effd5057 ]

ams_event_to_channel() may return a pointer past the end of dev->channels when no matching scan_index is found. This can lead to invalid memory access in ams_handle_event().

Add a bounds check in ams_event_to_channel() and return NULL when no channel is found. Also guard the caller to safely handle this case.

Fixes d5c70627a794 ("iio: adc: Add Xilinx AMS driver")
---
 drivers/iio/adc/xilinx-ams.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/iio/adc/xilinx-ams.c +5 -0
index e1a1f50b4885f4..9045e2fa1154d8 100644
@@ -861,6 +861,9 @@ static const struct iio_chan_spec *ams_event_to_channel(struct iio_dev *dev,
 		if (dev->channels[i].scan_index == scan_index)
 			break;
 
+	if (i == dev->num_channels)
+		return NULL;
+
 	return &dev->channels[i];
 }
 
@@ -1002,6 +1005,8 @@ static void ams_handle_event(struct iio_dev *indio_dev, u32 event)
 	const struct iio_chan_spec *chan;
 
 	chan = ams_event_to_channel(indio_dev, event);
+	if (!chan)
+		return;
 
 	if (chan->type == IIO_TEMP) {
 		/*
Signature · 1 line
2.53.0
author maintainer
#498 lore raw

PATCH 494/1067 iio: accel: mma8452: handle I2C read error(s) in mma8452_read()

In reply to Greg Kroah-Hartman

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

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

From: Sanjay Chitroda <[email protected]>

[ Upstream commit 5bdff291d20c31b365d9ddfe9c426fbfb41da5bb ]

Currently, If i2c_smbus_read_i2c_block_data() fails but mma8452_set_runtime_pm_state() succeeds, mma8452_read() returns 0.

As a result, the caller mma8452_read_raw() assumes the read was successful and proceeds to use a buffer containing uninitialized stack memory.

Add proper checking of the I2C read return value and propagate errors to the caller.

Fixes 96c0cb2bbfe0 ("iio: mma8452: add support for runtime power management")
---
 drivers/iio/accel/mma8452.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/iio/accel/mma8452.c +2 -0
index ad7b7770d52628..28002c714ea98d 100644
@@ -254,6 +254,8 @@ static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
 
 	ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
 					    3 * sizeof(__be16), (u8 *)buf);
+	if (ret < 0)
+		return ret;
 
 	ret = mma8452_set_runtime_pm_state(data->client, false);
 
Signature · 1 line
2.53.0
author maintainer
#499 lore raw

PATCH 495/1067 clk: at91: keep securam node alive while mapping it

In reply to Greg Kroah-Hartman

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

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

From: Yuho Choi <[email protected]>

[ Upstream commit 22fa1c39ba6fe726b547c877c924379b7fee260a ]

pmc_register_ops() gets an owned reference to the "atmel,sama5d2-securam" node with of_find_compatible_node(). The success path dropped that reference before passing the node to of_iomap(), leaving of_iomap() to consume a node pointer after the caller had released its reference.

Move of_node_put() after of_iomap() so the node remains referenced for the mapping operation. The unavailable-node error path already releases the reference.

Fixes 4d21be864092 ("clk: at91: pmc: execute suspend/resume only for backup mode")
---
 drivers/clk/at91/pmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/at91/pmc.c +1 -1
index 5aa9c1f1c8866d..40bdc1c80ab086 100644
@@ -176,9 +176,9 @@ static int __init pmc_register_ops(void)
 		of_node_put(np);
 		return -ENODEV;
 	}
-	of_node_put(np);
 
 	at91_pmc_backup_suspend = of_iomap(np, 0);
+	of_node_put(np);
 	if (!at91_pmc_backup_suspend) {
 		pr_warn("%s(): unable to map securam\n", __func__);
 		return -ENOMEM;
Signature · 1 line
2.53.0
author maintainer
#500 lore raw

PATCH 496/1067 HID: logitech-hidpp: remove excess kernel-doc member in hidpp_scroll_counter

In reply to Greg Kroah-Hartman

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

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

From: Rosen Penev <[email protected]>

[ Upstream commit f22a5db8a7d38152556f230d6d68e59dbc27971b ]

The @dev member described in the kernel-doc does not exist in the struct. Remove the stale entry.

Fixes 0610430e3dea ("HID: logitech-hidpp: add input_device ptr to struct hidpp_device")
Assisted-by opencode:big-pickle
---
 drivers/hid/hid-logitech-hidpp.c | 1 -
 1 file changed, 1 deletion(-)
drivers/hid/hid-logitech-hidpp.c +0 -1
index 89b0374bb9a851..eae0b0b46439d8 100644
@@ -159,7 +159,6 @@ struct hidpp_battery {
 /**
  * struct hidpp_scroll_counter - Utility class for processing high-resolution
  *                             scroll events.
- * @dev: the input device for which events should be reported.
  * @wheel_multiplier: the scalar multiplier to be applied to each wheel event
  * @remainder: counts the number of high-resolution units moved since the last
  *             low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should
Signature · 1 line
2.53.0
author maintainer
#501 lore raw

PATCH 497/1067 fs/ntfs3: add bounds check to run_get_highest_vcn()

In reply to Greg Kroah-Hartman

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

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

From: Konstantin Komarov <[email protected]>

[ Upstream commit bb11485a87fbb2254b62cfed630b699d50e57da8 ]

run_get_highest_vcn() parses a packed NTFS mapping-pairs buffer without any length bound, relying solely on a 0x00 terminator to stop. A crafted $LogFile UpdateMappingPairs record whose embedded attribute contains mapping-pairs runs without a terminator causes the function to read past the slab allocation, triggering a KASAN slab-out-of-bounds read on mount.

The sibling function run_unpack() received an analogous bounds-check in commit b62567bca474 ("ntfs3: add buffer boundary checks to run_unpack()"), but run_get_highest_vcn() was missed.

Take a run_buf_size parameter and reject any run header whose payload would extend past the buffer end, mirroring the pattern used by run_unpack(). The caller in fslog.c passes the remaining attribute bytes after the mapping-pairs offset.

KASAN report (on mainline v7.1 merge window HEAD):

  BUG: KASAN: slab-out-of-bounds in run_get_highest_vcn+0x3c0/0x410
  Read of size 1 at addr ffff88800e2d5400 by task mount/72
  Call Trace:
   run_get_highest_vcn+0x3c0/0x410
   do_action.isra.0+0x3ba8/0x7b50
   log_replay+0x9ddd/0x10200
   ntfs_loadlog_and_replay+0x4ad/0x610
   ntfs_fill_super+0x214a/0x4540
Fixes b62567bca474 ("ntfs3: add buffer boundary checks to run_unpack()")
---
 fs/ntfs3/fslog.c   | 5 ++++-
 fs/ntfs3/ntfs_fs.h | 3 ++-
 fs/ntfs3/run.c     | 9 +++++++--
 3 files changed, 13 insertions(+), 4 deletions(-)
fs/ntfs3/fslog.c +4 -1
index 412d6a3bfaee43..993c771a9790bd 100644
@@ -3367,7 +3367,10 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,
 		memmove(Add2Ptr(attr, aoff), data, dlen);
 
 		if (run_get_highest_vcn(le64_to_cpu(attr->nres.svcn),
-					attr_run(attr), &t64)) {
+					attr_run(attr),
+				        le32_to_cpu(attr->size) - 
+				                le16_to_cpu(attr->nres.run_off),	
+					&t64)) {
 			goto dirty_vol;
 		}
 
fs/ntfs3/ntfs_fs.h +2 -1
index c93217ed3f6c12..482958c0164449 100644
@@ -809,7 +809,8 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
 #else
 #define run_unpack_ex run_unpack
 #endif
-int run_get_highest_vcn(CLST vcn, const u8 *run_buf, u64 *highest_vcn);
+int run_get_highest_vcn(CLST vcn, const u8 *run_buf, size_t run_buf_size, 
+		       u64 *highest_vcn);
 int run_clone(const struct runs_tree *run, struct runs_tree *new_run);
 
 /* Globals from super.c */
fs/ntfs3/run.c +7 -2
index 311ac60a7ad1f7..c6eee7875c0003 100644
@@ -1152,18 +1152,23 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
  * Return the highest vcn from a mapping pairs array
  * it used while replaying log file.
  */
-int run_get_highest_vcn(CLST vcn, const u8 *run_buf, u64 *highest_vcn)
+int run_get_highest_vcn(CLST vcn, const u8 *run_buf, size_t run_buf_size, 
+		       u64 *highest_vcn)
 {
+	const u8 *run_last = run_buf + run_buf_size;
 	u64 vcn64 = vcn;
 	u8 size_size;
 
-	while ((size_size = *run_buf & 0xF)) {
+	while (run_buf < run_last && (size_size = *run_buf & 0xF)) {
 		u8 offset_size = *run_buf++ >> 4;
 		u64 len;
 
 		if (size_size > 8 || offset_size > 8)
 			return -EINVAL;
 
+		if (run_buf + size_size + offset_size > run_last) 
+			return -EINVAL;
+
 		len = run_unpack_s64(run_buf, size_size, 0);
 		if (!len)
 			return -EINVAL;
Signature · 1 line
2.53.0
author maintainer
#502 lore raw

PATCH 498/1067 drm/amd/display: Add missing kdoc for ALLM parameters

In reply to Greg Kroah-Hartman

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

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

From: Srinivasan Shanmugam <[email protected]>

[ Upstream commit d4c6ec729fb7a8bf8a27b19bd70a1b945ad93dac ]

Add descriptions for the missing parameters for ALLMEnabled and ALLMValue to keep the function documentation synchronized with the function prototype mod_build_hf_vsif_infopacket().

Fixes the below with gcc W=1:
../display/modules/info_packet/info_packet.c:507 function parameter 'ALLMEnabled' not described in 'mod_build_hf_vsif_infopacket' ../display/modules/info_packet/info_packet.c:507 function parameter 'ALLMValue' not described in 'mod_build_hf_vsif_infopacket'

Fixes 3c2381b92cba ("drm/amd/display: add support for VSIP info packet")
Cc Roman Li <[email protected]>
Cc Alex Hung <[email protected]>
Cc Tom Chung <[email protected]>
Cc Aurabindo Pillai <[email protected]>
Cc Wayne Lin <[email protected]>
Cc Nicholas Kazlauskas <[email protected]>
Cc Bhawanpreet Lakha <[email protected]>
---
 drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +2 -0
index 69691058ab8981..6602ac882d6bce 100644
@@ -445,6 +445,8 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
  *
  *  @stream:      contains data we may need to construct VSIF (i.e. timing_3d_format, etc.)
  *  @info_packet: output structure where to store VSIF
+ *  @ALLMEnabled: indicates whether ALLM HF-VSIF should be generated
+ *  @ALLMValue:   ALLM bit value to advertise in HF-VSIF
  */
 void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
 		struct dc_info_packet *info_packet)
Signature · 1 line
2.53.0
author maintainer
#503 lore raw

PATCH 499/1067 dmaengine: imx-sdma: Refine spba bus searching in probe

In reply to Greg Kroah-Hartman

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

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

From: Shengjiu Wang <[email protected]>

[ Upstream commit d52d42e2e5d9f13166e81ac837ebb023d1306e61 ]

There are multi spba-busses for i.MX8M* platforms, if only search for the first spba-bus in DT, the found spba-bus may not the real bus of audio devices, which cause issue for sdma p2p case, as the sdma p2p script presently does not deal with the transactions involving two devices connected to the AIPS bus.

Search the SDMA parent node first, which should be the AIPS bus, then search the child node whose compatible string is spba-bus under that AIPS bus for the above multi spba-busses case.

Fixes 8391ecf465ec ("dmaengine: imx-sdma: Add device to device support")
---
 drivers/dma/imx-sdma.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/dma/imx-sdma.c +3 -1
index b926abe4fa43ac..2db37bb8a763a2 100644
@@ -2301,7 +2301,9 @@ static int sdma_probe(struct platform_device *pdev)
 			goto err_register;
 		}
 
-		spba_bus = of_find_compatible_node(NULL, NULL, "fsl,spba-bus");
+		struct device_node *sdma_parent_np __free(device_node) = of_get_parent(np);
+
+		spba_bus = of_get_compatible_child(sdma_parent_np, "fsl,spba-bus");
 		ret = of_address_to_resource(spba_bus, 0, &spba_res);
 		if (!ret) {
 			sdma->spba_start_addr = spba_res.start;
Signature · 1 line
2.53.0
author maintainer
#504 lore raw

PATCH 500/1067 perf: Fix off-by-one stack buffer overflow in kallsyms__parse()

In reply to Greg Kroah-Hartman

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

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

From: Rui Qi <[email protected]>

[ Upstream commit 68018df3f55eba96a20dd703f5f276a6518f4963 ]

In kallsyms__parse(), the loop reading symbol names iterates with i < sizeof(symbol_name), which allows i to reach sizeof(symbol_name) upon loop exit. The subsequent symbol_name[i] = '\0' then writes one byte past the end of the stack-allocated symbol_name[] array.

Fix this by changing the loop bound to KSYM_NAME_LEN, so the null terminator always lands within the array. The overflow is triggerable by a kallsyms entry with a symbol name of KSYM_NAME_LEN+1 or more characters (e.g., long Rust mangled names or a malicious /proc/kallsyms).

Fixes 53df2b9344128984 ("libsymbols kallsyms: Parse using io api")
Cc Adrian Hunter <[email protected]>
Cc Alexander Shishkin <[email protected]>
Cc Ian Rogers <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc James Clark <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Mark Rutland <[email protected]>
Cc Peter Zijlstra <[email protected]>
---
 tools/lib/symbol/kallsyms.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
tools/lib/symbol/kallsyms.c +4 -1
index e335ac2b9e1972..d64bd9cc82a90e 100644
@@ -60,7 +60,7 @@ int kallsyms__parse(const char *filename, void *arg,
 			read_to_eol(&io);
 			continue;
 		}
-		for (i = 0; i < sizeof(symbol_name); i++) {
+		for (i = 0; i < KSYM_NAME_LEN; i++) {
 			ch = io__get_char(&io);
 			if (ch < 0 || ch == '\n')
 				break;
@@ -68,6 +68,9 @@ int kallsyms__parse(const char *filename, void *arg,
 		}
 		symbol_name[i]  = '\0';
 
+		if (i == KSYM_NAME_LEN)
+			read_to_eol(&io);
+
 		err = process_symbol(arg, symbol_name, symbol_type, start);
 		if (err)
 			break;
Signature · 1 line
2.53.0
author maintainer
#505 lore raw

PATCH 501/1067 perf sched: Replace BUG_ON on invalid CPU with graceful skip

In reply to Greg Kroah-Hartman

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

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

From: Arnaldo Carvalho de Melo <[email protected]>

[ Upstream commit 1e2c83f732deb329ebce23e26cbc482f4c4bf194 ]

latency_switch_event(), latency_runtime_event(), and map_switch_event() use BUG_ON(cpu >= MAX_CPUS || cpu < 0) to validate the sample CPU. When PERF_SAMPLE_CPU is absent from the sample type, evsel__parse_sample() initializes sample->cpu to (u32)-1. Casting this to int yields -1, which triggers the BUG_ON and aborts perf sched.

The central CPU validation in perf_session__deliver_event() intentionally preserves the (u32)-1 sentinel for downstream tools like perf script and perf inject, so leaf callbacks must handle it themselves.

Replace the three BUG_ON calls with graceful skips using pr_warning(), matching the existing pattern in process_sched_switch_event() and process_sched_runtime_event() earlier in the same file. Include the file offset for cross-referencing with perf report -D.

Stable-dep-of: 8cbca8a480e1 ("perf sched: Fix NULL dereference in latency_runtime_event")

---
 tools/perf/builtin-sched.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)
tools/perf/builtin-sched.c +19 -3
index 6584e39b2a8d48..2c954de3ed419c 100644
@@ -1154,7 +1154,12 @@ static int latency_switch_event(struct perf_sched *sched,
 	int cpu = sample->cpu, err = -1;
 	s64 delta;
 
-	BUG_ON(cpu >= MAX_CPUS || cpu < 0);
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
+	if (cpu >= MAX_CPUS || cpu < 0) {
+		pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
+			   sample->file_offset, cpu);
+		return 0;
+	}
 
 	timestamp0 = sched->cpu_last_switched[cpu];
 	sched->cpu_last_switched[cpu] = timestamp;
@@ -1225,7 +1230,13 @@ static int latency_runtime_event(struct perf_sched *sched,
 	if (thread == NULL)
 		return -1;
 
-	BUG_ON(cpu >= MAX_CPUS || cpu < 0);
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
+	if (cpu >= MAX_CPUS || cpu < 0) {
+		pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
+			   sample->file_offset, cpu);
+		err = 0;
+		goto out_put;
+	}
 	if (!atoms) {
 		if (thread_atoms_insert(sched, thread))
 			goto out_put;
@@ -1581,7 +1592,12 @@ static int map_switch_event(struct perf_sched *sched, struct evsel *evsel,
 	const char *color = PERF_COLOR_NORMAL;
 	char stimestamp[32];
 
-	BUG_ON(this_cpu.cpu >= MAX_CPUS || this_cpu.cpu < 0);
+	/* perf.data is untrusted input — CPU may be absent or corrupted */
+	if (this_cpu.cpu >= MAX_CPUS || this_cpu.cpu < 0) {
+		pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
+			   sample->file_offset, this_cpu.cpu);
+		return 0;
+	}
 
 	if (this_cpu.cpu > sched->max_cpu.cpu)
 		sched->max_cpu = this_cpu;
Signature · 1 line
2.53.0
author maintainer
#506 lore raw

PATCH 502/1067 perf sched: Fix NULL dereference in latency_runtime_event

In reply to Greg Kroah-Hartman

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

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

From: Arnaldo Carvalho de Melo <[email protected]>

[ Upstream commit 8cbca8a480e15f6326ce94287570993f27a4b2d5 ]

latency_runtime_event() passes the return value of machine__findnew_thread() directly to thread_atoms_search() at line 1216, before checking for NULL at line 1220. thread_atoms_search() calls pid_cmp() which dereferences the thread pointer via thread__tid(), causing a NULL pointer dereference if the allocation fails.

All other callers of thread_atoms_search() in this file (latency_switch_event, latency_wakeup_event, latency_migrate_task_event) correctly check for NULL first.

Move the atoms assignment after the NULL check to match the pattern used by the other callers.

Fixes b91fc39f4ad7 ("perf machine: Protect the machine->threads with a rwlock")
Assisted-by Claude:claude-opus-4.6
---
 tools/perf/builtin-sched.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/builtin-sched.c +3 -1
index 2c954de3ed419c..927c0ece3a074f 100644
@@ -1223,13 +1223,15 @@ static int latency_runtime_event(struct perf_sched *sched,
 	const u32 pid	   = evsel__intval(evsel, sample, "pid");
 	const u64 runtime  = evsel__intval(evsel, sample, "runtime");
 	struct thread *thread = machine__findnew_thread(machine, -1, pid);
-	struct work_atoms *atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
+	struct work_atoms *atoms;
 	u64 timestamp = sample->time;
 	int cpu = sample->cpu, err = -1;
 
 	if (thread == NULL)
 		return -1;
 
+	atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
+
 	/* perf.data is untrusted input — CPU may be absent or corrupted */
 	if (cpu >= MAX_CPUS || cpu < 0) {
 		pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
Signature · 1 line
2.53.0
author maintainer
#507 lore raw

PATCH 503/1067 perf tools: Add bounds check to cpu__get_node()

In reply to Greg Kroah-Hartman

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

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

From: Arnaldo Carvalho de Melo <[email protected]>

[ Upstream commit 1e7921d7227de5da0dfc167943092c823ec7e49b ]

cpu__get_node() accesses cpunode_map[cpu.cpu] without checking against max_cpu_num, the allocation size of cpunode_map. Callers such as builtin-kmem.c:evsel__process_alloc_event() pass sample->cpu from perf.data events, which may exceed the host's CPU count when analyzing cross-machine recordings.

Add a bounds check against max_cpu_num before indexing, returning -1 for out-of-range values. This is a central fix that protects all callers.

Fixes 86895b480a2f ("perf stat: Add --per-node agregation support")
Cc Jiri Olsa <[email protected]>
Assisted-by Claude:claude-opus-4.6
---
 tools/perf/util/cpumap.c | 4 ++++
 1 file changed, 4 insertions(+)
tools/perf/util/cpumap.c +4 -0
index 8486ca3bec75ff..370bc498b7a2e4 100644
@@ -486,6 +486,10 @@ int cpu__get_node(struct perf_cpu cpu)
 		return -1;
 	}
 
+	/* cpunode_map allocated for max_cpu_num entries; input may be untrusted */
+	if (cpu.cpu < 0 || cpu.cpu >= max_cpu_num.cpu)
+		return -1;
+
 	return cpunode_map[cpu.cpu];
 }
 
Signature · 1 line
2.53.0
author maintainer
#508 lore raw

PATCH 504/1067 perf mmap: Guard cpu__get_node() return in aio_bind()

In reply to Greg Kroah-Hartman

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

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

From: Arnaldo Carvalho de Melo <[email protected]>

[ Upstream commit f32dc302a090f48893477ef297a888db109ec0bd ]

perf_mmap__aio_bind() passes the cpu__get_node() return value directly to an unsigned long variable (node_index). When cpu__get_node() returns -1 for an unknown CPU, the implicit int-to-unsigned-long conversion sign-extends it to ULONG_MAX.

This causes bitmap_zalloc(ULONG_MAX + 1) which wraps to bitmap_zalloc(0), returning a zero-sized allocation. The subsequent __set_bit(ULONG_MAX, node_mask) then writes massively out of bounds.

Check the return value in a signed temporary before assigning to node_index, and skip the NUMA binding when the node is unknown.

Fixes c44a8b44ca9f ("perf record: Bind the AIO user space buffers to nodes")
Cc Alexey Budankov <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Namhyung Kim <[email protected]>
Assisted-by Claude:claude-opus-4.6
---
 tools/perf/util/mmap.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
tools/perf/util/mmap.c +7 -1
index a4dff881be39b6..63d8a05e60544a 100644
@@ -103,9 +103,15 @@ static int perf_mmap__aio_bind(struct mmap *map, int idx, struct perf_cpu cpu, i
 	int err = 0;
 
 	if (affinity != PERF_AFFINITY_SYS && cpu__max_node() > 1) {
+		int node;
+
 		data = map->aio.data[idx];
 		mmap_len = mmap__mmap_len(map);
-		node_index = cpu__get_node(cpu);
+		node = cpu__get_node(cpu);
+		/* -1 sign-extends to ULONG_MAX, wrapping bitmap_zalloc(0) and OOB __set_bit */
+		if (node < 0)
+			return 0;
+		node_index = node;
 		node_mask = bitmap_zalloc(node_index + 1);
 		if (!node_mask) {
 			pr_err("Failed to allocate node mask for mbind: error %m\n");
Signature · 1 line
2.53.0
author maintainer
#509 lore raw

PATCH 505/1067 perf sched: Clean up idle_threads entry on init failure

In reply to Greg Kroah-Hartman

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

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

From: Arnaldo Carvalho de Melo <[email protected]>

[ Upstream commit cda5a94ad9181cd60cbf04be11d524201bf489a2 ]

get_idle_thread() allocates a thread via thread__new() and stores it in idle_threads[cpu], then calls init_idle_thread() to set up the private data. If init_idle_thread() fails (e.g. OOM for the idle_thread_runtime struct), the function returns NULL but leaves the partially initialized thread in idle_threads[cpu].

On subsequent calls for the same CPU, get_idle_thread() finds a non-NULL idle_threads[cpu], skips allocation, and returns thread__get() on a thread that has no priv data. Callers then get a thread whose thread__priv() returns NULL, leading to unexpected behavior.

Release the thread and reset the slot to NULL on init failure so the entry doesn't persist in a corrupted state.

Fixes 49394a2a24c7 ("perf sched timehist: Introduce timehist command")
Cc David Ahern <[email protected]>
Cc Namhyung Kim <[email protected]>
Assisted-by Claude:claude-opus-4.6
---
 tools/perf/builtin-sched.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
tools/perf/builtin-sched.c +4 -1
index 927c0ece3a074f..167532c7adf006 100644
@@ -2349,8 +2349,11 @@ static struct thread *get_idle_thread(int cpu)
 		idle_threads[cpu] = thread__new(0, 0);
 
 		if (idle_threads[cpu]) {
-			if (init_idle_thread(idle_threads[cpu]) < 0)
+			if (init_idle_thread(idle_threads[cpu]) < 0) {
+				/* clean up so next call doesn't find a half-initialized thread */
+				thread__zput(idle_threads[cpu]);
 				return NULL;
+			}
 		}
 	}
 
Signature · 1 line
2.53.0
author maintainer
#510 lore raw

PATCH 506/1067 perf sched: Replace BUG_ON and add NULL checks in replay event helpers

In reply to Greg Kroah-Hartman

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

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

From: Arnaldo Carvalho de Melo <[email protected]>

[ Upstream commit 75eafe4a3a93a0143a20c0cc286bfb9008ac1478 ]

get_new_event() has three issues:

1. The zalloc() result is dereferenced without a NULL check, crashing on allocation failure.

2. BUG_ON(!task->atoms) kills the process when realloc() fails. Since perf.data is untrusted input, this should be a graceful error.

3. The realloc pattern assigns directly to task->atoms, losing the old pointer on failure. task->nr_events is also incremented before the realloc, leaving corrupted state on failure.

Fix get_new_event() to:
- Check the zalloc() result before dereferencing
- Use a temporary for realloc() to avoid losing the old pointer
- Increment nr_events only after successful realloc
- Return NULL instead of calling BUG_ON on failure

Also fix add_sched_event_wakeup() where zalloc() for wait_sem is passed to sem_init() without a NULL check.

Update all callers (add_sched_event_run, add_sched_event_wakeup, add_sched_event_sleep) to handle NULL returns by returning early. The replay may produce incomplete output on OOM but will not crash.

Fixes ec156764d424 ("perf sched: Import schedbench.c")
Cc Ingo Molnar <[email protected]>
Cc Namhyung Kim <[email protected]>
Assisted-by Claude:claude-opus-4.6
---
 tools/perf/builtin-sched.c | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)
tools/perf/builtin-sched.c +25 -3
index 167532c7adf006..9fa02e8ab091c0 100644
@@ -363,14 +363,25 @@ get_new_event(struct task_desc *task, u64 timestamp)
 	struct sched_atom *event = zalloc(sizeof(*event));
 	unsigned long idx = task->nr_events;
 	size_t size;
+	struct sched_atom **atoms_p;
+
+	if (event == NULL) {
+		pr_err("ERROR: sched: failed to allocate event\n");
+		return NULL;
+	}
 
 	event->timestamp = timestamp;
 	event->nr = idx;
 
+	size = sizeof(struct sched_atom *) * (task->nr_events + 1);
+	atoms_p = realloc(task->atoms, size);
+	if (!atoms_p) {
+		pr_err("ERROR: sched: failed to grow atoms array\n");
+		free(event);
+		return NULL;
+	}
+	task->atoms = atoms_p;
 	task->nr_events++;
-	size = sizeof(struct sched_atom *) * task->nr_events;
-	task->atoms = realloc(task->atoms, size);
-	BUG_ON(!task->atoms);
 
 	task->atoms[idx] = event;
 
@@ -401,6 +412,8 @@ static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task
 	}
 
 	event = get_new_event(task, timestamp);
+	if (event == NULL)
+		return;
 
 	event->type = SCHED_EVENT_RUN;
 	event->duration = duration;
@@ -414,6 +427,8 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t
 	struct sched_atom *event, *wakee_event;
 
 	event = get_new_event(task, timestamp);
+	if (event == NULL)
+		return;
 	event->type = SCHED_EVENT_WAKEUP;
 	event->wakee = wakee;
 
@@ -428,6 +443,10 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t
 	}
 
 	wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
+	if (!wakee_event->wait_sem) {
+		pr_err("ERROR: sched: failed to allocate semaphore\n");
+		return;
+	}
 	sem_init(wakee_event->wait_sem, 0, 0);
 	wakee_event->specific_wait = 1;
 	event->wait_sem = wakee_event->wait_sem;
@@ -440,6 +459,9 @@ static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *ta
 {
 	struct sched_atom *event = get_new_event(task, timestamp);
 
+	if (event == NULL)
+		return;
+
 	event->type = SCHED_EVENT_SLEEP;
 
 	sched->nr_sleep_events++;
Signature · 1 line
2.53.0
author maintainer
#511 lore raw

PATCH 507/1067 perf mmap: Fix NULL deref in aio cleanup on alloc failure

In reply to Greg Kroah-Hartman

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

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

From: Arnaldo Carvalho de Melo <[email protected]>

[ Upstream commit 25627346b10e6a564610ea2c49dc6dd54812226d ]

perf_mmap__aio_mmap() sets map->aio.nr_cblocks before allocating the data array. If calloc() for aiocb or cblocks fails before the data array is allocated, the return -1 path leads to perf_mmap__aio_munmap() which loops nr_cblocks times calling perf_mmap__aio_free(). Both versions of perf_mmap__aio_free() (NUMA and non-NUMA) dereference map->aio.data[idx] without checking if data is NULL, causing a NULL pointer dereference.

Add NULL checks for map->aio.data at the top of both perf_mmap__aio_free() variants so the cleanup path is safe when allocation fails partway through perf_mmap__aio_mmap().

Fixes d3d1af6f011a553a ("perf record: Enable asynchronous trace writing")
Cc Alexey Budankov <[email protected]>
Assisted-by Claude:claude-opus-4.6
---
 tools/perf/util/mmap.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
tools/perf/util/mmap.c +6 -4
index 63d8a05e60544a..adc2ee6eeb8e26 100644
@@ -88,10 +88,10 @@ static int perf_mmap__aio_alloc(struct mmap *map, int idx)
 
 static void perf_mmap__aio_free(struct mmap *map, int idx)
 {
-	if (map->aio.data[idx]) {
-		munmap(map->aio.data[idx], mmap__mmap_len(map));
-		map->aio.data[idx] = NULL;
-	}
+	if (!map->aio.data || !map->aio.data[idx])
+		return;
+	munmap(map->aio.data[idx], mmap__mmap_len(map));
+	map->aio.data[idx] = NULL;
 }
 
 static int perf_mmap__aio_bind(struct mmap *map, int idx, struct perf_cpu cpu, int affinity)
@@ -140,6 +140,8 @@ static int perf_mmap__aio_alloc(struct mmap *map, int idx)
 
 static void perf_mmap__aio_free(struct mmap *map, int idx)
 {
+	if (!map->aio.data)
+		return;
 	zfree(&(map->aio.data[idx]));
 }
 
Signature · 1 line
2.53.0
author maintainer
#512 lore raw

PATCH 508/1067 perf c2c: Fix use-after-free in he__get_c2c_hists() error path

In reply to Greg Kroah-Hartman

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

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

From: Arnaldo Carvalho de Melo <[email protected]>

[ Upstream commit 5e5e6196d737c5be03d20647428316b36621608d ]

he__get_c2c_hists() assigns c2c_he->hists before calling c2c_hists__init(). If init fails, the error path calls free(hists) but leaves c2c_he->hists pointing to freed memory. On teardown, c2c_he_free() finds the non-NULL pointer and calls hists__delete_entries() on it, causing a use-after-free.

Set c2c_he->hists to NULL before freeing so teardown skips the already-freed allocation.

Fixes b2252ae67b687d2b ("perf c2c report: Decode c2c_stats for hist entries")
Cc Jiri Olsa <[email protected]>
Assisted-by Claude:claude-opus-4.6
---
 tools/perf/builtin-c2c.c | 1 +
 1 file changed, 1 insertion(+)
tools/perf/builtin-c2c.c +1 -0
index a9190458d2d500..bfba131693bed5 100644
@@ -216,6 +216,7 @@ he__get_c2c_hists(struct hist_entry *he,
 
 	ret = c2c_hists__init(hists, sort, nr_header_lines);
 	if (ret) {
+		c2c_he->hists = NULL;
 		free(hists);
 		return NULL;
 	}
Signature · 1 line
2.53.0
author maintainer
#513 lore raw

PATCH 509/1067 dmaengine: qcom: gpi: set DMA_PRIVATE capability

In reply to Greg Kroah-Hartman

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

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

From: Icenowy Zheng <[email protected]>

[ Upstream commit 4e351f408743354d54ee1af5193fc78234f2044e ]

The GPI DMA controller is only responsible for QUP peripherals, and cannot work as a general-purpose DMA accelerator.

Set DMA_PRIVATE capability for it.

This fixes error messages about GPI being shown when an async-tx consumer is loaded.

---
 drivers/dma/qcom/gpi.c | 1 +
 1 file changed, 1 insertion(+)
drivers/dma/qcom/gpi.c +1 -0
index 846b532d77a568..ccf781b6c05f1d 100644
@@ -2253,6 +2253,7 @@ static int gpi_probe(struct platform_device *pdev)
 	/* clear and Set capabilities */
 	dma_cap_zero(gpi_dev->dma_device.cap_mask);
 	dma_cap_set(DMA_SLAVE, gpi_dev->dma_device.cap_mask);
+	dma_cap_set(DMA_PRIVATE, gpi_dev->dma_device.cap_mask);
 
 	/* configure dmaengine apis */
 	gpi_dev->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
Signature · 1 line
2.53.0
author maintainer
#514 lore raw

PATCH 510/1067 dmaengine: Fix possible use after free

In reply to Greg Kroah-Hartman

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

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

From: Nuno Sá <[email protected]>

[ Upstream commit 92f853f0645aebf1d05d333e97ab7c342ace1892 ]

In dma_release_channel(), check chan->device->privatecnt after call dma_chan_put(). However, dma_chan_put() call dma_device_put() which could release the last reference of the device if the DMA provider is already gone and hence free it.

Fixes it by moving dma_chan_put() after the check.

Fixes 0f571515c332 ("dmaengine: Add privatecnt to revert DMA_PRIVATE property")
---
 drivers/dma/dmaengine.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/dma/dmaengine.c +2 -1
index 892e8389232e7f..d89827d0927e40 100644
@@ -905,11 +905,12 @@ void dma_release_channel(struct dma_chan *chan)
 	mutex_lock(&dma_list_mutex);
 	WARN_ONCE(chan->client_count != 1,
 		  "chan reference count %d != 1\n", chan->client_count);
-	dma_chan_put(chan);
 	/* drop PRIVATE cap enabled by __dma_request_channel() */
 	if (--chan->device->privatecnt == 0)
 		dma_cap_clear(DMA_PRIVATE, chan->device->cap_mask);
 
+	dma_chan_put(chan);
+
 	if (chan->slave) {
 		sysfs_remove_link(&chan->dev->device.kobj, DMA_SLAVE_NAME);
 		sysfs_remove_link(&chan->slave->kobj, chan->name);
Signature · 1 line
2.53.0
author maintainer
#515 lore raw

PATCH 511/1067 clk: qcom: a53: Corrected frequency multiplier for 1152MHz

In reply to Greg Kroah-Hartman

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

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

From: Phillip Varney <[email protected]>

[ Upstream commit bb56147ea9fce98ebde1d367335ba006cba61fbd ]

The 1152MHz frequency entry for the a53 currently selects a multiplier of 62, giving 1190MHz. This changes the mulitiplier to 60 giving the intended 1152MHz.

---
 drivers/clk/qcom/a53-pll.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/qcom/a53-pll.c +1 -1
index f9c5e296dba2a0..c878d4001da52d 100644
@@ -20,7 +20,7 @@
 static const struct pll_freq_tbl a53pll_freq[] = {
 	{  998400000, 52, 0x0, 0x1, 0 },
 	{ 1094400000, 57, 0x0, 0x1, 0 },
-	{ 1152000000, 62, 0x0, 0x1, 0 },
+	{ 1152000000, 60, 0x0, 0x1, 0 },
 	{ 1209600000, 63, 0x0, 0x1, 0 },
 	{ 1248000000, 65, 0x0, 0x1, 0 },
 	{ 1363200000, 71, 0x0, 0x1, 0 },
Signature · 1 line
2.53.0
author maintainer
#516 lore raw

PATCH 512/1067 pNFS/filelayout: fix cheking if a layout is striped

In reply to Greg Kroah-Hartman

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

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

From: Sagi Grimberg <[email protected]>

[ Upstream commit 91668417d4e925c98cae4a55b1b9860380ddbf16 ]

A layout can still be striped with num_fh = 1 as it is perfectly possible that both MDS and DSs can handle the same filehandle. Hence check according to stripe_count > 1, which is the correct check to begin with.

We should not be called with flseg->dsaddr = NULL, but if for some reason we do, return our best guess with is flseg->num_fh > 1.

Fixes a6b9d2fa0024 ("pNFS/filelayout: Fix coalescing test for single DS")
---
 fs/nfs/filelayout/filelayout.c | 2 ++
 1 file changed, 2 insertions(+)
fs/nfs/filelayout/filelayout.c +2 -0
index b363e1bdacdac6..9fa58811534dd1 100644
@@ -786,6 +786,8 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
 static bool
 filelayout_lseg_is_striped(const struct nfs4_filelayout_segment *flseg)
 {
+	if (flseg->dsaddr)
+		return flseg->dsaddr->stripe_count > 1;
 	return flseg->num_fh > 1;
 }
 
Signature · 1 line
2.53.0
author maintainer
#517 lore raw

PATCH 513/1067 xprtrdma: Remove temp allocation of rpcrdma_rep objects

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

[ Upstream commit 0e13dd9ea8be46f980a46c3ffd8cb786f3e2fb5b ]

The original code was designed so that most calls to rpcrdma_rep_create() would occur on the NUMA node that the device preferred. There are a few cases where that's not possible, so those reps are marked as temporary.

However, we have the device (and its preferred node) already in rpcrdma_rep_create(), so let's use that to guarantee the memory is allocated from the correct node.

Stable-dep-of: e786233d2e0b ("xprtrdma: Decouple req recycling from RPC completion")

---
 net/sunrpc/xprtrdma/rpc_rdma.c  |  3 +-
 net/sunrpc/xprtrdma/verbs.c     | 57 ++++++++++++++-------------------
 net/sunrpc/xprtrdma/xprt_rdma.h |  3 +-
 3 files changed, 26 insertions(+), 37 deletions(-)
net/sunrpc/xprtrdma/rpc_rdma.c +1 -2
index 190a4de239c85a..1478c41c7e9da7 100644
@@ -1471,8 +1471,7 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep)
 		credits = 1;	/* don't deadlock */
 	else if (credits > r_xprt->rx_ep->re_max_requests)
 		credits = r_xprt->rx_ep->re_max_requests;
-	rpcrdma_post_recvs(r_xprt, credits + (buf->rb_bc_srv_max_requests << 1),
-			   false);
+	rpcrdma_post_recvs(r_xprt, credits + (buf->rb_bc_srv_max_requests << 1));
 	if (buf->rb_credits != credits)
 		rpcrdma_update_cwnd(r_xprt, credits);
 
net/sunrpc/xprtrdma/verbs.c +24 -33

146 lines not on this page · raw message

net/sunrpc/xprtrdma/xprt_rdma.h +1 -2
index 5e5ff6784ef5ff..4b810c0b63081b 100644
@@ -198,7 +198,6 @@ struct rpcrdma_rep {
 	__be32			rr_proc;
 	int			rr_wc_flags;
 	u32			rr_inv_rkey;
-	bool			rr_temp;
 	struct rpcrdma_regbuf	*rr_rdmabuf;
 	struct rpcrdma_xprt	*rr_rxprt;
 	struct rpc_rqst		*rr_rqst;
@@ -466,7 +465,7 @@ void rpcrdma_flush_disconnect(struct rpcrdma_xprt *r_xprt, struct ib_wc *wc);
 int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt);
 void rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt);
 
-void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed, bool temp);
+void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed);
 
 /*
  * Buffer calls - xprtrdma/verbs.c
Signature · 1 line
2.53.0
author maintainer
#518 lore raw

PATCH 514/1067 xprtrdma: Avoid 250 ms delay on backlog wakeup

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

[ Upstream commit 100142093e22b3f7741ac88e94878bb3694e306f ]

Commit a721035477fb ("SUNRPC/xprt: async tasks mustn't block waiting for memory") changed xprt_rdma_alloc_slot() to set tk_status to -ENOMEM so that call_reserveresult() would sleep HZ/4 before retrying. That rationale applies to xprt_dynamic_alloc_slot(), where an immediate retry under memory pressure wastes CPU, but not to the RDMA backlog path: a task woken from the backlog has a slot waiting for it, so the 250 ms rpc_delay adds latency without benefit.

This also aligns the code with the existing kernel-doc for xprt_rdma_alloc_slot(), which already documented %-EAGAIN.

Fixes a721035477fb ("SUNRPC/xprt: async tasks mustn't block waiting for memory")

Stable-dep-of: e786233d2e0b ("xprtrdma: Decouple req recycling from RPC completion")

---
 net/sunrpc/xprtrdma/transport.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/sunrpc/xprtrdma/transport.c +1 -1
index 10bb2b929c6d70..80731cbb1365ee 100644
@@ -520,7 +520,7 @@ xprt_rdma_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
 	return;
 
 out_sleep:
-	task->tk_status = -ENOMEM;
+	task->tk_status = -EAGAIN;
 	xprt_add_backlog(xprt, task);
 }
 
Signature · 1 line
2.53.0
author maintainer
#519 lore raw

PATCH 515/1067 xprtrdma: Close lost-wakeup race in xprt_rdma_alloc_slot

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

[ Upstream commit 765bde47fe7f197dabeb12da76831f40d0b20377 ]

xprt_rdma_alloc_slot() and xprt_rdma_free_slot() lack serialization between the buffer pool and the backlog queue. A buffer freed after rpcrdma_buffer_get() finds the pool empty but before rpc_sleep_on() places the task on the backlog is returned to the pool with no waiter to wake, leaving the task stuck on the backlog indefinitely.

After joining the backlog, re-check the pool and route any recovered buffer through xprt_wake_up_backlog(), whose queue lock serializes with concurrent wakeups and avoids double-assignment of slots.

Because xprt_rdma_free_slot() does not hold reserve_lock, the XPRT_CONGESTED double-check in xprt_throttle_congested() is
ineffective: a task can join the backlog through that path after free_slot has already found it empty and cleared the bit. Avoid this by using xprt_add_backlog_noncongested(), which queues the task without setting XPRT_CONGESTED, so every allocation reaches xprt_rdma_alloc_slot() and its post-sleep re-check.

Fixes edb41e61a54e ("xprtrdma: Make rpc_rqst part of rpcrdma_req")

Stable-dep-of: e786233d2e0b ("xprtrdma: Decouple req recycling from RPC completion")

---
 include/linux/sunrpc/xprt.h     |  2 ++
 net/sunrpc/xprt.c               | 16 ++++++++++++++++
 net/sunrpc/xprtrdma/transport.c | 15 ++++++++++++++-
 3 files changed, 32 insertions(+), 1 deletion(-)
include/linux/sunrpc/xprt.h +2 -0
index b9f59aabee53bf..3a50fdbb024d00 100644
@@ -378,6 +378,8 @@ struct rpc_xprt *	xprt_alloc(struct net *net, size_t size,
 				unsigned int max_req);
 void			xprt_free(struct rpc_xprt *);
 void			xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task);
+void			xprt_add_backlog_noncongested(struct rpc_xprt *xprt,
+					struct rpc_task *task);
 bool			xprt_wake_up_backlog(struct rpc_xprt *xprt, struct rpc_rqst *req);
 void			xprt_cleanup_ids(void);
 
net/sunrpc/xprt.c +16 -0
index ab453ede54f0cd..562aa8beae0ecb 100644
@@ -1651,6 +1651,22 @@ void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task)
 }
 EXPORT_SYMBOL_GPL(xprt_add_backlog);
 
+/**
+ * xprt_add_backlog_noncongested - queue task on backlog
+ * @xprt: transport whose backlog queue receives the task
+ * @task: task to queue
+ *
+ * Like xprt_add_backlog, but does not set XPRT_CONGESTED.
+ * For transports whose free_slot path does not synchronize
+ * with xprt_throttle_congested via reserve_lock.
+ */
+void xprt_add_backlog_noncongested(struct rpc_xprt *xprt,
+				   struct rpc_task *task)
+{
+	rpc_sleep_on(&xprt->backlog, task, xprt_complete_request_init);
+}
+EXPORT_SYMBOL_GPL(xprt_add_backlog_noncongested);
+
 static bool __xprt_set_rq(struct rpc_task *task, void *data)
 {
 	struct rpc_rqst *req = data;
net/sunrpc/xprtrdma/transport.c +14 -1
index 80731cbb1365ee..44e7cd14af70b5 100644
@@ -521,7 +521,20 @@ xprt_rdma_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
 
 out_sleep:
 	task->tk_status = -EAGAIN;
-	xprt_add_backlog(xprt, task);
+	xprt_add_backlog_noncongested(xprt, task);
+	/* A buffer freed between buffer_get and rpc_sleep_on
+	 * goes back to the pool with no waiter to wake.
+	 * Re-check after joining the backlog to close that gap.
+	 */
+	req = rpcrdma_buffer_get(&r_xprt->rx_buf);
+	if (req) {
+		struct rpc_rqst *rqst = &req->rl_slot;
+
+		if (!xprt_wake_up_backlog(xprt, rqst)) {
+			memset(rqst, 0, sizeof(*rqst));
+			rpcrdma_buffer_put(&r_xprt->rx_buf, req);
+		}
+	}
 }
 
 /**
Signature · 1 line
2.53.0
author maintainer
#520 lore raw

PATCH 516/1067 xprtrdma: Post receive buffers after RPC completion

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

[ Upstream commit 704f3f640f72db4d44ec5ce3db8d4e150c974bc7 ]

rpcrdma_post_recvs() runs in CQ poll context and its cost falls on the latency-critical path between polling a Receive completion and waking the RPC consumer. Every cycle spent refilling the Receive Queue delays delivery of the reply to the NFS layer.

Move the rpcrdma_post_recvs() call in rpcrdma_reply_handler() to after the RPC has been decoded and completed. The larger batch size from the preceding patch provides sufficient Receive Queue headroom to absorb the brief delay before buffers are replenished.

Stable-dep-of: e786233d2e0b ("xprtrdma: Decouple req recycling from RPC completion")

---
 net/sunrpc/xprtrdma/rpc_rdma.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)
net/sunrpc/xprtrdma/rpc_rdma.c +9 -5
index 1478c41c7e9da7..6e7bd1b47d7c7c 100644
@@ -1471,7 +1471,6 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep)
 		credits = 1;	/* don't deadlock */
 	else if (credits > r_xprt->rx_ep->re_max_requests)
 		credits = r_xprt->rx_ep->re_max_requests;
-	rpcrdma_post_recvs(r_xprt, credits + (buf->rb_bc_srv_max_requests << 1));
 	if (buf->rb_credits != credits)
 		rpcrdma_update_cwnd(r_xprt, credits);
 
@@ -1490,15 +1489,20 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep)
 		/* LocalInv completion will complete the RPC */
 	else
 		kref_put(&req->rl_kref, rpcrdma_reply_done);
-	return;
 
-out_badversion:
-	trace_xprtrdma_reply_vers_err(rep);
-	goto out;
+out_post:
+	rpcrdma_post_recvs(r_xprt,
+			   credits + (buf->rb_bc_srv_max_requests << 1));
+	return;
 
 out_norqst:
 	spin_unlock(&xprt->queue_lock);
 	trace_xprtrdma_reply_rqst_err(rep);
+	rpcrdma_rep_put(buf, rep);
+	goto out_post;
+
+out_badversion:
+	trace_xprtrdma_reply_vers_err(rep);
 	goto out;
 
 out_shortreply:
Signature · 1 line
2.53.0
author maintainer
#521 lore raw

PATCH 517/1067 xprtrdma: Use sendctx DMA state for Send signaling

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

[ Upstream commit 2797ae7c929610fb2d2303a996a08173fa096730 ]

Send signaling matters only when the prepared Send has page mappings to unmap. Today that test is expressed indirectly with rl_kref, because the Send-side reference is taken only for Sends with mapped SGEs.

Split the SGE DMA unmap loop into its own helper and use sc_unmap_count directly for the signaling decision. This keeps the current behavior but removes one dependency on the old rl_kref semantics before the request lifetime rules are changed.

Stable-dep-of: e786233d2e0b ("xprtrdma: Decouple req recycling from RPC completion")

---
 net/sunrpc/xprtrdma/frwr_ops.c |  2 +-
 net/sunrpc/xprtrdma/rpc_rdma.c | 22 +++++++++++++---------
 2 files changed, 14 insertions(+), 10 deletions(-)
net/sunrpc/xprtrdma/frwr_ops.c +1 -1
index 47f33bb7bff814..a0d49580dcb871 100644
@@ -404,7 +404,7 @@ int frwr_send(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
 		++num_wrs;
 	}
 
-	if ((kref_read(&req->rl_kref) > 1) || num_wrs > ep->re_send_count) {
+	if (req->rl_sendctx->sc_unmap_count || num_wrs > ep->re_send_count) {
 		send_wr->send_flags |= IB_SEND_SIGNALED;
 		ep->re_send_count = min_t(unsigned int, ep->re_send_batch,
 					  num_wrs - ep->re_send_count);
net/sunrpc/xprtrdma/rpc_rdma.c +13 -9
index 6e7bd1b47d7c7c..e6679adbedae51 100644
@@ -526,19 +526,11 @@ static void rpcrdma_sendctx_done(struct kref *kref)
 	rep->rr_rxprt->rx_stats.reply_waits_for_send++;
 }
 
-/**
- * rpcrdma_sendctx_unmap - DMA-unmap Send buffer
- * @sc: sendctx containing SGEs to unmap
- *
- */
-void rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc)
+static void rpcrdma_sendctx_dma_unmap(struct rpcrdma_sendctx *sc)
 {
 	struct rpcrdma_regbuf *rb = sc->sc_req->rl_sendbuf;
 	struct ib_sge *sge;
 
-	if (!sc->sc_unmap_count)
-		return;
-
 	/* The first two SGEs contain the transport header and
 	 * the inline buffer. These are always left mapped so
 	 * they can be cheaply re-used.
@@ -547,7 +539,19 @@ void rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc)
 	     ++sge, --sc->sc_unmap_count)
 		ib_dma_unmap_page(rdmab_device(rb), sge->addr, sge->length,
 				  DMA_TO_DEVICE);
+}
+
+/**
+ * rpcrdma_sendctx_unmap - DMA-unmap Send buffer
+ * @sc: sendctx containing SGEs to unmap
+ *
+ */
+void rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc)
+{
+	if (!sc->sc_unmap_count)
+		return;
 
+	rpcrdma_sendctx_dma_unmap(sc);
 	kref_put(&sc->sc_req->rl_kref, rpcrdma_sendctx_done);
 }
 
Signature · 1 line
2.53.0
author maintainer
#522 lore raw

PATCH 518/1067 xprtrdma: Decouple req recycling from RPC completion

In reply to Greg Kroah-Hartman

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

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

From: Chuck Lever <[email protected]>

[ Upstream commit e786233d2e0bbff9a82e43f02ae3a46ab4b08ec3 ]

rl_kref formerly served two distinct lifetimes through a single
refcount: it gated when a Reply could wake its RPC task, and it gated when an rpcrdma_req could return to its free pool. The marshal path took the Send-side reference only when SGEs needed DMA-unmap (sc_unmap_count > 0), which made a Send carrying only pre-registered buffers an exception: the Reply handler dropped rl_kref from 1 to 0 and freed the req while the HCA might still be DMA-reading from its send buffer.

Give rl_kref a narrower job. The RPC layer takes one reference when slot allocation hands a req out. rpcrdma_prepare_send_sges() takes a Send-side reference unconditionally after WR preparation succeeds. xprt_rdma_free_slot() and xprt_rdma_bc_free_rqst() drop the RPC-layer reference; rpcrdma_sendctx_unmap() drops the Send-side reference. The req returns to its free pool only after both owners have signed off.

The existing kref_init(&req->rl_kref) call in rpcrdma_prepare_send_sges() is removed. Initialization moves to the slot-allocation paths (xprt_rdma_alloc_slot and rpcrdma_bc_rqst_get), and the release callback re-arms rl_kref before the req returns to a free pool. A re-init in the marshal path would discard the RPC-layer reference that already exists on entry.

Three invariants follow:

- Any rpcrdma_req held by an rpc_rqst has rl_kref >= 1. xprt_rdma_alloc_slot(), rpcrdma_bc_rqst_get(), and the backlog-wake branch in xprt_rdma_alloc_slot() each kref_init rl_kref before publishing the req. Without this invariant, an RPC task that aborts between slot allocation and marshal (gss_refresh failure or signal during call_connect, for example) would drive xprt_release() -> xprt_rdma_free_slot() -> kref_put against a refcount of zero, saturating refcount_t and stranding the slot.

- The Send-side reference is taken only after WR prep succeeds. A mapping failure in rpcrdma_prepare_send_sges() runs rpcrdma_sendctx_cancel(), which DMA-unmaps the sendctx and clears sc_req without touching rl_kref. The sendctx ring walks in rpcrdma_sendctx_put_locked() and rpcrdma_sendctxs_destroy() skip entries with sc_req == NULL, so a burst of -EIO marshal failures cannot hold reqs off rb_send_bufs.

- The release callback re-arms rl_kref so the next consumer enters with the invariant satisfied.

Replies now complete the RPC directly. rpcrdma_reply_handler() calls rpcrdma_complete_rqst() in place of kref_put on the non-LocalInv branch. The LocalInv branch already completes the RPC from frwr_unmap_async() and is unaffected.

Because Send-side references can now outlive RPC completion, connection teardown drains sendctx entries whose unsignaled Sends never had a later signaled completion to walk the ring. rpcrdma_sendctxs_destroy() walks the active range and runs rpcrdma_sendctx_unmap() on each entry with a non-NULL sc_req before the request buffers are reset, and is moved ahead of rpcrdma_reqs_reset() in rpcrdma_xprt_disconnect() so the reqs are still in their pre-reset state when the Send-side refs are released.

The drain creates a teardown-ordering hazard on the backchannel path. With the new lifetime, releasing a bc_prealloc req from rpcrdma_req_release() re-adds it to bc_pa_list. The disconnect in xprt_rdma_destroy() runs after xprt_destroy_backchannel() has already emptied bc_pa_list, so the drained reqs would otherwise leak. xprt_rdma_destroy() now runs xprt_rdma_bc_destroy(xprt, 0) a second time after the disconnect to reclaim them.

Fixes 0ab115237025 ("xprtrdma: Wake RPCs directly in rpcrdma_wc_send path")
---
 net/sunrpc/xprtrdma/backchannel.c |  5 ++-
 net/sunrpc/xprtrdma/rpc_rdma.c    | 47 +++++++++++---------------
 net/sunrpc/xprtrdma/transport.c   | 55 ++++++++++++++++++++++++++++---
 net/sunrpc/xprtrdma/verbs.c       | 29 +++++++++++++---
 net/sunrpc/xprtrdma/xprt_rdma.h   |  2 +-
 5 files changed, 97 insertions(+), 41 deletions(-)
net/sunrpc/xprtrdma/backchannel.c +2 -3
index e4d84a13c566e7..5f304f2c61b13c 100644
@@ -158,9 +158,7 @@ void xprt_rdma_bc_free_rqst(struct rpc_rqst *rqst)
 	rpcrdma_rep_put(&r_xprt->rx_buf, rep);
 	req->rl_reply = NULL;
 
-	spin_lock(&xprt->bc_pa_lock);
-	list_add_tail(&rqst->rq_bc_pa_list, &xprt->bc_pa_list);
-	spin_unlock(&xprt->bc_pa_lock);
+	rpcrdma_req_put(req);
 	xprt_put(xprt);
 }
 
@@ -202,6 +200,7 @@ static struct rpc_rqst *rpcrdma_bc_rqst_get(struct rpcrdma_xprt *r_xprt)
 	rqst->rq_xprt = xprt;
 	__set_bit(RPC_BC_PA_IN_USE, &rqst->rq_bc_pa_state);
 	xdr_buf_init(&rqst->rq_snd_buf, rdmab_data(req->rl_sendbuf), size);
+	kref_init(&req->rl_kref);
 	return rqst;
 }
 
net/sunrpc/xprtrdma/rpc_rdma.c +19 -28

105 lines not on this page · raw message

net/sunrpc/xprtrdma/transport.c +50 -5

91 lines not on this page · raw message

net/sunrpc/xprtrdma/verbs.c +25 -4
index d468ebf6de8062..ad463196f8e95d 100644
@@ -65,6 +65,8 @@
 
 static int rpcrdma_sendctxs_create(struct rpcrdma_xprt *r_xprt);
 static void rpcrdma_sendctxs_destroy(struct rpcrdma_xprt *r_xprt);
+static unsigned long rpcrdma_sendctx_next(struct rpcrdma_buffer *buf,
+					  unsigned long item);
 static void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt,
 				       struct rpcrdma_sendctx *sc);
 static int rpcrdma_reqs_setup(struct rpcrdma_xprt *r_xprt);
@@ -566,9 +568,9 @@ void rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt)
 
 	rpcrdma_xprt_drain(r_xprt);
 	rpcrdma_reps_unmap(r_xprt);
+	rpcrdma_sendctxs_destroy(r_xprt);
 	rpcrdma_reqs_reset(r_xprt);
 	rpcrdma_mrs_destroy(r_xprt);
-	rpcrdma_sendctxs_destroy(r_xprt);
 
 	if (rpcrdma_ep_put(ep))
 		rdma_destroy_id(id);
@@ -600,6 +602,20 @@ static void rpcrdma_sendctxs_destroy(struct rpcrdma_xprt *r_xprt)
 
 	if (!buf->rb_sc_ctxs)
 		return;
+
+	/* The QP is drained, but the final unsignaled Sends might not
+	 * have been walked by a signaled Send completion. Release those
+	 * Send owners before request buffers are reset.
+	 */
+	for (i = rpcrdma_sendctx_next(buf, buf->rb_sc_tail);
+	     i != rpcrdma_sendctx_next(buf, buf->rb_sc_head);
+	     i = rpcrdma_sendctx_next(buf, i)) {
+		struct rpcrdma_sendctx *sc = buf->rb_sc_ctxs[i];
+
+		if (sc && sc->sc_req)
+			rpcrdma_sendctx_unmap(sc);
+	}
+
 	for (i = 0; i <= buf->rb_sc_last; i++)
 		kfree(buf->rb_sc_ctxs[i]);
 	kfree(buf->rb_sc_ctxs);
@@ -722,15 +738,20 @@ static void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt,
 	struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
 	unsigned long next_tail;
 
-	/* Unmap SGEs of previously completed but unsignaled
-	 * Sends by walking up the queue until @sc is found.
+	/* Release previously completed but unsignaled Sends by walking
+	 * up the queue until @sc is found. Entries left behind by a
+	 * failed rpcrdma_prepare_send_sges() have sc_req cleared.
 	 */
 	next_tail = buf->rb_sc_tail;
 	do {
+		struct rpcrdma_sendctx *cur;
+
 		next_tail = rpcrdma_sendctx_next(buf, next_tail);
 
 		/* ORDER: item must be accessed _before_ tail is updated */
-		rpcrdma_sendctx_unmap(buf->rb_sc_ctxs[next_tail]);
+		cur = buf->rb_sc_ctxs[next_tail];
+		if (cur->sc_req)
+			rpcrdma_sendctx_unmap(cur);
 
 	} while (buf->rb_sc_ctxs[next_tail] != sc);
 
net/sunrpc/xprtrdma/xprt_rdma.h +1 -1
index 4b810c0b63081b..29f13a6d463589 100644
@@ -408,7 +408,6 @@ struct rpcrdma_stats {
 	/* accessed when receiving a reply */
 	unsigned long long	total_rdma_reply;
 	unsigned long long	fixup_copy_count;
-	unsigned long		reply_waits_for_send;
 	unsigned long		local_inv_needed;
 	unsigned long		nomsg_call_count;
 	unsigned long		bcall_count;
@@ -486,6 +485,7 @@ void rpcrdma_buffer_put(struct rpcrdma_buffer *buffers,
 			struct rpcrdma_req *req);
 void rpcrdma_rep_put(struct rpcrdma_buffer *buf, struct rpcrdma_rep *rep);
 void rpcrdma_reply_put(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req);
+void rpcrdma_req_put(struct rpcrdma_req *req);
 
 bool rpcrdma_regbuf_realloc(struct rpcrdma_regbuf *rb, size_t size,
 			    gfp_t flags);
Signature · 1 line
2.53.0
author maintainer
#523 lore raw

PATCH 519/1067 NFSv4/pnfs: defer return_range callbacks until after inode unlock

In reply to Greg Kroah-Hartman

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

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

From: Dai Ngo <[email protected]>

[ Upstream commit 77b160b2d863d37f36b6c38e80a7d259ce939e69 ]

Sometimes unmounting an NFS filesystem mounted with pNFS SCSI layouts triggers the following warning:

     BUG: scheduling while atomic: umount.nfs4/...

    __schedule_bug+0xbd/0x100
     schedule_debug.constprop.0+0x19f/0x220
     __schedule+0x10d/0x10a0
     schedule+0x74/0x190
     schedule_timeout+0xf5/0x220
     io_schedule_timeout+0xd5/0x160
     __wait_for_common+0x186/0x4b0
     blk_execute_rq+0x2ef/0x3a0
     scsi_execute_cmd+0x1ff/0x700
     sd_pr_out_command.isra.0+0x242/0x380 [sd_mod]
     bl_unregister_scsi.constprop.0+0x109/0x3c0 [blocklayoutdriver]
     bl_unregister_dev+0x175/0x1c0 [blocklayoutdriver]
     bl_free_device+0x1f/0x1b0 [blocklayoutdriver]
     bl_free_deviceid_node+0x12/0x30 [blocklayoutdriver]
     nfs4_put_deviceid_node+0x171/0x360 [nfsv4]
     ext_tree_remove+0x11c/0x1d0 [blocklayoutdriver]
     _pnfs_return_layout+0x416/0x900 [nfsv4]
     nfs4_evict_inode+0x108/0x130 [nfsv4]
     evict+0x316/0x750
     dispose_list+0xf1/0x1a0
     evict_inodes+0x33f/0x440
     generic_shutdown_super+0xc9/0x4e0
     kill_anon_super+0x3a/0x90
     nfs_kill_super+0x44/0x60 [nfs]
     deactivate_locked_super+0xb8/0x1b0
     cleanup_mnt+0x25a/0x380
     task_work_run+0x13e/0x210
     exit_to_user_mode_loop+0x169/0x400
     do_syscall_64+0x467/0x1550
     entry_SYSCALL_64_after_hwframe+0x76/0x7e

The warning occurs because the block layout driver unregisters the SCSI device while the inode lock is still held. Device unregistration issues a SCSI PR command, which may sleep, resulting in a "scheduling while atomic" warning.

During layout return, ext_tree_remove() invokes the layout driver's return_range callback while holding the inode lock. For block layouts, this callback eventually calls bl_unregister_scsi(), which may block in scsi_execute_cmd() while issuing PR commands to the device.

Fix this by deferring the return_range callbacks until after the inode lock has been released. The layout header reference count is incremented before invoking return_range(), ensuring that the layout header remains valid while the layout driver removes extents from the extent tree.

Fixes c88953d87f5c8 ("pnfs: add return_range method")
---
 fs/nfs/callback_proc.c | 9 +++++----
 fs/nfs/pnfs.c          | 4 ++--
 2 files changed, 7 insertions(+), 6 deletions(-)
fs/nfs/callback_proc.c +5 -4
index c1eda73254e16f..25ba728d8eedd7 100644
@@ -248,6 +248,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
 	struct pnfs_layout_hdr *lo;
 	u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
 	LIST_HEAD(free_me_list);
+	bool return_range = false;
 
 	ino = nfs_layout_find_inode(clp, &args->cbl_fh, &args->cbl_stateid);
 	if (IS_ERR(ino)) {
@@ -292,13 +293,13 @@ static u32 initiate_file_draining(struct nfs_client *clp,
 		/* Embrace your forgetfulness! */
 		rv = NFS4ERR_NOMATCHING_LAYOUT;
 
-		if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
-			NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
-				&args->cbl_range);
-		}
+		return_range = true;
 	}
 unlock:
 	spin_unlock(&ino->i_lock);
+	if (return_range && NFS_SERVER(ino)->pnfs_curr_ld->return_range)
+		NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
+			&args->cbl_range);
 	pnfs_free_lseg_list(&free_me_list);
 	/* Free all lsegs that are attached to commit buckets */
 	nfs_commit_inode(ino, 0);
fs/nfs/pnfs.c +2 -2
index fa310bf1ed9abc..0eddfd74577846 100644
@@ -1375,8 +1375,6 @@ _pnfs_return_layout(struct inode *ino)
 	pnfs_clear_layoutcommit(ino, &tmp_list);
 	pnfs_mark_matching_lsegs_return(lo, &tmp_list, &range, 0);
 
-	if (NFS_SERVER(ino)->pnfs_curr_ld->return_range)
-		NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo, &range);
 
 	/* Don't send a LAYOUTRETURN if list was initially empty */
 	if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags) ||
@@ -1388,6 +1386,8 @@ _pnfs_return_layout(struct inode *ino)
 
 	send = pnfs_prepare_layoutreturn(lo, &stateid, &cred, NULL);
 	spin_unlock(&ino->i_lock);
+	if (NFS_SERVER(ino)->pnfs_curr_ld->return_range)
+		NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo, &range);
 	if (send)
 		status = pnfs_send_layoutreturn(lo, &stateid, &cred, IOMODE_ANY, true);
 out_wait_layoutreturn:
Signature · 1 line
2.53.0
author maintainer
#524 lore raw

PATCH 520/1067 NFSv4/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS on fatal DS connect errors

In reply to Greg Kroah-Hartman

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

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

From: Mike Snitzer <[email protected]>

[ Upstream commit 7a375cafc14ed151508f908ea5681caf0a9cc1d6 ]

Commit f06bedfa62d5 ("pNFS/flexfiles: don't attempt pnfs on fatal DS errors") teaches ff_layout_{read,write}_pagelist() to return PNFS_NOT_ATTEMPTED when nfs4_ff_layout_prepare_ds() fails with a nfs_error_is_fatal() errno (e.g. -ETIMEDOUT from a SOFTCONN connect deadline, -ENOMEM, -ERESTARTSYS), so that the client gives up instead of spinning. pnfs_do_{read,write}() then dispatches the I/O through pnfs_{read,write}_through_mds() → nfs_pageio_reset_{read,write}_mds().

That fallback is unconditional and silently violates FF_FLAGS_NO_IO_THRU_MDS:
when the layout segment carries the flag (typically single-mirror appliance layouts where MDS I/O is explicitly forbidden), the
out_failed: path's \&& !ds_fatal_error\ clause overrides the flag's short-circuit through ff_layout_avoid_mds_available_ds() and routes the I/O to the MDS file handle anyway.

This is reachable in practice during a data-server restart: SOFTCONN exhaustion produces -ETIMEDOUT, which is fatal per nfs_error_is_fatal(), which triggers PNFS_NOT_ATTEMPTED, which silently goes to MDS.

Preserve the upstream "don't spin on fatal errors" intent for layouts that permit MDS fallback. For layouts with FF_FLAGS_NO_IO_THRU_MDS set, mark the layout for return and request PNFS_TRY_AGAIN instead; if the server cannot supply a usable layout the failure now surfaces cleanly via pnfs_update_layout(), rather than via silent MDS I/O that contradicts the flag.

Fixes f06bedfa62d5 ("pNFS/flexfiles: don't attempt pnfs on fatal DS errors")
Assisted-by Claude:claude-opus-4-7
---
 fs/nfs/flexfilelayout/flexfilelayout.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
fs/nfs/flexfilelayout/flexfilelayout.c +16 -0
index 01378fb1958451..46e72a7ed15144 100644
@@ -1902,6 +1902,14 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr)
 out_failed:
 	if (ff_layout_avoid_mds_available_ds(lseg) && !ds_fatal_error)
 		return PNFS_TRY_AGAIN;
+	if (ff_layout_no_fallback_to_mds(lseg)) {
+		/*
+		 * FF_FLAGS_NO_IO_THRU_MDS: force fresh LAYOUTGET,
+		 * never fall through to MDS I/O.
+		 */
+		pnfs_error_mark_layout_for_return(hdr->inode, lseg);
+		return PNFS_TRY_AGAIN;
+	}
 	trace_pnfs_mds_fallback_read_pagelist(hdr->inode,
 			hdr->args.offset, hdr->args.count,
 			IOMODE_READ, NFS_I(hdr->inode)->layout, lseg);
@@ -1973,6 +1981,14 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
 out_failed:
 	if (ff_layout_avoid_mds_available_ds(lseg) && !ds_fatal_error)
 		return PNFS_TRY_AGAIN;
+	if (ff_layout_no_fallback_to_mds(lseg)) {
+		/*
+		 * FF_FLAGS_NO_IO_THRU_MDS: force fresh LAYOUTGET,
+		 * never fall through to MDS I/O.
+		 */
+		pnfs_error_mark_layout_for_return(hdr->inode, lseg);
+		return PNFS_TRY_AGAIN;
+	}
 	trace_pnfs_mds_fallback_write_pagelist(hdr->inode,
 			hdr->args.offset, hdr->args.count,
 			IOMODE_RW, NFS_I(hdr->inode)->layout, lseg);
Signature · 1 line
2.53.0
author maintainer
#525 lore raw

PATCH 521/1067 NFSv4/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS in pg_get_mirror_count_write

In reply to Greg Kroah-Hartman

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

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

From: Mike Snitzer <[email protected]>

[ Upstream commit 1d62e659c0bf11649cf48e002c2a55d148f2610a ]

The FF_FLAGS_NO_IO_THRU_MDS flag lives on each lseg, so any fallback decision made when there is no current lseg (e.g. between LAYOUTRETURN and the next LAYOUTGET) cannot run the per-lseg check.

Introduce a sticky hdr-level ditto for FF_FLAGS_NO_IO_THRU_MDS in struct nfs4_flexfile_layout::flags (NFS4_FF_HDR_NO_IO_THRU_MDS bit), set whenever ff_layout_alloc_lseg() parses an lseg with the flag. The bit is never cleared for the lifetime of the layout hdr; the server is assumed to be consistent in its no-fallback policy per file. kzalloc() in ff_layout_alloc_layout_hdr() zero-initializes the field.

Use the new ff_layout_hdr_no_fallback_to_mds() helper to gate ff_layout_pg_get_mirror_count_write(): when pnfs_update_layout() returns NULL (e.g. NFS_LAYOUT_BULK_RECALL, pnfs_layout_io_test_failed, pnfs_layoutgets_blocked) the existing code unconditionally calls nfs_pageio_reset_write_mds(). This is a source of unwanted WRITE to MDS. Fix it by checking NFS4_FF_HDR_NO_IO_THRU_MDS bit, and if set surface -EAGAIN instead; the writepage-side caller (nfs_do_writepage() for buffered, nfs_direct_write_reschedule() for O_DIRECT) then redirties the request so writeback retries via pNFS.

Fixes 260074cd8413 ("pNFS/flexfiles: Add support for FF_FLAGS_NO_IO_THRU_MDS")
Assisted-by Claude:claude-opus-4-7
---
 fs/nfs/flexfilelayout/flexfilelayout.c | 13 +++++++++++++
 fs/nfs/flexfilelayout/flexfilelayout.h | 16 ++++++++++++++++
 2 files changed, 29 insertions(+)
fs/nfs/flexfilelayout/flexfilelayout.c +13 -0
index 46e72a7ed15144..a5f69d1fce3fb7 100644
@@ -539,6 +539,9 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
 	if (!p)
 		goto out_sort_mirrors;
 	fls->flags = be32_to_cpup(p);
+	if (fls->flags & FF_FLAGS_NO_IO_THRU_MDS)
+		set_bit(NFS4_FF_HDR_NO_IO_THRU_MDS,
+			&FF_LAYOUT_FROM_HDR(lh)->flags);
 
 	p = xdr_inline_decode(&stream, 4);
 	if (!p)
@@ -992,6 +995,16 @@ ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,
 			0, NFS4_MAX_UINT64, IOMODE_RW,
 			NFS_I(pgio->pg_inode)->layout,
 			pgio->pg_lseg);
+	if (NFS_I(pgio->pg_inode)->layout &&
+	    ff_layout_hdr_no_fallback_to_mds(NFS_I(pgio->pg_inode)->layout)) {
+		/*
+		 * FF_FLAGS_NO_IO_THRU_MDS: no current lseg but the server's
+		 * policy forbids MDS fallback.  Surface -EAGAIN so writeback
+		 * retries rather than silently issuing the WRITE via MDS.
+		 */
+		pgio->pg_error = -EAGAIN;
+		goto out;
+	}
 	/* no lseg means that pnfs is not in use, so no mirroring here */
 	nfs_pageio_reset_write_mds(pgio);
 out:
fs/nfs/flexfilelayout/flexfilelayout.h +16 -0
index 354a031c69b172..1d4294c6a7ec48 100644
@@ -102,12 +102,16 @@ struct nfs4_ff_layout_segment {
 	struct nfs4_ff_layout_mirror	*mirror_array[];
 };
 
+/* nfs4_flexfile_layout::flags bit indices */
+#define NFS4_FF_HDR_NO_IO_THRU_MDS  0   /* any lseg has had FF_FLAGS_NO_IO_THRU_MDS */
+
 struct nfs4_flexfile_layout {
 	struct pnfs_layout_hdr generic_hdr;
 	struct pnfs_ds_commit_info commit_info;
 	struct list_head	mirrors;
 	struct list_head	error_list; /* nfs4_ff_layout_ds_err */
 	ktime_t			last_report_time; /* Layoutstat report times */
+	unsigned long		flags;
 };
 
 struct nfs4_flexfile_layoutreturn_args {
@@ -174,6 +178,18 @@ ff_layout_no_fallback_to_mds(struct pnfs_layout_segment *lseg)
 	return FF_LAYOUT_LSEG(lseg)->flags & FF_FLAGS_NO_IO_THRU_MDS;
 }
 
+/*
+ * Sticky hdr-level mirror of FF_FLAGS_NO_IO_THRU_MDS so callers that have
+ * no current lseg (e.g. between LAYOUTRETURN and the next LAYOUTGET) can
+ * still honor the no-MDS-fallback policy.
+ */
+static inline bool
+ff_layout_hdr_no_fallback_to_mds(struct pnfs_layout_hdr *lo)
+{
+	return test_bit(NFS4_FF_HDR_NO_IO_THRU_MDS,
+			&FF_LAYOUT_FROM_HDR(lo)->flags);
+}
+
 static inline bool
 ff_layout_no_read_on_rw(struct pnfs_layout_segment *lseg)
 {
Signature · 1 line
2.53.0
author maintainer
#526 lore raw

PATCH 522/1067 PCI: mediatek: Fix operator precedence in PCIE_FTS_NUM_L0 macro

In reply to Greg Kroah-Hartman

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

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

From: Li RongQing <[email protected]>

[ Upstream commit 282305d7e9c0e27fd8b4df34b7cd5506a1eccdd6 ]

The original PCIE_FTS_NUM_L0(x) macro was buggy due to improper operator precedence, where ((x) & 0xff << 8) was evaluated as ((x) & 0xff00).

Instead of just fixing the parentheses, use the standard FIELD_PREP() macro. This makes the code more robust by automatically handling masks and shifts, while also adding compile-time type and range checking to ensure the value fits within PCIE_FTS_NUM_MASK.

Fixes 637cfacae96f ("PCI: mediatek: Add MediaTek PCIe host controller support")
[mani: added the bitfield header include spotted by Sashiko]
---
 drivers/pci/controller/pcie-mediatek.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/pci/controller/pcie-mediatek.c +2 -1
index 03ac5df9bb1298..1e3a8461b5ce01 100644
@@ -7,6 +7,7 @@
  *	   Honghui Zhang <[email protected]>
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/iopoll.h>
@@ -60,7 +61,7 @@
 /* MediaTek specific configuration registers */
 #define PCIE_FTS_NUM		0x70c
 #define PCIE_FTS_NUM_MASK	GENMASK(15, 8)
-#define PCIE_FTS_NUM_L0(x)	((x) & 0xff << 8)
+#define PCIE_FTS_NUM_L0(x)	FIELD_PREP(PCIE_FTS_NUM_MASK, x)
 
 #define PCIE_FC_CREDIT		0x73c
 #define PCIE_FC_CREDIT_MASK	(GENMASK(31, 31) | GENMASK(28, 16))
Signature · 1 line
2.53.0
author maintainer
#527 lore raw

PATCH 523/1067 perf tools: Fix get_max_num() size_t underflow on empty sysfs file

In reply to Greg Kroah-Hartman

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

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

From: Arnaldo Carvalho de Melo <[email protected]>

[ Upstream commit 0a012113bb3a44482c163f16f4db03ccaa37a339 ]

get_max_num() reads a sysfs file (cpu/possible, cpu/present, or node/possible) and scans backward from the end to find the last number. If the file is empty, filename__read_str() returns num == 0. The loop while (--num) decrements the size_t from 0 to SIZE_MAX, reading backward across the heap until a comma or hyphen is found or unmapped memory is hit.

Add an early return for empty files before the backward scan.

Fixes 7780c25bae59fd04 ("perf tools: Allow ability to map cpus to nodes easily")
Cc Don Zickus <[email protected]>
Cc Ian Rogers <[email protected]>
Assisted-by Claude:claude-opus-4.6
---
 tools/perf/util/cpumap.c | 6 ++++++
 1 file changed, 6 insertions(+)
tools/perf/util/cpumap.c +6 -0
index 370bc498b7a2e4..4a882d4e183f26 100644
@@ -366,6 +366,12 @@ static int get_max_num(char *path, int *max)
 
 	buf[num] = '\0';
 
+	/* empty file — nothing to parse */
+	if (num == 0) {
+		err = -1;
+		goto out;
+	}
+
 	/* start on the right, to find highest node num */
 	while (--num) {
 		if ((buf[num] == ',') || (buf[num] == '-')) {
Signature · 1 line
2.53.0