Skip to contentSkip to conversation

7.2.8-rc1 review

PATCH In review Greg Kroah-Hartman 16 participants 454 messages Sep 23 – Sep 25 Stable branch Page 3 of 4

lore
Share & tools
lore
author maintainer
#252 lore raw

PATCH 249/438 posix-cpu-timers: Prevent freeing a timer which is queued on the expiry list

In reply to Greg Kroah-Hartman

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

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

From: Thomas Gleixner <[email protected]>

commit c21eaa72f02fc6e85621cbe09d303d8fb8bd39cd upstream.

Kijo analyzed another race in the POSIX CPU timer code:

Commit bf635681c906 converted cpu_timer::firing from a tristate value to a boolean. This lost the distinction between "not owned by the firing list" and "still owned, but delivery was canceled". The resulting race is:

    expiry handler              timer_settime()        timer_delete()
    --------------              ---------------        --------------

collect timer onto
private firing list
firing = true
observes firing = true
firing = false
return TIMER_RETRY
wait for handler
observes firing = false finish deletion unhash and free timer
resume list traversal
read freed elist.next
-> UAF

The firing bit is clearly the wrong indicator since that commit.

Check whether the timer is queued on the expiry list or not instead. If it is queued clear the firing bit to prevent signal delivery as before and return TIMER_RETRY so the caller unlocks the timer which allows the expiry code to make progress and remove it from the list.

---
 kernel/time/posix-cpu-timers.c |   40 ++++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)
kernel/time/posix-cpu-timers.c +22 -18
@@ -408,6 +408,7 @@ static int posix_cpu_timer_create(struct
 
 	new_timer->kclock = &clock_posix_cpu;
 	timerqueue_init(&new_timer->it.cpu.node);
+	INIT_LIST_HEAD(&new_timer->it.cpu.elist);
 	new_timer->it.cpu.pid = get_pid(pid);
 	rcu_read_unlock();
 	return 0;
@@ -566,6 +567,24 @@ static struct task_struct *timer_lock_si
 }
 
 /*
+ * If the timer is queued on the expiry list, then it cannot be dequeued because
+ * the firing list is not protected by sighand->lock. The delivery path is
+ * waiting for the timer lock. So go back, unlock and retry.
+ */
+static bool posix_cpu_timer_on_expiry_list(struct k_itimer *timer)
+{
+	if (list_empty(&timer->it.cpu.elist))
+		return false;
+
+	/*
+	 * Prevent signal delivery as there is no point in delivering a signal
+	 * which is made obsolete right away.
+	 */
+	timer->it.cpu.firing = false;
+	return true;
+}
+
+/*
  * Clean up a CPU-clock timer that is about to be destroyed.
  * This is called from timer deletion with the timer already locked.
  * If we return TIMER_RETRY, it's necessary to release the timer's lock
@@ -580,18 +599,10 @@ static int posix_cpu_timer_del(struct k_
 	p = timer_lock_sighand(timer, &flags);
 
 	if (likely(p)) {
-		if (timer->it.cpu.firing) {
-			/*
-			 * Prevent signal delivery. The timer cannot be dequeued
-			 * because it is on the firing list which is not protected
-			 * by sighand->lock. The delivery path is waiting for
-			 * the timer lock. So go back, unlock and retry.
-			 */
-			timer->it.cpu.firing = false;
+		if (posix_cpu_timer_on_expiry_list(timer))
 			ret = TIMER_RETRY;
-		} else {
+		else
 			disarm_timer(timer, p);
-		}
 		unlock_task_sighand(p, &flags);
 	}
 
@@ -731,14 +742,7 @@ static int posix_cpu_timer_set(struct k_
 	/* Retrieve the current expiry time before disarming the timer */
 	old_expires = cpu_timer_getexpires(ctmr);
 
-	if (unlikely(timer->it.cpu.firing)) {
-		/*
-		 * Prevent signal delivery. The timer cannot be dequeued
-		 * because it is on the firing list which is not protected
-		 * by sighand->lock. The delivery path is waiting for
-		 * the timer lock. So go back, unlock and retry.
-		 */
-		timer->it.cpu.firing = false;
+	if (posix_cpu_timer_on_expiry_list(timer)) {
 		ret = TIMER_RETRY;
 	} else {
 		cpu_timer_dequeue(ctmr);
author maintainer
#253 lore raw

PATCH 250/438 rds: ib: use rds_conn_drop() on protocol version mismatch

In reply to Greg Kroah-Hartman

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

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

From: Aohan Mei <[email protected]>

commit f97d8c7bab7843631206a114986c9059da03efeb upstream.

rds_ib_cm_connect_complete() runs from the RDMA-CM event handler with conn->c_cm_lock held. When the peer negotiates a protocol version older than RDS_PROTOCOL_COMPAT_VERSION, the handler calls rds_conn_destroy(), which is only safe in the rmmod path: it synchronously tears the connection down and flush_work()es the shutdown work cp_down_w.

That shutdown work (rds_conn_shutdown()) needs cp_cm_lock, which is the very lock the event handler still holds, so the flush never
completes: the two workers wait on each other and the RDS connection workqueues stall for good.

All other RDMA-CM failure paths (REJECTED, CONNECT_ERROR, DISCONNECTED) use rds_conn_drop(), which marks the connection RDS_CONN_ERROR and schedules the shutdown work asynchronously. Use it here as well.

---
 net/rds/ib_cm.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/rds/ib_cm.c +1 -1
@@ -115,7 +115,7 @@ void rds_ib_cm_connect_complete(struct r
 				  &conn->c_laddr, &conn->c_faddr,
 				  RDS_PROTOCOL_MAJOR(conn->c_version),
 				  RDS_PROTOCOL_MINOR(conn->c_version));
-			rds_conn_destroy(conn);
+			rds_conn_drop(conn);
 			return;
 		}
 	}
author maintainer
#254 lore raw

PATCH 251/438 signal: Prevent exec() race

In reply to Greg Kroah-Hartman

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

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

From: Thomas Gleixner <[email protected]>

commit d2710c8d938ae6a825a6463158e6e6f31eac792a upstream.

Hyunwoo debugged the following KASAN UAF splat:

  BUG: KASAN: slab-use-after-free in __send_signal_locked+0xb27/0xba0
  Write of size 8 at addr ffff888007ed80c8 by task poc/79
  ...
  Call Trace:
   __send_signal_locked+0xb27/0xba0
   do_send_sig_info+0xa7/0x160
   do_send_specific+0x76/0xa0
   __x64_sys_tgkill+0x193/0x270
  ...
  Allocated by task 80:
   do_timer_create+0x1a4/0x1030
   __x64_sys_timer_create+0x145/0x190
  ...
  Freed by task 12:
   kmem_cache_free_bulk+0x1f8/0x4a0
   kvfree_rcu_bulk+0x14f/0x1c0
   kfree_rcu_work+0x128/0x1a0
  ...
  Last potentially related work creation:
   kvfree_call_rcu+0x39/0x390
   __flush_itimer_signals+0x211/0x320
   flush_itimer_signals+0x47/0x90
   begin_new_exec+0xa6b/0x28c0

It turned out that this happens with a non-leader exec() as Hyunwoo explained:

de_thread() calls exchange_tids() before release_task(leader), so the struct pid held by a SIGEV_THREAD_ID timer created against the leader's tid now points to the thread which called execve(). pid_task() returns that thread and lock_task_sighand() on it succeeds.

If the timer signal is blocked, its sigqueue stays queued on the leader's task::pending. The next expiry of that timer can then run while release_task() flushes the queue.

posixtimer_send_sigqueue() checks whether the sigqueue is already queued with a plain list_empty(), which only reads list_head::next. list_del_init() is not atomic and INIT_LIST_HEAD() stores list_head::next before list_head::prev, so the check can pass in between. list_add_tail() queues the entry on the task::pending of the live thread, and the list_head::prev store from the flush then overwrites the list_head::prev link that list_add_tail() has just set.

__flush_itimer_signals() does not undo that either. With list_head::prev pointing at the entry itself, its list_del_init() only stores the same values again, so the entry is not removed from the list. It is still there after the last reference is dropped and the timer is freed by RCU, and the list_add_tail() of a later tgkill() follows that list_head::prev into the freed timer.

This problem surfaced with the recent commit which moved the sigqueue flush out of the sighand lock held region.

Hyonwoo proposed to fix this by using list_del_init_careful(), but that just papers over the problem. After some disucssions and various attempts to solve it, Eric pointed out that there is no reason to flush task::pending late in release_task() and it should be done in exit_signals() already.

As nothing can collect and deliver signals which are queued in a dying task's pending queue, there is no reason to delay it further.

But it has to be ensured that no signals can be queued into it after that point. exit_signals() sets PF_EXITING in task::flags, which can be used as an indicator for this.

Cure it by:

- Preventing signal queueing for task private signals (PIDTYPE_PID) when the task has PF_EXITING set in __send_signal_locked() and in posixtimer_send_sigqueue().

- Protecting the unlocked setting of PF_EXITING in exit_signals() for the task group empty and the group exit case with sighand lock

- Flushing task::pending signals right there.

Optimize that by moving the whole pending list to an on-stack list head under sighand lock and free the signals without the lock held.

There has been quite some discussion about the lockless flush and the non-leader exec case on weakly ordered systems. The problem is that a third party which tries to send a posix timer signal relies on the PID lookup to find the target task and that lookup might result in the new leader when the signal was originaly directed to the old leader. In case that the signal was queued on the old leader then the lockless flush raised a concern over the following situation:

old_leader new_leader third party

A: flush_list() // list_del_init() stores to sigqueue

LOCK (tasklist)
old_leader->exit_state = EXIT_ZOMBIE;
B: UNLOCK (tasklist)

C: LOCK (tasklist)

			if (old_leader->exit_state)
			   transfer_tids()
D:			     store PID
						posix_timer_send_sigqueue()
						// Observes #D so t = new_leader

E: t = get_target()

F: LOCK (sighand)

G: if (list_empty(sigqueue))
list_add(sigqueue)

The concern was that the third party might observe #D but not observe #A and therefore would proceed to #G while the list_del() stores (#A) in flush_list() are not visible yet, which could result in list corruption.

That would be possible if looking at it solely from a RELEASE+ACQUIRE ordering point of view, but B-C is a UNLOCK+LOCK hand-over, which is not the same as RELEASE+ACQUIRE:

RELEASE+ACQUIRE: RCpc, only the CPUs involved agree on the ordering
UNLOCK+LOCK: RCtso, the hand-over is store-ordering

As B-C is UNLOCK+LOCK, which is RCtso and that does impose store order, A stores must happen before the D store.

Combine with E-F, which has a data dependency from the LOAD to the LOCK and thereby constraints later LOADs, those sigqueue loads in G that come after F must in fact observe the A stores.

---
 kernel/exit.c   |   11 ++---
 kernel/signal.c |  117 +++++++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 92 insertions(+), 36 deletions(-)
kernel/exit.c +6 -5
@@ -303,12 +303,13 @@ repeat:
 	free_pids(post.pids);
 	release_thread(p);
 	/*
-	 * This task was already removed from the process/thread/pid lists
-	 * and lock_task_sighand(p) can't succeed. Nobody else can touch
-	 * ->pending or, if group dead, signal->shared_pending. We can call
-	 * flush_sigqueue() lockless.
+	 * This task was already removed from the process/thread/pid lists and
+	 * lock_task_sighand(p) can't succeed. If it's the group leader then
+	 * flush tsk->signal->shared_pending. tsk->pending has been flushed
+	 * already in exit_signals(). Nothing else can touch
+	 * signal->shared_pending anymore, so flush_sigqueue() can be invoked
+	 * lockless.
 	 */
-	flush_sigqueue(&p->pending);
 	if (thread_group_leader(p))
 		flush_sigqueue(&p->signal->shared_pending);
 
kernel/signal.c +86 -31

188 lines not on this page · raw message

author maintainer
#255 lore raw

PATCH 252/438 rust: net: phy: fix off-by-one bit positions in device status accessors

In reply to Greg Kroah-Hartman

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

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

From: Chunfeng Song <[email protected]>

commit 6fb0a9d9071f1ff0cc5cfc0782302d9c90d642cb upstream.

The hand-written bitfield offsets in is_link_up(), is_autoneg_enabled() and is_autoneg_completed() were correct when the abstraction was
merged: at that time autoneg, link, and autoneg_complete were at bits 13, 14, and 15 of struct phy_device's first bitfield unit. Commit 2796ff1e3dca ("net: phy: add flag is_genphy_driven to struct phy_device") later inserted is_genphy_driven just before autoneg, shifting the three fields up by one, so the accessors now read:

is_link_up() reads bit 14 = autoneg
is_autoneg_enabled() reads bit 13 = is_genphy_driven
is_autoneg_completed() reads bit 15 = link

The official ax88796b Rust driver uses all three accessors in its read_status() implementation, so it inherits the bug. phy_attach_direct() sets is_genphy_driven only when it falls back to the generic driver, and ax88796b has a real driver, so is_genphy_driven stays 0. The broken is_autoneg_enabled() therefore reads bit 13 as 0, compares it against AUTONEG_ENABLE (1), and always returns false, so read_status() never reaches the resolve_aneg_linkmode() call.

The ordinary bindgen accessors take &self. Calling them through (*phydev).link() would create a shared reference to the complete bindings::phy_device, which is not appropriate for an object wrapped in Opaque.

Use the bindgen-generated raw accessors (link_raw(), autoneg_raw(), and autoneg_complete_raw()) instead. They retain the bit positions and endianness handling generated from the C layout without creating a Rust reference to the complete phy_device. Drop the hand-written numbers together with the TODO comment that marked them as a stopgap.

The raw accessors are only emitted by bindgen 0.71 and later, and were added at the Rust-for-Linux project's request, so this fix can only be backported to stable branches whose minimum bindgen version is at least that, hence the scope on the Cc: stable line below.

Found by a static equivalence audit (C2RustDrv, a C-to-Rust driver migration tool) that compares hand-written bitfield offsets against the bindgen layout of struct phy_device. Verified by building the bindings and checking the generated accessors; no runtime testing was possible without PHY hardware.

Fixes 2796ff1e3dca ("net: phy: add flag is_genphy_driven to struct phy_device")
Cc [email protected] # Only 7.1.y and later (requires bindgen's raw pointer accessors).
---
 rust/kernel/net/phy.rs |   38 ++++++++++++++++++--------------------
 1 file changed, 18 insertions(+), 20 deletions(-)
rust/kernel/net/phy.rs +18 -20
@@ -123,39 +123,37 @@ impl Device {
     /// Gets the current link state.
     ///
     /// It returns true if the link is up.
+    #[inline]
     pub fn is_link_up(&self) -> bool {
-        const LINK_IS_UP: u64 = 1;
-        // TODO: the code to access to the bit field will be replaced with automatically
-        // generated code by bindgen when it becomes possible.
-        // SAFETY: The struct invariant ensures that we may access
-        // this field without additional synchronization.
-        let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
-        bit_field.get(14, 1) == LINK_IS_UP
+        let phydev = self.0.get().cast_const();
+        // SAFETY: By the type invariant of `Device`, `phydev` points to a valid
+        // `struct phy_device`, and there is no concurrent write to this field.
+        let link = unsafe { bindings::phy_device::link_raw(phydev) };
+        link == 1
     }
 
     /// Gets the current auto-negotiation configuration.
     ///
     /// It returns true if auto-negotiation is enabled.
+    #[inline]
     pub fn is_autoneg_enabled(&self) -> bool {
-        // TODO: the code to access to the bit field will be replaced with automatically
-        // generated code by bindgen when it becomes possible.
-        // SAFETY: The struct invariant ensures that we may access
-        // this field without additional synchronization.
-        let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
-        bit_field.get(13, 1) == u64::from(bindings::AUTONEG_ENABLE)
+        let phydev = self.0.get().cast_const();
+        // SAFETY: By the type invariant of `Device`, `phydev` points to a valid
+        // `struct phy_device`, and there is no concurrent write to this field.
+        let autoneg = unsafe { bindings::phy_device::autoneg_raw(phydev) };
+        autoneg == bindings::AUTONEG_ENABLE
     }
 
     /// Gets the current auto-negotiation state.
     ///
     /// It returns true if auto-negotiation is completed.
+    #[inline]
     pub fn is_autoneg_completed(&self) -> bool {
-        const AUTONEG_COMPLETED: u64 = 1;
-        // TODO: the code to access to the bit field will be replaced with automatically
-        // generated code by bindgen when it becomes possible.
-        // SAFETY: The struct invariant ensures that we may access
-        // this field without additional synchronization.
-        let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
-        bit_field.get(15, 1) == AUTONEG_COMPLETED
+        let phydev = self.0.get().cast_const();
+        // SAFETY: By the type invariant of `Device`, `phydev` points to a valid
+        // `struct phy_device`, and there is no concurrent write to this field.
+        let completed = unsafe { bindings::phy_device::autoneg_complete_raw(phydev) };
+        completed == 1
     }
 
     /// Sets the speed of the PHY.
author maintainer
#256 lore raw

PATCH 253/438 Revert "nouveau/gsp: fix suspend/resume regression on r570 firmware"

In reply to Greg Kroah-Hartman

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

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

From: Lyude Paul <[email protected]>

commit a5c41fa7f925fda2db394329fa0b26243fa63a81 upstream.

This reverts commit 8302d0afeaec0bc57d951dd085e0cffe997d4d18.

It turns out this looked like the right fix on some systems, but it's not - as this causes runtime PM to actually fail on many a laptop.

Fixes 8302d0afeaec ("nouveau/gsp: fix suspend/resume regression on r570 firmware")
Cc <[email protected]> # v6.19+
(cherry picked from commit 94097122bfd701976bc1a62ccd434c13f3f67cde)
---
 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c |    2 +-
 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c  |    2 +-
 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/fbsr.c |    8 ++++----
 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h        |    2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c +1 -1
@@ -208,7 +208,7 @@ r535_fbsr_resume(struct nvkm_gsp *gsp)
 }
 
 static int
-r535_fbsr_suspend(struct nvkm_gsp *gsp, bool runtime)
+r535_fbsr_suspend(struct nvkm_gsp *gsp)
 {
 	struct nvkm_subdev *subdev = &gsp->subdev;
 	struct nvkm_device *device = subdev->device;
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c +1 -1
@@ -1749,7 +1749,7 @@ r535_gsp_fini(struct nvkm_gsp *gsp, enum
 		sr->sysmemAddrOfSuspendResumeData = gsp->sr.radix3.lvl0.addr;
 		sr->sizeOfSuspendResumeData = len;
 
-		ret = rm->api->fbsr->suspend(gsp, suspend == NVKM_RUNTIME_SUSPEND);
+		ret = rm->api->fbsr->suspend(gsp);
 		if (ret) {
 			nvkm_gsp_mem_dtor(&gsp->sr.meta);
 			nvkm_gsp_radix3_dtor(gsp, &gsp->sr.radix3);
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/fbsr.c +4 -4
@@ -62,7 +62,7 @@ r570_fbsr_resume(struct nvkm_gsp *gsp)
 }
 
 static int
-r570_fbsr_init(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size, bool runtime)
+r570_fbsr_init(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size)
 {
 	NV2080_CTRL_INTERNAL_FBSR_INIT_PARAMS *ctrl;
 	struct nvkm_gsp_object memlist;
@@ -81,7 +81,7 @@ r570_fbsr_init(struct nvkm_gsp *gsp, str
 	ctrl->hClient = gsp->internal.client.object.handle;
 	ctrl->hSysMem = memlist.handle;
 	ctrl->sysmemAddrOfSuspendResumeData = gsp->sr.meta.addr;
-	ctrl->bEnteringGcoffState = runtime ? 1 : 0;
+	ctrl->bEnteringGcoffState = 1;
 
 	ret = nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);
 	if (ret)
@@ -92,7 +92,7 @@ r570_fbsr_init(struct nvkm_gsp *gsp, str
 }
 
 static int
-r570_fbsr_suspend(struct nvkm_gsp *gsp, bool runtime)
+r570_fbsr_suspend(struct nvkm_gsp *gsp)
 {
 	struct nvkm_subdev *subdev = &gsp->subdev;
 	struct nvkm_device *device = subdev->device;
@@ -133,7 +133,7 @@ r570_fbsr_suspend(struct nvkm_gsp *gsp,
 		return ret;
 
 	/* Initialise FBSR on RM. */
-	ret = r570_fbsr_init(gsp, &gsp->sr.fbsr, size, runtime);
+	ret = r570_fbsr_init(gsp, &gsp->sr.fbsr, size);
 	if (ret) {
 		nvkm_gsp_sg_free(device, &gsp->sr.fbsr);
 		return ret;
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h +1 -1
@@ -79,7 +79,7 @@ struct nvkm_rm_api {
 	} *device;
 
 	const struct nvkm_rm_api_fbsr {
-		int (*suspend)(struct nvkm_gsp *, bool runtime);
+		int (*suspend)(struct nvkm_gsp *);
 		void (*resume)(struct nvkm_gsp *);
 	} *fbsr;
 
author maintainer
#257 lore raw

PATCH 254/438 drm/nouveau/gsp: Increase delay for magic sleep in r535_gsp_fini()

In reply to Greg Kroah-Hartman

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

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

From: Lyude Paul <[email protected]>

commit bbb9293c9bb792f3f16c842f223b8c97bdbaf227 upstream.

As it turns out, Turing isn't the only architecture that needs this. On this Dell Precision 7780 with an AD103 GPU, along with pretty much every other laptop I tested, runtime PM is still somewhat unreliable. At first glance it seems as if it's fixed, but lowering the autosuspend delay to 500ms and then doing a stress test of suspend/resume cycles on the GPU ends up causing everything to start timing out.

After quite a lot of digging, I eventually landed back on this magic timeout in r535_gsp_fini(). As it turns out, increasing the timeout ends up fixing the runtime PM issues as far as I can tell, even during intense stress testing.

Unfortunately after spending quite a bit of time trying to dig through OpenRM to figure out what this magic sleep is actually doing, I've also come up short with any reasonable explanation. In lieu of that, I'm going to include the observations I did make while trying to figure this out in hopes someone eventually does figure this out:

* The magic sleep has to occur after fbsr is initialized. Performing it at any time before that doesn't appear to work.
* In situations where runtime PM starts getting flaky, some rather interesting visual effects end up happening on occasion before the GPU fully falls over. In particular, squares that look like the result of an incomplete blitting operation to a tiled buffer end up showing up on applications like vkcube. Interestingly enough, they remain in precisely the same place between runtime PM cycles until the GPU falls over - even when restarting vkcube multiple times, and even when vkcube is actively updating the screen. Even more interestingly, they're not limited to a specific framebuffer - you can see the squares changing as the cube rotates around.
We cannot however, say that this is likely to be a incomplete fbsr operation. The magic sleep happens before fbsr is actually saved (which happens on the GSP unload), so it's something else.
* During a short bit of testing with a desktop that I have, the magic sleep seemed to make no difference to whether or not suspend/resume works. It seems to generally work almost always. So we can assume this is likely exclusive to runtime PM, not S3.

As well, here's a list of the things I tried before settling on the magic sleep:

* Hooking up NV2080_CTRL_CMD_INTERNAL_GCX_ENTRY_PREREQUISITE and then blocking runtime PM until OpenRM signals that GC6/GCOFF is ready appears to make no difference.
* Hooking up some (maybe not all, unsure about that part) bits of comptag saving including:
* Fetching static memsys information from GSP
* Adding the size of the comptag storage to the fbsr data
* Adding a GA103+ workaround for disabling raw compression mode during fbsr (it doesn't seem like it applies for any systems I tried it on anyhow)
* Setting bPreserveVideoMemoryAllocations=1 in GspSystemInfo

So, until we can figure this out properly - just sleep for longer.

Fixes 53dac0623853 ("drm/nouveau/gsp: add support for 570.144")
Cc <[email protected]> # v6.16+
(cherry picked from commit 09b47186a4164f3aaa3591313f80794443117342)
---
 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c +5 -1
@@ -1761,8 +1761,12 @@ r535_gsp_fini(struct nvkm_gsp *gsp, enum
 		 * TODO: Debug the GSP firmware / RPC handling to find out why
 		 * without this Turing (but none of the other architectures)
 		 * ends up resetting all channels after resume.
+		 * Additionally, runtime suspend on other architectures quickly
+		 * becomes unreliable without this sleep. If you're experiencing
+		 * issues with runtime suspend, try bumping this delay up and
+		 * sending a patch if it fixes your GPU.
 		 */
-		msleep(50);
+		msleep(200);
 	}
 
 	ret = r535_gsp_rpc_unloading_guest_driver(gsp, suspend);
author maintainer
#258 lore raw

PATCH 255/438 drm/nouveau/gsp/r570: Set GcOff = 0 in fbsr

In reply to Greg Kroah-Hartman

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

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

From: Lyude Paul <[email protected]>

commit 12f6eff11ccf9cad3b2dfcdd94184fdb9ffface2 upstream.

Previously, it looked as if we were able to fix suspend/resume on some desktops by setting Gcoff based on whether or not we were entering runtime PM. This was a mistake though - the only time suspend/resume would end up actually working was if Gcoff = 0.

It seems like it's likely the main reason for this is the FBSR GcOff argument actually controls GSP's behavior with regards to which buffers it decides to save across suspend/resume. When GcOff = 1, RM reserved regions are saved unless they are marked as LOST_ON_SUSPEND, and RM channel-context and kernel-client buffers are also saved -including- when they are LOST_ON_SUSPEND. This means with GcOff = 1, we end up having GSP save and restore buffers that actually need to be reinitialized on resume - causing the failures we're setting.

Thanks to John Hubbard from Nvidia for providing some background on what these options do in the GSP firmware do!

Fixes 53dac0623853 ("drm/nouveau/gsp: add support for 570.144")
Cc <[email protected]> # v6.16+
(cherry picked from commit c7abe771e013848970421e5ca29c6b2f05c31965)
---
 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/fbsr.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/fbsr.c +1 -1
@@ -81,7 +81,7 @@ r570_fbsr_init(struct nvkm_gsp *gsp, str
 	ctrl->hClient = gsp->internal.client.object.handle;
 	ctrl->hSysMem = memlist.handle;
 	ctrl->sysmemAddrOfSuspendResumeData = gsp->sr.meta.addr;
-	ctrl->bEnteringGcoffState = 1;
+	ctrl->bEnteringGcoffState = 0;
 
 	ret = nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);
 	if (ret)
author maintainer
#259 lore raw

PATCH 256/438 drm/nouveau/gsp/r570: Enable S/R Display workaround in GSP

In reply to Greg Kroah-Hartman

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

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

From: Lyude Paul <[email protected]>

commit 24fbd6d4bcf3363ef13ebe0d36dea93f30396c6d upstream.

There's two flags that we've never been setting when asking GSP to suspend the GPU, which OpenRM does set:

GPU_STATE_FLAGS_PRESERVING
GPU_STATE_FLAGS_PM_TRANSITION

These flags aren't -supposed- to do much in GSP, they're mostly used by OpenRM itself for state tracking. The only thing they do from GSP's side is control whether or not a single display related workaround is applied during suspend.

But as it turns out, that single workaround is actually quite crucial for getting runtime PM working with nouveau - and without it set we end up seeing a lot more failures with runtime PM resume. So, let's start setting it.

Fixes 53dac0623853 ("drm/nouveau/gsp: add support for 570.144")
Cc <[email protected]> # v6.16+
(cherry picked from commit ca57629b3eb912c77bc4357178a2130ea6c2d6df)
---
 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c      |    3 ++-
 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/nvrm/gsp.h |    8 ++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c +2 -1
@@ -207,7 +207,8 @@ r570_gsp_set_rmargs(struct nvkm_gsp *gsp
 		args->srInitArguments.bInPMTransition = 0;
 	} else {
 		args->srInitArguments.oldLevel = NV2080_CTRL_GPU_SET_POWER_STATE_GPU_LEVEL_3;
-		args->srInitArguments.flags = 0;
+		args->srInitArguments.flags =
+			GPU_STATE_FLAGS_PRESERVING | GPU_STATE_FLAGS_PM_TRANSITION;
 		args->srInitArguments.bInPMTransition = 1;
 	}
 
drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/nvrm/gsp.h +8 -0
@@ -523,6 +523,14 @@ typedef struct
 
 #define NV2080_CTRL_GPU_SET_POWER_STATE_GPU_LEVEL_3            (0x00000003U)
 
+#define GPU_STATE_FLAGS_PRESERVING         BIT(0)  // GPU state is preserved
+#define GPU_STATE_FLAGS_VGA_TRANSITION     BIT(1)   // To be used with GPU_STATE_FLAGS_PRESERVING.
+#define GPU_STATE_FLAGS_PM_TRANSITION      BIT(2)   // To be used with GPU_STATE_FLAGS_PRESERVING.
+#define GPU_STATE_FLAGS_PM_SUSPEND         BIT(3)
+#define GPU_STATE_FLAGS_PM_HIBERNATE       BIT(4)
+#define GPU_STATE_FLAGS_GC6_TRANSITION     BIT(5)  // To be used with GPU_STATE_FLAGS_PRESERVING.
+#define GPU_STATE_FLAGS_FAST_UNLOAD        BIT(6)  // Used during windows restart, skips stateDestroy steps
+
 typedef struct
 {
     // Magic for verification by secure ucode
author maintainer
#260 lore raw

PATCH 257/438 x86/build/64: Prevent native builds from generating EGPR use

In reply to Greg Kroah-Hartman

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

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

From: Chang S. Bae <[email protected]>

commit 63edf5a009ae366369a1b484cd9ae4ee7c51946c upstream.

Omar reports that CONFIG_X86_NATIVE_CPU=y allows builds to opportunistically emit instructions using %r16-%r31 (EGPRs) when the build host supports APX since the commit:

ea1dcca1de12 ("x86/kbuild/64: Add the CONFIG_X86_NATIVE_CPU option to locally optimize the kernel with '-march=native'")

But the kernel is not yet prepared to use new registers internally. For example, there is no context-switch support for general in-kernel use.

Explicitly disable EGPR use when building with -march=native.

For C, since GCC 14 and Clang 18, both compilers support suppressing EGPR use with -mno-apx-features=egpr, whose availability can be detected via cc-option.

For Rust, pass features=-apxf through the generated JSON to avoid unstable-feature warnings, see

https://github.com/rust-lang/rust/issues/139284

Note Rust only accepts the option to disable APX instructions entirely or not.

Support for this gating also depends on the Rust/LLVM combination. Rust 1.88 introduced the apxf feature option, but versions prior to 1.93 may emit an apxf attribute to the backend that only LLVM 23 or later can interpret. Restrict native Rust builds accordingly.

Fixes ea1dcca1de12 ("x86/kbuild/64: Add the CONFIG_X86_NATIVE_CPU option to locally optimize the kernel with '-march=native'")
---
 arch/x86/Kconfig.cpu            |   11 +++++++++++
 arch/x86/Makefile               |    5 +++++
 scripts/generate_rust_target.rs |    5 +++++
 3 files changed, 21 insertions(+)
arch/x86/Kconfig.cpu +11 -0
@@ -204,10 +204,21 @@ config CC_HAS_MARCH_NATIVE
 	# usage warnings that only appear wth '-march=native'.
 	depends on CC_IS_GCC || CLANG_VERSION >= 190100
 
+config RUSTC_HAS_APXF
+	# The kernel isn't ready for in-kernel APX instructions. Without
+	# explicit frontend gating of APX, the backend may emit those
+	# instructions in native builds.
+	#
+	# Rust 1.88 added the `apxf` feature option, but versions before 1.93
+	# emit an `apxf` target attribute that only LLVM 23+ can interpret.
+	def_bool (RUSTC_VERSION >= 108800 && RUSTC_LLVM_MAJOR_VERSION >= 23) || \
+		 RUSTC_VERSION >= 109300
+
 config X86_NATIVE_CPU
 	bool "Build and optimize for local/native CPU"
 	depends on X86_64
 	depends on CC_HAS_MARCH_NATIVE
+	depends on !RUST || RUSTC_HAS_APXF
 	help
 	  Optimize for the current CPU used to compile the kernel.
 	  Use this option if you intend to build the kernel for your
arch/x86/Makefile +5 -0
@@ -161,6 +161,11 @@ else
 
 ifdef CONFIG_X86_NATIVE_CPU
         KBUILD_CFLAGS += -march=native
+        # Prevent the compiler from generating EGPR use. The kernel is
+        # not yet prepared for general in-kernel use.
+        KBUILD_CFLAGS += $(call cc-option,-mno-apx-features=egpr)
+
+        # generate_rust_target.rs handles Rust APX gating.
         KBUILD_RUSTFLAGS += -Ctarget-cpu=native
 else
         KBUILD_CFLAGS += -march=x86-64 -mtune=generic
scripts/generate_rust_target.rs +5 -0
@@ -224,6 +224,11 @@ fn main() {
             features += ",+harden-sls-ijmp";
             features += ",+harden-sls-ret";
         }
+        if cfg.has("X86_NATIVE_CPU") {
+            // Prevent the backend from generating APX instructions. The kernel is not yet prepared
+            // for general in-kernel EGPR use.
+            features += ",-apxf";
+        }
         ts.push("features", features);
         ts.push("llvm-target", "x86_64-linux-gnu");
         ts.push("supported-sanitizers", ["kcfi", "kernel-address"]);
author maintainer
#261 lore raw

PATCH 258/438 x86/microcode/intel: Reject problematic loading on Granite Rapids systems

In reply to Greg Kroah-Hartman

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

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

From: Chang S. Bae <[email protected]>

commit e7d3e2f46dd5a69046e6d95a0f189155a5516b93 upstream.

Microcode updates can usually jump revisions. However, there is an erratum on Granite Rapids systems. If they "jump over" revision 0x1000405, they result in an #MC. Avoid it.

---
 arch/x86/kernel/cpu/microcode/intel.c |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
arch/x86/kernel/cpu/microcode/intel.c +26 -0
@@ -345,6 +345,26 @@ static void save_microcode_patch(struct
 		pr_err("Unable to allocate microcode memory size: %u\n", size);
 }
 
+static bool revision_is_safe(struct cpu_signature *sig, u32 rev)
+{
+	u32 vfm = IFM(x86_family(sig->sig), x86_model(sig->sig));
+
+	/*
+	 * Erratum GNR98 can cause #MCs if "jumping over" revision 0x1000405.
+	 * Avoid the jumps.
+	 */
+	if (vfm == INTEL_GRANITERAPIDS_X &&
+	    x86_stepping(sig->sig) == 1 &&
+	    sig->pf & 0x95 &&
+	    sig->rev < 0x1000405 &&
+	    rev > 0x1000405) {
+		pr_err_once("Erratum GNR98: skipping revision 0x%x.\n", rev);
+		return false;
+	}
+
+	return true;
+}
+
 /* Scan blob for microcode matching the boot CPUs family, model, stepping */
 static __init struct microcode_intel *scan_microcode(void *data, size_t size,
 						     struct ucode_cpu_info *uci,
@@ -366,6 +386,9 @@ static __init struct microcode_intel *sc
 		if (!intel_find_matching_signature(data, &uci->cpu_sig))
 			continue;
 
+		if (!revision_is_safe(&uci->cpu_sig, mc_header->rev))
+			continue;
+
 		/*
 		 * For saving the early microcode, find the matching revision which
 		 * was loaded on the BSP.
@@ -914,6 +937,9 @@ static enum ucode_state parse_microcode_
 		if (!intel_find_matching_signature(mc, &uci->cpu_sig))
 			continue;
 
+		if (!revision_is_safe(&uci->cpu_sig, mc_header.rev))
+			continue;
+
 		is_safe = ucode_validate_minrev(&mc_header);
 		if (force_minrev && !is_safe)
 			continue;
author maintainer
#262 lore raw

PATCH 259/438 tcp: exclude old ACKs from tcp fast path

In reply to Greg Kroah-Hartman

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

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

From: Inbal Schussheim <[email protected]>

commit f81e6c3fb06327bc49cdd6e559845293ba06a704 upstream.

Exclude old ACKs before SND.UNA from the tcp fast path as well as ACKs after SND.NXT.

Such ACKs will fall through to the slow path, where tcp_ack() performs the appropriate validation and challenge ACK handling according to RFC5961 and Commit 3d501dd326fb1c7 ("tcp: do not accept ACK of bytes we never sent").

This prevents old ACKs from being accepted
or modifying connection state as part of the fast path before appropriate ACK validation is applied.
In particular, this prevents payload carried by a segment with an excessively old ACK from advancing RCV.NXT before the ACK is rejected.

---
 net/ipv4/tcp_input.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/ipv4/tcp_input.c +2 -1
@@ -6490,6 +6490,7 @@ reset:
  *	  or pure receivers (this means either the sequence number or the ack
  *	  value must stay constant)
  *	- Unexpected TCP option.
+ *	- ACK sequence number is outside [SND.UNA, SND.NXT].
  *
  *	When these conditions are not satisfied it drops into a standard
  *	receive procedure patterned after RFC793 to handle all cases.
@@ -6539,7 +6540,7 @@ void tcp_rcv_established(struct sock *sk
 
 	if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
 	    TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&
-	    !after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) {
+	    between(TCP_SKB_CB(skb)->ack_seq, tp->snd_una, tp->snd_nxt)) {
 		int tcp_header_len = tp->tcp_header_len;
 		s32 delta = 0;
 		int flag = 0;
author maintainer
#263 lore raw

PATCH 260/438 swiotlb: use the adjusted address for the highmem page lookup

In reply to Greg Kroah-Hartman

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

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

From: Donggeun Yoo <[email protected]>

commit b7d7914a9ae3097e63d113007e4fb44d33d515b1 upstream.

swiotlb_bounce() reads the page frame number from the slot's recorded orig_addr, then advances orig_addr by tlb_offset to reach the address the caller asked about. The highmem branch mixes the two: the offset within the page comes from the adjusted address, the page from the value before it.

Once the adjustment crosses a page boundary the pair no longer describes one location, and the whole copy lands one page below the intended one for a positive tlb_offset, one above for a negative one. DMA_FROM_DEVICE writes the device data over the wrong page and leaves the intended one stale, DMA_TO_DEVICE feeds the device from a page the mapping may not cover. Partial syncs through dma_sync_single_range_for_*() are what make tlb_offset non-zero.

The branch test is picked the same way, so a slot recorded in lowmem can be adjusted into highmem and the lowmem path then hands a highmem address to phys_to_virt().

Take both from orig_addr once it is final and keep pfn in the branch that uses it. PhysHighMem() asks the question straight from the address, as dma-debug already does.

---
 kernel/dma/swiotlb.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/dma/swiotlb.c +2 -2
@@ -867,7 +867,6 @@ static void swiotlb_bounce(struct device
 	int index = (tlb_addr - mem->start) >> IO_TLB_SHIFT;
 	phys_addr_t orig_addr = mem->slots[index].orig_addr;
 	size_t alloc_size = mem->slots[index].alloc_size;
-	unsigned long pfn = PFN_DOWN(orig_addr);
 	unsigned char *vaddr = mem->vaddr + tlb_addr - mem->start;
 	int tlb_offset;
 
@@ -900,7 +899,8 @@ static void swiotlb_bounce(struct device
 		size = alloc_size;
 	}
 
-	if (PageHighMem(pfn_to_page(pfn))) {
+	if (PhysHighMem(orig_addr)) {
+		unsigned long pfn = PFN_DOWN(orig_addr);
 		unsigned int offset = orig_addr & ~PAGE_MASK;
 		struct page *page;
 		unsigned int sz = 0;
author maintainer
#264 lore raw

PATCH 261/438 soundwire: dmi-quirks: Disable ghost Realtek on Asus GX651AX

In reply to Greg Kroah-Hartman

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

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

From: Ian Luites <[email protected]>

commit 6d49beec658f61801e79019fd73691b17252dee3 upstream.

The Asus ROG Zephyrus Duo GX651AX exposes a Realtek RT722 device in ACPI which does not exist in the physical hardware. The device remains unattached while the CS42L43 and both CS35L56 devices attach successfully.

This confuses the function topology machine driver into creating duplicate DAI links named SDW3-Playback-SimpleJack, and the sof_sdw probe fails with error -12. Add a model-specific quirk to remove the ghost RT722 device.

Fixes 45cf24da0a10 ("ASoC: Intel: soc-acpi-intel-ptl-match: Remove unnecessary cs42l43 match")
Assisted-by LLM
---
 drivers/soundwire/dmi-quirks.c |    7 +++++++
 1 file changed, 7 insertions(+)
drivers/soundwire/dmi-quirks.c +7 -0
@@ -194,6 +194,13 @@ static const struct dmi_system_id adr_re
 	},
 	{
 		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
+			DMI_MATCH(DMI_BOARD_NAME, "GX651AX"),
+		},
+		.driver_data = (void *)ghost_realtek,
+	},
+	{
+		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "83SF"),
 		},
author maintainer
#265 lore raw

PATCH 262/438 spi: fsl-qspi: Reprogram the clock rate when the operation frequency changes

In reply to Greg Kroah-Hartman

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

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

From: Frieder Schrempf <[email protected]>

commit 3d743adf090cd4c9a2120c1e02b0482e88aa0d2d upstream.

fsl_qspi_select_mem() returns early when the chip select has not changed, which happens before it reaches clk_set_rate(). Since the rate is now taken from the spi-mem operation rather than from the SPI device, the controller honours op->max_freq exactly once per chip select and ignores it for every operation after that.

q->selected is only reset to -1 in fsl_qspi_default_setup(), i.e. at probe and on resume, so on the common single chip select board the very first operation latches a rate that all subsequent operations inherit, whatever frequency they asked for.

This results in operations being issued with the wrong frequency.

Cache the operation frequency the clock was programmed for next to the selected chip select, and redo the clock setup when either changes.

Fixes 2438db5253eb ("spi: fsl-qspi: Support per spi-mem operation frequency switches")
Assisted-by Claude:claude-opus-5
---
 drivers/spi/spi-fsl-qspi.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/spi/spi-fsl-qspi.c +4 -1
@@ -289,6 +289,7 @@ struct fsl_qspi {
 	struct pm_qos_request pm_qos_req;
 	struct device *dev;
 	int selected;
+	u32 selected_freq;
 	u32 memmap_phy;
 };
 
@@ -551,7 +552,8 @@ static void fsl_qspi_select_mem(struct f
 	unsigned long rate = op->max_freq;
 	int ret;
 
-	if (q->selected == spi_get_chipselect(spi, 0))
+	if (q->selected == spi_get_chipselect(spi, 0) &&
+	    q->selected_freq == op->max_freq)
 		return;
 
 	if (needs_4x_clock(q))
@@ -571,6 +573,7 @@ static void fsl_qspi_select_mem(struct f
 	}
 
 	q->selected = spi_get_chipselect(spi, 0);
+	q->selected_freq = op->max_freq;
 
 	fsl_qspi_invalidate(q);
 }
author maintainer
#266 lore raw

PATCH 263/438 spi: spi-zynqmp-gqspi: stop the controller on shutdown

In reply to Greg Kroah-Hartman

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

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

From: Itai Handler <[email protected]>

commit e922bad8b2d5028c51a096d083fea41cd0987154 upstream.

The driver has no ->shutdown, and platform_drv_shutdown() has no fallback of its own. Unlike pci_device_shutdown(), which clears bus mastering when kexec_in_progress, nothing on the platform bus disarms a device that can still write to memory. The normal kexec path never calls ->suspend either, so the quiesce in zynqmp_qspi_suspend() is not reached.

A controller that is still executing a DMA read may therefore keep writing to memory across a kexec. QSPIDMA_DST_ADDR still points at memory owned by the kernel that called kexec, DST_SIZE is non-zero and the flash is still clocked, so data can keep landing in RAM while the new kernel is being relocated, and after it has started executing.

That destination is a physical address which means nothing to the new kernel, so the writes can corrupt whatever now occupies it: kernel text or data, page tables, or the initrd. Nothing reports an error and the resulting behaviour is undefined.

This can be observed by reading GQSPI_EN (offset 0x114) and QSPIDMA_DST_ADDR/SIZE/STS/CTRL (offsets 0x800 to 0x80c) early in the new kernel, before the driver probes: without this patch GQSPI_EN reads 1 and QSPIDMA_DST_ADDR still points into the previous kernel's memory.

Add a ->shutdown that stops the controller the way zynqmp_qspi_suspend() already does. spi_controller_suspend() stops the queue, waits for a message that is already executing and makes any later transfer fail with -ESHUTDOWN, so nothing can be cut short by the register write that follows. It may sleep, which is fine here: device_shutdown() runs in process context. Unlike ->suspend this cannot abort on error, because a controller left mastering the bus is worse than a truncated transfer, so a failure to drain is only logged.

GQSPI_EN_OFST is then cleared, as zynqmp_qspi_remove() and zynqmp_qspi_suspend() already do. Skip that write only when pm_runtime_get_if_in_use() returns 0, i.e. runtime suspended: the clocks are gated, so the registers are unreachable and the controller cannot be mastering the bus. A negative return is not the same thing - it is what the CONFIG_PM=n stub always returns, and there probe() has enabled pclk and refclk for good, so the controller is running and must be stopped.

Fixes dfe11a11d523 ("spi: Add support for Zynq Ultrascale+ MPSoC GQSPI controller")
---
 drivers/spi/spi-zynqmp-gqspi.c |   34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)
drivers/spi/spi-zynqmp-gqspi.c +34 -0
@@ -1374,11 +1374,45 @@ static void zynqmp_qspi_remove(struct pl
 	clk_disable_unprepare(xqspi->pclk);
 }
 
+static void zynqmp_qspi_shutdown(struct platform_device *pdev)
+{
+	struct zynqmp_qspi *xqspi = platform_get_drvdata(pdev);
+	int ret;
+
+	/*
+	 * Stop the queue and reject any later transfer first, so the write
+	 * below cannot cut into a message that is still being executed.
+	 * Unlike ->suspend this cannot abort on error: a controller left
+	 * mastering the bus is worse than a truncated transfer.
+	 */
+	ret = spi_controller_suspend(xqspi->ctlr);
+	if (ret)
+		dev_warn(&pdev->dev, "could not stop the queue: %d\n", ret);
+
+	/*
+	 * Only a runtime suspended controller can be left alone: its clocks
+	 * are gated, so it cannot be mastering the bus, and its registers
+	 * must not be accessed either.  Any other answer means it may be
+	 * running and has to be stopped.  In particular, on a kernel built
+	 * without runtime PM this returns -EINVAL, and there the clocks
+	 * enabled in probe() are never gated at all.
+	 */
+	ret = pm_runtime_get_if_in_use(&pdev->dev);
+	if (!ret)
+		return;
+
+	zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0);
+
+	if (ret > 0)
+		pm_runtime_put_noidle(&pdev->dev);
+}
+
 MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match);
 
 static struct platform_driver zynqmp_qspi_driver = {
 	.probe = zynqmp_qspi_probe,
 	.remove = zynqmp_qspi_remove,
+	.shutdown = zynqmp_qspi_shutdown,
 	.driver = {
 		.name = "zynqmp-qspi",
 		.of_match_table = zynqmp_qspi_of_match,
author maintainer
#267 lore raw

PATCH 264/438 spi: virtio: Use the per-transfer bits per word

In reply to Greg Kroah-Hartman

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

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

From: Hao-Qun Huang <[email protected]>

commit 095858324f063dba830041f067872f0a08765d2f upstream.

virtio_spi_transfer_one() puts spi->bits_per_word into the request header, so a transfer that sets its own word size reaches the backend with the device default instead. The SPI core has already copied that default into xfer->bits_per_word when the transfer leaves it at zero, the same way it does for xfer->speed_hz, which this function already uses.

Per-transfer word sizes are ordinary SPI usage. mipi_dbi, for one, sends a 9-bit command and reads the reply as 8-bit data in the same message. With a 16-bit device default, a one-byte transfer asking for 8 bits goes out as a partial 16-bit word, which the backend may reject.

---
 drivers/spi/spi-virtio.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/spi-virtio.c +1 -1
@@ -168,7 +168,7 @@ static int virtio_spi_transfer_one(struc
 
 	/* Fill struct spi_transfer_head */
 	th->chip_select_id = spi_get_chipselect(spi, 0);
-	th->bits_per_word = spi->bits_per_word;
+	th->bits_per_word = xfer->bits_per_word;
 	th->cs_change = xfer->cs_change;
 	th->tx_nbits = xfer->tx_nbits;
 	th->rx_nbits = xfer->rx_nbits;
author maintainer
#268 lore raw

PATCH 265/438 RDMA/ucma: Serialize join and leave on copy_to_user failure

In reply to Greg Kroah-Hartman

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

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

From: Quanye Yang <[email protected]>

commit 662ade4de9ff5eceb0820a9f8e9fac70ba6a815b upstream.

rdma_join_multicast() queues RoCE work that later reads the ucma_multicast through event->param.ud.private_data, then list_add()s the CMA multicast at the head of id_priv->mc_list. rdma_leave_multicast() matches only by sockaddr and destroys the first hit.

ucma_process_join() used to drop ctx->mutex after a successful join and retake it only if copy_to_user() failed. Two concurrent JOIN_MCAST calls with the same address can therefore insert a second CMA entry before the first thread's leave. leave then cancels the newer work and the older worker still dereferences the ucma_multicast that the first thread frees.

Keep ctx->mutex held from rdma_join_multicast() through copy_to_user() and, on -EFAULT, through rdma_leave_multicast() so leave cannot miss this join. Do not leave if join itself failed: that path never published this address on mc_list, and a leave-by-addr would destroy an earlier successful join.

---
 drivers/infiniband/core/ucma.c |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/infiniband/core/ucma.c +4 -3
@@ -1556,9 +1556,10 @@ static ssize_t ucma_process_join(struct
 	mutex_lock(&ctx->mutex);
 	ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *)&mc->addr,
 				  join_state, mc);
-	mutex_unlock(&ctx->mutex);
-	if (ret)
+	if (ret) {
+		mutex_unlock(&ctx->mutex);
 		goto err_xa_erase;
+	}
 
 	resp.id = mc->id;
 	if (copy_to_user(u64_to_user_ptr(cmd->response),
@@ -1566,6 +1567,7 @@ static ssize_t ucma_process_join(struct
 		ret = -EFAULT;
 		goto err_leave_multicast;
 	}
+	mutex_unlock(&ctx->mutex);
 
 	xa_store(&multicast_table, mc->id, mc, 0);
 
@@ -1573,7 +1575,6 @@ static ssize_t ucma_process_join(struct
 	return 0;
 
 err_leave_multicast:
-	mutex_lock(&ctx->mutex);
 	rdma_leave_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr);
 	mutex_unlock(&ctx->mutex);
 	ucma_cleanup_mc_events(mc);
author maintainer
#269 lore raw

PATCH 266/438 RDMA/core: fix refcount bug in iwpm_get_nlmsg_request()

In reply to Greg Kroah-Hartman

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

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

From: Jeffin Philip <[email protected]>

commit 33fb59da49c4c3f5c2ec9f9d4447a56857a02c02 upstream.

iwpm_get_nlmsg_request() initializes refcount _after_ list_add_tail() making it accessible to global list where another CPU can kref_get() on nlmsg_request causing a refcount "addition on 0" bug. Fix this by initializing kref _before_ list_add_tail() so refcount for nlmsg_request can be incremented/decremented normally. In addition, also initialize every field before list_add_tail().

---
 drivers/infiniband/core/iwpm_util.c |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/infiniband/core/iwpm_util.c +5 -4
@@ -314,10 +314,6 @@ struct iwpm_nlmsg_request *iwpm_get_nlms
 	if (!nlmsg_request)
 		return NULL;
 
-	spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
-	list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list);
-	spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
-
 	kref_init(&nlmsg_request->kref);
 	kref_get(&nlmsg_request->kref);
 	nlmsg_request->nlmsg_seq = nlmsg_seq;
@@ -326,6 +322,11 @@ struct iwpm_nlmsg_request *iwpm_get_nlms
 	nlmsg_request->err_code = 0;
 	sema_init(&nlmsg_request->sem, 1);
 	down(&nlmsg_request->sem);
+
+	spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
+	list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list);
+	spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
+
 	return nlmsg_request;
 }
 
author maintainer
#270 lore raw

PATCH 267/438 openvswitch: avoid reallocating confirmed conntrack labels

In reply to Greg Kroah-Hartman

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

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

From: Zhiling Zou <[email protected]>

commit 3f118c8217c109fd13ca61caa301d72c483897ef upstream.

ovs_ct_get_conn_labels() adds the labels extension when a conntrack entry does not have one. Confirmed conntracks can be read locklessly, so adding an extension may reallocate and free the extension block while another CPU accesses it.

Only add the extension for unconfirmed conntracks. A confirmed conntrack without labels now fails the caller's label operation instead of reallocating its extension storage.

---
 net/openvswitch/conntrack.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/openvswitch/conntrack.c +1 -1
@@ -366,7 +366,7 @@ static struct nf_conn_labels *ovs_ct_get
 	struct nf_conn_labels *cl;
 
 	cl = nf_ct_labels_find(ct);
-	if (!cl) {
+	if (!cl && !nf_ct_is_confirmed(ct)) {
 		nf_ct_labels_ext_add(ct);
 		cl = nf_ct_labels_find(ct);
 	}
author maintainer
#271 lore raw

PATCH 268/438 nfsd: fix handling of NFSEXP_PNFS in the netlink codepath

In reply to Greg Kroah-Hartman

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

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

From: Jeff Layton <[email protected]>

commit f76017a7663c4ce5e379f8a8d39f032bdb1fd865 upstream.

The rework of how block layouts were checked moved the check for NFSEXP_PNFS out of nfsd4_setup_layout_type() and into the callers. That patch didn't account for the new call in nfsd4_setup_layout_type().

Cc Christoph Hellwig <[email protected]>
Fixes da9baa5470dc ("exportfs,nfsd: rework checking for layout-based block device access support")
---
 fs/nfsd/export.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
fs/nfsd/export.c +2 -1
index a47c90f40422..1f678583f612 100644
@@ -1006,7 +1006,8 @@ static int nfsd_nl_parse_one_export(struct cache_detail *cd,
 			goto out_uuid;
 		err = 0;
 
-		nfsd4_setup_layout_type(&exp);
+		if (exp.ex_flags & NFSEXP_PNFS)
+			nfsd4_setup_layout_type(&exp);
 	}
 
 	expp = svc_export_lookup(&exp);
Signature · 1 line
2.55.0
author maintainer
#272 lore raw

PATCH 269/438 net: xfrm: reject unrepresentable espintcp transport headers

In reply to Greg Kroah-Hartman

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

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

From: Wyatt Feng <[email protected]>

commit 96f01b53c2d05e003b040892256de54a586e8529 upstream.

ESP-in-TCP can hand xfrm packets whose transport header offset no longer fits after the stream parser trims the TCP envelope. The plain transport header reset truncates that offset and triggers the skb warning path.

Use the careful transport-header helper and drop the skb through the existing XFRM error path when the offset cannot be represented.

Fixes e27cca96cd68 ("xfrm: add espintcp (RFC 8229)")
Assisted-by Codex:GPT-5.4
---
 net/xfrm/espintcp.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
net/xfrm/espintcp.c +5 -1
@@ -30,7 +30,11 @@ static void handle_esp(struct sk_buff *s
 {
 	struct tcp_skb_cb *tcp_cb = (struct tcp_skb_cb *)skb->cb;
 
-	skb_reset_transport_header(skb);
+	if (!skb_reset_transport_header_careful(skb)) {
+		XFRM_INC_STATS(sock_net(sk), LINUX_MIB_XFRMINERROR);
+		kfree_skb(skb);
+		return;
+	}
 
 	/* restore IP CB, we need at least IP6CB->nhoff */
 	memmove(skb->cb, &tcp_cb->header, sizeof(tcp_cb->header));
author maintainer
#273 lore raw

PATCH 270/438 kselftest/arm64: Fix size of thread_data values for pthread_join()

In reply to Greg Kroah-Hartman

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

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

From: Thomas Huth <[email protected]>

commit 3d1ba5cbfb622025690c218d8f20da92a9ecb383 upstream.

pthread_join() stores the thread's return value (a "void *", i.e. 8 bytes on 64 bit computers) into the address that is passed as second parameter. However, the entries of thread_data are only normal "int"s, i.e. only 4 bytes. The additional 4 bytes of the return value clobber whatever is adjacent on the stack, i.e. other members of the thread_data array (which will be re-written in the next iteration of the for-loop, so that nobody noticed this problem), or another other local variable on the stack for the last iteration. Use "intptr_t" to declare the thread_data array entries with the correct size.

Fixes 29f080881601c ("kselftest/arm64: check GCR_EL1 after context switch")
---
 tools/testing/selftests/arm64/mte/check_gcr_el1_cswitch.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/arm64/mte/check_gcr_el1_cswitch.c +1 -1
@@ -69,7 +69,7 @@ fail:
 int execute_test(pid_t pid)
 {
 	pthread_t thread_id[MAX_THREADS];
-	int thread_data[MAX_THREADS];
+	intptr_t thread_data[MAX_THREADS];
 
 	for (int i = 0; i < MAX_THREADS; i++)
 		pthread_create(&thread_id[i], NULL,
author maintainer
#274 lore raw

PATCH 271/438 arm64: hibernate: pass HVC_SET_VECTORS args to the resume hvc

In reply to Greg Kroah-Hartman

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

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

From: Bradley Morgan <[email protected]>

commit 955d86e5f3b95b731991fdb84966c50b16314629 upstream.

swsusp_arch_suspend_exit() reinstalls the restored kernel's hyp stub vectors with an hvc, but never passes the arguments. x0 is not set to HVC_SET_VECTORS and x1 is not set to the vector address, so the stub dispatch falls through and returns without writing vbar_el2. EL2 is left pointing at the trans_pgd copy of the vectors, a page that swsusp_free() releases right after resume.

Set the arguments up the same way __hyp_set_vectors() does.

Without this fix, Vladimir was able to trigger a hang when resuming from hibernation with CONFIG_PAGE_POISONING=y and page_poison=on.

Fixes 788bfdd97434 ("arm64: trans_pgd: hibernate: Add trans_pgd_copy_el2_vectors")
---
 arch/arm64/kernel/hibernate-asm.S |    2 ++
 1 file changed, 2 insertions(+)
arch/arm64/kernel/hibernate-asm.S +2 -0
@@ -89,6 +89,8 @@ alternative_insn "dc cvau, x4",  "dc civ
 	isb
 
 	cbz	x24, 3f		/* Do we need to re-initialise EL2? */
+	mov	x1, x24
+	mov	x0, #HVC_SET_VECTORS
 	hvc	#0
 3:	ret
 SYM_CODE_END(swsusp_arch_suspend_exit)
author maintainer
#275 lore raw

PATCH 272/438 arm64: dts: renesas: r8a779f0: Set UFS lane count

In reply to Greg Kroah-Hartman

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

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

From: Koichiro Den <[email protected]>

commit 8dc2615d5702059b2b71fca6f93c0d7d10ae54cb upstream.

Since commit e72323f3b09f ("scsi: ufs: core: Configure only active lanes during link"), the following error is observed on R-Car S4:

ufshcd-renesas e6860000.ufs: Tx lane mismatch [config,reported] [2,1] ufshcd-renesas e6860000.ufs: link startup failed -67
ufshcd-renesas e6860000.ufs: error -ENOLINK: Initialization failed with error -67 ufshcd-renesas e6860000.ufs: probe with driver ufshcd-renesas failed with error -67

R-Car S4 has one UFS lane per direction, as described in section 152.1 of its hardware manual. Without lanes-per-direction, the UFS platform driver defaults to two lanes.

Previously, the core used PA_CONNECTEDRXDATALANES and PA_CONNECTEDTXDATALANES to configure the link without checking them against lanes-per-direction, so the missing property did not prevent initialization.

Explicitly set lanes-per-direction to 1, now that the validation is in place.

---
 arch/arm64/boot/dts/renesas/r8a779f0.dtsi |    1 +
 1 file changed, 1 insertion(+)
arch/arm64/boot/dts/renesas/r8a779f0.dtsi +1 -0
@@ -901,6 +901,7 @@
 			clocks = <&cpg CPG_MOD 1514>, <&ufs30_clk>;
 			clock-names = "fck", "ref_clk";
 			freq-table-hz = <200000000 200000000>, <38400000 38400000>;
+			lanes-per-direction = <1>;
 			power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
 			resets = <&cpg 1514>;
 			status = "disabled";
author maintainer
#276 lore raw

PATCH 273/438 arm64: dts: socfpga: change access permission from 755 to 644

In reply to Greg Kroah-Hartman

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

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

From: Dinh Nguyen <[email protected]>

commit 5f8cb07d7a8573753c5d31dc76b51cab8e5e9460 upstream.

These files have an incorrect access permission of 755 instead of 644. Change them to the correct access permission of 644.

Fixes 4bc04eb90b7c ("arm64: dts: socfpga: stratix10: Add emmc support")
Cc <[email protected]> # v7.1+
---
 arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dtsi     | 0
 arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_emmc.dts | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 mode change 100755 => 100644 arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dtsi
 mode change 100755 => 100644 arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_emmc.dts
arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dtsi +0 -0
old mode 100755
new mode 100644
arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_emmc.dts +0 -0
old mode 100755
new mode 100644
Signature · 1 line
2.55.0
author maintainer
#277 lore raw

PATCH 274/438 arm64: percpu: Fix this_cpu_write() casting

In reply to Greg Kroah-Hartman

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

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

From: Mark Rutland <[email protected]>

commit 885bff055a0f251a51a0d4fd4f0a7b525582a3de upstream.

The arm64 implementation of this_cpu_write() casts 'val' to unsigned long. This is necessary to handle cases where 'val' is a pointer type, and to avoid spurious compiler warnings for the (unreachable!) cases where the pointer type would be cast to a smaller integer type.

Unfortunately, the cast is applied to 'val' rather than '(val)', which won't always generate the expected value when 'val' is an expression.

For example, for this_cpu_write(pcp, zero - 1), where 'pcp' is a u64 and 'zero' is a u32:

* 'zero'                      ===> (u32) 0x00000000
* 'zero - 1'                  ===> (u32) 0xffffffff
* '(unsigned long)zero - 1'   ===> (u64) 0xffffffffffffffff

* '(unsigned long)(zero - 1)' ===> (u64) 0x00000000ffffffff

Fix this by adding brackets around 'val'.

Fixes 959bf2fd03b5 ("arm64: percpu: Rewrite per-cpu ops to allow use of LSE atomics")
Cc Ada Couprie Diaz <[email protected]>
Cc Ard Biesheuvel <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc James Morse <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Vladimir Murzin <[email protected]>
Cc Will Deacon <[email protected]>
Cc Yang Shi <[email protected]>
---
 arch/arm64/include/asm/percpu.h |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/include/asm/percpu.h +4 -4
@@ -179,13 +179,13 @@ PERCPU_RET_OP(add, add, ldadd)
 	_pcp_protect_return(__percpu_read_64, pcp)
 
 #define this_cpu_write_1(pcp, val)	\
-	_pcp_protect(__percpu_write_8, pcp, (unsigned long)val)
+	_pcp_protect(__percpu_write_8, pcp, (unsigned long)(val))
 #define this_cpu_write_2(pcp, val)	\
-	_pcp_protect(__percpu_write_16, pcp, (unsigned long)val)
+	_pcp_protect(__percpu_write_16, pcp, (unsigned long)(val))
 #define this_cpu_write_4(pcp, val)	\
-	_pcp_protect(__percpu_write_32, pcp, (unsigned long)val)
+	_pcp_protect(__percpu_write_32, pcp, (unsigned long)(val))
 #define this_cpu_write_8(pcp, val)	\
-	_pcp_protect(__percpu_write_64, pcp, (unsigned long)val)
+	_pcp_protect(__percpu_write_64, pcp, (unsigned long)(val))
 
 #define this_cpu_add_1(pcp, val)	\
 	_pcp_protect(__percpu_add_case_8, pcp, val)
author maintainer
#278 lore raw

PATCH 275/438 arm64: percpu: Fix this_cpu_and() mask generation

In reply to Greg Kroah-Hartman

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

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

From: Mark Rutland <[email protected]>

commit 44274c657256b4911de82f8104e9e22f054cf742 upstream.

The arm64 implementation of this_cpu_and(pcp, val) is built in terms of ANDNOT operations, which requires the 'val' argument to be bitwise negated. The bitwise negation is not implemented correctly, with two bugs described below.

(1) The bitwise negation is performed as '~val' rather than '~(val)'. This won't always generate the expected value when 'val' is an expression.

For example, for this_cpu_and(pcp, 1 - 1):

* 'val' is '1 - 1' ===> (int) 0x00000000
* '~val' is '~1 - 1' ===> (int) 0xfffffffd
* '~(val)' is '~(1 - 1)' ===> (int) 0xffffffff

... and thus bit[1] of 'pcp' would be preserved unexpectedly by the ANDNOT operation.

(2) The bitwise negation is performed on 'val' before it has been cast to (at least) the width of 'pcp'. This won't always generate the expected value for the upper bits.

For example, for this_cpu_and(pcp, zero), where 'pcp' is a u64 and 'zero' is a u32:

* 'zero' ===> (u32) 0x00000000
* '~(zero)' ===> (u32) 0xffffffff
* '(u64)~(zero)' ===> (u64) 0x00000000ffffffff
* '~((u64)(zero))' ===> (u64) 0xffffffffffffffff

... and thus bits[63:32] of 'pcp' would be preserved unexpectedly by the ANDNOT operation.

Fix these issues by adding brackets around 'val', and by casting 'val' to an appropriately-sized type before bitwise negation.

Fixes 959bf2fd03b5 ("arm64: percpu: Rewrite per-cpu ops to allow use of LSE atomics")
Cc Ada Couprie Diaz <[email protected]>
Cc Ard Biesheuvel <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc James Morse <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Vladimir Murzin <[email protected]>
Cc Will Deacon <[email protected]>
Cc Yang Shi <[email protected]>
---
 arch/arm64/include/asm/percpu.h |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/include/asm/percpu.h +4 -4
@@ -206,13 +206,13 @@ PERCPU_RET_OP(add, add, ldadd)
 	_pcp_protect_return(__percpu_add_return_case_64, pcp, val)
 
 #define this_cpu_and_1(pcp, val)	\
-	_pcp_protect(__percpu_andnot_case_8, pcp, ~val)
+	_pcp_protect(__percpu_andnot_case_8, pcp, ~(u8)(val))
 #define this_cpu_and_2(pcp, val)	\
-	_pcp_protect(__percpu_andnot_case_16, pcp, ~val)
+	_pcp_protect(__percpu_andnot_case_16, pcp, ~(u16)(val))
 #define this_cpu_and_4(pcp, val)	\
-	_pcp_protect(__percpu_andnot_case_32, pcp, ~val)
+	_pcp_protect(__percpu_andnot_case_32, pcp, ~(u32)(val))
 #define this_cpu_and_8(pcp, val)	\
-	_pcp_protect(__percpu_andnot_case_64, pcp, ~val)
+	_pcp_protect(__percpu_andnot_case_64, pcp, ~(u64)(val))
 
 #define this_cpu_or_1(pcp, val)		\
 	_pcp_protect(__percpu_or_case_8, pcp, val)
author maintainer
#279 lore raw

PATCH 276/438 arm64: percpu: Fix LSE operations on {8,16}-bit types

In reply to Greg Kroah-Hartman

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

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

From: Mark Rutland <[email protected]>

commit 8cf2093f5372952a9ebc805c418d45df7112cd14 upstream.

The assembly for __percpu_##name##_case_##sz() and __percpu_##name##_return_case_##sz() doesn't use the 'sfx' macro argument to form the LSE instruction. Without 'sfx', a W register argument will imply a 32-bit memory location, and consequently {8,16}-bit ops will erroneously read and write 32 bits of memory when the LSE instruction is used.

Fix this by appending 'sfx' to 'op_lse' to LSE instruction. It is not necessary (and not valid) to append 'sfx' to 'op_llsc', as 'op_llsc' is a register-register operation which does not access memory (and does not take a size suffix).

Fixes 959bf2fd03b5 ("arm64: percpu: Rewrite per-cpu ops to allow use of LSE atomics")
Cc Ada Couprie Diaz <[email protected]>
Cc Ard Biesheuvel <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc James Morse <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Vladimir Murzin <[email protected]>
Cc Will Deacon <[email protected]>
Cc Yang Shi <[email protected]>
---
 arch/arm64/include/asm/percpu.h |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/include/asm/percpu.h +2 -2
@@ -77,7 +77,7 @@ __percpu_##name##_case_##sz(void *ptr, u
 	"	stxr" #sfx "\t%w[loop], %" #w "[tmp], %[ptr]\n"		\
 	"	cbnz	%w[loop], 1b",					\
 	/* LSE atomics */						\
-		#op_lse "\t%" #w "[val], %" #w "[tmp], %[ptr]\n"	\
+		#op_lse #sfx "\t%" #w "[val], %" #w "[tmp], %[ptr]\n"	\
 		__nops(3))						\
 	: [loop] "=&r" (loop), [tmp] "=&r" (tmp),			\
 	  [ptr] "+Q"(*(u##sz *)ptr)					\
@@ -98,7 +98,7 @@ __percpu_##name##_return_case_##sz(void
 	"	stxr" #sfx "\t%w[loop], %" #w "[ret], %[ptr]\n"		\
 	"	cbnz	%w[loop], 1b",					\
 	/* LSE atomics */						\
-		#op_lse "\t%" #w "[val], %" #w "[ret], %[ptr]\n"	\
+		#op_lse #sfx "\t%" #w "[val], %" #w "[ret], %[ptr]\n"	\
 		#op_llsc "\t%" #w "[ret], %" #w "[ret], %" #w "[val]\n"	\
 		__nops(2))						\
 	: [loop] "=&r" (loop), [ret] "=&r" (ret),			\
author maintainer
#280 lore raw

PATCH 277/438 Bluetooth: btusb: fix NXP IW610 composite device handling

In reply to Greg Kroah-Hartman

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

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

From: Nicolas Thibert <[email protected]>

commit 2b50adefed9808a56d84d1de803cad882cc787fa upstream.

The NXP IW610 module exposes itself as a composite USB device (0471:0215) with three interfaces: two real Bluetooth HCI interfaces (class 0xe0) and one vendor-specific WiFi interface (class 0xff) used by mwifiex-nxp.

The composite device's whole USB descriptor reports class 0xe0/01/01 (Bluetooth), so btusb_table's generic USB_DEVICE_INFO(0xe0, 0x01, 0x01) entry matches every interface, not just the two real HCI ones -- btusb ends up binding the WiFi interface too, and mwifiex-nxp never gets it.

Fix:
1. In btusb_table (the table the USB core actually matches against), explicitly ignore the WiFi interface via BTUSB_IGNORE, ahead of the generic entry.
2. In quirks_table, scope the existing BTUSB_MARVELL entry to the BT interface class instead of matching the whole device by VID/PID (harmless either way since quirks_table isn't consulted for initial binding, but keep it correct).

Not upstream anywhere: checked NXP's own i.MX kernel fork (nxp-imx/linux-imx), no IW610 references in btusb.c on any branch -- their reference designs wire this chip differently (WiFi over SDIO per their release notes), so they never hit this.

---
 drivers/bluetooth/btusb.c |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)
drivers/bluetooth/btusb.c +17 -0
@@ -71,6 +71,15 @@ static struct usb_driver btusb_driver;
 #define BTUSB_BROKEN_EXT_SCAN		BIT(29)
 
 static const struct usb_device_id btusb_table[] = {
+	/*
+	 * NXP IW610 (0471:0215): the composite device reports Bluetooth
+	 * class at the whole-device level, so the generic entry below
+	 * would also match this WiFi vendor interface. Ignore it here
+	 * first so mwifiex-nxp can bind it instead.
+	 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xff, 0xff, 0xff),
+	  .driver_info = BTUSB_IGNORE },
+
 	/* Generic Bluetooth USB device */
 	{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
 
@@ -475,6 +484,14 @@ static const struct usb_device_id quirks
 	{ USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
 	{ USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL },
 
+	/*
+	 * NXP IW610 BT interfaces (Marvell-lineage silicon, same quirk as
+	 * the 0x1286 entries above). Scoped to the BT interface class,
+	 * not just VID/PID -- see the btusb_table entry above.
+	 */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xe0, 0x01, 0x01),
+	  .driver_info = BTUSB_MARVELL },
+
 	/* Intel Bluetooth devices */
 	{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED },
 	{ USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_COMBINED },
author maintainer
#281 lore raw

PATCH 278/438 Bluetooth: eir: validate service data length before reading UUID

In reply to Greg Kroah-Hartman

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

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

From: Aamir Ahmed <[email protected]>

commit e8241766794cf551d787fa3a77c0d54bbea6f6aa upstream.

eir_get_service_data() reads a 16-bit UUID from the service data using get_unaligned_le16() without first checking that the data is long enough to hold a UUID16 (2 bytes). If a malformed EIR entry has a service data field with only 1 byte of payload (field_len=2), eir_get_data() returns dlen=1. The subsequent get_unaligned_le16() then reads 1 byte past the field boundary.

Additionally, if the corrupted UUID happens to match, the length calculation "dlen - 2" underflows to SIZE_MAX since dlen is size_t. Current callers either pass NULL for the length parameter or bounds-check the returned length, but future callers may not.

Add a check that dlen >= sizeof(u16) and skip fields that are too short to contain a valid UUID16.

Fixes 8f9ae5b3ae80 ("Bluetooth: eir: Add helpers for managing service data")
---
 net/bluetooth/eir.c |   10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
net/bluetooth/eir.c +9 -1
@@ -373,7 +373,15 @@ void *eir_get_service_data(u8 *eir, size
 	size_t dlen;
 
 	while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, &dlen))) {
-		u16 value = get_unaligned_le16(eir);
+		u16 value;
+
+		if (dlen < sizeof(value)) {
+			eir += dlen;
+			eir_len = eir_end - eir;
+			continue;
+		}
+
+		value = get_unaligned_le16(eir);
 
 		if (uuid == value) {
 			if (len)
author maintainer
#282 lore raw

PATCH 279/438 Bluetooth: hci_codec: validate vendor codec count length

In reply to Greg Kroah-Hartman

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

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

From: Laxman Acharya Padhya <[email protected]>

commit d0795cfd6f655f4de84868a4f4bb41a03f037b3d upstream.

The Read Local Supported Codecs parsers consume the variable-sized standard codec array before parsing the vendor codec count. Although the initial reply-size check includes a vendor count byte in the fixed layout, it does not guarantee that the byte remains after the standard codec array.

If a controller reply ends immediately after that array, calculating the vendor codec array size reads vnd_codecs->num beyond the skb data. Use skb_pull_data() to validate and consume each codec header before using its count in both command variants.

Fixes 8961987f3f5f ("Bluetooth: Enumerate local supported codec and cache details")
Fixes 9ae664028a9e ("Bluetooth: Add support for Read Local Supported Codecs V2")
---
 net/bluetooth/hci_codec.c |   36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)
net/bluetooth/hci_codec.c +18 -18
@@ -145,11 +145,12 @@ void hci_read_supported_codecs(struct hc
 
 	skb_pull(skb, sizeof(rp->status));
 
-	std_codecs = (void *)skb->data;
+	std_codecs = skb_pull_data(skb, sizeof(*std_codecs));
+	if (!std_codecs)
+		goto error;
 
 	/* validate codecs length before accessing */
-	if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
-	    + sizeof(std_codecs->num))
+	if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num))
 		goto error;
 
 	/* enumerate codec capabilities of standard codecs */
@@ -161,15 +162,14 @@ void hci_read_supported_codecs(struct hc
 					    LOCAL_CODEC_ACL_MASK | LOCAL_CODEC_SCO_MASK, &caps);
 	}
 
-	skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
-		 + sizeof(std_codecs->num));
+	skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num));
 
-	vnd_codecs = (void *)skb->data;
+	vnd_codecs = skb_pull_data(skb, sizeof(*vnd_codecs));
+	if (!vnd_codecs)
+		goto error;
 
 	/* validate vendor codecs length before accessing */
-	if (skb->len <
-	    flex_array_size(vnd_codecs, codec, vnd_codecs->num)
-	    + sizeof(vnd_codecs->num))
+	if (skb->len < flex_array_size(vnd_codecs, codec, vnd_codecs->num))
 		goto error;
 
 	/* enumerate vendor codec capabilities */
@@ -214,11 +214,12 @@ void hci_read_supported_codecs_v2(struct
 
 	skb_pull(skb, sizeof(rp->status));
 
-	std_codecs = (void *)skb->data;
+	std_codecs = skb_pull_data(skb, sizeof(*std_codecs));
+	if (!std_codecs)
+		goto error;
 
 	/* check for payload data length before accessing */
-	if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
-	    + sizeof(std_codecs->num))
+	if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num))
 		goto error;
 
 	memset(&caps, 0, sizeof(caps));
@@ -229,15 +230,14 @@ void hci_read_supported_codecs_v2(struct
 					    &caps);
 	}
 
-	skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
-		 + sizeof(std_codecs->num));
+	skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num));
 
-	vnd_codecs = (void *)skb->data;
+	vnd_codecs = skb_pull_data(skb, sizeof(*vnd_codecs));
+	if (!vnd_codecs)
+		goto error;
 
 	/* check for payload data length before accessing */
-	if (skb->len <
-	    flex_array_size(vnd_codecs, codec, vnd_codecs->num)
-	    + sizeof(vnd_codecs->num))
+	if (skb->len < flex_array_size(vnd_codecs, codec, vnd_codecs->num))
 		goto error;
 
 	for (i = 0; i < vnd_codecs->num; i++) {
author maintainer
#283 lore raw

PATCH 280/438 Bluetooth: hci_sync: Serialize local codec list cleanup

In reply to Greg Kroah-Hartman

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

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

From: Chengfeng Ye <[email protected]>

commit 9a10987a2f160a44a638c9a35994ca6e3089696e upstream.

hci_dev_close_sync() clears hdev->local_codecs after releasing hdev->lock. Codec list additions and both traversals in sco_sock_getsockopt() use that lock, but the close path does not. A close and BT_CODEC query can therefore interleave as follows:

hci_dev_close_sync() sco_sock_getsockopt()
hci_dev_lock()
fetch codec entry
hci_codec_list_clear()

    kfree(entry)
                                read entry->id

The reader then accesses an entry which the close path has freed. KASAN reported:

  BUG: KASAN: slab-use-after-free in sco_sock_getsockopt+0xfa0/0xfe0
  Read of size 1 at addr ffff8881001c3450
  Call Trace:
   sco_sock_getsockopt+0xfa0/0xfe0
   do_sock_getsockopt+0x537/0x7b0
   __sys_getsockopt+0xf2/0x170
  Allocated by task 92:
   hci_codec_list_add.isra.0+0x2c/0x440
   hci_read_codec_capabilities+0x224/0x590
   hci_read_supported_codecs+0x2c2/0x640
  Freed by task 92:
   kfree+0x131/0x3c0
   hci_codec_list_clear+0xd8/0x160
   hci_dev_close_sync+0x92a/0xfa0

Take hdev->lock around the clear operation at its existing point in the close path. This makes the clear wait for active readers and prevents a new traversal until the list is empty without changing teardown ordering.

Fixes b938790e7054 ("Bluetooth: hci_codec: Fix leaking content of local_codecs")
---
 net/bluetooth/hci_sync.c |    2 ++
 1 file changed, 2 insertions(+)
net/bluetooth/hci_sync.c +2 -0
@@ -5587,7 +5587,9 @@ int hci_dev_close_sync(struct hci_dev *h
 	memset(hdev->eir, 0, sizeof(hdev->eir));
 	memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
 	bacpy(&hdev->random_addr, BDADDR_ANY);
+	hci_dev_lock(hdev);
 	hci_codec_list_clear(&hdev->local_codecs);
+	hci_dev_unlock(hdev);
 
 	hci_dev_put(hdev);
 	return err;
author maintainer
#284 lore raw

PATCH 281/438 Bluetooth: keep dst_type with dst when reusing an LE connection

In reply to Greg Kroah-Hartman

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

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

From: Radek Podgorny <[email protected]>

commit 555cd2bd860e7c4bdc3f4e4405b05515b0d9bc87 upstream.

hci_connect_le() swaps the caller's identity address for the peer's cached RPA when one is known, and stamps the matching ADDR_LE_DEV_RANDOM on the local dst_type. On the conn-reuse path only the address is copied into the connection:

  if (conn) {
          bacpy(&conn->dst, dst);

so conn->dst ends up holding an RPA while conn->dst_type still names the identity it was resolved from, and hci_le_create_conn_sync() puts that pair on air unchanged. An RPA declared as a public address is not something any peer can answer.

Measured on a CYW43438 against a peer advertising an RPA the host holds the IRK for, connecting to the identity address over a raw L2CAP socket. The first attempt creates the connection, the second takes the reuse path:

  LE Create Connection  3C:78:95:78:37:C3  type public
  LE Create Connection  5B:75:A2:26:D6:18  type public

LE Connection Complete: Unknown Connection Identifier (0x02)

The second address is the peer's RPA. btmon annotates it with an OUI lookup rather than "(Resolvable)" precisely because the command declares it public; the same bit pattern annotates as resolvable once the type is right.

The mistyped pair is also why nothing downstream repairs it. hci_bdaddr_is_rpa() tests the type before the address, so an RPA carrying a public type is not recognised as one, and hci_find_irk_by_addr() then searches for an identity address that does not match it either.

Copy the type along with the address.

The assignment used to be unconditional just below this block and covered both paths; it moved into hci_conn_add_unset(), which the reuse path does not go through.

Fixes 14b06c3a88f7 ("Bluetooth: HCI: Always use the identity address when initializing a connection")
Assisted-by Claude:claude-opus-5
---
 net/bluetooth/hci_conn.c |    8 ++++++++
 1 file changed, 8 insertions(+)
net/bluetooth/hci_conn.c +8 -0
@@ -1518,7 +1518,15 @@ struct hci_conn *hci_connect_le(struct h
 	}
 
 	if (conn) {
+		/* dst may just have been swapped for the peer's RPA above, and
+		 * dst_type describes dst -- it has to travel with it. Leaving
+		 * the identity type behind makes the pair describe a peer that
+		 * does not exist, and nothing downstream repairs it:
+		 * hci_bdaddr_is_rpa() tests the type before the address, so
+		 * the RPA is never treated as one.
+		 */
 		bacpy(&conn->dst, dst);
+		conn->dst_type = dst_type;
 	} else {
 		conn = hci_conn_add_unset(hdev, LE_LINK, dst, dst_type, role);
 		if (IS_ERR(conn))
author maintainer
#285 lore raw

PATCH 282/438 btrfs: take commit root semaphore when iterating in mark_block_group_to_copy()

In reply to Greg Kroah-Hartman

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

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

From: Hongling Zeng <[email protected]>

commit 0594e3423f4ba3137c734371169491f9a98e9af4 upstream.

mark_block_group_to_copy() iterates over the commit root with skip_locking=true. A concurrent transaction commit can swap and free the commit root during iteration, causing use-after-free when accessing extent buffers.

Fix it by using path->need_commit_sem to protect the commit root search.

Fixes 78ce9fc269af ("btrfs: zoned: mark block groups to copy for device-replace")
Assisted-by Codex:gpt-5.5
---
 fs/btrfs/dev-replace.c |    1 +
 1 file changed, 1 insertion(+)
fs/btrfs/dev-replace.c +1 -0
@@ -493,6 +493,7 @@ static int mark_block_group_to_copy(stru
 	path->reada = READA_FORWARD;
 	path->search_commit_root = true;
 	path->skip_locking = true;
+	path->need_commit_sem = true;
 
 	key.objectid = src_dev->devid;
 	key.type = BTRFS_DEV_EXTENT_KEY;
author maintainer
#286 lore raw

PATCH 283/438 btrfs: fix creation of compressed inline extents that dont save space

In reply to Greg Kroah-Hartman

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

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

From: Filipe Manana <[email protected]>

commit cc337324cc6be1ce0ae7e5a068dcb7e99ae1b59c upstream.

If the compressed data of an inline extent is larger than or equals to the size of the uncompressed data, we are still allowing the creation of the compressed inline extent, which does not result in any benefits, quite the contrary as we waste metadata space and have to decompress when reading.

This is a recent regression introduced in commit 3eaf5f082c4c ("btrfs:
extract inlined creation into a dedicated delalloc helper").

It happens because we are passing the block size to btrfs_compress_bio(), so we don't get -E2BIG from the compression code anymore, but we can not pass i_size either, because if i_size is smaller than sector size, we end up never creating lzo compressed inline extent for such small i_size values. So refuse the compressed result at run_delalloc_inline() if its size is not smaller than the uncompressed size (i_size).

Fixes 3eaf5f082c4c ("btrfs: extract inlined creation into a dedicated delalloc helper")
---
 fs/btrfs/inode.c |   15 +++++++++++++++
 1 file changed, 15 insertions(+)
fs/btrfs/inode.c +15 -0
@@ -2338,12 +2338,27 @@ static int run_delalloc_inline(struct bt
 		} else if (inode->prop_compress) {
 			compress_type = inode->prop_compress;
 		}
+		/*
+		 * We need to pass blocksize and not i_size, otherwise we can't
+		 * create compressed inline extents for data smaller than sector
+		 * size with lzo.
+		 */
 		cb = btrfs_compress_bio(inode, 0, blocksize, compress_type, compress_level, 0);
 		if (IS_ERR(cb)) {
 			cb = NULL;
 			/* Just fall back to non-compressed case. */
 		} else {
 			compressed_size = cb->bbio.bio.bi_iter.bi_size;
+			/*
+			 * If we did not save space, it's pointless and wasteful
+			 * to have an inline compressed extent, so fallback to
+			 * an uncompressed inline extent.
+			 */
+			if (compressed_size >= i_size) {
+				cleanup_compressed_bio(cb);
+				cb = NULL;
+				compressed_size = 0;
+			}
 		}
 	}
 	if (!can_cow_file_range_inline(inode, 0, i_size, compressed_size)) {
author maintainer
#287 lore raw

PATCH 284/438 btrfs: derive f_fsid with dev_t only when temp_fsid is active

In reply to Greg Kroah-Hartman

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

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

From: Anand Jain <[email protected]>

commit 72de4807ba84da485dda1a91572d66da9149e95a upstream.

Commit c2a74ed0494c ("btrfs: derive f_fsid from on-disk fsid and dev_t") mixed dev_t into f_fsid for all single-device setups to avoid f_fsid collisions with cloned filesystems.

However, doing this unconditionally breaks backward compatibility. statfs(2) f_fsid changes after a kernel upgrade, and also can shift across reboots or dev re-attaches as dev_t values change.

Fix this by only mixing dev_t when temp_fsid is active. This means for non-temp_fsid setups or the original mount, we use the old method of deriving fsid based on the UUID.

So in the case of a cloned Btrfs filesystem, we won't be able to maintain the same fsid across mount recycle if the mount order changes.

---
 fs/btrfs/super.c |    8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
fs/btrfs/super.c +6 -2
@@ -1845,8 +1845,12 @@ static int btrfs_statfs(struct dentry *d
 	f_fsid.val[0] ^= btrfs_root_id(BTRFS_I(d_inode(dentry))->root) >> 32;
 	f_fsid.val[1] ^= btrfs_root_id(BTRFS_I(d_inode(dentry))->root);
 
-	/* Hash dev_t to avoid f_fsid collision with cloned filesystems. */
-	if (fs_info->fs_devices->total_devices == 1) {
+	/*
+	 * Hash dev_t to avoid f_fsid collisions with cloned filesystems.
+	 * Only do this when a clone is present so the original filesystem
+	 * (mounted first) maintains backward-compatible f_fsid behavior.
+	 */
+	if (fs_info->fs_devices->temp_fsid) {
 		__kernel_fsid_t dev_fsid =
 			u64_to_fsid(huge_encode_dev(fs_info->fs_devices->latest_dev->bdev->bd_dev));
 
author maintainer
#288 lore raw

PATCH 285/438 btrfs: clear free space tree creation state on rebuild failure

In reply to Greg Kroah-Hartman

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

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

From: Guanghui Yang <[email protected]>

commit 3565893cc72cdf6b795cf6a33e7ff9605322334d upstream.

btrfs_rebuild_free_space_tree() sets BTRFS_FS_CREATING_FREE_SPACE_TREE before rebuilding the free space tree. Several error paths return without clearing this flag.

The transaction restart failure path can leave the flag set on a live filesystem, causing delayed reference processing to be skipped. Clear it on all free space tree rebuild failure paths. Keep BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED set, since a failed rebuild leaves the free space tree untrusted. Callers must fall back to extent-tree caching.

Fixes 882af9f13e83 ("btrfs: handle free space tree rebuild in multiple transactions")
Assisted-by LLM
---
 fs/btrfs/free-space-tree.c |   14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)
fs/btrfs/free-space-tree.c +10 -4
@@ -1353,7 +1353,7 @@ int btrfs_rebuild_free_space_tree(struct
 	if (unlikely(ret)) {
 		btrfs_abort_transaction(trans, ret);
 		btrfs_end_transaction(trans);
-		return ret;
+		goto out_clear;
 	}
 
 	node = rb_first_cached(&fs_info->block_group_cache_tree);
@@ -1371,14 +1371,16 @@ int btrfs_rebuild_free_space_tree(struct
 		if (unlikely(ret)) {
 			btrfs_abort_transaction(trans, ret);
 			btrfs_end_transaction(trans);
-			return ret;
+			goto out_clear;
 		}
 next:
 		if (btrfs_should_end_transaction(trans)) {
 			btrfs_end_transaction(trans);
 			trans = btrfs_start_transaction(free_space_root, 1);
-			if (IS_ERR(trans))
-				return PTR_ERR(trans);
+			if (IS_ERR(trans)) {
+				ret = PTR_ERR(trans);
+				goto out_clear;
+			}
 		}
 		node = rb_next(node);
 	}
@@ -1390,6 +1392,10 @@ next:
 	ret = btrfs_commit_transaction(trans);
 	clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
 	return ret;
+
+out_clear:
+	clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
+	return ret;
 }
 
 static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
author maintainer
#289 lore raw

PATCH 286/438 gpiolib: Put fwnode reference on failure

In reply to Greg Kroah-Hartman

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

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

From: Michail Tatas <[email protected]>

commit 16b10f64c63f78220c3b4035f1ed6cd3bdcb0b02 upstream.

We get a reference to the fwnode handle which we pass to gpio_shared_make_ref. In case it fails we do not put the reference. Fix by putting the reference in the failure case

Fixes 49416483a953 ("gpio: shared: allow sharing a reset-gpios pin between reset-gpio and gpiolib")
---
 drivers/gpio/gpiolib-shared.c |    9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/gpio/gpiolib-shared.c +6 -3
@@ -261,10 +261,13 @@ static int gpio_shared_of_traverse(struc
 				con_id[con_id_len - suffix_len] = '\0';
 			}
 
-			ref = gpio_shared_make_ref(fwnode_handle_get(of_fwnode_handle(curr)),
-						   con_id, args.args[1]);
-			if (!ref)
+			struct fwnode_handle *curr_fwnode =
+				fwnode_handle_get(of_fwnode_handle(curr));
+			ref = gpio_shared_make_ref(curr_fwnode, con_id, args.args[1]);
+			if (!ref) {
+				fwnode_handle_put(curr_fwnode);
 				return -ENOMEM;
+			}
 
 			if (!list_empty(&entry->refs))
 				pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n",
author maintainer
#290 lore raw

PATCH 287/438 gpiolib: of: dont mark hog nodes OF_POPULATED before a chip is found

In reply to Greg Kroah-Hartman

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

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

From: Abdurrahman Hussain <[email protected]>

commit 1f1d0812f6a8ab8e6f709c599f137c99646512cc upstream.

When a gpio-hog node is attached by a device-tree overlay before its parent GPIO chip has been registered, of_gpio_notify() sets OF_POPULATED on the node via of_node_test_and_set_flag() and only then discovers that there is no gpio_device for the parent, returning NOTIFY_DONE without clearing the flag.

Since gpiochip_hog_lines() skips any hog child whose of_node carries OF_POPULATED, the leaked flag makes the hog silently ignored when the chip is registered later. Applying an overlay containing both a GPIO controller node and its hog children - and populating devices only after the overlay apply completes - hits this on every boot; the hog is only applied if the chip driver is unbound (which clears the flag in the remove path) and rebound.

Look up the parent gpio_device before claiming the node so that a hog attached ahead of its chip stays unclaimed and is picked up normally by gpiochip_hog_lines() at registration time.

---
 drivers/gpio/gpiolib-of.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/gpio/gpiolib-of.c +3 -3
index 940b566946ce..f36e4b171fa7 100644
@@ -788,13 +788,13 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
 		if (!of_property_read_bool(rd->dn, "gpio-hog"))
 			return NOTIFY_DONE;	/* not for us */
 
-		if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
-			return NOTIFY_DONE;
-
 		gdev = of_find_gpio_device_by_node(rd->dn->parent);
 		if (!gdev)
 			return NOTIFY_DONE;	/* not for us */
 
+		if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
+			return NOTIFY_DONE;
+
 		ret = gpiochip_add_hog(gpio_device_get_chip(gdev), of_fwnode_handle(rd->dn));
 		if (ret < 0) {
 			pr_err("%s: failed to add hogs for %pOF\n", __func__,
Signature · 1 line
2.55.0
author maintainer
#291 lore raw

PATCH 288/438 dmaengine: sun6i: fix non-atomic read of DMA position registers

In reply to Greg Kroah-Hartman

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

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

From: Christian Lugnberg <[email protected]>

commit c90b6973daa37f4c283342dff881ae001dea4fe6 upstream.

sun6i_get_chan_size() reads DMA_CHAN_LLI_ADDR and DMA_CHAN_CUR_CNT in two separate readl() calls with no synchronisation between them:

    pos   = readl(pchan->base + DMA_CHAN_LLI_ADDR);
    bytes = readl(pchan->base + DMA_CHAN_CUR_CNT);

DMA_CHAN_LLI_ADDR holds the physical address of the *next* descriptor the engine will load once the current one completes. DMA_CHAN_CUR_CNT holds the remaining byte count for the *current* descriptor. If the DMA engine advances to the next LLI entry between the two reads, pos becomes stale: it still points to what was the next descriptor at the time of the first read, but that descriptor is now the current one and CUR_CNT reflects its initial (full) byte count. The subsequent virtual-chain walk starts one entry too early and accumulates an extra full period's worth of bytes into the residue estimate.

Fix this by re-reading DMA_CHAN_LLI_ADDR after DMA_CHAN_CUR_CNT and retrying if the value changed. This double-read pattern guarantees that both registers were sampled during the same descriptor interval. The cost is at most one extra readl() pair per call in the racy case, which occurs only at descriptor boundaries (~every 2 ms) and is negligible.

Fixes a90e173f3faf ("dmaengine: sun6i: Add cyclic capability")
Assisted-by Claude:claude-sonnet-4-6
---
 drivers/dma/sun6i-dma.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/dma/sun6i-dma.c +4 -2
@@ -354,8 +354,10 @@ static size_t sun6i_get_chan_size(struct
 	size_t bytes;
 	dma_addr_t pos;
 
-	pos = readl(pchan->base + DMA_CHAN_LLI_ADDR);
-	bytes = readl(pchan->base + DMA_CHAN_CUR_CNT);
+	do {
+		pos = readl(pchan->base + DMA_CHAN_LLI_ADDR);
+		bytes = readl(pchan->base + DMA_CHAN_CUR_CNT);
+	} while (pos != readl(pchan->base + DMA_CHAN_LLI_ADDR));
 
 	if (pos == LLI_LAST_ITEM)
 		return bytes;
author maintainer
#292 lore raw

PATCH 289/438 dmaengine: sun6i: fix undefined behaviour in sun6i_dma_tx_status

In reply to Greg Kroah-Hartman

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

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

From: Christian Lugnberg <[email protected]>

commit 9096bdc8d930147f7c39a493a859acbd3a8485d8 upstream.

sun6i_dma_tx_status() calls vchan_find_desc() to look up the virtual descriptor for a given cookie, before checking whether the pointer vd is NULL:

    vd = vchan_find_desc(&vchan->vc, cookie);
    txd = to_sun6i_desc(&vd->tx);   /* vd may be NULL here */

    if (vd) {
        for (lli = txd->v_lli; ...)

vchan_find_desc() returns NULL when the descriptor has already been completed or is in-flight on a physical channel and no longer present in the virtual channel's descriptor list. When vd is NULL, to_sun6i_desc() is called unconditionally on &vd->tx before the NULL check, which is undefined behaviour. Move the call inside the if (vd) guard to ensure it is only reached with a valid pointer.

    vd = vchan_find_desc(&vchan->vc, cookie);
    if (vd) {
        struct sun6i_desc *txd = to_sun6i_desc(&vd->tx);
        for (lli = txd->v_lli; ...)
Fixes 555859308723 ("dmaengine: sun6i: Add driver for the Allwinner A31 DMA controller")
Assisted-by Claude:claude-sonnet-4-6
---
 drivers/dma/sun6i-dma.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/dma/sun6i-dma.c +1 -2
@@ -981,7 +981,6 @@ static enum dma_status sun6i_dma_tx_stat
 	struct sun6i_pchan *pchan = vchan->phy;
 	struct sun6i_dma_lli *lli;
 	struct virt_dma_desc *vd;
-	struct sun6i_desc *txd;
 	enum dma_status ret;
 	unsigned long flags;
 	size_t bytes = 0;
@@ -993,9 +992,9 @@ static enum dma_status sun6i_dma_tx_stat
 	spin_lock_irqsave(&vchan->vc.lock, flags);
 
 	vd = vchan_find_desc(&vchan->vc, cookie);
-	txd = to_sun6i_desc(&vd->tx);
 
 	if (vd) {
+		struct sun6i_desc *txd = to_sun6i_desc(&vd->tx);
 		for (lli = txd->v_lli; lli != NULL; lli = lli->v_lli_next)
 			bytes += lli->len;
 	} else if (!pchan || !pchan->desc) {
author maintainer
#293 lore raw

PATCH 290/438 dmaengine: ti: k3-udma-glue: fix NULL dereference in k3_udma_glue_release_rx_chn()

In reply to Greg Kroah-Hartman

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

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

From: Alexander Chesnokov <[email protected]>

commit 0294b6dd515256c03ea2dbf508ddd3826d788579 upstream.

If devm_kcalloc() for rx_chn->flows fails in a channel request function, the error path calls k3_udma_glue_release_rx_chn(), which dereferences the NULL rx_chn->flows pointer in k3_udma_glue_release_rx_flow().

Skip the flow release loop in k3_udma_glue_release_rx_chn() when rx_chn->flows is not allocated.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

---
 drivers/dma/ti/k3-udma-glue.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/dma/ti/k3-udma-glue.c +3 -2
@@ -1243,8 +1243,9 @@ void k3_udma_glue_release_rx_chn(struct
 		rx_chn->psil_paired = false;
 	}
 
-	for (i = 0; i < rx_chn->flow_num; i++)
-		k3_udma_glue_release_rx_flow(rx_chn, i);
+	if (rx_chn->flows)
+		for (i = 0; i < rx_chn->flow_num; i++)
+			k3_udma_glue_release_rx_flow(rx_chn, i);
 
 	if (xudma_rflow_is_gp(rx_chn->common.udmax, rx_chn->flow_id_base))
 		xudma_free_gp_rflow_range(rx_chn->common.udmax,
author maintainer
#294 lore raw

PATCH 291/438 dma-buf/dma-fence: fix checking signaling bit for timeline and driver name v3

In reply to Greg Kroah-Hartman

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

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

From: Christian König <[email protected]>

commit 3ed11c671ff7ec58c8fd96410233c677df23f407 upstream.

The patch "dma-buf: dma-fence: Fix potential NULL pointer dereference" changed the check to test for the ops pointer instead of the signaled bit to avoid a potential NULL dereference when the ops pointer has been cleared.

The problem is now that the ops pointer is cleared only when neither the release nor the wait callback is implemented and this isn't true for a lot of dma_fence implementations yet. So those implementations lost the RCU protection after signaling of the returned string resulting in potential use after free.

Add the signaling check additional to the ops pointer check so that we have both the protection against NULL dereference as well as the RCU protection after signaling for the returned string.

v2: improve comments to note RCU protection and explain why we check
both signaling state and ops pointer
v3: some comment improvements suggested by Philip

---
 drivers/dma-buf/dma-fence.c |   14 ++++++++++++--
 include/linux/dma-fence.h   |    6 ++++++
 2 files changed, 18 insertions(+), 2 deletions(-)
drivers/dma-buf/dma-fence.c +12 -2
@@ -1168,7 +1168,12 @@ const char __rcu *dma_fence_driver_name(
 
 	/* RCU protection is required for safe access to returned string */
 	ops = rcu_dereference(fence->ops);
-	if (ops)
+
+	/*
+	 * Make load ordering irrelevant by checking both signaled state and ops
+	 * pointer and ops pointer is only set to NULL on newer implementations.
+	 */
+	if (!dma_fence_test_signaled_flag(fence) && ops)
 		return (const char __rcu *)ops->get_driver_name(fence);
 	else
 		return (const char __rcu *)"detached-driver";
@@ -1201,7 +1206,12 @@ const char __rcu *dma_fence_timeline_nam
 
 	/* RCU protection is required for safe access to returned string */
 	ops = rcu_dereference(fence->ops);
-	if (ops)
+
+	/*
+	 * Make load ordering irrelevant by checking both signaled state and ops
+	 * pointer and ops pointer is only set to NULL on newer implementations.
+	 */
+	if (!dma_fence_test_signaled_flag(fence) && ops)
 		return (const char __rcu *)ops->get_timeline_name(fence);
 	else
 		return (const char __rcu *)"signaled-timeline";
include/linux/dma-fence.h +6 -0
@@ -141,6 +141,9 @@ struct dma_fence_ops {
 	 * compute the name at runtime, without having it to store permanently
 	 * for each fence, or build a cache of some sort.
 	 *
+	 * The returned string is RCU protected and can be freed after the fence
+	 * signaled and a RCU grace period passed.
+	 *
 	 * This callback is mandatory.
 	 */
 	const char * (*get_driver_name)(struct dma_fence *fence);
@@ -153,6 +156,9 @@ struct dma_fence_ops {
 	 * having it to store permanently for each fence, or build a cache of
 	 * some sort.
 	 *
+	 * The returned string is RCU protected and can be freed after the fence
+	 * signaled and a RCU grace period passed.
+	 *
 	 * This callback is mandatory.
 	 */
 	const char * (*get_timeline_name)(struct dma_fence *fence);
author maintainer
#295 lore raw

PATCH 292/438 dma-buf: Fix silent overflow for phys vec to sgt

In reply to Greg Kroah-Hartman

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

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

From: David Hu <[email protected]>

commit b344ca94e8cc85796f16ea25e2e5a8e0303fe813 upstream.

In case MMIO size is bigger than 4G and peer2peer DMA goes through host bridge, we trigger a code path that assigns the total linked IOVA (which is greater than 4G) to mapped_len.

Previously, mapped_len was declared as 32-bit unsigned int. When accumulating size_t lengths, this leads to a silent wrap-around. This truncation causes truncated lengths to be passed to functions like fill_sg_entry().

Fix this by changing mapped_len to size_t (64-bit). While at it, fix similar potential overflow issues in calc_sg_nents by using check_add_overflow() for nents and using unsigned int for the loop iterator in fill_sg_entry to match.

---
 drivers/dma-buf/dma-buf-mapping.c |   16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)
drivers/dma-buf/dma-buf-mapping.c +12 -4
@@ -5,12 +5,13 @@
  */
 #include <linux/dma-buf-mapping.h>
 #include <linux/dma-resv.h>
+#include <linux/overflow.h>
 
 static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length,
 					 dma_addr_t addr)
 {
 	unsigned int len, nents;
-	int i;
+	unsigned int i;
 
 	nents = DIV_ROUND_UP(length, UINT_MAX);
 	for (i = 0; i < nents; i++) {
@@ -40,8 +41,12 @@ static unsigned int calc_sg_nents(struct
 	size_t i;
 
 	if (!state || !dma_use_iova(state)) {
-		for (i = 0; i < nr_ranges; i++)
-			nents += DIV_ROUND_UP(phys_vec[i].len, UINT_MAX);
+		for (i = 0; i < nr_ranges; i++) {
+			unsigned int added = DIV_ROUND_UP(phys_vec[i].len, UINT_MAX);
+
+			if (check_add_overflow(nents, added, &nents))
+				return 0;
+		}
 	} else {
 		/*
 		 * In IOVA case, there is only one SG entry which spans
@@ -95,9 +100,10 @@ struct sg_table *dma_buf_phys_vec_to_sgt
 					 size_t nr_ranges, size_t size,
 					 enum dma_data_direction dir)
 {
-	unsigned int nents, mapped_len = 0;
 	struct dma_buf_dma *dma;
 	struct scatterlist *sgl;
+	size_t mapped_len = 0;
+	unsigned int nents;
 	dma_addr_t addr;
 	size_t i;
 	int ret;
@@ -133,6 +139,8 @@ struct sg_table *dma_buf_phys_vec_to_sgt
 	}
 
 	nents = calc_sg_nents(dma->state, phys_vec, nr_ranges, size);
+
+	/* sg_alloc_table will cleanly fail and return -EINVAL if nents == 0 */
 	ret = sg_alloc_table(&dma->sgt, nents, GFP_KERNEL | __GFP_ZERO);
 	if (ret)
 		goto err_free_state;
author maintainer
#296 lore raw

PATCH 293/438 dma-buf: Split sgl by largest page-aligned chunk

In reply to Greg Kroah-Hartman

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

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

From: David Hu <[email protected]>

commit 06dd5e1ae8ce4e129791087c8c66594950f0ba03 upstream.

Currently, fill_sg_entry() splits the scatterlist using UINT_MAX. This creates a non-page-aligned DMA length (0xFFFFFFFF) for the first entry, resulting in non-page-aligned DMA addresses for all subsequent entries.

While the underlying IOMMU mapping may be contiguous, hardware DMA engines often require explicit address alignment (e.g., page, cacheline, or storage sector boundaries). Passing unaligned addresses and lengths can cause explicit failures in DMA descriptor creation or silent data corruption if lower unaligned bits are truncated.

In addition, a non-page-aligned sgl length will trigger an edge case in ib_umem_find_best_pgsz(). In case of a discontinuity in later buffers, we will have a va with lowest bit set to 1. That will lead to ib_umem_find_best_pgsz() always return 0, and break the promise to find best page size for the mapping on the NIC side.

Fix this by splitting the scatterlist by the largest possible page aligned chunk within UINT_MAX (ALIGN_DOWN(UINT_MAX, PAGE_SIZE)). This ensures all scatterlist DMA addresses and lengths remain page aligned, while minimizing the total number of sgl entries.

Page-aligned entries allow the system to cleanly chunk payloads into PCIe MaxPayloadSize (MPS) (e.g., 128 bytes, 256 bytes, 512 bytes). As a result, this may help reduce TLP fragmentation in P2P transfers and alleviate potential congestion within a logical PCIe switch partition, especially when Relaxed Ordering is not possible due to hardware constraints.

---
 drivers/dma-buf/dma-buf-mapping.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)
drivers/dma-buf/dma-buf-mapping.c +11 -8
index 80f6ab2f4809..833be519e1e6 100644
@@ -6,16 +6,17 @@
 #include <linux/dma-buf-mapping.h>
 #include <linux/dma-resv.h>
 #include <linux/overflow.h>
+#include <linux/align.h>
+
+#define MAX_SG_ENT_SZ ALIGN_DOWN(UINT_MAX, PAGE_SIZE)
 
 static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length,
 					 dma_addr_t addr)
 {
-	unsigned int len, nents;
-	unsigned int i;
+	size_t len;
 
-	nents = DIV_ROUND_UP(length, UINT_MAX);
-	for (i = 0; i < nents; i++) {
-		len = min_t(size_t, length, UINT_MAX);
+	while (length) {
+		len = min(length, MAX_SG_ENT_SZ);
 		length -= len;
 		/*
 		 * DMABUF abuses scatterlist to create a scatterlist
@@ -25,8 +26,10 @@ static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length,
 		 * does not require the CPU list for mapping or unmapping.
 		 */
 		sg_set_page(sgl, NULL, 0, 0);
-		sg_dma_address(sgl) = addr + (dma_addr_t)i * UINT_MAX;
+		sg_dma_address(sgl) = addr;
 		sg_dma_len(sgl) = len;
+		addr += len;
+		/* Unconditionally advance. On last segment, this becomes NULL */
 		sgl = sg_next(sgl);
 	}
 
@@ -42,7 +45,7 @@ static unsigned int calc_sg_nents(struct dma_iova_state *state,
 
 	if (!state || !dma_use_iova(state)) {
 		for (i = 0; i < nr_ranges; i++) {
-			unsigned int added = DIV_ROUND_UP(phys_vec[i].len, UINT_MAX);
+			unsigned int added = DIV_ROUND_UP(phys_vec[i].len, MAX_SG_ENT_SZ);
 
 			if (check_add_overflow(nents, added, &nents))
 				return 0;
@@ -53,7 +56,7 @@ static unsigned int calc_sg_nents(struct dma_iova_state *state,
 		 * for whole IOVA address space, but we need to make sure
 		 * that it fits sg->length, maybe we need more.
 		 */
-		nents = DIV_ROUND_UP(size, UINT_MAX);
+		nents = DIV_ROUND_UP(size, MAX_SG_ENT_SZ);
 	}
 
 	return nents;
Signature · 1 line
2.55.0
author maintainer
#297 lore raw

PATCH 294/438 ipv6: xfrm: use full sockets in local error paths

In reply to Greg Kroah-Hartman

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

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

From: Zhiling Zou <[email protected]>

commit 6973a21ee73c5567f883813c8ef414774b45892f upstream.

xfrm6_local_rxpmtu() and xfrm6_local_error() dereference skb->sk as if it always pointed at a full IPv6 socket.

That is not guaranteed. TCP SYN-ACK skbs can be owned by a TCP_NEW_SYN_RECV request_sock while the output path itself is driven by the full listener. If rerouting selects an IPv6 XFRM tunnel route with a lower MTU, the local PMTU/error handling path can reach these callbacks with that mini-socket still attached to the skb.

The callbacks then miscast the request socket as a full inet/IPv6 socket and can read beyond the request_sock allocation when they access inet_sock or ipv6_pinfo state.

Resolve the owner with skb_to_full_sk() in both callbacks and bail out when no full socket is attached. This matches the surrounding XFRM IPv6 PMTU/error logic, which already reasons about full sockets with skb_to_full_sk().

Fixes dd767856a36e ("xfrm6: Don't call icmpv6_send on local error")
---
 net/ipv6/xfrm6_output.c |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
net/ipv6/xfrm6_output.c +8 -2
@@ -19,7 +19,10 @@
 void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu)
 {
 	struct flowi6 fl6;
-	struct sock *sk = skb->sk;
+	struct sock *sk = skb_to_full_sk(skb);
+
+	if (!sk)
+		return;
 
 	fl6.flowi6_oif = sk->sk_bound_dev_if;
 	fl6.daddr = ipv6_hdr(skb)->daddr;
@@ -31,7 +34,10 @@ void xfrm6_local_error(struct sk_buff *s
 {
 	struct flowi6 fl6;
 	const struct ipv6hdr *hdr;
-	struct sock *sk = skb->sk;
+	struct sock *sk = skb_to_full_sk(skb);
+
+	if (!sk)
+		return;
 
 	hdr = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
 	fl6.fl6_dport = inet_sk(sk)->inet_dport;
author maintainer
#298 lore raw

PATCH 295/438 net: ip_tunnel: initialize `options_len` before referencing options

In reply to Greg Kroah-Hartman

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

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

From: Gris Ge <[email protected]>

commit 455ebeadf714f51e1dbbd6a022c74c9215b1cd76 upstream.

The following command triggers a kernel panic:

ip link add d0 type dummy; ip link set d0 up

  ip route add 10.30.0.0/16 \
    encap ip id 300 geneve_opts 4660:66:11223344 dev d0

memcpy: detected buffer overflow: 4 byte write of buffer size 0 kernel BUG at lib/string_helpers.c:1044!
...

  ip_tun_parse_opts.part.0.cold+0x10/0x10
  ip_tun_build_state+0x116/0x2a0

On kernels built with GCC 15+ and CONFIG_FORTIFY_SOURCE, the fortified memcpy() got 0 sized destination with request of 4 bytes length:

  static int ip_tun_parse_opts_geneve(...)
  {
      ...
      attr = tb[LWTUNNEL_IP_OPT_GENEVE_DATA];
      data_len = nla_len(attr); /* == 4 */
      struct geneve_opt *opt = ip_tunnel_info_opts(info) + opts_len;
      memcpy(opt->opt_data, nla_data(attr), data_len);
      /*     ^^^^^^^^^^^^^ 0 since options_len is assigned afterwards */

Fixed by initializing the counter before the options are referenced. Matching what tunnel_key_opts_set() already does.

---
 net/ipv4/ip_tunnel_core.c |   16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
net/ipv4/ip_tunnel_core.c +11 -5
@@ -680,8 +680,14 @@ static int ip_tun_get_optlen(struct nlat
 }
 
 static int ip_tun_set_opts(struct nlattr *attr, struct ip_tunnel_info *info,
-			   struct netlink_ext_ack *extack)
+			   int opts_len, struct netlink_ext_ack *extack)
 {
+	/* `options_len` is the __counted_by() annotation of the `options`
+	 * flexible array, it must be initialized before parsing writes
+	 * into it.
+	 */
+	info->options_len = opts_len;
+
 	return ip_tun_parse_opts(attr, info, extack);
 }
 
@@ -712,7 +718,8 @@ static int ip_tun_build_state(struct net
 
 	tun_info = lwt_tun_info(new_state);
 
-	err = ip_tun_set_opts(tb[LWTUNNEL_IP_OPTS], tun_info, extack);
+	err = ip_tun_set_opts(tb[LWTUNNEL_IP_OPTS], tun_info, opt_len,
+			      extack);
 	if (err < 0) {
 		lwtstate_free(new_state);
 		return err;
@@ -753,7 +760,6 @@ static int ip_tun_build_state(struct net
 	}
 
 	tun_info->mode = IP_TUNNEL_INFO_TX;
-	tun_info->options_len = opt_len;
 
 	*ts = new_state;
 
@@ -1006,7 +1012,8 @@ static int ip6_tun_build_state(struct ne
 
 	tun_info = lwt_tun_info(new_state);
 
-	err = ip_tun_set_opts(tb[LWTUNNEL_IP6_OPTS], tun_info, extack);
+	err = ip_tun_set_opts(tb[LWTUNNEL_IP6_OPTS], tun_info, opt_len,
+			      extack);
 	if (err < 0) {
 		lwtstate_free(new_state);
 		return err;
@@ -1040,7 +1047,6 @@ static int ip6_tun_build_state(struct ne
 	}
 
 	tun_info->mode = IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6;
-	tun_info->options_len = opt_len;
 
 	*ts = new_state;
 
author maintainer
#299 lore raw

PATCH 296/438 net: lan743x: fix RX checksum use-after-free

In reply to Greg Kroah-Hartman

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

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

From: Mark Amirkan <[email protected]>

commit a9ce4053dc945c5372dedba5017ee675b30dc0c5 upstream.

lan743x_rx_process_buffer() adds each non-first receive buffer to the head skb's frag_list. On the last descriptor, lan743x_rx_trim_skb() linearizes the head and frees the fragment skb metadata.

The checksum-success path then writes ip_summed through the local skb pointer, which still points to the final fragment. This causes a use-after-free write when a packet spans more than one receive buffer.

Set ip_summed on the surviving head skb instead. Multi-buffer receive can occur after a live MTU increase because existing ring entries keep their old buffer size until they are replenished.

A KUnit test invoking lan743x_rx_process_buffer() with a two-buffer packet produced a one-byte KASAN use-after-free write before this change. The same test passed after the change. The driver object also builds with W=1. This was not tested on physical LAN743x hardware.

Fixes cd6910501cfd ("net: lan743x: Add support for Rx IP & TCP checksum offload")
---
 drivers/net/ethernet/microchip/lan743x_main.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/microchip/lan743x_main.c +1 -1
@@ -2594,7 +2594,7 @@ process_extension:
 							rx->adapter->netdev);
 		if (rx->adapter->netdev->features & NETIF_F_RXCSUM) {
 			if (!is_ice && !is_tce && !is_icsm)
-				skb->ip_summed = CHECKSUM_UNNECESSARY;
+				rx->skb_head->ip_summed = CHECKSUM_UNNECESSARY;
 		}
 		netdev_dbg(netdev, "sending %d byte frame to OS",
 			   rx->skb_head->len);
author maintainer
#300 lore raw

PATCH 297/438 net: phy: mediatek: do not report link and per-speed LED rules together

In reply to Greg Kroah-Hartman

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

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

From: Ahmed Naseef <[email protected]>

commit bde5212360bd44506edec073ebbd6d0c72f75820 upstream.

mtk_phy_led_hw_ctrl_get() reports TRIGGER_NETDEV_LINK whenever any of the speed bits in on_set is on, and in addition reports every individual TRIGGER_NETDEV_LINK_* bit that is set. The netdev trigger refuses that
combination: netdev_led_attr_store() rejects TRIGGER_NETDEV_LINK together with any per-speed rule, and it validates the whole resulting mode rather than just the bit being written. Once the hardware has any link bit programmed, every write to the trigger attributes of that LED therefore fails with -EINVAL and the LED can no longer be configured.

The rules are also fed back into the hardware: the trigger stores what is read back, and a later write of device_name programs it again, expanding TRIGGER_NETDEV_LINK to every speed in on_set. An LED configured for a single speed is thereby silently widened to "on at any link speed".

Both are easy to see on the EcoNet EN7528, whose four PHYs share one LED block. The first LED programs the block correctly, the second reads those rules back and rewrites them widened, and the remaining two then read the widened value, so an LED configured for "link_10 link_100" ends up lit on a 1000 Mbps link.

on_set holds every speed the LED can indicate and is exactly what mtk_phy_led_hw_ctrl_set() programs for TRIGGER_NETDEV_LINK, so report the speed independent rule only when all of them are on, and the individual speeds otherwise. The mapping is then the inverse of the one used when programming the LED and round trips without changing the register.

---
 drivers/net/phy/mediatek/mtk-phy-lib.c |   33 ++++++++++++++++++++-------------
 1 file changed, 20 insertions(+), 13 deletions(-)
drivers/net/phy/mediatek/mtk-phy-lib.c +20 -13
@@ -156,20 +156,27 @@ int mtk_phy_led_hw_ctrl_get(struct phy_d
 	if (!rules)
 		return 0;
 
-	if (on & on_set)
+	/* TRIGGER_NETDEV_LINK must not be reported together with any of the
+	 * per-speed rules, the netdev trigger rejects that combination.
+	 * on_set holds every speed this LED can indicate and is what
+	 * mtk_phy_led_hw_ctrl_set() programs for TRIGGER_NETDEV_LINK, so
+	 * report the speed independent rule only when they are all on.
+	 */
+	if ((on & on_set) == on_set) {
 		*rules |= BIT(TRIGGER_NETDEV_LINK);
-
-	if (on & MTK_PHY_LED_ON_LINK10)
-		*rules |= BIT(TRIGGER_NETDEV_LINK_10);
-
-	if (on & MTK_PHY_LED_ON_LINK100)
-		*rules |= BIT(TRIGGER_NETDEV_LINK_100);
-
-	if (on & MTK_PHY_LED_ON_LINK1000)
-		*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-
-	if (on & MTK_PHY_LED_ON_LINK2500)
-		*rules |= BIT(TRIGGER_NETDEV_LINK_2500);
+	} else {
+		if (on & MTK_PHY_LED_ON_LINK10)
+			*rules |= BIT(TRIGGER_NETDEV_LINK_10);
+
+		if (on & MTK_PHY_LED_ON_LINK100)
+			*rules |= BIT(TRIGGER_NETDEV_LINK_100);
+
+		if (on & MTK_PHY_LED_ON_LINK1000)
+			*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
+
+		if (on & MTK_PHY_LED_ON_LINK2500)
+			*rules |= BIT(TRIGGER_NETDEV_LINK_2500);
+	}
 
 	if (on & MTK_PHY_LED_ON_FDX)
 		*rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
author maintainer
#301 lore raw

PATCH 298/438 net: wwan: t7xx: validate the netif index in t7xx_ccmni_recv_skb()

In reply to Greg Kroah-Hartman

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

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

From: Guanglei Zhu <[email protected]>

commit c7ead9704249d57d4693a04697e3bbd285138fa9 upstream.

The netif index carried in the DPMAIF PIT header is five bits wide, but ccmni_inst[] only has room for NIC_DEV_MAX (21) entries. t7xx_ccmni_recv_skb() indexes the array without a bounds check, so indexes 21 to 31 read past it. The out-of-bounds value lands in the callback table that follows the array, which is never NULL, so the existing !ccmni check does not catch it and the driver dereferences whatever sits there as a struct t7xx_ccmni.

Drop the skb when the index is out of range.

Fixes 05d19bf500f8 ("net: wwan: t7xx: Add WWAN network interface")

Verified in a QEMU guest with a fault injector setting the netif index to 25: the unpatched driver reads a value past ccmni_inst[], which lands in the callback table, and dereferences it far enough to queue the skb. With this check the packet is dropped. Well-formed traffic on index 0 is unaffected.

Changes in v2: none.

---
 drivers/net/wwan/t7xx/t7xx_netdev.c |    4 ++++
 1 file changed, 4 insertions(+)
drivers/net/wwan/t7xx/t7xx_netdev.c +4 -0
@@ -420,6 +420,10 @@ static void t7xx_ccmni_recv_skb(struct t
 
 	skb_cb = T7XX_SKB_CB(skb);
 	netif_id = skb_cb->netif_idx;
+	if (netif_id >= NIC_DEV_MAX) {
+		dev_kfree_skb(skb);
+		return;
+	}
 	ccmni = READ_ONCE(ccmni_ctlb->ccmni_inst[netif_id]);
 	if (!ccmni) {
 		dev_kfree_skb(skb);
author maintainer
#302 lore raw

PATCH 299/438 net: wwan: mhi_wwan_mbim: guard against a cyclic NDP chain

In reply to Greg Kroah-Hartman

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

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

From: Guanglei Zhu <[email protected]>

commit 5d063822ac5184939c1ed377a339a01d8ae814e8 upstream.

The NDP traversal in mhi_mbim_rx() only stops when wNextNdpIndex is zero. Nothing requires the offsets to advance, so a modem that points an NDP at itself, or at an earlier NDP, keeps the loop spinning forever on one CPU.

Break out when the next NDP offset is not larger than the current one.

Fixes aa730a9905b7 ("net: wwan: Add MHI MBIM network driver")

Verified in a QEMU guest with a fault injector feeding the driver's receive callback an NTB whose single NDP points at itself: the unpatched driver spins in mhi_mbim_rx() with one CPU pinned at 100% and the thread never returns. With this check the loop terminates within one iteration.

Changes in v2: move the non-increasing check to the wNextNdpIndex retrieval site, as suggested by Loic Poulain, instead of tracking the previous offset in a separate variable.

---
 drivers/net/wwan/mhi_wwan_mbim.c |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/net/wwan/mhi_wwan_mbim.c +7 -3
@@ -349,9 +349,13 @@ static void mhi_mbim_rx(struct mhi_mbim_
 unlock:
 		rcu_read_unlock();
 next_ndp:
-		/* Other NDP to process? */
-		ndpoffset = (int)le16_to_cpu(ndp16.wNextNdpIndex);
-		if (!ndpoffset)
+		/* Other NDP to process?  The offsets must advance, or a
+		 * self-referencing NDP keeps the loop spinning forever.
+		 */
+		n = (int)le16_to_cpu(ndp16.wNextNdpIndex);
+		if (n > ndpoffset)
+			ndpoffset = n;
+		else
 			break;
 	}
 
author maintainer
#303 lore raw

PATCH 300/438 net: wwan: mhi_wwan_mbim: check skb_copy_bits() return value

In reply to Greg Kroah-Hartman

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

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

From: Guanglei Zhu <[email protected]>

commit 31550d585589fde1ae95bf7f7a8188b2d2fdf1c7 upstream.

mhi_mbim_rx() ignores the return value of skb_copy_bits() when it copies each datagram out of the NTB. The datagram offset and length come from the DPE, which is only checked to lie within the NTB itself, so a modem can point a datagram outside the received skb. The copy then fails and the freshly allocated skbn is passed to netif_rx() with its uninitialized contents still in place, leaking kernel heap memory into the network stack.

Free the skb and account an error when the copy fails.

Fixes aa730a9905b7 ("net: wwan: Add MHI MBIM network driver")

Verified in a QEMU guest with a fault injector pointing a DPE outside the received NTB: the copy fails, and the unpatched driver hands the uninitialized skbn to the network stack (observed as "unknown protocol" on bytes that were never written). With this check the failed datagram is dropped and counted as an rx error.

Changes in v2: factor the free-and-count sequence out into mhi_mbim_rx_drop(), shared with the unknown-protocol path, as suggested by Loic Poulain.

---
 drivers/net/wwan/mhi_wwan_mbim.c |   18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)
drivers/net/wwan/mhi_wwan_mbim.c +13 -5
@@ -251,6 +251,14 @@ static int mbim_rx_verify_ndp16(struct s
 	return ret;
 }
 
+static void mhi_mbim_rx_drop(struct mhi_mbim_link *link, struct sk_buff *skb)
+{
+	dev_kfree_skb_any(skb);
+	u64_stats_update_begin(&link->rx_syncp);
+	u64_stats_inc(&link->rx_errors);
+	u64_stats_update_end(&link->rx_syncp);
+}
+
 static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb)
 {
 	int ndpoffset;
@@ -320,7 +328,10 @@ static void mhi_mbim_rx(struct mhi_mbim_
 				continue;
 
 			skb_put(skbn, dgram_len);
-			skb_copy_bits(skb, dgram_offset, skbn->data, dgram_len);
+			if (skb_copy_bits(skb, dgram_offset, skbn->data, dgram_len)) {
+				mhi_mbim_rx_drop(link, skbn);
+				continue;
+			}
 
 			switch (skbn->data[0] & 0xf0) {
 			case 0x40:
@@ -332,10 +343,7 @@ static void mhi_mbim_rx(struct mhi_mbim_
 			default:
 				net_err_ratelimited("%s: unknown protocol\n",
 						    link->ndev->name);
-				dev_kfree_skb_any(skbn);
-				u64_stats_update_begin(&link->rx_syncp);
-				u64_stats_inc(&link->rx_errors);
-				u64_stats_update_end(&link->rx_syncp);
+				mhi_mbim_rx_drop(link, skbn);
 				continue;
 			}
 
author maintainer
#304 lore raw

PATCH 301/438 net/sched: act_api: release tail references on DELACTION failure

In reply to Greg Kroah-Hartman

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

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

From: Xuanqiang Luo <[email protected]>

commit 6e05e46fa821a5c1b281355f1f622ac76cb6080a upstream.

A batched RTM_DELACTION request takes a temporary reference on each action before attempting any deletion. tcf_action_delete() clears each processed slot and drops its temporary reference before attempting the deletion. If deletion fails, tca_action_gd() calls tcf_action_put_many() to release the remaining references, but its tcf_act_for_each_action() iterator stops at the first NULL slot.

When a batch stops at an action bound to a filter, this leaks a reference on each subsequent action. A later delete of an unbound action can then return success without removing it from the IDR.

Walk the full array in tcf_action_put_many() and skip NULL slots to release the references held on the unprocessed actions.

Fixes a0e947c9ccff ("net/sched: act_api: avoid non-contiguous action array")
---
 net/sched/act_api.c |   11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
net/sched/act_api.c +8 -3
@@ -1218,11 +1218,16 @@ static int tcf_action_put(struct tc_acti
 
 static void tcf_action_put_many(struct tc_action *actions[])
 {
-	struct tc_action *a;
 	int i;
 
-	tcf_act_for_each_action(i, a, actions) {
-		const struct tc_action_ops *ops = a->ops;
+	/* Deletion may have cleared entries before failing. */
+	for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
+		struct tc_action *a = actions[i];
+		const struct tc_action_ops *ops;
+
+		if (!a)
+			continue;
+		ops = a->ops;
 		if (tcf_action_put(a))
 			module_put(ops->owner);
 	}
author maintainer
#305 lore raw

PATCH 302/438 net/sched: hhf: cap hh_flows_limit at change time

In reply to Greg Kroah-Hartman

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

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

From: Jamal Hadi Salim <[email protected]>

commit 2cef2588c995722a901368def30befeef9ae55c6 upstream.

hhf_change() stores TCA_HHF_HH_FLOWS_LIMIT with no upper bound. A huge hh_flows_limit lets each new heavy-hitter flow pass the hh_flows_current_cnt check in alloc_new_hh() and forces a fixed-size kzalloc(GFP_ATOMIC) per flow under spoofed traffic, for unbounded memory growth.

Bound the attribute with NLA_POLICY_MAX() at 2*HH_FLOWS_CNT (the hhf_init() default) and report the rejected value via extack. The deprecated nested parse is kept: legacy tc does not set NLA_F_NESTED on TCA_OPTIONS. Configs relying on hh_limit above the default were relying on unbounded, unsafe behaviour and are not supported going forward.

hhf_init() also ran hhf_change() before setting the default hh_flows_limit, so a user-supplied hh_limit at add time was clobbered back to 2048. Set the default before hhf_change() so the configured value sticks.

This is a follow-up to commit eb56a495f59b ("net/sched: hhf: clamp quantum in change and init paths"), which bounded the quantum of the same qdisc; the hh_flows_limit bound is the remaining unbounded knob of that series' scope.

Conditions to recreate the bug: CAP_NET_ADMIN in a user namespace; tc qdisc change dev X root hhf hh_limit 4294967295 succeeds and the value is echoed by tc qdisc show, unbounding heavy-hitter flow allocations; also tc qdisc add dev X root hhf hh_limit 500 stores 2048 instead of 500.

---
 net/sched/sch_hhf.c |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
net/sched/sch_hhf.c +5 -4
@@ -527,7 +527,7 @@ static void hhf_destroy(struct Qdisc *sc
 static const struct nla_policy hhf_policy[TCA_HHF_MAX + 1] = {
 	[TCA_HHF_BACKLOG_LIMIT]	 = { .type = NLA_U32 },
 	[TCA_HHF_QUANTUM]	 = { .type = NLA_U32 },
-	[TCA_HHF_HH_FLOWS_LIMIT] = { .type = NLA_U32 },
+	[TCA_HHF_HH_FLOWS_LIMIT] = NLA_POLICY_MAX(NLA_U32, 2 * HH_FLOWS_CNT),
 	[TCA_HHF_RESET_TIMEOUT]	 = { .type = NLA_U32 },
 	[TCA_HHF_ADMIT_BYTES]	 = { .type = NLA_U32 },
 	[TCA_HHF_EVICT_TIMEOUT]	 = { .type = NLA_U32 },
@@ -546,7 +546,7 @@ static int hhf_change(struct Qdisc *sch,
 	u32 new_hhf_non_hh_weight = q->hhf_non_hh_weight;
 
 	err = nla_parse_nested_deprecated(tb, TCA_HHF_MAX, opt, hhf_policy,
-					  NULL);
+					  extack);
 	if (err < 0)
 		return err;
 
@@ -624,6 +624,9 @@ static int hhf_init(struct Qdisc *sch, s
 	q->hhf_evict_timeout = HZ;      /* 1  sec */
 	q->hhf_non_hh_weight = 2;
 
+	/* Cap max active HHs at twice len of hh_flows table. */
+	q->hh_flows_limit = 2 * HH_FLOWS_CNT;
+
 	if (opt) {
 		int err = hhf_change(sch, opt, extack);
 
@@ -639,8 +642,6 @@ static int hhf_init(struct Qdisc *sch, s
 		for (i = 0; i < HH_FLOWS_CNT; i++)
 			INIT_LIST_HEAD(&q->hh_flows[i]);
 
-		/* Cap max active HHs at twice len of hh_flows table. */
-		q->hh_flows_limit = 2 * HH_FLOWS_CNT;
 		q->hh_flows_overlimit = 0;
 		q->hh_flows_total_cnt = 0;
 		q->hh_flows_current_cnt = 0;
author maintainer
#306 lore raw

PATCH 303/438 net/packet: clear RX owner on VNET header error

In reply to Greg Kroah-Hartman

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

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

From: Mark Amirkan <[email protected]>

commit 33ff111d7ba3beb86e28938d6382bb5beabd865a upstream.

Commit 61fad6816fc1 ("net/packet: tpacket_rcv: avoid a producer race condition") added rx_owner_map and made tpacket_rcv() claim a V1 or V2 ring slot before converting the virtio-net header. If the conversion fails, the drop path leaves the slot claimed.

With a one-frame TPACKET_V2 ring, an unsupported UDP GSO packet leaves the only slot unavailable, so the ring also drops the next valid packet.

Clear the ownership bit on this error path. TPACKET_V3 already clears its block state here.

---
 net/packet/af_packet.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
net/packet/af_packet.c +3 -1
@@ -2384,7 +2384,9 @@ static int tpacket_rcv(struct sk_buff *s
 	    virtio_net_hdr_from_skb(skb, h.raw + macoff -
 				    sizeof(struct virtio_net_hdr),
 				    vio_le(), true, 0)) {
-		if (po->tp_version == TPACKET_V3)
+		if (po->tp_version <= TPACKET_V2)
+			__clear_bit(slot_id, po->rx_ring.rx_owner_map);
+		else
 			prb_clear_blk_fill_status(&po->rx_ring);
 		goto drop_n_account;
 	}
author maintainer
#307 lore raw

PATCH 304/438 net/packet: avoid truncating TPACKET_V3 private size

In reply to Greg Kroah-Hartman

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

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

From: Mark Amirkan <[email protected]>

commit 37213e61120297920ae4c937fcb326a360da5084 upstream.

tpacket_req3.tp_sizeof_priv is an unsigned int, and packet_set_ring() validates the full value against the block size. init_prb_bdqc() then stores it in the unsigned short blk_sizeof_priv field.

Commit 2b6867c2ce76 ("net/packet: fix overflow in check for priv area size") fixed the validation arithmetic, but an accepted value above USHRT_MAX still narrows when it is stored.

For a 131072-byte block, tp_sizeof_priv=65536 is valid. The narrowing makes offset_to_first_pkt 48 instead of 65584, so packet records can be placed in the private area that userspace asked the kernel to preserve.

blk_sizeof_priv is internal state, so widen it to hold the validated UAPI value.

---
 net/packet/internal.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/packet/internal.h +1 -1
@@ -21,7 +21,7 @@ struct tpacket_kbdq_core {
 	unsigned int	hdrlen;
 	unsigned char	reset_pending_on_curr_blk;
 	unsigned short	kactive_blk_num;
-	unsigned short	blk_sizeof_priv;
+	unsigned int	blk_sizeof_priv;
 
 	unsigned short  version;
 
author maintainer
#308 lore raw

PATCH 305/438 scsi: core: Validate MODE SENSE lengths in scsi_cdl_enable()

In reply to Greg Kroah-Hartman

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

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

From: Alberto Carboneri <[email protected]>

commit 3d676e458fe0c566f5a62753dc696b6a862fc412 upstream.

scsi_cdl_enable() uses length fields returned by MODE SENSE to locate the ATA feature mode page in a 64-byte stack buffer. A target can report a total length shorter than its mode header and block descriptors. The unsigned subtraction used for the MODE SELECT length can wrap, and the separately computed buf_data can point beyond buf.

During automatic scan, enable is false, so the read-modify-write of buf_data[4] can clear the low two bits of a target-selected out-of-bounds stack byte. scsi_mode_select() can then copy up to 64 bytes from outside the buffer into the outgoing MODE SELECT payload, disclosing stack contents to the target.

This is reachable while scanning a USB storage device that identifies as an ATA device and advertises CDL support. No filesystem mount or userspace access to the block device is required.

On upstream commit cee9395acd80 ("Linux 7.3-rc1"), a build-specific, one-vCPU QEMU/Raw Gadget proof using QEMU-only multi-UDC allocator sampling executed a fixed proof command inside the guest and created a UID-0-owned marker during automatic enumeration, with KASLR and NX enabled.

The issue was independently found during security research at Drivesec S.r.l.

Cap the available length to the buffer size. Validate and consume the mode header and block descriptor lengths before using the page, and require the five bytes needed to access the CDL field.

---
 drivers/scsi/scsi.c |   24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)
drivers/scsi/scsi.c +19 -5
@@ -727,6 +727,7 @@ int scsi_cdl_enable(struct scsi_device *
 		struct scsi_mode_data data;
 		struct scsi_sense_hdr sshdr;
 		char *buf_data;
+		size_t avail, offset;
 		int len;
 
 		ret = scsi_mode_sense(sdev, 0x08, 0x0a, 0xf2, buf, sizeof(buf),
@@ -735,11 +736,24 @@ int scsi_cdl_enable(struct scsi_device *
 			return -EINVAL;
 
 		/* Enable or disable CDL using the ATA feature page */
-		len = min_t(size_t, sizeof(buf),
-			    data.length - data.header_length -
-			    data.block_descriptor_length);
-		buf_data = buf + data.header_length +
-			data.block_descriptor_length;
+		avail = min_t(size_t, data.length, sizeof(buf));
+		if (data.header_length > avail)
+			return -EINVAL;
+
+		offset = data.header_length;
+		avail -= data.header_length;
+
+		if (data.block_descriptor_length > avail)
+			return -EINVAL;
+
+		offset += data.block_descriptor_length;
+		avail -= data.block_descriptor_length;
+
+		if (avail < 5)
+			return -EINVAL;
+
+		buf_data = buf + offset;
+		len = avail;
 
 		/*
 		 * If we want to enable CDL and CDL is already enabled on the
author maintainer
#309 lore raw

PATCH 306/438 xfrm: serialize state GC with device state flush

In reply to Greg Kroah-Hartman

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

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

From: Chengfeng Ye <[email protected]>

commit 89fefad9f971bc637fb22373078144f2563c4be9 upstream.

The deferred-device pass in xfrm_dev_state_flush() finds states under xfrm_state_dev_gc_lock, but drops the lock before calling xfrm_dev_state_free() because the driver callback may sleep. The device GC list does not hold an xfrm_state reference, so the state GC worker can destroy the same state concurrently.

The race can proceed as follows:

CPU 0 CPU 1
find x on the device GC list
drop xfrm_state_dev_gc_lock
read x->xso.dev
xfrm_state_gc_destroy(x) xfrm_dev_state_free(x) xfrm_state_free(x)
continue xfrm_dev_state_free(x)

Both paths can invoke the driver callback and drop the device reference. CPU 0 can also access the xfrm_state after CPU 1 has freed it.

KASAN reported:

  BUG: KASAN: slab-use-after-free in xfrm_dev_state_free+0x24c/0x2a0
  Read of size 8 at addr ffff88810bbaa960 by task poc/102

  Call Trace:
   xfrm_dev_state_free+0x24c/0x2a0
   xfrm_dev_state_flush+0x353/0x400
   xfrm_dev_event+0x26d/0x3a0
   notifier_call_chain+0xc0/0x280
   __dev_notify_flags+0x169/0x250
   netif_change_flags+0xe7/0x160
   dev_change_flags+0x96/0x220
   devinet_ioctl+0x7f4/0x1880

  Allocated by task 87:
   xfrm_state_alloc+0x1e/0x5c0
   xfrm_add_sa+0xe7f/0x5820
   xfrm_user_rcv_msg+0x4f3/0x940

  Freed by task 57:
   kmem_cache_free+0xcb/0x3d0
   xfrm_state_gc_task+0x4a8/0x650
   process_one_work+0x63a/0x1070

Serialize xfrm_state destruction against the deferred-device pass with a mutex. Keep xfrm_state_dev_gc_lock limited to list operations and retain the existing callback and device-reference release ordering.

Fixes 07b87f9eea0c ("xfrm: Fix unregister netdevice hang on hardware offload.")
---
 net/xfrm/xfrm_state.c |    5 +++++
 1 file changed, 5 insertions(+)
net/xfrm/xfrm_state.c +5 -0
@@ -226,6 +226,7 @@ static struct xfrm_state_afinfo __rcu *x
 
 static DEFINE_SPINLOCK(xfrm_state_gc_lock);
 static DEFINE_SPINLOCK(xfrm_state_dev_gc_lock);
+static DEFINE_MUTEX(xfrm_state_gc_mutex);
 
 int __xfrm_state_delete(struct xfrm_state *x);
 
@@ -632,8 +633,10 @@ static void xfrm_state_gc_task(struct wo
 
 	synchronize_rcu();
 
+	mutex_lock(&xfrm_state_gc_mutex);
 	hlist_for_each_entry_safe(x, tmp, &gc_list, gclist)
 		xfrm_state_gc_destroy(x);
+	mutex_unlock(&xfrm_state_gc_mutex);
 }
 
 static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
@@ -1000,6 +1003,7 @@ restart:
 out:
 	spin_unlock_bh(&net->xfrm.xfrm_state_lock);
 
+	mutex_lock(&xfrm_state_gc_mutex);
 	spin_lock_bh(&xfrm_state_dev_gc_lock);
 restart_gc:
 	hlist_for_each_entry_safe(x, tmp, &xfrm_state_dev_gc_list, dev_gclist) {
@@ -1014,6 +1018,7 @@ restart_gc:
 
 	}
 	spin_unlock_bh(&xfrm_state_dev_gc_lock);
+	mutex_unlock(&xfrm_state_gc_mutex);
 
 	xfrm_flush_gc();
 
author maintainer
#310 lore raw

PATCH 307/438 xfrm: use hlist_del_init_rcu for state_cache and state_cache_input

In reply to Greg Kroah-Hartman

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

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

From: Siwei Zhang <[email protected]>

commit 2afb8dc1f4390f164db8352f8e685e126e9db566 upstream.

Commit 14acf9652e56 ("xfrm: defensively unhash xfrm_state lists in __xfrm_state_delete") converted bydst/bysrc/byseq/byspi from hlist_del_rcu() to hlist_del_init_rcu() so that a second __xfrm_state_delete() on the same object becomes a no-op rather than a write through LIST_POISON pprev. It missed state_cache and state_cache_input, which kept hlist_del_rcu():

- hlist_del_rcu() leaves pprev = LIST_POISON2 (non-NULL), so hlist_unhashed() returns false.
- hlist_del_init_rcu() leaves pprev = NULL, so hlist_unhashed() returns true.

A second __xfrm_state_delete() therefore enters __hlist_del() on the already-deleted state_cache/state_cache_input nodes and does WRITE_ONCE(*pprev, next) through LIST_POISON2 — a write use-after-free once the slab is reused. The corruption can in turn cause a subsequent hlist_for_each_entry_rcu traversal to follow a dangling next pointer, producing the read use-after-free reported in xfrm_input_state_lookup().

Switch state_cache and state_cache_input to hlist_del_init_rcu() to match the other four lists, closing the write use-after-free and, with it, the read use-after-free it spawns.

Assisted-by CodeBuddy:GLM-5.2
Fixes 0045e3d80613 ("xfrm: Cache used outbound xfrm states at the policy.")
Fixes 81a331a0e72d ("xfrm: Add an inbound percpu state cache.")
---
 net/xfrm/xfrm_state.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
net/xfrm/xfrm_state.c +2 -2
@@ -826,9 +826,9 @@ int __xfrm_state_delete(struct xfrm_stat
 		if (!hlist_unhashed(&x->byseq))
 			hlist_del_init_rcu(&x->byseq);
 		if (!hlist_unhashed(&x->state_cache))
-			hlist_del_rcu(&x->state_cache);
+			hlist_del_init_rcu(&x->state_cache);
 		if (!hlist_unhashed(&x->state_cache_input))
-			hlist_del_rcu(&x->state_cache_input);
+			hlist_del_init_rcu(&x->state_cache_input);
 
 		if (!hlist_unhashed(&x->byspi))
 			hlist_del_init_rcu(&x->byspi);
author maintainer
#311 lore raw

PATCH 308/438 xfrm: save input state data before secpath resets

In reply to Greg Kroah-Hartman

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

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

From: Zhiling Zou <[email protected]>

commit 3cf5cdecd99c9c186a5ea518d93bbf3045b6e3aa upstream.

xfrm_input() stores the current xfrm_state in the skb secpath while it continues receive-side processing. Some input paths can reset that secpath before xfrm_input() has finished dereferencing the state.

Receive callback users such as VTI and XFRM interfaces can reset the secpath. The VTI receive path does so before checking whether the packet crosses network namespaces, while the XFRM interface path does so only for cross-network-namespace packets. The XFRM_MAX_DEPTH error path can also reset the secpath before the final drop callback reports the current state's protocol.

If secpath_reset() drops the last state reference while the state is concurrently deleted, xfrm_input() can still dereference the freed state when selecting transport_finish() or reporting the drop callback protocol.

Save the state protocol on the stack while the state is still valid, and use the already saved address family for transport_finish(). A larval XFRM_STATE_ACQ state has no type, so retain nexthdr as its protocol. This preserves the existing drop-path fallback while avoiding the post-reset state dereferences without adding an extra state reference to every received packet.

Fixes df3893c176e9 ("vti: Update the ipv4 side to use it's own receive hook.")
---
 net/xfrm/xfrm_input.c |   11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
net/xfrm/xfrm_input.c +8 -3
@@ -474,6 +474,7 @@ int xfrm_input(struct sk_buff *skb, int
 	struct xfrm_state *x = NULL;
 	xfrm_address_t *daddr;
 	u32 mark = skb->mark;
+	u8 xfrm_proto = nexthdr;
 	unsigned int family = AF_UNSPEC;
 	int decaps = 0;
 	int async = 0;
@@ -485,6 +486,7 @@ int xfrm_input(struct sk_buff *skb, int
 	if (encap_type < 0 || (xo && (xo->flags & XFRM_GRO || encap_type == 0 ||
 				      encap_type == UDP_ENCAP_ESPINUDP))) {
 		x = xfrm_input_state(skb);
+		xfrm_proto = x->type ? x->type->proto : nexthdr;
 
 		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
 			if (x->km.state == XFRM_STATE_ACQ)
@@ -592,11 +594,13 @@ int xfrm_input(struct sk_buff *skb, int
 
 		x = xfrm_input_state_lookup(net, mark, daddr, spi, nexthdr, family);
 		if (x == NULL) {
+			xfrm_proto = nexthdr;
 			secpath_reset(skb);
 			XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
 			xfrm_audit_state_notfound(skb, family, spi, seq);
 			goto drop;
 		}
+		xfrm_proto = x->type ? x->type->proto : nexthdr;
 
 		if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
 			secpath_reset(skb);
@@ -604,6 +608,7 @@ int xfrm_input(struct sk_buff *skb, int
 			xfrm_audit_state_notfound(skb, family, spi, seq);
 			xfrm_state_put(x);
 			x = NULL;
+			xfrm_proto = nexthdr;
 			goto drop;
 		}
 
@@ -728,7 +733,7 @@ resume_decapped:
 	} while (!err);
 
 	rcu_read_lock();
-	err = xfrm_rcv_cb(skb, family, x->type->proto, 0);
+	err = xfrm_rcv_cb(skb, family, xfrm_proto, 0);
 	if (err) {
 		rcu_read_unlock();
 		goto drop;
@@ -753,7 +758,7 @@ resume_decapped:
 			xfrm_gro = xo->flags & XFRM_GRO;
 
 		err = -EAFNOSUPPORT;
-		afinfo = xfrm_state_afinfo_get_rcu(x->props.family);
+		afinfo = xfrm_state_afinfo_get_rcu(family);
 		if (likely(afinfo))
 			err = afinfo->transport_finish(skb, xfrm_gro || async);
 		if (xfrm_gro) {
@@ -776,7 +781,7 @@ drop_unlock:
 drop:
 	if (async)
 		dev_put(dev);
-	xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
+	xfrm_rcv_cb(skb, family, xfrm_proto, -1);
 	kfree_skb(skb);
 	return 0;
 }
author maintainer
#312 lore raw

PATCH 309/438 soc: samsung: exynos-pmu: fix use-after-free of interrupt generator node

In reply to Greg Kroah-Hartman

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

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

From: Alexey Klimov <[email protected]>

commit 4dd1999783d7d12434006289338373e49492dc96 upstream.

The setup_cpuhp_and_cpuidle() parses the device tree node for the interrupt generation block via of_parse_phandle() and decrements its reference count using of_node_put() immediately after fetching the resource address. However, later the intr_gen_node pointer is passed into of_syscon_register_regmap().

Fix this by declaring intr_gen_node with __free() and removing of_node_put().

---
 drivers/soc/samsung/exynos-pmu.c |    7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/soc/samsung/exynos-pmu.c +2 -5
@@ -409,13 +409,12 @@ static struct notifier_block exynos_cpup
 
 static int setup_cpuhp_and_cpuidle(struct device *dev)
 {
-	struct device_node *intr_gen_node;
+	struct device_node *intr_gen_node __free(device_node) =
+		of_parse_phandle(dev->of_node, "google,pmu-intr-gen-syscon", 0);
 	struct resource intrgen_res;
 	void __iomem *virt_addr;
 	int ret, cpu;
 
-	intr_gen_node = of_parse_phandle(dev->of_node,
-					 "google,pmu-intr-gen-syscon", 0);
 	if (!intr_gen_node) {
 		/*
 		 * To maintain support for older DTs that didn't specify syscon
@@ -431,8 +430,6 @@ static int setup_cpuhp_and_cpuidle(struc
 	 * syscon provided regmap.
 	 */
 	ret = of_address_to_resource(intr_gen_node, 0, &intrgen_res);
-	of_node_put(intr_gen_node);
-
 	virt_addr = devm_ioremap(dev, intrgen_res.start,
 				 resource_size(&intrgen_res));
 	if (!virt_addr)
author maintainer
#313 lore raw

PATCH 310/438 mips: select CONFIG_WEAK_REORDERING_BEYOND_LLSC from CONFIG_EYEQ

In reply to Greg Kroah-Hartman

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

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

From: Théo Lebrun <[email protected]>

commit bbc448c541ed90d52f9ec22f17394304e3bf170e upstream.

On I6500 CPU cores, lld and scd give no ordering guarantees (same as all other instructions). To respect the assumption that arch_cmpxchg() is fully ordered, we must inject sync instructions above and below our lld/scd loops using the already in place WEAK_REORDERING_BEYOND_LLSC infrastructure.

Otherwise, bad things can happen:

[   34.054496] CPU 3 Unable to handle kernel paging request at virtual address 0000000000000000, epc == a80000080838e01c, ra == a80000080838dfc4
[   34.054559] Oops[#1]:
[   34.069561] CPU: 3 UID: 0 PID: 170 Comm: pipe_race Not tainted 7.2.0-rc6-01553-gb73c35220968-dirty #103 VOLUNTARY
[   34.079932] Hardware name: Mobile EyeQ5 MP5 Evaluation board
[   34.085592] $ 0   : 0000000000000000 0000000000000001 0000000000000000 0000000000000000
[   34.093616] $ 4   : a800000808ee2618 000000000b7a879d 0000000000001000 0000000000000000
[   34.101638] $ 8   : 0000000000e3f2c9 0000000000000000 a800000808a2a9f8 0000000000000000
[   34.109660] $12   : a8000008139ffcd8 ffffffff84080018 a80000080837fae0 7878787878787878
[   34.117682] $16   : a800000807e82940 0000000000001000 0000000000000000 0000000000000000
[   34.125704] $20   : a800000802920e00 a8000008139ffdf8 a800000802649400 0000000000e3f2c9
[   34.133726] $24   : 0000000000000006 00000001200406e0
[   34.141783] $28   : a8000008139fc000 a8000008139ffd10 0000000000e3f2c8 a80000080838dfc4
[   34.149837] epc   : a80000080838e01c anon_pipe_read+0xd4/0x428
[   34.155697] ra    : a80000080838dfc4 anon_pipe_read+0x7c/0x428
[   34.161549] Status: 140000e3  KX SX UX KERNEL EXL IE
[   34.166551] Cause : 40800408 (ExcCode 02)
[   34.170574] BadVA : 0000000000000000
[   34.174161] PrId  : 0001b028 (MIPS I6500)
[   34.178183] Process pipe_race (pid: 170, threadinfo=000000005ca35720, task=00000000e1013890, tls=000000014ebbb780)
[   34.188568] Stack : a800000802649400 0000000000000000 0000000000000000 a8000008139ffdd0
[   34.196623]	 0000000000000fba a800000808ee0000 0000000000000001 a8000008130c3e80
[   34.204676]	 a8000008080d1280 a8000008139ffd58 a8000008139ffd58 1dbd2b22ea1dd500
[   34.212729]	 a800000802649400 a800000808ee0000 ffffffffffffffea 0000000000000001
[   34.220783]	 0000000000001000 0000000000000000 00000001200ae518 ffffffffffffffff
[   34.228836]	 000000fffbe0e530 a80000080837edf4 000000fffbe0e530 0000000000000000
[   34.236890]	 0000000000000000 0000000000000000 000000014ebb55a0 0000000000001000
[   34.244943]	 0000000000000001 a800000802649400 0000000000000000 0000000000000000
[   34.252996]	 0000000000000000 0000400400000000 0000000000000000 1dbd2b22ea1dd500
[   34.261049]	 00000000140000e3 a800000802649400 a800000802649400 a800000808ee0000
[   34.269103]	 ...
[   34.271568] Call Trace:
[   34.274026] [<a80000080838e01c>] anon_pipe_read+0xd4/0x428
[   34.279533] [<a80000080837edf4>] vfs_read+0x25c/0x318
[   34.284607] [<a80000080837faac>] ksys_read+0x104/0x138
[   34.289763] [<a80000080802b9cc>] syscall_common+0x44/0x68
[   34.295187]
[   34.296689] Code: f84000cf  02209825  de020010 <dc420000> d8400004  02002825  0040f809  02802025  f84000c3
[   34.306504]
[   34.308099] ---[ end trace 0000000000000000 ]---

My initial reproducer was the xdp-tools test suite. A standalone reproducer would be an lld/scd loop that, when the read is reordered by the CPU, triggers a fault. We can achieve this from userspace by stressing an anonymous pipe, which uses a mutex. Program used:

	// SPDX-License-Identifier: GPL-2.0
	// pipe_race.c - reproducer for MIPS LL/SC reordering vs fs/pipe.c
	//
	// Two userspace processes on an anonymous pipe:
	//   parent  = writer: tight write() loop
	//   child   = reader: tight read() loop

	#define _GNU_SOURCE
	#include <assert.h>
	#include <errno.h>
	#include <sched.h>
	#include <signal.h>
	#include <stdio.h>
	#include <stdlib.h>
	#include <string.h>
	#include <sys/types.h>
	#include <sys/wait.h>
	#include <time.h>
	#include <unistd.h>

	int main(void)
	{
		long wrsize = 70;	// bytes per write()
		long rdsize = 4096;	// bytes per read()
		int pfd[2];
		char *buf;
		pid_t pid;
		int ret;

		ret = pipe(pfd);
		assert(!ret);

		pid = fork();
		assert(pid >= 0);

		if (pid == 0) {			/* reader */
			close(pfd[1]);
			buf = malloc(rdsize);
			assert(buf);
			for (;;) {
				ssize_t n = read(pfd[0], buf, rdsize);

				if (n < 0 && errno == EINTR)
					continue;
				if (n <= 0)
					_exit(n < 0 ? 1 : 0);
			}
		}

		close(pfd[0]);			/* writer */
		buf = malloc(wrsize);
		assert(buf);
		memset(buf, 'x', wrsize);

		for (;;) {
			ssize_t n = write(pfd[1], buf, wrsize);

			if (n < 0 && errno == EINTR)
				continue;
			if (n != wrsize)
				break;
		}

		kill(pid, SIGKILL);
		wait(NULL);
		return 0;
	}
Fixes fbe0fae601b7 ("MIPS: mobileye: Add EyeQ6H support")
---
 arch/mips/Kconfig |    1 +
 1 file changed, 1 insertion(+)
arch/mips/Kconfig +1 -0
@@ -659,6 +659,7 @@ config EYEQ
 	select USB_UHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
 	select USE_OF
 	select HOTPLUG_PARALLEL if HOTPLUG_CPU
+	select WEAK_REORDERING_BEYOND_LLSC
 	help
 	  Select this to build a kernel supporting EyeQ SoC from Mobileye.
 
author maintainer
#314 lore raw

PATCH 311/438 memcg: avoid charging the root memcg from obj_cgroup_charge_pages()

In reply to Greg Kroah-Hartman

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

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

From: Shakeel Butt <[email protected]>

commit 6e673d0879ef78c395cfe0d3ba316690a60055d8 upstream.

obj_cgroup_charge_pages() resolves the objcg to its memcg and calls try_charge_memcg(), which does not short circuit the root memcg. That memcg can be the root memcg: obj_cgroup_is_root() reflects the memcg the objcg was created for and is never updated, while memcg_reparent_objcgs() does redirect objcg->memcg to the parent on rmdir. An objcg of a dying child of root therefore passes every obj_cgroup_is_root() filter but resolves to the root memcg.

Folios keep the objcg they were charged with, so this is easy to reach through zswap: allocate anon memory in a cgroup, move the task out, remove the cgroup, then write to the root cgroup's memory.reclaim. The reclaimed folios are charged through the reparented objcg and end up in refill_stock() with the root memcg:

  WARNING: mm/memcontrol.c:2198 at refill_stock+0x644/0x940
   refill_stock+0x644/0x940
   try_charge_memcg+0x12d6/0x1570
   __obj_cgroup_charge+0x35/0xf0
   obj_cgroup_charge+0x1de/0x210
   obj_cgroup_charge_zswap+0x83/0x270
   zswap_store+0x1620/0x2000
   swap_writeout+0x94c/0x14c0
   shrink_folio_list+0x3388/0x52b0
   [...]
   try_to_free_mem_cgroup_pages+0x30d/0x830
   user_proactive_reclaim+0x504/0x840
   memory_reclaim+0x1f/0x30

Beyond the warning, the charge is asymmetric: obj_cgroup_uncharge_pages() skips refill_stock() for the root memcg, so the root's page counter grows and is never uncharged. It is not user visible, since memory.current is not exposed on the root, but it is a leak.

Use try_charge(), which returns early for the root memcg, restoring the symmetry with obj_cgroup_uncharge_pages().

The above sequence was scripted into a standalone reproducer (zswap on, swap on a virtio disk, 512MB of anon memory faulted in inside a child of the root cgroup, the task then migrated to the root cgroup, the child removed, followed by "echo 600M swappiness=max > memory.reclaim" on the root) and run in a CONFIG_DEBUG_VM=y VM. It reproduces the splat on the first zswap store of a reparented folio, with the same call chain as the report. With this patch applied the splat is gone while the zswap store count over the run is unchanged, so the same path is still exercised. cgroup selftests test_zswap, test_kmem and test_memcontrol show no new failures.

---
 mm/memcontrol.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/memcontrol.c +1 -1
@@ -3107,7 +3107,7 @@ static int obj_cgroup_charge_pages(struc
 
 	memcg = get_mem_cgroup_from_objcg(objcg);
 
-	ret = try_charge_memcg(memcg, gfp, nr_pages);
+	ret = try_charge(memcg, gfp, nr_pages);
 	if (ret)
 		goto out;
 
author maintainer
#315 lore raw

PATCH 312/438 memstick: ms_block: destroy io_queue workqueue on removal

In reply to Greg Kroah-Hartman

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

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

From: Yifei Gao <[email protected]>

commit 90af7fde083e1b22c349c3a8b1626728e44e474c upstream.

msb_init_disk() creates the per-card ordered workqueue msb->io_queue with alloc_ordered_workqueue(). It is torn down with destroy_workqueue() only on the init error path; msb_remove() never destroys it. msb_stop() merely flushes the queue, and neither msb_data_clear() nor put_disk() free it. As a result every card insert/remove cycle leaks the workqueue and its kworker, exhausting kernel memory over repeated cycles.

Destroy the workqueue in msb_remove() after the disk has been removed and the queue drained.

Fixes 0ab30494bc4f ("memstick: add support for legacy memorysticks")
Assisted-by Claude:claude-opus-4-8
---
 drivers/memstick/core/ms_block.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/memstick/core/ms_block.c +2 -0
@@ -2204,6 +2204,8 @@ static void msb_remove(struct memstick_d
 	msb_data_clear(msb);
 	mutex_unlock(&msb_disk_lock);
 
+	destroy_workqueue(msb->io_queue);
+
 	put_disk(msb->disk);
 	memstick_set_drvdata(card, NULL);
 }
author maintainer
#316 lore raw

PATCH 313/438 mm, swap: fix SWAP_USAGE_OFFLIST_BIT collision with real usage count

In reply to Greg Kroah-Hartman

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

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

From: Nhat Pham <[email protected]>

commit 12e9ac7bc5b254048f886bf421e3a15491106c1f upstream.

SWAP_USAGE_OFFLIST_BIT is embedded in the si->inuse_pages usage counter, and is meant to sit above any value that counter can reach. However, it is defined from BITS_PER_TYPE(atomic_t), so it is bit 30. On a system with 4 KiB pages the flag collides with the usage count once that count reaches 4 TiB.

swap_usage_in_pages() masks bit 30 out, so whenever the real count has that bit set, every caller of it reads 4 TiB low:

* /proc/swaps understates Used by 4 TiB.

* A raw count of exactly 2^30 masks to zero, so try_to_unuse() takes its "if (!swap_usage_in_pages(si)) goto success;" early exit and swapoff tears the device down while pages are still swapped out. Nothing in the rest of swapoff aborts the teardown, so those pages are lost.

Independently of swapoff, the collision also corrupts the counter and the plist. On a device in normal use, a free that leaves bit 30 set in the count makes swap_usage_sub() see the flag where there is only count, and call add_to_avail_list(). It clears the bit with fetch_and(~SWAP_USAGE_OFFLIST_BIT), leaving the stored count 4 TiB below the real one, and calls plist_add() on a device that is already listed, tripping the WARN_ON(!plist_node_empty(node)) in plist_add() and linking the node a second time.

Change the definition of SWAP_USAGE_OFFLIST_BIT to be based on atomic_long_t instead. Note that the usage counter field itself is of this same type, so it is still a valid bit.

---
 mm/swapfile.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/swapfile.c +1 -1
@@ -156,7 +156,7 @@ static struct swap_info_struct *swap_ent
  * This bit will be set if the device is not on the plist and not
  * usable, will be cleared if the device is on the plist.
  */
-#define SWAP_USAGE_OFFLIST_BIT (1UL << (BITS_PER_TYPE(atomic_t) - 2))
+#define SWAP_USAGE_OFFLIST_BIT (1UL << (BITS_PER_TYPE(atomic_long_t) - 2))
 #define SWAP_USAGE_COUNTER_MASK (~SWAP_USAGE_OFFLIST_BIT)
 static long swap_usage_in_pages(struct swap_info_struct *si)
 {
author maintainer
#317 lore raw

PATCH 314/438 mm/huge_memory: bypass THP tuneables for huge pfnmap mappings

In reply to Greg Kroah-Hartman

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

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

From: Lorenzo Stoakes (ARM) <[email protected]>

commit e384abeb559d10d6505aec053ede9368d81d4c71 upstream.

The sysfs THP tuneables at /sys/kernel/mm/transparent_huge_pages/ rather confusingly only control the behaviour of THP in some instances.

They are not applicable to MADV_COLLAPSE operations, nor to DAX mappings.

Long-term, THP is predicated upon compaction being able to obtain large folios to populate THP ranges.

However, vm_normal_folio() returns NULL for PFN map mappings, thus their reference count is maintained by the driver, not core mm.

As a consequence, the folios are not subject to reclaim nor compaction, so are not truly part of the THP mechanism at all.

However, since commit 5dd40721f147 ("mm: allow THP orders for PFNMAPs") introduced the ability to establish huge PFN maps, they have been subject to THP tuneables.

This is incorrect - if a huge PFN map is available (defined by vma->vm_ops->huge_fault being non-NULL for a VMA_PFNMAP_BIT VMA), then it should be mapped huge upon fault-in.

Correct this by explicitly checking for this while ensuring that smaps continues to accurately report THPeligible statistics.

While here, abstract the entire file-backed THP check in vma_can_map_huge_file(), with sensible separation of logic into helper functions.

Note that drm_gem_shmem_mmap() and panthor_gem_mmap() establish huge PFN maps of shmem folios, however they are marked unevictable in drm_gem_get_pages(), and in any case would fail the reference check in __remove_mapping() even if they weren't.

Failing to map huge PFN maps has resulted in significant real-world performance degradation, see links for details.

---
 mm/huge_memory.c |   86 ++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 64 insertions(+), 22 deletions(-)
mm/huge_memory.c +64 -22
@@ -92,7 +92,7 @@ unsigned long huge_anon_orders_madvise _
 unsigned long huge_anon_orders_inherit __read_mostly;
 static bool anon_orders_configured __initdata;
 
-static inline bool file_thp_enabled(struct vm_area_struct *vma)
+static inline bool file_thp_enabled(const struct vm_area_struct *vma)
 {
 	struct inode *inode;
 
@@ -118,6 +118,67 @@ static bool vma_is_special_huge(const st
 	return vma_test_any(vma, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT);
 }
 
+static bool vma_file_bypass_thp_tuneables(const struct vm_area_struct *vma,
+		enum tva_type type)
+{
+	const bool has_huge_fault = vma->vm_ops->huge_fault;
+
+	/* MADV_COLLAPSE ignores tuneables. */
+	if (type == TVA_FORCED_COLLAPSE)
+		return true;
+	/* Huge PFN mappings are uncompactable so the policy doesn't apply. */
+	if (vma_test(vma, VMA_PFNMAP_BIT) && has_huge_fault)
+		return true;
+	return false;
+}
+
+static bool vma_file_allow_thp_tuneables(vm_flags_t vm_flags)
+{
+	/* THP=always? */
+	if (hugepage_global_always())
+		return true;
+	/* THP=madvise and marked MADV_HUGEPAGE? */
+	if (hugepage_global_enabled() && (vm_flags & VM_HUGEPAGE))
+		return true;
+	return false;
+}
+
+static bool vma_file_check_thp_tuneables(const struct vm_area_struct *vma,
+		vm_flags_t vm_flags, enum tva_type type)
+{
+	return vma_file_bypass_thp_tuneables(vma, type) ||
+		vma_file_allow_thp_tuneables(vm_flags);
+}
+
+static bool vma_can_map_huge_file(const struct vm_area_struct *vma,
+		vm_flags_t vm_flags, enum tva_type type)
+{
+	const bool has_huge_fault = vma->vm_ops->huge_fault;
+
+	/*
+	 * Enforce THP collapse requirements as necessary. Anonymous vmas
+	 * were already handled in thp_vma_allowable_orders().
+	 */
+	if (!vma_file_check_thp_tuneables(vma, vm_flags, type))
+		return false;
+
+	switch (type) {
+	case TVA_PAGEFAULT:
+		/*
+		 * Trust that ->huge_fault() handlers know what they are doing
+		 * in fault path.
+		 */
+		return has_huge_fault;
+	case TVA_SMAPS:
+		if (has_huge_fault)
+			return true;
+		fallthrough;
+	default:
+		/* Only regular file is valid in collapse path. */
+		return file_thp_enabled(vma);
+	}
+}
+
 unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma,
 					 vm_flags_t vm_flags,
 					 enum tva_type type,
@@ -190,27 +251,8 @@ unsigned long __thp_vma_allowable_orders
 						   vma, vma->vm_pgoff, 0,
 						   forced_collapse);
 
-	if (!vma_is_anonymous(vma)) {
-		/*
-		 * Enforce THP collapse requirements as necessary. Anonymous vmas
-		 * were already handled in thp_vma_allowable_orders().
-		 */
-		if (!forced_collapse &&
-		    (!hugepage_global_enabled() || (!(vm_flags & VM_HUGEPAGE) &&
-						    !hugepage_global_always())))
-			return 0;
-
-		/*
-		 * Trust that ->huge_fault() handlers know what they are doing
-		 * in fault path.
-		 */
-		if (((in_pf || smaps)) && vma->vm_ops->huge_fault)
-			return orders;
-		/* Only regular file is valid in collapse path */
-		if (((!in_pf || smaps)) && file_thp_enabled(vma))
-			return orders;
-		return 0;
-	}
+	if (!vma_is_anonymous(vma))
+		return vma_can_map_huge_file(vma, vm_flags, type) ? orders : 0;
 
 	if (vma_is_temporary_stack(vma))
 		return 0;
author maintainer
#318 lore raw

PATCH 315/438 mm/mlock: use the IRQ-safe accessor for NR_MLOCK in __munlock_folio()

In reply to Greg Kroah-Hartman

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

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

From: Shakeel Butt <[email protected]>

commit e14a3454806468b086fe2e4ca2e1bff95b528531 upstream.

NR_MLOCK is updated from interrupt context. __free_pages_prepare() clears a stray PG_mlocked and adjusts NR_MLOCK, and a folio can reach it with the flag still set from a bio completion handler:

  __free_pages_ok+0x6af/0x7a0
  <IRQ>
  __bio_release_pages+0xde/0x260
  __iomap_dio_bio_end_io+0x16e/0x1a0
  blk_update_request+0x14b/0x3d0
  blk_mq_end_request+0x18/0x30
  blk_done_softirq+0x49/0x60

The folio gets there like this. A MAP_SHARED file mapping is mlocked, so its page cache folios carry PG_mlocked, and an O_DIRECT write sourced from that mapping GUP-pins those same folios. munlock() then runs mlock_vma_pages_range(), which clears VM_LOCKED before walking the page tables to munlock each folio. A concurrent hole punch reaches the folio through the rmap (i_mmap_rwsem, not mmap_lock) and can land inside that
window: __folio_remove_rmap() -> munlock_vma_folio() sees VM_LOCKED already clear, so it neither queues the folio on the mlock batch nor takes a reference, and the pte it clears makes the pending mlock_pte_range() walk skip the folio at its !pte_present() check. filemap_remove_folio() then drops the page cache reference, leaving the bio's pin as the last one, released from the completion handler above.

So __zone_stat_mod_folio() here needs interrupts disabled, not merely preemption, and __munlock_folio() has a path where they are not: when the folio has already been taken off the LRU by somebody else the function jumps straight to the counter update without taking the lruvec lock. The read-modify-write of the per-CPU NR_MLOCK diff can then be interrupted by the softirq above, and one of the two decrements is lost, leaving Mlocked in /proc/meminfo permanently overstated.

Use zone_stat_mod_folio(). mod_zone_state()'s this_cpu_try_cmpxchg() is atomic against a same-CPU interrupt and retries, and on the path where the lruvec lock is held its cost is negligible next to the lock itself.

The UNEVICTABLE_PG* events are deliberately left on the __ accessors: they occupy different vm_event_states slots from the UNEVICTABLE_PGCLEARED that __free_pages_prepare() bumps, and nothing updates those two from interrupt context.

Fixes 2fbb0c10d1e8 ("mm/munlock: mlock_page() munlock_page() batch by pagevec")
Reported-by [email protected]
Cc Jann Horn <[email protected]>
Cc Liam R. Howlett <[email protected]>
Cc Lorenzo Stoakes <[email protected]>
Cc Matthew Wilcox (Oracle) <[email protected]>
Cc Pedro Falcato <[email protected]>
Cc Vlastimil Babka <[email protected]>
---
 mm/mlock.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/mlock.c +1 -1
@@ -141,7 +141,7 @@ static struct lruvec *__munlock_folio(st
 
 munlock:
 	if (folio_test_clear_mlocked(folio)) {
-		__zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);
+		zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages);
 		if (isolated || !folio_test_unevictable(folio))
 			__count_vm_events(UNEVICTABLE_PGMUNLOCKED, nr_pages);
 		else
author maintainer
#319 lore raw

PATCH 316/438 mm/mremap: account mm->locked_vm correctly for MREMAP_DONTUNMAP

In reply to Greg Kroah-Hartman

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

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

From: Lorenzo Stoakes (ARM) <[email protected]>

commit 397432cab17bccb600fd6c16ed593f1149042268 upstream.

When a VMA is mremap()'d with MREMAP_DONTUNMAP set, that results in the VMA being copied, but the source VMA not being unmapped.

If the VMA is mlock()'d this is a legal operation, though the source VMA has its VMA_LOCKED_BIT cleared.

However this is done in dontunmap_complete(), after mm->locked_vm was incremented via vrm_stat_account(), resulting in double-counting.

Worse, this is not even corrected when source VMA is unmapped, due to the VMA_LOCKED_BIT flag having been cleared.

This all works fine in the usual mremap() case (without MREMAP_DONTUNMAP), as the source VMA is unmapped with VMA_LOCKED_BIT intact, at which time mm->locked_vm is decremented accordingly.

Resolve the issue by invoking vrm_stat_account() only after dontunmap_complete() has run.

Note that MREMAP_DONTUNMAP requires old_len == new_len, so no need to account for a delta in size in this case.

The bug was introduced by commit b714ccb02a76 ("mm/mremap: complete refactor of move_vma()") which incorrectly reordered the accounting and the clearing of the VMA_LOCKED_BIT flag.

---
 mm/mremap.c |    9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)
mm/mremap.c +4 -5
@@ -1344,12 +1344,11 @@ static void dontunmap_complete(struct vm
 		if (vma_is_anonymous(vma) && !vma->vm_file)
 			vma->vm_pgoff = pgoff_unfaulted;
 	}
-
-	/* Because we won't unmap we don't need to touch locked_vm. */
 }
 
 static unsigned long move_vma(struct vma_remap_struct *vrm)
 {
+	const bool is_dontunmap = vrm->flags & MREMAP_DONTUNMAP;
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *new_vma;
 	unsigned long hiwater_vm;
@@ -1390,10 +1389,10 @@ static unsigned long move_vma(struct vma
 	 */
 	hiwater_vm = mm->hiwater_vm;
 
-	vrm_stat_account(vrm, vrm->new_len);
-	if (unlikely(!err && (vrm->flags & MREMAP_DONTUNMAP)))
+	if (unlikely(is_dontunmap && !err))
 		dontunmap_complete(vrm, new_vma);
-	else
+	vrm_stat_account(vrm, vrm->new_len);
+	if (!is_dontunmap || err)
 		unmap_source_vma(vrm);
 
 	mm->hiwater_vm = hiwater_vm;
author maintainer
#320 lore raw

PATCH 317/438 mm/shrinker: fix bogus set_shrinker_bit() with cgroup.memory=nokmem

In reply to Greg Kroah-Hartman

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

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

From: Jiayuan Chen <[email protected]>

commit 932cfb25e7ce98d1f93895671ec186a3087e4f80 upstream.

With cgroup.memory=nokmem, shrinker_memcg_alloc() bails out early and never allocates an id, so shrinker->id keeps the 0 it got from the kzalloc() in shrinker_alloc(). __list_lru_init() then copies that 0 into lru->shrinker_id, where it looks like a valid bit index.

Nothing calls expand_shrinker_info() on nokmem either, so shrinker_nr_max stays 0 and every memcg ends up with an empty map (map_nr_max == 0).

deferred_split_folio() hands a real memcg to __list_lru_add() regardless of whether the lru is memcg aware, so the first THP queued in a cgroup does set_shrinker_bit(memcg, nid, 0) and trips the bounds check:

WARNING: mm/shrinker.c:212 at set_shrinker_bit+0x7d/0x90, CPU#126
Call Trace:
 <TASK>
 deferred_split_folio+0x18c/0x220
 map_anon_folio_pmd_nopf+0xdd/0x130
 map_anon_folio_pmd_pf+0x14/0xb0
 do_huge_pmd_anonymous_page+0x1a1/0x620
 __handle_mm_fault+0xea9/0x10d0
 handle_mm_fault+0xe5/0x320
 do_user_addr_fault+0x1cc/0x870
 exc_page_fault+0x81/0x1b0
 asm_exc_page_fault+0x27/0x30
 </TASK>

Harmless, the WARN_ON_ONCE() is what keeps the out of bounds unit[] read from happening, but the id should not look valid in the first place. Clear it before returning.

Two other spots could paper over this: drop the id in __list_lru_init() when nokmem turns memcg_aware off, or make deferred_split_folio() pass NULL like list_lru_add_obj() does. Both leave shrinker->id lying around for the next caller, so fix it where the id is handed out.

Fixes fafaeceb89a5 ("mm: switch deferred split shrinker to list_lru")
Cc Usama Arif <[email protected]>
Cc Dave Chinner <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Kairui Song <[email protected]>
Cc Muchun Song <[email protected]>
Cc Roman Gushchin <[email protected]>
---
 mm/shrinker.c | 2 ++
 1 file changed, 2 insertions(+)
mm/shrinker.c +2 -0
index a70aab124a0e..7ec2a9704f6f 100644
@@ -227,6 +227,8 @@ static int shrinker_memcg_alloc(struct shrinker *shrinker)
 {
 	int id;
 
+	shrinker->id = -1;
+
 	if (mem_cgroup_disabled())
 		return -ENOSYS;
 	if (mem_cgroup_kmem_disabled() && !(shrinker->flags & SHRINKER_NONSLAB))
Signature · 1 line
2.55.0
author maintainer
#321 lore raw

PATCH 318/438 mm/vma: correctly unaccount on mmap_prepare() failure

In reply to Greg Kroah-Hartman

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

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

From: Lorenzo Stoakes (ARM) <[email protected]>

commit 6cc27d82196385fe06853319f74312a7d8019726 upstream.

__mmap_setup() accounts memory for relevant mappings via:

security_vm_enough_memory_mm()
-> __vm_enough_memory()

    -> vm_acct_memory()

If __mmap_setup() fails, this indicates that this accounting did not take place, and thus it's appropriate for __mmap_region() to jump to abort_munmap.

However if call_mmap_prepare() fails, it also jumps there and any accounted memory is not correctly unaccounted.

Fix this by handling each error separately.

Fixes c84bf6dd2b83 ("mm: introduce new .mmap_prepare() file callback")
Cc Jann Horn <[email protected]>
Cc Liam R. Howlett <[email protected]>
Cc Pedro Falcato <[email protected]>
Cc Vlastimil Babka <[email protected]>
---
 mm/vma.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
mm/vma.c +4 -2
@@ -2754,10 +2754,12 @@ static unsigned long __mmap_region(struc
 	map.check_ksm_early = can_set_ksm_flags_early(&map);
 
 	error = __mmap_setup(&map, &desc, uf);
-	if (!error && have_mmap_prepare)
-		error = call_mmap_prepare(&map, &desc);
 	if (error)
 		goto abort_munmap;
+	if (have_mmap_prepare)
+		error = call_mmap_prepare(&map, &desc);
+	if (error)
+		goto unacct_error;
 
 	if (map.check_ksm_early)
 		update_ksm_flags(&map);
author maintainer
#322 lore raw

PATCH 319/438 mm: filemap: retain mapped dropbehind folios

In reply to Greg Kroah-Hartman

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

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

From: Wenjie Qi <[email protected]>

commit 848d2ce2fce15fbdc083fbf9691bfa72911033c4 upstream.

Fault-around can map ready dropbehind folios without going through the normal page-cache lookup that clears dropbehind. A mapping represents a competing cached user, so retain the folio instead of forcibly unmapping it when writeback completes.

For a mapped folio, folio_unmap_invalidate() can call unmap_mapping_folio(), which takes i_mmap_rwsem and may sleep. Retaining mapped folios avoids this path when folio_end_dropbehind() runs in non-preemptible task context.

Tal was able to trigger a sleeping-in-atomic warning due to this [1].

Unmapped dropbehind folios continue through the existing invalidation path.

---
 mm/filemap.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
mm/filemap.c +1 -1
@@ -1616,7 +1616,7 @@ static void filemap_end_dropbehind(struc
 		return;
 	if (!folio_test_clear_dropbehind(folio))
 		return;
-	if (mapping)
+	if (mapping && !folio_mapped(folio))
 		folio_unmap_invalidate(mapping, folio, 0);
 }
 
author maintainer
#323 lore raw

PATCH 320/438 KEYS: encrypted: fix integer overflow of datablob_len

In reply to Greg Kroah-Hartman

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

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

From: Cen Zhang <[email protected]>

commit 8697c431e297eb0d0ab13dda6bc172b48a34f05c upstream.

encrypted_key_alloc() stores datablob_len in a u16. It is computed from multiple string and payload lengths. If the result exceeds U16_MAX, the assignment truncates the allocation size. KASAN reports a 32760-byte slab-out-of-bounds write when __ekey_init() copies the master key description into the undersized buffer.

The total payload length stored in key->datalen is also a u16. Use check_add_overflow() to reject values that do not fit either destination, and use kzalloc_flex() for the flexible-array allocation.

---
 security/keys/encrypted-keys/encrypted.c |   20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)
security/keys/encrypted-keys/encrypted.c +14 -6
@@ -19,6 +19,7 @@
 #include <linux/parser.h>
 #include <linux/string.h>
 #include <linux/err.h>
+#include <linux/overflow.h>
 #include <keys/user-type.h>
 #include <keys/trusted-type.h>
 #include <keys/encrypted-type.h>
@@ -579,6 +580,7 @@ static struct encrypted_key_payload *enc
 {
 	struct encrypted_key_payload *epayload = NULL;
 	unsigned short datablob_len;
+	unsigned short payload_totallen;
 	unsigned short decrypted_datalen;
 	unsigned short payload_datalen;
 	unsigned int encrypted_datalen;
@@ -632,16 +634,22 @@ static struct encrypted_key_payload *enc
 
 	encrypted_datalen = roundup(decrypted_datalen, blksize);
 
-	datablob_len = format_len + 1 + strlen(master_desc) + 1
-	    + strlen(datalen) + 1 + ivsize + 1 + encrypted_datalen;
+	if (check_add_overflow(format_len + 1 + strlen(master_desc) + 1
+			       + strlen(datalen) + 1 + ivsize + 1,
+			       encrypted_datalen, &datablob_len))
+		return ERR_PTR(-EINVAL);
+
+	if (check_add_overflow(datablob_len,
+			       payload_datalen + HASH_SIZE + 1,
+			       &payload_totallen))
+		return ERR_PTR(-EINVAL);
 
-	ret = key_payload_reserve(key, payload_datalen + datablob_len
-				  + HASH_SIZE + 1);
+	ret = key_payload_reserve(key, payload_totallen);
 	if (ret < 0)
 		return ERR_PTR(ret);
 
-	epayload = kzalloc(sizeof(*epayload) + payload_datalen +
-			   datablob_len + HASH_SIZE + 1, GFP_KERNEL);
+	epayload = kzalloc_flex(*epayload, payload_data, payload_totallen,
+				GFP_KERNEL);
 	if (!epayload)
 		return ERR_PTR(-ENOMEM);
 
author maintainer
#324 lore raw

PATCH 321/438 keys: translate request_key_auth pid for the reading procfs instance

In reply to Greg Kroah-Hartman

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

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

From: Maoyi Xie <[email protected]>

commit 0d6a4268b06084baafd8ee5d66955c7e1c2e053b upstream.

request_key_auth_describe() prints rka->pid into /proc/keys as a raw pid_t in the initial pid namespace. A reader can open /proc/keys through a mount in another pid namespace. That reader sees a number with no meaning there. The number can even name an unrelated task. The line needs VIEW on the key. So the reader either shares the key owner's uid or possesses the key.

The fix keeps a struct pid. Commit 4f82f45730c6 ("net ip6 flowlabel:
Make owner a union of struct pid * and kuid_t") gave /proc/net/ip6_flowlabel the same storage. The print goes through pid_nr_ns(). It renders against the pid namespace of the procfs instance the line is read through. Commit ad08978ab41c ("ipv6/flowlabel: simplify pid namespace lookup") moved that print to the same anchor. Output through an initial namespace /proc does not change. The line shows 0 for a requestor with no number in that namespace.

Translating at read time was the alternative. find_pid_ns() can resolve a recycled number. The line would then name a live task with no connection to the key. A stored struct pid gives 0 instead when the requestor has no number there.

---
 include/keys/request_key_auth-type.h |    2 +-
 security/keys/request_key_auth.c     |   12 +++++++++---
 2 files changed, 10 insertions(+), 4 deletions(-)
include/keys/request_key_auth-type.h +1 -1
@@ -22,7 +22,7 @@ struct request_key_auth {
 	const struct cred	*cred;
 	void			*callout_info;
 	size_t			callout_len;
-	pid_t			pid;
+	struct pid		*pid;
 	char			op[8];
 } __randomize_layout;
 
security/keys/request_key_auth.c +9 -3
@@ -9,6 +9,8 @@
 
 #include <linux/sched.h>
 #include <linux/err.h>
+#include <linux/pid.h>
+#include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
@@ -73,7 +75,10 @@ static void request_key_auth_describe(co
 	seq_puts(m, "key:");
 	seq_puts(m, key->description);
 	if (key_is_positive(key))
-		seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
+		seq_printf(m, " pid:%d ci:%zu",
+			   pid_nr_ns(rka->pid,
+				     proc_pid_ns(file_inode(m->file)->i_sb)),
+			   rka->callout_len);
 }
 
 /*
@@ -113,6 +118,7 @@ static void free_request_key_auth(struct
 	if (rka->cred)
 		put_cred(rka->cred);
 	kfree(rka->callout_info);
+	put_pid(rka->pid);
 	kfree(rka);
 }
 
@@ -226,14 +232,14 @@ struct key *request_key_auth_new(struct
 
 		irka = cred->request_key_auth->payload.data[0];
 		rka->cred = get_cred(irka->cred);
-		rka->pid = irka->pid;
+		rka->pid = get_pid(irka->pid);
 
 		up_read(&cred->request_key_auth->sem);
 	}
 	else {
 		/* it isn't - use this process as the context */
 		rka->cred = get_cred(cred);
-		rka->pid = current->pid;
+		rka->pid = get_pid(task_pid(current));
 	}
 
 	rka->target_key = key_get(target);
author maintainer
#325 lore raw

PATCH 322/438 KEYS: trusted: Fix tpm2_load_cmd() boundary check

In reply to Greg Kroah-Hartman

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

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

From: Jarkko Sakkinen <[email protected]>

commit 114f00d738f15dd8c7318369edcdc53dd6d08763 upstream.

tpm2_load_cmd() does boundary checks against the ASN.1 size i.e., payload->blob_len. Address this by passing the decoded blob size to tpm2_load_cmd(), and use it for the boundary checks.

---
 security/keys/trusted-keys/trusted_tpm2.c |   12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
security/keys/trusted-keys/trusted_tpm2.c +7 -5
@@ -100,7 +100,7 @@ struct tpm2_key_context {
 
 static int tpm2_key_decode(struct trusted_key_payload *payload,
 			   struct trusted_key_options *options,
-			   u8 **buf)
+			   u8 **buf, unsigned int *blob_len)
 {
 	int ret;
 	struct tpm2_key_context ctx;
@@ -121,6 +121,7 @@ static int tpm2_key_decode(struct truste
 		return -ENOMEM;
 
 	*buf = blob;
+	*blob_len = ctx.priv_len + ctx.pub_len;
 	options->keyhandle = ctx.parent;
 
 	memcpy(blob, ctx.priv, ctx.priv_len);
@@ -381,10 +382,11 @@ static int tpm2_load_cmd(struct tpm_chip
 	int rc;
 	u32 attrs;
 
-	rc = tpm2_key_decode(payload, options, &blob);
+	rc = tpm2_key_decode(payload, options, &blob, &blob_len);
 	if (rc) {
 		/* old form */
 		blob = payload->blob;
+		blob_len = payload->blob_len;
 		payload->old_format = 1;
 	} else {
 		/* Bind for cleanup: */
@@ -396,17 +398,17 @@ static int tpm2_load_cmd(struct tpm_chip
 		return -EINVAL;
 
 	/* must be big enough for at least the two be16 size counts */
-	if (payload->blob_len < 4)
+	if (blob_len < 4)
 		return -EINVAL;
 
 	private_len = get_unaligned_be16(blob);
 
 	/* must be big enough for following public_len */
-	if (private_len + 2 + 2 > (payload->blob_len))
+	if (private_len + 2 + 2 > blob_len)
 		return -E2BIG;
 
 	public_len = get_unaligned_be16(blob + 2 + private_len);
-	if (private_len + 2 + public_len + 2 > payload->blob_len)
+	if (private_len + 2 + public_len + 2 > blob_len)
 		return -E2BIG;
 
 	pub = blob + 2 + private_len + 2;
author maintainer
#326 lore raw

PATCH 323/438 sched_ext: Fix NULL sched deref in kfunc sub-sched error paths

In reply to Greg Kroah-Hartman

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

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

From: Wanwu Li <[email protected]>

commit 0a85182723b65ad8bee8131bc38fcf0347d6679b upstream.

When the root scheduler has sub-scheds attached, the COMPAT kfunc wrappers scx_bpf_select_cpu_and() and scx_bpf_dsq_insert_vtime() refuse the call and report to @p's scheduler:

	scx_error(scx_task_sched(p), "... must be used");

The wrappers are reachable with tasks that have no scheduler. scx_bpf_select_cpu_and() is in the select_cpu kfunc group, which scx_kfunc_context_filter() opens to BPF_PROG_TYPE_SYSCALL programs; scx_bpf_dsq_insert_vtime() is in the enqueue_dispatch group, which ops.enqueue() and ops.dispatch() may call with any KF_RCU task -- the group has no kf_tasks validation, and scx_dsq_insert_preamble() checks task ownership with scx_task_on_sched() precisely because @p may be an arbitrary task.

scx_task_sched(p) is p->scx.sched, which is NULL for tasks past sched_ext_dead() -- which clears it via scx_disable_and_exit_task() on exit -- and for idle tasks, which the enable paths skip as they are never scheduled through SCX. It is also an rcu_dereference_protected() that expects @p's pi_lock or rq lock, which neither wrapper holds. Passing NULL to scx_error() reaches scx_vexit(), which dereferences sch->exit_info, oopsing the kernel.

One concrete trigger exercised while developing the fix: a BPF_PROG_TYPE_SYSCALL program calling the select_cpu_and wrapper on an exited-but-not-reaped task while a sub-scheduler was attached (its pid stays findable while the zombie is unreaped; faulting instruction is the scx_vexit() prologue "mov r15,[rdi+0x398]" with RDI=NULL and 0x398 the offset of sch->exit_info):

sched_ext: BPF scheduler "kfunc_subsched_null" enabled
sched_ext: BPF sub-scheduler "kfunc_subsched_null" enabled
sched_ext: Unassociated program run_select_cpu_ (id 76)

  BUG: kernel NULL pointer dereference, address: 0000000000000398
  #PF: supervisor read access in kernel mode
  #PF: error_code(0x0000) - not-present page
  Oops: Oops: 0000 [#1] SMP NOPTI
  CPU: 7 UID: 0 PID: 8201 Comm: kfunc_test_runn Tainted: G W
  RIP: 0010:scx_vexit+0x25/0xa0
  Code: ... <4c> 8b bf 98 03 00 00 ...
  CR2: 0000000000000398
  Call Trace:
   <TASK>
   __scx_exit+0x4f/0x70
   scx_bpf_select_cpu_and+0xab/0xb0
   bpf_prog_430ed61a7b66e03a_run_select_cpu_and+0x9c/0xe7
   ? __x64_sys_bpf+0x2c/0x40
   bpf_prog_test_run_syscall+0x130/0x2f0
   __sys_bpf+0x930/0x10d0
   ? __x64_sys_bpf+0x2c/0x40
   __x64_sys_bpf+0x2c/0x40
   do_syscall_64+0xbc/0x460
   entry_SYSCALL_64_after_hwframe+0x76/0x7e
   </TASK>

Read @p's scheduler under RCU instead, which the wrappers can do from their guard(rcu)(): fault it when it can be determined, and when it can't be determined -- @p is a task past sched_ext_dead() or an idle task -- there is nothing obviously wrong to report, so just refuse the call as before without faulting any scheduler.

These COMPAT wrappers are scheduled for eventual removal once the deprecation grace period elapses, but until then -- and regardless of their removal timeline -- they must not oops the kernel on a task they are handed.

Fixes a5fa0708cbfd ("sched_ext: Enforce scheduling authority in dispatch and select_cpu operations")
---
 kernel/sched/ext/ext.c  |   11 +++++++++--
 kernel/sched/ext/idle.c |   11 +++++++++--
 2 files changed, 18 insertions(+), 4 deletions(-)
kernel/sched/ext/ext.c +9 -2
@@ -8964,10 +8964,17 @@ __bpf_kfunc void scx_bpf_dsq_insert_vtim
 #ifdef CONFIG_EXT_SUB_SCHED
 	/*
 	 * Disallow if any sub-scheds are attached. There is no way to tell
-	 * which scheduler called us, just error out @p's scheduler.
+	 * which scheduler called us, so error out @p's scheduler -- read it
+	 * under RCU as @p's locks aren't necessarily held here. @p may be a
+	 * task past sched_ext_dead() or an idle task, in which case its
+	 * scheduler can't be determined and there is nothing obviously wrong
+	 * to report; just refuse the call.
 	 */
 	if (unlikely(!list_empty(&sch->children))) {
-		scx_error(scx_task_sched(p), "__scx_bpf_dsq_insert_vtime() must be used");
+		struct scx_sched *tsch = scx_task_sched_rcu(p);
+
+		if (tsch)
+			scx_error(tsch, "__scx_bpf_dsq_insert_vtime() must be used");
 		return;
 	}
 #endif
kernel/sched/ext/idle.c +9 -2
@@ -1097,10 +1097,17 @@ __bpf_kfunc s32 scx_bpf_select_cpu_and(s
 #ifdef CONFIG_EXT_SUB_SCHED
 	/*
 	 * Disallow if any sub-scheds are attached. There is no way to tell
-	 * which scheduler called us, just error out @p's scheduler.
+	 * which scheduler called us, so error out @p's scheduler -- read it
+	 * under RCU as @p's locks aren't necessarily held here. @p may be a
+	 * task past sched_ext_dead() or an idle task, in which case its
+	 * scheduler can't be determined and there is nothing obviously wrong
+	 * to report; just refuse the call.
 	 */
 	if (unlikely(!list_empty(&sch->children))) {
-		scx_error(scx_task_sched(p), "__scx_bpf_select_cpu_and() must be used");
+		struct scx_sched *tsch = scx_task_sched_rcu(p);
+
+		if (tsch)
+			scx_error(tsch, "__scx_bpf_select_cpu_and() must be used");
 		return -EINVAL;
 	}
 #endif
author maintainer
#327 lore raw

PATCH 324/438 sched_ext: Close the pre-enable ops error claim window

In reply to Greg Kroah-Hartman

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

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

From: fangqiurong <[email protected]>

commit c7a1c6e8004ab12a9c9bfdcb603f60f9bf4a3cee upstream.

scx_alloc_and_add_sched() publishes ops->priv before scx_root_enable_workfn() switches the state to SCX_ENABLING. An error claimed via scx_bpf_error_bstr() from an associated BPF program in that window is consumed by scx_disable_workfn(), which takes the pre-enable shortcut in scx_root_disable(). The shortcut returns without any teardown and restores SCX_DISABLED with an unconditional scx_set_enable_state() xchg racing the enable workfn's own transition. The enable then completes with the claim consumed: the scheduler stays up but can never be disabled again, and bpf_scx_unreg() frees it while still in use, resulting in a use-after-free. Both WARN_ON_ONCE()s fire back to back:

  WARNING: kernel/sched/ext/ext.c:7522 at
  scx_root_enable_workfn+0xeec/0x1be0, CPU#3: scx_enable_help/276

  WARNING: kernel/sched/ext/ext.c:6398 at scx_root_disable+0xb50/0xdb8,
  CPU#0: sched_ext_helpe/664

scx_root_enable_workfn() switches to SCX_ENABLING before the scheduler allocation, so ops->priv is never visible while SCX_DISABLED. The allocation failure path restores SCX_DISABLED.

Fixes 105dcd005be2 ("sched_ext: Introduce scx_prog_sched()")
---
 kernel/sched/ext/ext.c |   16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)
kernel/sched/ext/ext.c +9 -7
@@ -7282,22 +7282,24 @@ static void scx_root_enable_workfn(struc
 #ifdef CONFIG_EXT_SUB_SCHED
 	cgroup_get(cgrp);
 #endif
+	/*
+	 * Transition to ENABLING to arm the disable path. Allocation failure
+	 * still unwinds locally. Full disabling on failure applies only after
+	 * scx_alloc_and_add_sched() succeeds.
+	 */
+	WARN_ON_ONCE(scx_set_enable_state(SCX_ENABLING) != SCX_DISABLED);
+	WARN_ON_ONCE(scx_root);
+
 	sch = scx_alloc_and_add_sched(cmd, cgrp, NULL);
 	if (IS_ERR(sch)) {
 		ret = PTR_ERR(sch);
+		WARN_ON_ONCE(scx_set_enable_state(SCX_DISABLED) != SCX_ENABLING);
 		goto err_free_tid_hash;
 	}
 
 	if (sch->is_cid_type)
 		static_branch_enable(&__scx_is_cid_type);
 
-	/*
-	 * Transition to ENABLING and clear exit info to arm the disable path.
-	 * Failure triggers full disabling from here on.
-	 */
-	WARN_ON_ONCE(scx_set_enable_state(SCX_ENABLING) != SCX_DISABLED);
-	WARN_ON_ONCE(scx_root);
-
 	atomic_long_set(&scx_nr_rejected, 0);
 
 	for_each_possible_cpu(cpu) {
author maintainer
#328 lore raw

PATCH 325/438 i2c: at91: release DMA channels on remove and probe error

In reply to Greg Kroah-Hartman

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

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

From: Shengzhuo Wei <[email protected]>

commit f7eeb1af8537b05953fb1c88ab8b59d94059a381 upstream.

at91_twi_configure_dma() requests exclusive tx/rx DMA channels, but nothing ever releases them on driver detach, and the probe error path after the channels are acquired (i2c_add_numbered_adapter() failure) returns without releasing them either, because the remove callback is not invoked after a failed probe.

Move the release into a helper, call it from the existing configure-failure path, the adapter-registration failure path, and at91_twi_remove().

---
 drivers/i2c/busses/i2c-at91-core.c   |    3 +++
 drivers/i2c/busses/i2c-at91-master.c |   12 +++++++++++-
 drivers/i2c/busses/i2c-at91.h        |    1 +
 3 files changed, 15 insertions(+), 1 deletion(-)
drivers/i2c/busses/i2c-at91-core.c +3 -0
@@ -255,6 +255,7 @@ static int at91_twi_probe(struct platfor
 	if (rc) {
 		pm_runtime_disable(dev->dev);
 		pm_runtime_set_suspended(dev->dev);
+		at91_twi_dma_release(dev);
 
 		return rc;
 	}
@@ -270,6 +271,8 @@ static void at91_twi_remove(struct platf
 
 	i2c_del_adapter(&dev->adapter);
 
+	at91_twi_dma_release(dev);
+
 	pm_runtime_disable(dev->dev);
 	pm_runtime_set_suspended(dev->dev);
 }
drivers/i2c/busses/i2c-at91-master.c +11 -1
@@ -817,11 +817,21 @@ static int at91_twi_configure_dma(struct
 error:
 	if (ret != -EPROBE_DEFER)
 		dev_info(dev->dev, "can't get DMA channel, continue without DMA support\n");
+	at91_twi_dma_release(dev);
+	return ret;
+}
+
+void at91_twi_dma_release(struct at91_twi_dev *dev)
+{
+	struct at91_twi_dma *dma = &dev->dma;
+
 	if (dma->chan_rx)
 		dma_release_channel(dma->chan_rx);
 	if (dma->chan_tx)
 		dma_release_channel(dma->chan_tx);
-	return ret;
+	dma->chan_rx = NULL;
+	dma->chan_tx = NULL;
+	dev->use_dma = false;
 }
 
 static int at91_init_twi_recovery_gpio(struct platform_device *pdev,
drivers/i2c/busses/i2c-at91.h +1 -0
@@ -172,6 +172,7 @@ void at91_twi_irq_restore(struct at91_tw
 void at91_init_twi_bus(struct at91_twi_dev *dev);
 
 void at91_init_twi_bus_master(struct at91_twi_dev *dev);
+void at91_twi_dma_release(struct at91_twi_dev *dev);
 int at91_twi_probe_master(struct platform_device *pdev, u32 phy_addr,
 			  struct at91_twi_dev *dev);
 
author maintainer
#329 lore raw

PATCH 326/438 i2c: atr: fix dangling adapter pointer on add failure

In reply to Greg Kroah-Hartman

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

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

From: Linkai Gong <[email protected]>

commit ad34235808b63a70ca4989b7a2852923193d06ef upstream.

i2c_atr_add_adapter() stores atr->adapter[chan_id] before i2c_add_adapter() so that the I2C bus notifier can match child clients during registration. On failure the channel is freed but the slot was left pointing at freed memory, which can lead to use-after-free in i2c_atr_del_adapter() / cleanup and also block reuse with -EEXIST.

Clear the slot on the i2c_add_adapter() error path before freeing chan.

Fixes a076a860acae ("media: i2c: add I2C Address Translator (ATR) support")
Cc <[email protected]> # v6.6+
---
 drivers/i2c/i2c-atr.c |    1 +
 1 file changed, 1 insertion(+)
drivers/i2c/i2c-atr.c +1 -0
@@ -855,6 +855,7 @@ int i2c_atr_add_adapter(struct i2c_atr *
 
 	ret = i2c_add_adapter(&chan->adap);
 	if (ret) {
+		atr->adapter[chan_id] = NULL;
 		dev_err(dev, "failed to add atr-adapter %u (error=%d)\n",
 			chan_id, ret);
 		goto err_free_alias_pool;
author maintainer
#330 lore raw

PATCH 327/438 i2c: qcom-cci: fix device_node refcount leak in cci_probe()/cci_remove()

In reply to Greg Kroah-Hartman

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

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

From: Liu Zhenlong <[email protected]>

commit 7362a1553eb09a8cdf8be7e509bd5309a8342486 upstream.

The of_node_put() matching of_node_get() runs after i2c_del_adapter(), whose trailing memset() zeroes adap->dev and thus adap->dev.of_node, making the put a no-op and leaking the node on every adapter removal and error cleanup.

Use a devm action: the pointer is captured at registration, out of reach of that memset(), and devres runs the put once on probe failure and detach, replacing the three manual of_node_put() calls. The setup loop uses the scoped iterator form so the child node is released automatically if devm_add_action_or_reset() fails mid-loop.

Fixes 02a4a69667a2 ("i2c: qcom-cci: don't put a device tree node before i2c_add_adapter()")
Assisted-by Claude:claude-opus-5
Cc <[email protected]> # v5.17+
---
 drivers/i2c/busses/i2c-qcom-cci.c |   20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/i2c/busses/i2c-qcom-cci.c +11 -9
@@ -497,10 +497,14 @@ static const struct dev_pm_ops qcom_cci_
 	SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL)
 };
 
+static void cci_put_of_node(void *data)
+{
+	of_node_put(data);
+}
+
 static int cci_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *child;
 	struct resource *r;
 	struct cci *cci;
 	int ret, i;
@@ -516,7 +520,7 @@ static int cci_probe(struct platform_dev
 	if (!cci->data)
 		return -ENOENT;
 
-	for_each_available_child_of_node(dev->of_node, child) {
+	for_each_available_child_of_node_scoped(dev->of_node, child) {
 		struct cci_master *master;
 		u32 idx;
 
@@ -537,6 +541,9 @@ static int cci_probe(struct platform_dev
 		master->adap.algo = &cci_algo;
 		master->adap.dev.parent = dev;
 		master->adap.dev.of_node = of_node_get(child);
+		ret = devm_add_action_or_reset(dev, cci_put_of_node, child);
+		if (ret)
+			return ret;
 		master->master = idx;
 		master->cci = cci;
 
@@ -606,10 +613,8 @@ static int cci_probe(struct platform_dev
 			continue;
 
 		ret = i2c_add_adapter(&cci->master[i].adap);
-		if (ret < 0) {
-			of_node_put(cci->master[i].adap.dev.of_node);
+		if (ret < 0)
 			goto error_i2c;
-		}
 	}
 
 	return 0;
@@ -617,10 +622,8 @@ static int cci_probe(struct platform_dev
 error_i2c:
 
 	for (--i ; i >= 0; i--) {
-		if (cci->master[i].cci) {
+		if (cci->master[i].cci)
 			i2c_del_adapter(&cci->master[i].adap);
-			of_node_put(cci->master[i].adap.dev.of_node);
-		}
 	}
 disable_clocks:
 	cci_disable_clocks(cci);
@@ -636,7 +639,6 @@ static void cci_remove(struct platform_d
 	for (i = 0; i < cci->data->num_masters; i++) {
 		if (cci->master[i].cci) {
 			i2c_del_adapter(&cci->master[i].adap);
-			of_node_put(cci->master[i].adap.dev.of_node);
 			cci_halt(cci, i);
 		}
 	}
author maintainer
#331 lore raw

PATCH 328/438 i2c: imx: release DMA channels on probe error

In reply to Greg Kroah-Hartman

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

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

From: Shengzhuo Wei <[email protected]>

commit e9f03b9625e2eeaca357b065c92d5b14064a1583 upstream.

i2c_imx_dma_request() acquires exclusive tx/rx DMA channels and is
optional: on errors other than -EPROBE_DEFER the driver falls back to PIO mode and probe continues. If i2c_add_numbered_adapter() then fails, probe returns through clk_notifier_unregister without releasing the channels, because the remove callback is not invoked after a failed probe.

Release the channels on the probe error path, mirroring i2c_imx_remove().

Fixes ce1a78840ff7 ("i2c: imx: add DMA support for freescale i2c driver")
Assisted-by GLM:5.3
Cc <[email protected]> # v3.19+
---
 drivers/i2c/busses/i2c-imx.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/i2c/busses/i2c-imx.c +2 -0
@@ -1880,6 +1880,8 @@ static int i2c_imx_probe(struct platform
 
 clk_notifier_unregister:
 	clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
+	if (i2c_imx->dma)
+		i2c_imx_dma_free(i2c_imx);
 	free_irq(irq, i2c_imx);
 rpm_disable:
 	pm_runtime_put_noidle(&pdev->dev);
author maintainer
#332 lore raw

PATCH 329/438 i2c: imx: disable autosuspend on remove

In reply to Greg Kroah-Hartman

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

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

From: Guangshuo Li <[email protected]>

commit e0c3e9d76adbe522dd420a766ce42d03ce887c29 upstream.

i2c_imx_probe() enables runtime PM autosuspend with pm_runtime_use_autosuspend(). The probe error path correctly undoes this setting with pm_runtime_dont_use_autosuspend(), but the normal remove path only disables runtime PM.

The runtime PM API requires pm_runtime_use_autosuspend() to be undone with pm_runtime_dont_use_autosuspend() at driver exit unless runtime PM was enabled with devm_pm_runtime_enable(). Leaving the autosuspend flag set therefore leaves the runtime PM state incompletely cleaned up after the driver is unbound.

Add the missing pm_runtime_dont_use_autosuspend() call to the remove path.

This issue was found by manual code inspection.

Fixes 588eb93ea49f ("i2c: imx: add runtime pm support to improve the performance")
Cc <[email protected]> # v4.5+
---
 drivers/i2c/busses/i2c-imx.c |    1 +
 1 file changed, 1 insertion(+)
drivers/i2c/busses/i2c-imx.c +1 -0
@@ -1922,6 +1922,7 @@ static void i2c_imx_remove(struct platfo
 
 	pm_runtime_put_noidle(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
 }
 
 static int i2c_imx_runtime_suspend(struct device *dev)
author maintainer
#333 lore raw

PATCH 330/438 IB/mlx4: Fix use-after-free on pkey sysfs registration failure

In reply to Greg Kroah-Hartman

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

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

From: Shuangpeng Bai <[email protected]>

commit 1af874e9f4ce22ccf8b10ab5462f32c70d3be21a upstream.

register_pkey_tree() ignores errors from register_one_pkey_tree() and continues registering the remaining slaves. The per-slave error path has already released the pkey parent kobjects, but their pointers remain stored in the device. A later device cleanup therefore passes the stale pointers to kobject_put(), causing a use-after-free.

Clear the parent pointers after releasing a failed slave tree and skip unregistered trees during device cleanup. This preserves the existing best-effort registration behavior while preventing a second cleanup of the failed tree.

Fixes c1e7e466120b ("IB/mlx4: Add iov directory in sysfs under the ib device")
---
 drivers/infiniband/hw/mlx4/sysfs.c |    4 ++++
 1 file changed, 4 insertions(+)
drivers/infiniband/hw/mlx4/sysfs.c +4 -0
@@ -751,11 +751,13 @@ err_add:
 		kobject_put(p);
 	}
 	kobject_put(dev->dev_ports_parent[slave]);
+	dev->dev_ports_parent[slave] = NULL;
 
 err_ports:
 	kobject_put(dev->pkeys.device_parent[slave]);
 	/* extra put for the device_parent create_and_add */
 	kobject_put(dev->pkeys.device_parent[slave]);
+	dev->pkeys.device_parent[slave] = NULL;
 
 fail_dev:
 	kobject_put(dev->iov_parent);
@@ -785,6 +787,8 @@ static void unregister_pkey_tree(struct
 		return;
 
 	for (slave = device->dev->persist->num_vfs; slave >= 0; --slave) {
+		if (!device->pkeys.device_parent[slave])
+			continue;
 		list_for_each_entry_safe(p, t,
 					 &device->pkeys.pkey_port_list[slave],
 					 entry) {
author maintainer
#334 lore raw

PATCH 331/438 IB/hfi1: Resolve the credit-return buffer through the send contexts node

In reply to Greg Kroah-Hartman

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

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

From: Shuhei Takeshita <[email protected]>

commit 975396b9e5a4028e649f4b9a6a5ca5dfb76a824b upstream.

hfi1_file_mmap()'s PIO_CRED case derives this context's credit-return page offset, and the DMA handle for it, from dd->cr_base[uctxt->numa_id]. uctxt->numa_id is the node of whichever CPU the process happened to be running on, but the entry itself lives in the credit-return allocation of the send context's own node:

	sc->hw_free = &sc->dd->cr_base[sc->node].va[gc].cr[index];

and user send contexts are allocated with sc_alloc(dd, SC_USER, ..., dd->node), the HFI-local node. On a multi-socket host with the process running off that node the two allocations differ, so the subtraction produces an offset into an unrelated buffer and the DMA handle belongs to the wrong allocation.

Use the send context's own node for all three references. The continuation lines are reindented at the same time; they mixed spaces and tabs.

---
 drivers/infiniband/hw/hfi1/file_ops.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/infiniband/hw/hfi1/file_ops.c +4 -4
@@ -382,10 +382,10 @@ static int hfi1_file_mmap(struct file *f
 		 * of enabled contexts > 64 and 128 respectively).
 		 */
 		cr_page_offset = ((u64)uctxt->sc->hw_free -
-			  	     (u64)dd->cr_base[uctxt->numa_id].va) &
-				   PAGE_MASK;
-		memvirt = dd->cr_base[uctxt->numa_id].va + cr_page_offset;
-		memdma = dd->cr_base[uctxt->numa_id].dma + cr_page_offset;
+				  (u64)dd->cr_base[uctxt->sc->node].va) &
+				 PAGE_MASK;
+		memvirt = dd->cr_base[uctxt->sc->node].va + cr_page_offset;
+		memdma = dd->cr_base[uctxt->sc->node].dma + cr_page_offset;
 		memlen = PAGE_SIZE;
 		flags &= ~VM_MAYWRITE;
 		flags |= VM_DONTCOPY | VM_DONTEXPAND;
author maintainer
#335 lore raw

PATCH 332/438 IB/hfi1: Fix the PIO_CRED credit-return mmap

In reply to Greg Kroah-Hartman

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

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

From: Shuhei Takeshita <[email protected]>

commit 62f0f34fbd2b2d5653d33d3b9d42fdcabb1c0101 upstream.

hfi1_file_mmap()'s PIO_CRED case must hand user space the single credit-return page that holds this context's entry. That page is the second or third page of the per-node credit-return allocation once the hardware send context index reaches 64 or 128, so the failure below is
intermittent: when the entry lands on the first page the offset is zero and everything works.

Two things are wrong.

First, cr_page_offset is a byte offset but .va is a struct credit_return *, so adding it is pointer arithmetic and scales the offset by sizeof(struct credit_return) == 64. memvirt then lands 256 KiB or 512 KiB past a 10240-byte allocation. With an IOMMU translating, that address is inside the vmalloc range but in no vm_area, so dma_mmap_coherent() -> iommu_dma_mmap() finds no pages, vmalloc_to_pfn() returns page_to_pfn(NULL), and remap_pfn_range() installs a frame above MAXPHYADDR. The first user read then takes:

psm2_ep_open_pr: Corrupted page table at address 7a14d007e000 PGD 800000013886a067 P4D 800000013886a067 PUD 13886b067 PMD 13886c067

                                            PTE 800049168e911235
  Oops: Bad pagetable: 000d [#1] SMP PTI

Second, and still wrong once the arithmetic is corrected, dma_mmap_coherent() describes a whole coherent buffer and selects the page within it with vma->vm_pgoff. Offsetting cpu_addr has no effect:
for a vmap'd allocation iommu_dma_mmap() uses cpu_addr only to locate the vm_area and then maps pages[vm_pgoff], which hfi1_file_mmap() has just set to 0. User space therefore always receives the first credit-return page, every credit read is for the wrong context, and send PIO stalls forever.

Use the DMA API as intended: pass the base of the allocation with its full length and select the page with vm_pgoff. A separate length is needed because memlen must keep describing the VMA for the existing size check. The dma-direct path stays correct as well, since dma_direct_mmap() adds the same vm_pgoff to the base pfn.

Tested on a Dell T7610 (Xeon E5-2650 v2, Intel IOMMU in DMA-FQ mode) against a Threadripper PRO 3995WX peer, both Omni-Path 100. Before this change psm2_ep_open() Oopses the kernel; with only the arithmetic corrected psm2_ep_open() succeeds but any transfer that uses send PIO hangs, PSM2_SDMA=2 (send PIO disabled) completing normally while PSM2_SDMA=0 (send PIO only) hangs every time. With this change send PIO, send DMA and the default mixed mode all work.

Fixes 1ec82317a1da ("IB/hfi1: Use dma_mmap_coherent for matching buffers")
---
 drivers/infiniband/hw/hfi1/file_ops.c |   21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)
drivers/infiniband/hw/hfi1/file_ops.c +16 -5
@@ -326,6 +326,7 @@ static int hfi1_file_mmap(struct file *f
 	void *memvirt = NULL;
 	dma_addr_t memdma = 0;
 	u8 subctxt, mapio = 0, vmf = 0, type;
+	size_t memdmalen = 0;
 	ssize_t memlen = 0;
 	int ret = 0;
 	u16 ctxt;
@@ -371,7 +372,9 @@ static int hfi1_file_mmap(struct file *f
 		mapio = 1;
 		break;
 	case PIO_CRED: {
+		struct credit_return_base *cr = &dd->cr_base[uctxt->sc->node];
 		u64 cr_page_offset;
+
 		if (flags & VM_WRITE) {
 			ret = -EPERM;
 			goto done;
@@ -381,11 +384,18 @@ static int hfi1_file_mmap(struct file *f
 		 * second or third page allocated for credit returns (if number
 		 * of enabled contexts > 64 and 128 respectively).
 		 */
-		cr_page_offset = ((u64)uctxt->sc->hw_free -
-				  (u64)dd->cr_base[uctxt->sc->node].va) &
+		cr_page_offset = ((u64)uctxt->sc->hw_free - (u64)cr->va) &
 				 PAGE_MASK;
-		memvirt = dd->cr_base[uctxt->sc->node].va + cr_page_offset;
-		memdma = dd->cr_base[uctxt->sc->node].dma + cr_page_offset;
+		/*
+		 * dma_mmap_coherent() describes the whole coherent buffer and
+		 * selects the page within it with vma->vm_pgoff, so pass the
+		 * base of the allocation and its length and let vm_pgoff pick
+		 * the page.
+		 */
+		vma->vm_pgoff = cr_page_offset >> PAGE_SHIFT;
+		memvirt = cr->va;
+		memdma = cr->dma;
+		memdmalen = TXE_NUM_CONTEXTS * sizeof(struct credit_return);
 		memlen = PAGE_SIZE;
 		flags &= ~VM_MAYWRITE;
 		flags |= VM_DONTCOPY | VM_DONTEXPAND;
@@ -567,7 +577,8 @@ static int hfi1_file_mmap(struct file *f
 		ret = 0;
 	} else if (memdma) {
 		ret = dma_mmap_coherent(&dd->pcidev->dev, vma,
-					memvirt, memdma, memlen);
+					memvirt, memdma,
+					memdmalen ? memdmalen : memlen);
 	} else if (mapio) {
 		ret = io_remap_pfn_range(vma, vma->vm_start,
 					 PFN_DOWN(memaddr),
author maintainer
#336 lore raw

PATCH 333/438 selinux: preserve user SID across nested backing files

In reply to Greg Kroah-Hartman

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

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

From: Karl Mehltretter <[email protected]>

commit 8c0c602202b9a4909b00bc3354e3c0355bc69e65 upstream.

SELinux saves the user file SID in a backing-file security blob so it remains available after mmap() replaces vma->vm_file with a backing file.

For nested backing files (overlayfs over overlayfs, or FUSE passthrough backed by overlayfs), user_file may itself be a backing file. Its fsec->sid is the SID of the mounter that opened it, rather than the user that opened the top-level file. mprotect() then checks fd { use } against the mounter SID. This can incorrectly deny access without a domain transition, or check the wrong target SID after one.

Copy the saved user SID when user_file is a backing file. Keep using the regular file SID for the first backing layer.

With two nested overlayfs mounts and SELinux enforcing, mprotect(PROT_READ) returns EACCES with an fd { use } denial against the mounter SID. With this change, mprotect() succeeds.

Tested on arm64 QEMU with a small BusyBox initramfs and a purpose-built SELinux policy. The original test was also repeated with Fedora Cloud Base 44 userspace and gave the same result.

Fixes 82544d36b172 ("selinux: fix overlayfs mmap() and mprotect() access checks")
Assisted-by LLM
---
 security/selinux/hooks.c          |    9 ++++++++-
 security/selinux/include/objsec.h |    2 +-
 2 files changed, 9 insertions(+), 2 deletions(-)
security/selinux/hooks.c +8 -1
@@ -3841,13 +3841,20 @@ static int selinux_file_alloc_security(s
 	return 0;
 }
 
+static inline u32 selinux_file_user_sid(const struct file *file)
+{
+	if (unlikely(file->f_mode & FMODE_BACKING))
+		return selinux_backing_file(file)->uf_sid;
+	return selinux_file(file)->sid;
+}
+
 static int selinux_backing_file_alloc(struct file *backing_file,
 				      const struct file *user_file)
 {
 	struct backing_file_security_struct *bfsec;
 
 	bfsec = selinux_backing_file(backing_file);
-	bfsec->uf_sid = selinux_file(user_file)->sid;
+	bfsec->uf_sid = selinux_file_user_sid(user_file);
 
 	return 0;
 }
security/selinux/include/objsec.h +1 -1
@@ -87,7 +87,7 @@ struct file_security_struct {
 };
 
 struct backing_file_security_struct {
-	u32 uf_sid; /* associated user file fsec->sid */
+	u32 uf_sid; /* top-level user file fsec->sid */
 };
 
 struct superblock_security_struct {
author maintainer
#337 lore raw

PATCH 334/438 selinux: recheck intermediate backing files on mprotect()

In reply to Greg Kroah-Hartman

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

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

From: Karl Mehltretter <[email protected]>

commit 78fc54b934bfb2c18aad8154c7302067146946f9 upstream.

mprotect() can be used to bypass the SELinux checks that mmap() performs against the intermediate layers of a stacked filesystem.

mmap() checks every backing layer as the request descends through the stack. mprotect() only has the lowest backing file in vma->vm_file, so it rechecks the top-level user and the lowest mounter, but skips the mounters of every layer in between. With two nested overlayfs mounts and a policy denying mounter_t -> middle_file_t:file { execute }, a direct mmap(PROT_EXEC) is denied:

avc: denied { execute } for pid=71 comm="nested_exec"
path="/payload" dev="overlay" ino=9 scontext=user_u:base_r:mounter_t tcontext=user_u:object_r:middle_file_t tclass=file permissive=0

while mmap(PROT_NONE) followed by mprotect(PROT_EXEC) succeeds.

Preserve each intermediate path, mounter SID and file-description SID in the backing-file security blob, copying the saved entries when another backing layer is opened. Allocate the array only for nested backing files, and release it and the path references in the backing_file_free hook.

During mprotect(), recheck fd { use } and the requested inode permissions for every saved mounter, and include the intermediate layers in the execmod checks. Policy for nested stacking may then need to grant intermediate mounters what a direct mmap() already requires, and execmod on intermediate labels for binaries using text relocations.

Tested on arm64 QEMU with a small BusyBox initramfs and a purpose-built SELinux policy, on a mainline tree containing
commit f2381b546e7e ("fs: fix user path of nested backing files").

Fixes 82544d36b172 ("selinux: fix overlayfs mmap() and mprotect() access checks")
Assisted-by LLM
[PM: subject tweak]
---
 security/selinux/hooks.c          |  141 +++++++++++++++++++++++++++++++++-----
 security/selinux/include/objsec.h |    8 ++
 2 files changed, 133 insertions(+), 16 deletions(-)
security/selinux/hooks.c +125 -16
@@ -1672,26 +1672,32 @@ static int cred_has_capability(const str
 	return rc;
 }
 
-/* Check whether a task has a particular permission to an inode.
-   The 'adp' parameter is optional and allows other audit
-   data to be passed (e.g. the dentry). */
-static int inode_has_perm(const struct cred *cred,
-			  struct inode *inode,
-			  u32 perms,
-			  struct common_audit_data *adp)
+/*
+ * Check whether a SID has a particular permission to an inode.  The 'adp'
+ * parameter is optional and allows other audit data to be passed (e.g. the
+ * dentry).
+ */
+static int inode_sid_has_perm(u32 sid, struct inode *inode, u32 perms,
+			      struct common_audit_data *adp)
 {
 	struct inode_security_struct *isec;
-	u32 sid;
 
 	if (unlikely(IS_PRIVATE(inode)))
 		return 0;
 
-	sid = cred_sid(cred);
 	isec = selinux_inode(inode);
 
 	return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
 }
 
+static int inode_has_perm(const struct cred *cred,
+			  struct inode *inode,
+			  u32 perms,
+			  struct common_audit_data *adp)
+{
+	return inode_sid_has_perm(cred_sid(cred), inode, perms, adp);
+}
+
 /* Same as inode_has_perm, but pass explicit audit data containing
    the dentry to help the auditing code to more easily generate the
    pathname if needed. */
@@ -3852,13 +3858,63 @@ static int selinux_backing_file_alloc(st
 				      const struct file *user_file)
 {
 	struct backing_file_security_struct *bfsec;
+	const struct backing_file_security_struct *ubfsec;
+	struct backing_file_security_layer *layer;
+	u32 i;
 
 	bfsec = selinux_backing_file(backing_file);
 	bfsec->uf_sid = selinux_file_user_sid(user_file);
+	if (!(user_file->f_mode & FMODE_BACKING))
+		return 0;
+
+	ubfsec = selinux_backing_file(user_file);
+	/* a wrapped count would make kmalloc_array() return ZERO_SIZE_PTR */
+	if (unlikely(ubfsec->layer_count == U32_MAX))
+		return -EOVERFLOW;
+
+	/*
+	 * The final VMA only retains the lowest backing file, so record the
+	 * whole chain here rather than in the mmap hook, where concurrent
+	 * mappings would have to be serialized.  Size it dynamically: erofs
+	 * inode sharing adds a backing file without bumping s_stack_depth.
+	 */
+	bfsec->layers = kmalloc_array(ubfsec->layer_count + 1,
+				      sizeof(*bfsec->layers), GFP_KERNEL);
+	if (!bfsec->layers)
+		return -ENOMEM;
+
+	for (i = 0; i < ubfsec->layer_count; i++) {
+		layer = &bfsec->layers[i];
+		*layer = ubfsec->layers[i];
+		path_get(&layer->path);
+	}
+
+	/* f_path, not file_user_path(): this layer, not the top-level file */
+	layer = &bfsec->layers[i];
+	layer->path = user_file->f_path;
+	layer->mounter_sid = cred_sid(user_file->f_cred);
+	layer->fd_sid = selinux_file(user_file)->sid;
+	path_get(&layer->path);
+	bfsec->layer_count = ubfsec->layer_count + 1;
 
 	return 0;
 }
 
+static void selinux_backing_file_free(struct file *backing_file)
+{
+	struct backing_file_security_struct *bfsec;
+
+	/* security_backing_file_free() may be called twice after an error */
+	if (!backing_file_security(backing_file))
+		return;
+
+	bfsec = selinux_backing_file(backing_file);
+	while (bfsec->layer_count)
+		path_put(&bfsec->layers[--bfsec->layer_count].path);
+	kfree(bfsec->layers);
+	bfsec->layers = NULL;
+}
+
 /*
  * Check whether a task has the ioctl permission and cmd
  * operation to an inode.
@@ -3976,6 +4032,53 @@ static int selinux_file_ioctl_compat(str
 
 static int default_noexec __ro_after_init;
 
+static u32 file_map_prot_to_av(unsigned long prot, bool shared)
+{
+	u32 av = FILE__READ;
+
+	if (shared && (prot & PROT_WRITE))
+		av |= FILE__WRITE;
+	if (prot & PROT_EXEC)
+		av |= FILE__EXECUTE;
+
+	return av;
+}
+
+static int backing_mounters_has_perm(const struct file *file, u32 av)
+{
+	const struct backing_file_security_struct *bfsec;
+	const struct backing_file_security_layer *layer;
+	struct common_audit_data ad;
+	struct inode *inode;
+	u32 i;
+	int rc;
+
+	if (WARN_ON_ONCE(!(file->f_mode & FMODE_BACKING)))
+		return -EIO;
+
+	bfsec = selinux_backing_file(file);
+	for (i = 0; i < bfsec->layer_count; i++) {
+		layer = &bfsec->layers[i];
+		inode = d_inode(layer->path.dentry);
+
+		ad.type = LSM_AUDIT_DATA_PATH;
+		ad.u.path = layer->path;
+
+		if (layer->mounter_sid != layer->fd_sid) {
+			rc = avc_has_perm(layer->mounter_sid, layer->fd_sid,
+					  SECCLASS_FD, FD__USE, &ad);
+			if (rc)
+				return rc;
+		}
+
+		rc = inode_sid_has_perm(layer->mounter_sid, inode, av, &ad);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
 static int __file_map_prot_check(const struct file *file, unsigned long prot,
 				 bool shared, bool mounter_check,
 				 bool bf_user_file)
@@ -4009,14 +4112,10 @@ static int __file_map_prot_check(const s
 	if (file) {
 		const struct cred *cred = mounter_check ?
 				file->f_cred : current_cred();
-		/* "read" always possible, "write" only if shared */
-		u32 av = FILE__READ;
-		if (shared && prot_write)
-			av |= FILE__WRITE;
-		if (prot_exec)
-			av |= FILE__EXECUTE;
 
-		return __file_has_perm(cred, file, av, bf_user_file);
+		return __file_has_perm(cred, file,
+				       file_map_prot_to_av(prot, shared),
+				       bf_user_file);
 	}
 
 	return 0;
@@ -4111,6 +4210,7 @@ static int selinux_file_mprotect(struct
 	int rc;
 	const struct cred *cred = current_cred();
 	u32 sid = cred_sid(cred);
+	u32 av;
 	const struct file *file = vma->vm_file;
 	bool backing_file;
 	bool shared = vma->vm_flags & VM_SHARED;
@@ -4154,6 +4254,10 @@ static int selinux_file_mprotect(struct
 			if (rc)
 				return rc;
 			if (backing_file) {
+				rc = backing_mounters_has_perm(file,
+							       FILE__EXECMOD);
+				if (rc)
+					return rc;
 				rc = file_has_perm(file->f_cred, file,
 						   FILE__EXECMOD);
 				if (rc)
@@ -4166,6 +4270,10 @@ static int selinux_file_mprotect(struct
 	if (rc)
 		return rc;
 	if (backing_file) {
+		av = file_map_prot_to_av(prot, shared);
+		rc = backing_mounters_has_perm(file, av);
+		if (rc)
+			return rc;
 		rc = file_map_prot_check(file, prot, shared, true);
 		if (rc)
 			return rc;
@@ -7635,6 +7743,7 @@ static struct security_hook_list selinux
 	LSM_HOOK_INIT(file_permission, selinux_file_permission),
 	LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
 	LSM_HOOK_INIT(backing_file_alloc, selinux_backing_file_alloc),
+	LSM_HOOK_INIT(backing_file_free, selinux_backing_file_free),
 	LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
 	LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat),
 	LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
security/selinux/include/objsec.h +8 -0
@@ -86,8 +86,16 @@ struct file_security_struct {
 	u32 pseqno; /* Policy seqno at the time of file open */
 };
 
+struct backing_file_security_layer {
+	struct path path; /* this layer's real path */
+	u32 mounter_sid; /* SID of the mounter that opened it */
+	u32 fd_sid; /* SID of its open file description */
+};
+
 struct backing_file_security_struct {
 	u32 uf_sid; /* top-level user file fsec->sid */
+	u32 layer_count; /* number of intermediate backing files */
+	struct backing_file_security_layer *layers;
 };
 
 struct superblock_security_struct {
author maintainer
#338 lore raw

PATCH 335/438 selinux: always fill AVC decision in avc_has_perm_noaudit()

In reply to Greg Kroah-Hartman

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

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

From: Christian Göttsche <[email protected]>

commit 8861db305103107199b1426f25fde1fb6d465583 upstream.

avc_has_perm_noaudit() is documented to return a copy of the access decision in @avd, but its early return for an empty requested permission set leaves the buffer untouched. All callers pass an uninitialized stack variable and afterwards feed it to avc_audit(), and the inode hook even stores it in the per-task decision cache.

Fill in a deny-all, audit-all decision, similar to avd_init(), so every caller receives a defined value at no cost on the hot path.

Fixes e6f2f381e4015386 ("selinux: replace BUG_ONs with WARN_ONs in avc.c")
---
 security/selinux/avc.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
security/selinux/avc.c +4 -1
@@ -1150,8 +1150,11 @@ inline int avc_has_perm_noaudit(u32 ssid
 	u32 denied;
 	struct avc_node *node;
 
-	if (WARN_ON(!requested))
+	if (WARN_ON(!requested)) {
+		/* Provide a deny-all, audit-all decision to the caller. */
+		*avd = (struct av_decision){ .auditdeny = 0xffffffff };
 		return -EACCES;
+	}
 
 	rcu_read_lock();
 	node = avc_lookup(ssid, tsid, tclass);
author maintainer
#339 lore raw

PATCH 336/438 power: sequencing: dont call .post_enable() if pwrseq_unit_enable() failed

In reply to Greg Kroah-Hartman

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

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

From: Bartosz Golaszewski <[email protected]>

commit 5f90f85eae4e9d2e9628b2019870994ba830b533 upstream.

If the call to pwrseq_unit_enable() failed in pwrseq_enable(), bail out instead of calling target->post_enable() which assumes the target was successfully enabled.

Fixes 249ebf3f65f8 ("power: sequencing: implement the pwrseq core")
---
 drivers/power/sequencing/core.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/power/sequencing/core.c +2 -0
@@ -912,6 +912,8 @@ int pwrseq_power_on(struct pwrseq_desc *
 		if (!ret)
 			desc->powered_on = true;
 	}
+	if (ret)
+		return ret;
 
 	if (target->post_enable) {
 		ret = target->post_enable(pwrseq);
author maintainer
#340 lore raw

PATCH 337/438 power: sequencing: fix NULL-pointer dereference in pwrseq_unit_new()

In reply to Greg Kroah-Hartman

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

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

From: Bartosz Golaszewski <[email protected]>

commit 115b303e8e093d964089ec6f3c40d984d77b33d0 upstream.

If memory allocation fails in pwrseq_unit_setup_deps(), pwrseq_unit_put() is called to release the partially initialized unit. However, we've never initialized unit->list and pwrseq_unit_release() will unconditionally call list_del() on it. Initialize unit->list right after allocating the unit struct.

---
 drivers/power/sequencing/core.c |    1 +
 1 file changed, 1 insertion(+)
drivers/power/sequencing/core.c +1 -0
@@ -101,6 +101,7 @@ static struct pwrseq_unit *pwrseq_unit_n
 	}
 
 	kref_init(&unit->ref);
+	INIT_LIST_HEAD(&unit->list);
 	INIT_LIST_HEAD(&unit->deps);
 	unit->enable = data->enable;
 	unit->disable = data->disable;
author maintainer
#341 lore raw

PATCH 338/438 power: sequencing: fix NULL-pointer dereference in pwrseq_device_register()

In reply to Greg Kroah-Hartman

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

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

From: Bartosz Golaszewski <[email protected]>

commit 242da4318d97380741516b595af3920207b2f0f1 upstream.

If dev_set_name() fails in pwrseq_device_register(), we jump to the err_put_pwrseq label before initializing pwrseq->targets. pwrseq_release() will try to iterate over targets unconditionally and subsequently dereference an invalid pointer. Move the call to dev_set_name() after the list head is initialized.

---
 drivers/power/sequencing/core.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/power/sequencing/core.c +4 -4
@@ -505,10 +505,6 @@ pwrseq_device_register(const struct pwrs
 	 */
 	device_initialize(&pwrseq->dev);
 
-	ret = dev_set_name(&pwrseq->dev, "pwrseq.%d", pwrseq->id);
-	if (ret)
-		goto err_put_pwrseq;
-
 	pwrseq->owner = config->owner ?: THIS_MODULE;
 	pwrseq->match = config->match;
 
@@ -517,6 +513,10 @@ pwrseq_device_register(const struct pwrs
 	INIT_LIST_HEAD(&pwrseq->targets);
 	INIT_LIST_HEAD(&pwrseq->units);
 
+	ret = dev_set_name(&pwrseq->dev, "pwrseq.%d", pwrseq->id);
+	if (ret)
+		goto err_put_pwrseq;
+
 	ret = pwrseq_setup_targets(config->targets, pwrseq);
 	if (ret)
 		goto err_put_pwrseq;
author maintainer
#342 lore raw

PATCH 339/438 mmc: core: Cancel SDIO IRQ work before freeing host

In reply to Greg Kroah-Hartman

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

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

From: Fan Wu <[email protected]>

commit 6feadbecdae60a6324c967f3b1493741083793a3 upstream.

A host controller that uses sdio_signal_irq() schedules host->sdio_irq_work from its interrupt handler. That work is only cancelled on the suspend path (mmc_sdio_suspend()), not on the remove/free path, so a worker armed just before the controller freed its IRQ can run after mmc_host_classdev_release() has freed the host and dereference it through container_of().

Cancel host->sdio_irq_work in mmc_free_host(), like the existing host->detect drain added by commit 1036f69e2513 ("mmc: core: Cancel delayed work before releasing host").

This issue was found by an in-house static analysis tool.

Fixes 682696605c70 ("mmc: sdio: Add API to manage SDIO IRQs from a workqueue")
Assisted-by Codex:gpt-5.6
---
 drivers/mmc/core/host.c |    1 +
 1 file changed, 1 insertion(+)
drivers/mmc/core/host.c +1 -0
@@ -698,6 +698,7 @@ EXPORT_SYMBOL(mmc_remove_host);
 void mmc_free_host(struct mmc_host *host)
 {
 	cancel_delayed_work_sync(&host->detect);
+	cancel_work_sync(&host->sdio_irq_work);
 	mmc_pwrseq_free(host);
 	put_device(&host->class_dev);
 }
author maintainer
#343 lore raw

PATCH 340/438 mmc: core: Fix OF node reference leak on card add failure

In reply to Greg Kroah-Hartman

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

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

From: Zhu Ling <[email protected]>

commit 08b54e16d547d5c1aa61bf7a3595bb1620975eeb upstream.

mmc_of_find_child_device() returns a device node with its reference count incremented. mmc_add_card() stores the reference before calling device_add(), while the card is marked present only after device_add() succeeds.

If device_add() fails, the callers release the card through mmc_remove_card(). However, mmc_remove_card() only drops the OF node reference for a present card, leaking the reference on this error path.

Move of_node_put() outside the present-card conditional so the reference is released for both registered cards and card-add failures.

Fixes 25185f3f31c9 ("mmc: Add SDIO function devicetree subnode parsing")
---
 drivers/mmc/core/bus.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mmc/core/bus.c +1 -1
@@ -417,8 +417,8 @@ void mmc_remove_card(struct mmc_card *ca
 				mmc_hostname(card->host), card->rca);
 		}
 		device_del(&card->dev);
-		of_node_put(card->dev.of_node);
 	}
+	of_node_put(card->dev.of_node);
 
 	if (host->cqe_enabled) {
 		host->cqe_ops->cqe_disable(host);
author maintainer
#344 lore raw

PATCH 341/438 mmc: hsq: Fix use-after-free in retry work

In reply to Greg Kroah-Hartman

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

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

From: Fan Wu <[email protected]>

commit 5d132990475f02cfa1debe03d50b479432864ebd upstream.

mmc_hsq_pump_requests() queues retry_work when request_atomic() returns -EBUSY; today sdhci-sprd is the only consumer that implements request_atomic(). The work is embedded in a devm-allocated mmc_hsq, but is never cancelled during driver removal. Work still pending at unbind can therefore run after the devm allocation has been released and dereference hsq->mmc and hsq->mrq.

Use devm_work_autocancel() to cancel and drain retry_work before the devm allocation is released. By the time devres cleanup begins, mmc_remove_host() has already stopped the host, so no new requests can arm the work.

This issue was found by an in-house static analysis tool.

Fixes 6db96e5810e0 ("mmc: host: Introduce the request_atomic() for the host")
Assisted-by Codex:gpt-5.6
---
 drivers/mmc/host/mmc_hsq.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/mmc/host/mmc_hsq.c +7 -1
@@ -7,6 +7,7 @@
  * Author: Baolin Wang <[email protected]>
  */
 
+#include <linux/devm-helpers.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/module.h>
@@ -345,6 +346,7 @@ static const struct mmc_cqe_ops mmc_hsq_
 
 int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
 {
+	int ret;
 	int i;
 	hsq->num_slots = HSQ_NUM_SLOTS;
 	hsq->next_tag = HSQ_INVALID_TAG;
@@ -363,7 +365,11 @@ int mmc_hsq_init(struct mmc_hsq *hsq, st
 	for (i = 0; i < HSQ_NUM_SLOTS; i++)
 		hsq->tag_slot[i] = HSQ_INVALID_TAG;
 
-	INIT_WORK(&hsq->retry_work, mmc_hsq_retry_handler);
+	ret = devm_work_autocancel(mmc_dev(mmc), &hsq->retry_work,
+				   mmc_hsq_retry_handler);
+	if (ret)
+		return ret;
+
 	spin_lock_init(&hsq->lock);
 	init_waitqueue_head(&hsq->wait_queue);
 
author maintainer
#345 lore raw

PATCH 342/438 mmc: mmci: Fix use-after-free in busy-timeout work

In reply to Greg Kroah-Hartman

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

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

From: Fan Wu <[email protected]>

commit 2b19cf3e50cddaff07b657dae1a8f30f06032852 upstream.

ux500_busy_complete() can queue ux500_busy_timeout_work for an R1b command, but mmci_remove() never cancels it. The work can subsequently dereference the devm-allocated mmci_host after it has been released.

Mask the controller interrupts and disable the delayed work during removal. This drains any queued instance and stops an IRQ handler that is still in progress from queueing the work again once it has been disabled.

This issue was found by an in-house static analysis tool.

Fixes b1a665932dc2 ("mmc: mmci: Add support for SW busy-end timeouts")
Cc [email protected] # v6.10+
Assisted-by Codex:gpt-5.6
---
 drivers/mmc/host/mmci.c |    3 +++
 1 file changed, 3 insertions(+)
drivers/mmc/host/mmci.c +3 -0
@@ -2511,6 +2511,9 @@ static void mmci_remove(struct amba_devi
 		writel(0, host->base + MMCICOMMAND);
 		writel(0, host->base + MMCIDATACTRL);
 
+		if (variant->busy_detect)
+			disable_delayed_work_sync(&host->ux500_busy_timeout_work);
+
 		mmci_dma_release(host);
 		clk_disable_unprepare(host->clk);
 	}
author maintainer
#346 lore raw

PATCH 343/438 mmc: mxcmmc: cancel data work and watchdog on remove

In reply to Greg Kroah-Hartman

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

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

From: Fan Wu <[email protected]>

commit d3a421c82412344022982d5b91ba23194a0a6f29 upstream.

mxcmci_remove() frees the host through the devm tail, but neither it nor mmc_remove_host() drains the driver's own asynchronous state. host->watchdog, a 10 s timer armed on the DMA path in mxcmci_setup_data(), is deleted only by the DMA- and IRQ-complete paths, which the remove path does not explicitly drain; it can therefore fire after the host is freed and dereference it in mxcmci_watchdog(). host->datawork, armed from the IRQ handler on the PIO path, is not cancelled by the remove path either.

Free the devm-registered IRQ, then cancel datawork and delete the watchdog in mxcmci_remove(), before dma_release_channel(). Freeing the IRQ first keeps a trailing handler from re-arming datawork between the cancel and the host free. Both callbacks are non-self-rearming.

This issue was found by an in-house static analysis tool.

Fixes f6ad0a481342 ("mmc: mxcmmc: fix bug that may block a data transfer forever")
Assisted-by Codex:gpt-5.6
---
 drivers/mmc/host/mxcmmc.c |    4 ++++
 1 file changed, 4 insertions(+)
drivers/mmc/host/mxcmmc.c +4 -0
@@ -1173,6 +1173,10 @@ static void mxcmci_remove(struct platfor
 
 	mmc_remove_host(mmc);
 
+	devm_free_irq(&pdev->dev, platform_get_irq(pdev, 0), host);
+	cancel_work_sync(&host->datawork);
+	timer_delete_sync(&host->watchdog);
+
 	if (host->pdata && host->pdata->exit)
 		host->pdata->exit(&pdev->dev, mmc);
 
author maintainer
#347 lore raw

PATCH 344/438 mmc: rtsx_pci_sdmmc: ignore broken write-protect on ThinkPad X260

In reply to Greg Kroah-Hartman

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

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

From: Florian Maillard <[email protected]>

commit 9c182bc5d7817437a7d04ab96133f9191846d93d upstream.

The Realtek RTS522A card reader in the Lenovo ThinkPad X260 (subsystem 17aa:504a) incorrectly reports inserted SD cards as write-protected.

This causes the MMC core to expose the card as read-only:

mmcblk0: mmc0:aaaa SN256 238 GiB (ro)

and /sys/block/mmcblk0/ro reports 1.

Setting MMC_CAP2_NO_WRITE_PROTECT makes the card writable again. Limit the quirk to the affected Lenovo subsystem.

---
 drivers/mmc/host/rtsx_pci_sdmmc.c |    5 +++++
 1 file changed, 5 insertions(+)
drivers/mmc/host/rtsx_pci_sdmmc.c +5 -0
@@ -1425,6 +1425,11 @@ static void realtek_init_host(struct rea
 		mmc->caps = mmc->caps | MMC_CAP_AGGRESSIVE_PM;
 	mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE |
 		MMC_CAP2_NO_SDIO;
+
+	if (pcr->pci->device == 0x522a &&
+	    pcr->pci->subsystem_vendor == PCI_VENDOR_ID_LENOVO &&
+	    pcr->pci->subsystem_device == 0x504a)
+		mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
 	mmc->max_current_330 = 400;
 	mmc->max_current_180 = 800;
 	mmc->ops = &realtek_pci_sdmmc_ops;
author maintainer
#348 lore raw

PATCH 345/438 mmc: sdhci-of-aspeed: Remove children before releasing SDC resources

In reply to Greg Kroah-Hartman

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

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

From: Myeonghun Pak <[email protected]>

commit 4396d70bb7fec531bcf934fed016b2f3300c670b upstream.

Probe failure and removal leave SDHCI child devices registered after the parent clock and managed resources are released.

Unregister the OF children in reverse order before disabling the parent clock on both paths. Use of_platform_device_destroy() because manual child creation does not set the flag required by of_platform_depopulate().

This issue was identified during our ongoing static-analysis research while reviewing kernel code.

Fixes bb7b8ec62dfb ("mmc: sdhci-of-aspeed: Add support for the ASPEED SD controller")
Assisted-by OpenAI:GPT-5.6
---
 drivers/mmc/host/sdhci-of-aspeed.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci-of-aspeed.c +4 -1
@@ -560,12 +560,14 @@ static int aspeed_sdc_probe(struct platf
 		cpdev = of_platform_device_create(child, NULL, &pdev->dev);
 		if (!cpdev) {
 			ret = -ENODEV;
-			goto err_clk;
+			goto err_children;
 		}
 	}
 
 	return 0;
 
+err_children:
+	device_for_each_child_reverse(&pdev->dev, NULL, of_platform_device_destroy);
 err_clk:
 	clk_disable_unprepare(sdc->clk);
 	return ret;
@@ -575,6 +577,7 @@ static void aspeed_sdc_remove(struct pla
 {
 	struct aspeed_sdc *sdc = dev_get_drvdata(&pdev->dev);
 
+	device_for_each_child_reverse(&pdev->dev, NULL, of_platform_device_destroy);
 	clk_disable_unprepare(sdc->clk);
 }
 
author maintainer
#349 lore raw

PATCH 346/438 mmc: sdio_uart: fix xmit_fifo leak when the port table is full

In reply to Greg Kroah-Hartman

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

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

From: Felix Gu <[email protected]>

commit 53823e25793a97d07e6e98e0904bbf74cac8bc76 upstream.

sdio_uart_add_port() allocates the transmit fifo before claiming a slot in sdio_uart_table[]. When all UART_NR slots are taken, it returns -EBUSY with the fifo still allocated, but the probe error path only kfree()s the port, leaking the transmit fifo.

Free the fifo in the failure path of sdio_uart_add_port() itself so the function retains nothing on error.

Fixes 8b197a5ce7a7 ("sdio_uart: Use kfifo instead of the messy circ stuff")
---
 drivers/mmc/core/sdio_uart.c |    3 +++
 1 file changed, 3 insertions(+)
drivers/mmc/core/sdio_uart.c +3 -0
@@ -104,6 +104,9 @@ static int sdio_uart_add_port(struct sdi
 	}
 	spin_unlock(&sdio_uart_table_lock);
 
+	if (ret)
+		kfifo_free(&port->xmit_fifo);
+
 	return ret;
 }
 
author maintainer
#350 lore raw

PATCH 347/438 mmc: sh_mmcif: initialize IRQ-thread mutex before requesting interrupt

In reply to Greg Kroah-Hartman

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

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

From: Runyu Xiao <[email protected]>

commit d5ea0d226e8f0801d78702142a124d78c317d822 upstream.

The threaded IRQ handler can run before devm_request_threaded_irq() returns, but thread_lock was initialized afterwards. Initialize it before requesting either interrupt.

Fixes 8047310ee984 ("mmc: sh_mmcif: fix a race, causing an Oops on SMP")
Assisted-by Codex:GPT-5
---
 drivers/mmc/host/sh_mmcif.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/mmc/host/sh_mmcif.c +1 -2
@@ -1461,6 +1461,7 @@ static int sh_mmcif_probe(struct platfor
 	host->pd = pdev;
 
 	spin_lock_init(&host->lock);
+	mutex_init(&host->thread_lock);
 
 	mmc->ops = &sh_mmcif_ops;
 	sh_mmcif_init_ocr(host);
@@ -1519,8 +1520,6 @@ static int sh_mmcif_probe(struct platfor
 		}
 	}
 
-	mutex_init(&host->thread_lock);
-
 	ret = mmc_add_host(mmc);
 	if (ret < 0)
 		goto err_clk;
author maintainer
#351 lore raw

PATCH 348/438 mmc: spi: reset bytes_xfered before retrying CRC failures

In reply to Greg Kroah-Hartman

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

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

From: Xu Rao <[email protected]>

commit 8b0cc8707f65e0f51912e764e1b309b2559db1ec upstream.

mmc_spi_data_do() updates data->bytes_xfered after each block has been transferred successfully. If a later block in the same data request fails with a CRC error, data->bytes_xfered may therefore contain the number of bytes completed before the failing block.

mmc_spi_request() has a private recovery path for such CRC failures. It sends STOP_TRANSMISSION, clears data->error and jumps back to crc_recover to issue the same command and data request again. However, it does not clear data->bytes_xfered before the retry.

If the retry succeeds, the request is completed with the bytes from the failed attempt still included in data->bytes_xfered. For a multi-block request this can make the completed request report more bytes than were transferred by the successful retry, and can even exceed the request size when most blocks completed before the CRC error.

This is most likely to be observed on MMC-over-SPI systems where long multi-block transfers occasionally hit a data CRC error but the mmc_spi-internal retry succeeds. The data itself is retried, but the completion accounting is not.

Clear data->bytes_xfered together with data->error before repeating the request so the final completion reports only the bytes transferred by the successful attempt.

Fixes 061c6c847eeb ("mmc_spi: Recover from CRC errors for r/w operation over SPI.")
---
 drivers/mmc/host/mmc_spi.c |    1 +
 1 file changed, 1 insertion(+)
drivers/mmc/host/mmc_spi.c +1 -0
@@ -952,6 +952,7 @@ crc_recover:
 			status = mmc_spi_command_send(host, mrq, &stop, 0);
 			crc_retry--;
 			mrq->data->error = 0;
+			mrq->data->bytes_xfered = 0;
 			goto crc_recover;
 		}
 
author maintainer
#352 lore raw

PATCH 349/438 mmc: sdhci_am654: Move tuning_loop to local variable

In reply to Greg Kroah-Hartman

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

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

From: Diogo Ivo (Schneider Electric) <[email protected]>

commit ff894dced1a7ad7523f9c65dbdb53d02474cca0f upstream.

The tuning_loop field in struct sdhci_am654_data is only used within sdhci_am654_platform_execute_tuning() as a loop counter that is initialized to 0 in sdhci_am654_init(). Since it shouldn't persist across function calls, otherwise every failure expends its "budget", move it to a local variable and remove the struct field along with the now-unnecessary initialization.

Fixes de31f6ab68a3 ("mmc: sdhci_am654: Reset Command and Data line after tuning")
---
 drivers/mmc/host/sdhci_am654.c |    7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/mmc/host/sdhci_am654.c +2 -5
@@ -151,7 +151,6 @@ struct sdhci_am654_data {
 	u32 flags;
 	u32 quirks;
 	bool dll_enable;
-	u32 tuning_loop;
 
 #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0)
 #define SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA BIT(1)
@@ -576,13 +575,14 @@ static int sdhci_am654_platform_execute_
 	struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
 	unsigned char timing = host->mmc->ios.timing;
 	struct device *dev = mmc_dev(host->mmc);
+	unsigned int tuning_loop = 0;
 	int itapdly;
 
 	do {
 		itapdly = sdhci_am654_do_tuning(host, opcode);
 		if (itapdly >= 0)
 			break;
-	} while (++sdhci_am654->tuning_loop < RETRY_TUNING_MAX);
+	} while (++tuning_loop < RETRY_TUNING_MAX);
 
 	if (itapdly < 0) {
 		dev_err(dev, "Failed to find itapdly, fail tuning\n");
@@ -806,9 +806,6 @@ static int sdhci_am654_init(struct sdhci
 	regmap_update_bits(sdhci_am654->base, CTL_CFG_3, TUNINGFORSDR50_MASK,
 			   TUNINGFORSDR50_MASK);
 
-	/* Use to re-execute tuning */
-	sdhci_am654->tuning_loop = 0;
-
 	ret = sdhci_setup_host(host);
 	if (ret)
 		return ret;
author maintainer
#353 lore raw

PATCH 350/438 mmc: sdhci_am654: Reset command and data lines on failed tuning

In reply to Greg Kroah-Hartman

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

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

From: Diogo Ivo (Schneider Electric) <[email protected]>

commit 7197d9107d9545730153b82ea5a411c5208b443f upstream.

The CMD/DATA reset after tuning should be performed regardless of whether tuning succeeded or failed, since tuning data may remain in the buffer in either case. Move the error return after the reset so that the controller is always cleaned up.

Fixes de31f6ab68a3 ("mmc: sdhci_am654: Reset Command and Data line after tuning")
---
 drivers/mmc/host/sdhci_am654.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/mmc/host/sdhci_am654.c +1 -3
@@ -442,15 +442,13 @@ static int sdhci_am654_execute_tuning(st
 	struct sdhci_host *host = mmc_priv(mmc);
 	int err = sdhci_execute_tuning(mmc, opcode);
 
-	if (err)
-		return err;
 	/*
 	 * Tuning data remains in the buffer after tuning.
 	 * Do a command and data reset to get rid of it
 	 */
 	sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
-	return 0;
+	return err;
 }
 
 static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask)
author maintainer
#354 lore raw

PATCH 351/438 mmc: sdhci_am654: Clear ITAPDLY on tuning failure

In reply to Greg Kroah-Hartman

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

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

From: Diogo Ivo (Schneider Electric) <[email protected]>

commit c9f47cc8c37f7659897142ffe216c250fbc1d4ed upstream.

When tuning fails, stale ITAPDLY values can persist and interfere with subsequent I/O accesses, for example in DDR50 mode in cards with no tuning support. Move the ITAPDLY enable setting out of the tuning loop to after successful tuning, and explicitly clear ITAPDLY (delay and enable) when tuning fails so that we are sure only working values are actually left in hardware.

---
 drivers/mmc/host/sdhci_am654.c |   12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/mmc/host/sdhci_am654.c +7 -5
@@ -527,7 +527,6 @@ static int sdhci_am654_do_tuning(struct
 {
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
-	unsigned char timing = host->mmc->ios.timing;
 	struct window fail_window[ITAPDLY_LENGTH];
 	struct device *dev = mmc_dev(host->mmc);
 	u8 curr_pass, itap;
@@ -536,11 +535,8 @@ static int sdhci_am654_do_tuning(struct
 
 	memset(fail_window, 0, sizeof(fail_window));
 
-	/* Enable ITAPDLY */
-	sdhci_am654->itap_del_ena[timing] = 0x1;
-
 	for (itap = 0; itap < ITAPDLY_LENGTH; itap++) {
-		sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]);
+		sdhci_am654_write_itapdly(sdhci_am654, itap, 0x1);
 
 		curr_pass = !mmc_send_tuning(host->mmc, opcode, NULL);
 
@@ -584,10 +580,16 @@ static int sdhci_am654_platform_execute_
 
 	if (itapdly < 0) {
 		dev_err(dev, "Failed to find itapdly, fail tuning\n");
+		sdhci_am654_write_itapdly(sdhci_am654, 0, 0);
+		sdhci_am654->itap_del_ena[timing] = 0;
+		sdhci_am654->itap_del_sel[timing] = 0;
 		return -1;
 	}
 
 	dev_dbg(dev, "Passed tuning, final itapdly=%d\n", itapdly);
+
+	/* Enable ITAPDLY */
+	sdhci_am654->itap_del_ena[timing] = 0x1;
 	sdhci_am654_write_itapdly(sdhci_am654, itapdly, sdhci_am654->itap_del_ena[timing]);
 	/* Save ITAPDLY */
 	sdhci_am654->itap_del_sel[timing] = itapdly;
author maintainer
#355 lore raw

PATCH 352/438 mmc: sdhci_am654: Fallback to DT-provided itap delay on DDR50 tuning failure

In reply to Greg Kroah-Hartman

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

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

From: Diogo Ivo (Schneider Electric) <[email protected]>

commit 308d05225281d86150d88141990d6caf8c902349 upstream.

DDR50 mode is not required to support the tuning command CMD19, meaning that calibration may fail on cards that do not implement it, in which case a known-good itap delay value should be programmed into the host controller.

Do this by reading the (already defined) itap delay DT property for DDR50 and, if tuning fails for this mode, fall back to the DT-provided itap delay value. If the DT does not provide a value for DDR50 fallback then this simply disables using itapdly.

---
 drivers/mmc/host/sdhci_am654.c |   26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)
drivers/mmc/host/sdhci_am654.c +21 -5
@@ -126,7 +126,7 @@ static const struct timing_data td[] = {
 				   NULL,
 				   MMC_CAP_UHS_SDR104},
 	[MMC_TIMING_UHS_DDR50]	= {"ti,otap-del-sel-ddr50",
-				   NULL,
+				   "ti,itap-del-sel-ddr50",
 				   MMC_CAP_UHS_DDR50},
 	[MMC_TIMING_MMC_DDR52]	= {"ti,otap-del-sel-ddr52",
 				   "ti,itap-del-sel-ddr52",
@@ -144,6 +144,8 @@ struct sdhci_am654_data {
 	u32 otap_del_sel[ARRAY_SIZE(td)];
 	u32 itap_del_sel[ARRAY_SIZE(td)];
 	u32 itap_del_ena[ARRAY_SIZE(td)];
+	u32 itap_del_sel_dt_ddr50;
+	u32 itap_del_ena_dt_ddr50;
 	int clkbuf_sel;
 	int trm_icp;
 	int drv_strength;
@@ -579,10 +581,19 @@ static int sdhci_am654_platform_execute_
 	} while (++tuning_loop < RETRY_TUNING_MAX);
 
 	if (itapdly < 0) {
-		dev_err(dev, "Failed to find itapdly, fail tuning\n");
-		sdhci_am654_write_itapdly(sdhci_am654, 0, 0);
-		sdhci_am654->itap_del_ena[timing] = 0;
-		sdhci_am654->itap_del_sel[timing] = 0;
+		if (timing == MMC_TIMING_UHS_DDR50) {
+			dev_dbg(dev, "Failed DDR50 tuning, fallback to DT ITAP\n");
+			sdhci_am654->itap_del_sel[timing] = sdhci_am654->itap_del_sel_dt_ddr50;
+			sdhci_am654->itap_del_ena[timing] = sdhci_am654->itap_del_ena_dt_ddr50;
+		} else {
+			dev_err(dev, "Failed to find itapdly, fail tuning\n");
+			sdhci_am654->itap_del_ena[timing] = 0;
+			sdhci_am654->itap_del_sel[timing] = 0;
+		}
+
+		sdhci_am654_write_itapdly(sdhci_am654,
+					  sdhci_am654->itap_del_sel[timing],
+					  sdhci_am654->itap_del_ena[timing]);
 		return -1;
 	}
 
@@ -758,6 +769,11 @@ static int sdhci_am654_get_otap_delay(st
 		}
 	}
 
+	sdhci_am654->itap_del_sel_dt_ddr50 =
+		sdhci_am654->itap_del_sel[MMC_TIMING_UHS_DDR50];
+	sdhci_am654->itap_del_ena_dt_ddr50 =
+		sdhci_am654->itap_del_ena[MMC_TIMING_UHS_DDR50];
+
 	return 0;
 }
 
author maintainer
#356 lore raw

PATCH 353/438 Input: adp5588-keys - cache GPIO state before registering the gpiochip

In reply to Greg Kroah-Hartman

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

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

From: Alvin Šipraga <[email protected]>

commit 21efadc62272cabee9bec27777ae75d84a9ca8a8 upstream.

So as not to clobber any pre-programmed GPIO state in the execution of its gpiochip ops, the driver caches things during probe time. However, since those ops can be called both during and immediately after the call to devm_gpiochip_add_data(), it is imperative that things are cached before that. That's not the case right now, so reorder the two steps to prevent any clobbering.

In the concrete example which motivated this change, a bootloader was preconfiguring an important GPIO output to HIGH before booting the kernel. Linux would then inadvertently set that output to LOW while configuring a GPIO hog on a discrete GPIO line within the same 8-bit bank (because the cached value was 0=LOW).

---
 drivers/input/keyboard/adp5588-keys.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/input/keyboard/adp5588-keys.c +6 -6
@@ -446,12 +446,6 @@ static int adp5588_gpio_add(struct adp55
 
 	mutex_init(&kpad->gpio_lock);
 
-	error = devm_gpiochip_add_data(dev, &kpad->gc, kpad);
-	if (error) {
-		dev_err(dev, "gpiochip_add failed: %d\n", error);
-		return error;
-	}
-
 	for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
 		kpad->dat_out[i] = adp5588_read(kpad->client,
 						GPIO_DAT_OUT1 + i);
@@ -459,6 +453,12 @@ static int adp5588_gpio_add(struct adp55
 		kpad->pull_dis[i] = adp5588_read(kpad->client, GPIO_PULL1 + i);
 	}
 
+	error = devm_gpiochip_add_data(dev, &kpad->gc, kpad);
+	if (error) {
+		dev_err(dev, "gpiochip_add failed: %d\n", error);
+		return error;
+	}
+
 	return 0;
 }
 
author maintainer
#357 lore raw

PATCH 354/438 Input: atkbd - skip deactivate for Xiaomi Redmi Book Pro 16 2026

In reply to Greg Kroah-Hartman

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

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

From: Alexei Turtanov <[email protected]>

commit aefbda23eeba234c3ff0f135dc5be6e294bd25a6 upstream.

The internal keyboard of the Xiaomi Redmi Book Pro 16 2026 (board TM2425) does not work: atkbd_probe() succeeds and every command is ACKed, but no scancodes ever arrive afterwards.

Testing on the hardware through serio_raw shows that ATKBD_CMD_RESET_DIS (0xF5) is the culprit. After 0xF5 the embedded controller keeps ACKing commands but stops delivering scancodes, and neither ATKBD_CMD_ENABLE (0xF4) nor ATKBD_CMD_RESET_BAT (0xFF) bring them back. Only re-enabling the keyboard interface at the controller level (i8042 command 0xAE, or rewriting the command byte as i8042_port_close() does) revives it. Running the init sequence without 0xF5 (0xED 0x00, 0xF3 0x00, 0xF4) keeps the keyboard working.

'i8042.dumbkbd=1' also works around this, but then the driver never writes to the keyboard and the LEDs cannot be controlled. Use the existing atkbd_deactivate_fixup quirk instead, as done for the sibling TM2424 by commit 3a046db33bb9 ("Input: atkbd - skip deactivate for Xiaomi Book Pro 14's internal keyboard"). Tested on v7.2: keyboard, Caps Lock LED and s2idle suspend/resume all work.

DMI: XIAOMI REDMI Book Pro 16 2026/TM2425, BIOS RMAPT6B0P0909 05/22/2026

Fixes 9cf6e24c9fbf ("Input: atkbd - do not skip atkbd_deactivate() when skipping ATKBD_CMD_GETID")
---
 drivers/input/keyboard/atkbd.c |    8 ++++++++
 1 file changed, 8 insertions(+)
drivers/input/keyboard/atkbd.c +8 -0
@@ -1954,6 +1954,14 @@ static const struct dmi_system_id atkbd_
 		},
 		.callback = atkbd_deactivate_fixup,
 	},
+	{
+		/* Xiaomi Redmi Book Pro 16 2026 (TM2425) */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "XIAOMI"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "REDMI Book Pro 16 2026"),
+		},
+		.callback = atkbd_deactivate_fixup,
+	},
 	{ }
 };
 
author maintainer
#358 lore raw

PATCH 355/438 Input: cyttsp5 - clamp the HID report size before memcpy

In reply to Greg Kroah-Hartman

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

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

From: Linkai Gong <[email protected]>

commit 85f080fb87ed5cd3e46121be677f52c82f26a0ab upstream.

The size field comes from the device and is used as the memcpy() length into response_buf, which is CY_MAX_INPUT bytes.

Fixes 5b0c03e24a06 ("Input: Add driver for Cypress Generation 5 touchscreen")
---
 drivers/input/touchscreen/cyttsp5.c |    1 +
 1 file changed, 1 insertion(+)
drivers/input/touchscreen/cyttsp5.c +1 -0
@@ -710,6 +710,7 @@ static irqreturn_t cyttsp5_handle_irq(in
 		size = 2;
 	} else {
 		report_id = ts->input_buf[2];
+		size = min(size, CY_MAX_INPUT);
 	}
 
 	switch (report_id) {
author maintainer
#359 lore raw

PATCH 356/438 Input: evdev - zero absinfo before partial copy in EVIOCSABS

In reply to Greg Kroah-Hartman

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

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

From: Iván Ezequiel Rodriguez <[email protected]>

commit 8b852965b8eaf910c314dc346967ed82c8d4f235 upstream.

The EVIOCSABS handler copies at most the user supplied ioctl size into an uninitialized on-stack struct input_absinfo:

	if (copy_from_user(&abs, p, min_t(size_t,
			size, sizeof(struct input_absinfo))))

The size comes from _IOC_SIZE() of the ioctl command and is therefore fully controlled by userspace. A short size leaves the trailing part of the structure holding whatever was on the kernel stack, and the whole structure is then stored into the device:

	dev->absinfo[t] = abs;

EVIOCGABS hands that back to userspace, disclosing the stale stack bytes. Only the resolution field is currently cleared, which covers the legacy struct layout but not an arbitrarily short size.

Zero the structure before the copy so any part not supplied by the caller reads back as zero. The existing resolution fixup is kept, since it also handles a size that partially overlaps that field.

---
 drivers/input/evdev.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/input/evdev.c +2 -0
@@ -1229,6 +1229,8 @@ static long evdev_do_ioctl(struct file *
 
 			t = _IOC_NR(cmd) & ABS_MAX;
 
+			memset(&abs, 0, sizeof(abs));
+
 			if (copy_from_user(&abs, p, min_t(size_t,
 					size, sizeof(struct input_absinfo))))
 				return -EFAULT;
author maintainer
#360 lore raw

PATCH 357/438 Input: hp_sdc - shut down kicker timer on module exit

In reply to Greg Kroah-Hartman

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

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

From: Runyu Xiao <[email protected]>

commit 309731e95917125bbd13626a7a5600490a5bf44f upstream.

hp_sdc_kicker() rearms hp_sdc.kicker with mod_timer() after scheduling the tasklet. The module exit path uses timer_delete_sync(). That waits for a callback already running but can still leave the timer rearmed.

A callback can therefore leave the timer pending while hp_sdc_exit() tears down the driver, allowing timer activity to access dismantled driver state.

Use timer_shutdown_sync() for final teardown. It waits for a running callback and prevents rearming after module exit begins.

---
 drivers/input/serio/hp_sdc.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/serio/hp_sdc.c +1 -1
@@ -981,7 +981,7 @@ static void hp_sdc_exit(void)
 	free_irq(hp_sdc.irq, &hp_sdc);
 	write_unlock_irq(&hp_sdc.lock);
 
-	timer_delete_sync(&hp_sdc.kicker);
+	timer_shutdown_sync(&hp_sdc.kicker);
 
 	tasklet_kill(&hp_sdc.task);
 
author maintainer
#361 lore raw

PATCH 358/438 Input: i8042 - add quirk for Acer Aspire Go 15 AG15-42P

In reply to Greg Kroah-Hartman

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

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

From: Chris Sommers <[email protected]>

commit 25e424eb4ae1a662d9c3573218d06ac32f797fc5 upstream.

On the Acer Aspire Go 15 (AG15-42P), the internal keyboard drops out ~5 seconds after boot on both Linux and Linux-LTS kernels. Keystrokes on the built-in keyboard stop registering while the trackpad and external keyboards remain functional.

Testing confirms that booting with the i8042.reset kernel parameter resolves the issue and keeps the internal keyboard responsive.

Add SERIO_QUIRK_RESET_ALWAYS to i8042_dmi_quirk_table for the Acer Aspire AG15-42P to automatically apply this quirk on boot.

---
 drivers/input/serio/i8042-acpipnpio.h |    7 +++++++
 1 file changed, 7 insertions(+)
drivers/input/serio/i8042-acpipnpio.h +7 -0
@@ -261,6 +261,13 @@ static const struct dmi_system_id i8042_
 	{
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire AG15-42P"),
+		},
+		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
+	},
+	{
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire ES1-132"),
 		},
 		.driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS)
author maintainer
#362 lore raw

PATCH 359/438 Input: rmi_smbus - fix out-of-bounds read in rmi_smb_write_block()

In reply to Greg Kroah-Hartman

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

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

From: Dmitry Torokhov <[email protected]>

commit 51cfe54f815ae175c7d1126b983d4d7c89715004 upstream.

When chunking writes into SMBus blocks in rmi_smb_write_block(), the loop calculates block_len using the original total length (len) instead of the remaining length (cur_len).

If len is greater than 32 bytes (SMB_MAX_COUNT), block_len remains 32 for every iteration, even on the final partial chunk where fewer than 32 bytes remain. This causes smb_block_write() to read 32 bytes from the advanced data buffer pointer, reading past the end of the input buffer.

Fix this by calculating block_len using cur_len and advancing the buffer and address pointers by block_len.

Fixes 82264d0cf7ae ("Input: synaptics-rmi4 - add SMBus support")
Reported-by [email protected]
Assisted-by LLM
---
 drivers/input/rmi4/rmi_smbus.c |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/input/rmi4/rmi_smbus.c +5 -5
@@ -140,7 +140,7 @@ static int rmi_smb_write_block(struct rm
 	u8 commandcode;
 	struct rmi_smb_xport *rmi_smb =
 		container_of(xport, struct rmi_smb_xport, xport);
-	int cur_len = (int)len;
+	size_t cur_len = len;
 
 	mutex_lock(&rmi_smb->page_mutex);
 
@@ -148,7 +148,7 @@ static int rmi_smb_write_block(struct rm
 		/*
 		 * break into 32 bytes chunks to write get command code
 		 */
-		int block_len = min_t(int, len, SMB_MAX_COUNT);
+		int block_len = min_t(size_t, cur_len, SMB_MAX_COUNT);
 
 		retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
 						  false, &commandcode);
@@ -161,9 +161,9 @@ static int rmi_smb_write_block(struct rm
 			goto exit;
 
 		/* prepare to write next block of bytes */
-		cur_len -= SMB_MAX_COUNT;
-		databuff += SMB_MAX_COUNT;
-		rmiaddr += SMB_MAX_COUNT;
+		cur_len -= block_len;
+		databuff += block_len;
+		rmiaddr += block_len;
 	}
 exit:
 	mutex_unlock(&rmi_smb->page_mutex);
author maintainer
#363 lore raw

PATCH 360/438 Input: soc_button_array - fix MS Surface Pro 11 probe failure

In reply to Greg Kroah-Hartman

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

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

From: Hans de Goede <[email protected]>

commit ed22ad5fdbdbf9b4cb4ad3003f60314b5a5eb89d upstream.

On the MS Surface Pro 11 soc_button_array probing races with the GPIO driver probing. If soc_button_array wins the race then gpiod_get() returns EPROBE_DEFER, which should normally take care of retrying later, but the soc_button_array code deliberately ignores EPROBE_DEFER causing it to fail its probe() which causes the volume and power buttons to now work.

The ignoring of EPROBE_DEFER is there to deal with a problem specific to older Bay Trail (BYT) and Cherry Trail (CHT) tablets which often use this driver. Modify the error handling to only ignore EPROBE_DEFER on BYT and CHT platforms and propagate EPROBE_DEFER normally on other platforms.

---
 drivers/input/misc/soc_button_array.c |   14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
drivers/input/misc/soc_button_array.c +11 -3
@@ -16,6 +16,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/gpio_keys.h>
 #include <linux/gpio.h>
+#include <linux/platform_data/x86/soc.h>
 #include <linux/platform_device.h>
 
 static bool use_low_level_irq;
@@ -160,7 +161,7 @@ soc_button_device_create(struct platform
 	struct gpio_keys_platform_data *gpio_keys_pdata;
 	const struct dmi_system_id *dmi_id;
 	int invalid_acpi_index = -1;
-	int error, gpio, irq;
+	int error, gpio, irq = 0;
 	int n_buttons = 0;
 
 	for (info = button_info; info->name; info++)
@@ -191,8 +192,9 @@ soc_button_device_create(struct platform
 		error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq);
 		if (error || irq < 0) {
 			/*
-			 * Skip GPIO if not present. Note we deliberately
-			 * ignore -EPROBE_DEFER errors here. On some devices
+			 * Propagate -EPROBE_DEFER, skip button on other errors.
+			 *
+			 * -EPROBE_DEFER is ignored on Bay & Cherry Trail. Here
 			 * Intel is using so called virtual GPIOs which are not
 			 * GPIOs at all but some way for AML code to check some
 			 * random status bits without need a custom opregion.
@@ -201,6 +203,12 @@ soc_button_device_create(struct platform
 			 * we do not have a driver for these so they will never
 			 * show up, therefore we ignore -EPROBE_DEFER.
 			 */
+			if ((error == -EPROBE_DEFER || irq == -EPROBE_DEFER) &&
+			    !(soc_intel_is_byt() || soc_intel_is_cht())) {
+				error = -EPROBE_DEFER;
+				goto err_free_mem;
+			}
+
 			continue;
 		}
 
author maintainer
#364 lore raw

PATCH 361/438 Input: soc_button_array - check btns_desc->package.count

In reply to Greg Kroah-Hartman

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

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

From: Hans de Goede <[email protected]>

commit fb5022278b6ea7f1838e3ef78028d5d5e3375f65 upstream.

Check that btns_desc->package.count is not 0 before accessing btns_desc->package.elements[0].

---
 drivers/input/misc/soc_button_array.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/misc/soc_button_array.c +1 -1
@@ -377,7 +377,7 @@ static struct soc_button_info *soc_butto
 		}
 	}
 
-	if (!btns_desc) {
+	if (!btns_desc || !btns_desc->package.count) {
 		dev_err(dev, "ACPI Button Descriptors not found\n");
 		button_info = ERR_PTR(-ENODEV);
 		goto out;
author maintainer
#365 lore raw

PATCH 362/438 Input: synaptics - disable InterTouch on ThinkPad T440p (board id 2722)

In reply to Greg Kroah-Hartman

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

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

From: Raphaël Larocque <[email protected]>

commit 26eb3d92c7a4d7adb1ae1740ca6e8e100b11d1ec upstream.

The Lenovo ThinkPad T440p (PNP ID LEN0036, board id 2722) has a Synaptics touchpad whose SMBus companion is not ready at boot and takes roughly 200 seconds to appear. During this window the touchpad and TrackPoint are completely unresponsive on approximately 50% of boots, making the machine unusable until the companion finally registers.

The device is in the topbuttonpad_pnp_ids[] SMBus allowlist, so the kernel attempts to use SMBus/RMI4 mode by default. When the companion is not ready, psmouse_smbus_init() leaves breadcrumbs and returns -EAGAIN, the PS/2 fallback path is taken, but the device does not function properly until the companion appears and RMI4 takes over.

Disable SMBus InterTouch for board id 2722 so the touchpad and TrackPoint work immediately via PS/2 from boot. Users can still force SMBus with psmouse.synaptics_intertouch=1 if needed.

---
 drivers/input/mouse/synaptics.c |    8 ++++++++
 1 file changed, 8 insertions(+)
drivers/input/mouse/synaptics.c +8 -0
@@ -1837,6 +1837,14 @@ static int synaptics_setup_intertouch(st
 
 			return -ENXIO;
 		}
+
+		/* Disable intertouch on known-broken board revisions */
+		if (info->board_id == 2722) {
+			psmouse_info(psmouse,
+				     "Disabling intertouch for board id %u\n",
+				     info->board_id);
+			return -ENXIO;
+		}
 	}
 
 	psmouse_info(psmouse, "Trying to set up SMBus access\n");
author maintainer
#366 lore raw

PATCH 363/438 Input: synaptics-rmi4 - fix GPF in suspend and resume when unbound

In reply to Greg Kroah-Hartman

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

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

From: Dmitry Torokhov <[email protected]>

commit fe10579b6dc3f0dac61e51e1797cacbba5039ac2 upstream.

Transport drivers (such as rmi_i2c and rmi_spi) invoke rmi_driver_suspend() and rmi_driver_resume() on their child rmi_dev device during system power management events. However, transport drivers are fully registered and operational even if the physical RMI driver failed to bind or probe the rmi_dev device.

When rmi_driver_suspend() or rmi_driver_resume() is called on an unbound rmi_dev, dev_get_drvdata() returns NULL. Calling rmi_disable_irq() or rmi_enable_irq() without driver data attached causes a NULL pointer dereference and General Protection Fault when attempting to lock data->enabled_mutex.

Fix this by checking if driver data is attached to rmi_dev in rmi_driver_suspend() and rmi_driver_resume(), exiting early if no driver data is present.

Fixes 2b6a321da9a2 ("Input: synaptics-rmi4 - add support for Synaptics RMI4 devices")
Reported-by [email protected]
Assisted-by LLM
---
 drivers/input/rmi4/rmi_driver.c |   13 +++++++++++++
 1 file changed, 13 insertions(+)
drivers/input/rmi4/rmi_driver.c +13 -0
@@ -991,6 +991,15 @@ int rmi_driver_suspend(struct rmi_device
 {
 	int retval;
 
+	/*
+	 * Transport driver will try to suspend RMI device even if physical
+	 * driver did not bind to the RMI device, because transport device
+	 * (I2C, SPI) is fully registered and operational. Exit early if
+	 * there is no driver data attached to the RMI device.
+	 */
+	if (!dev_get_drvdata(&rmi_dev->dev))
+		return 0;
+
 	retval = rmi_suspend_functions(rmi_dev);
 	if (retval)
 		dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
@@ -1005,6 +1014,10 @@ int rmi_driver_resume(struct rmi_device
 {
 	int retval;
 
+	/* Skip if not fully bound to RMI driver */
+	if (!dev_get_drvdata(&rmi_dev->dev))
+		return 0;
+
 	rmi_enable_irq(rmi_dev, clear_wake);
 
 	retval = rmi_resume_functions(rmi_dev);
author maintainer
#367 lore raw

PATCH 364/438 Input: zero ff_effect before compat copy in input_ff_effect_from_user

In reply to Greg Kroah-Hartman

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

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

From: Iván Ezequiel Rodriguez <[email protected]>

commit f84819ef8d66931ee3998fee3c4f03230f4cb6cc upstream.

In the compat path input_ff_effect_from_user() aliases the caller's native struct ff_effect with the smaller struct ff_effect_compat and copies only the compat sized prefix:

	compat_effect = (struct ff_effect_compat *)effect;

	if (copy_from_user(compat_effect, buffer,
			   sizeof(struct ff_effect_compat)))

The tail of the native structure is never written. Callers pass an uninitialized on-stack object, for example evdev_do_ioctl() for EVIOCSFF, so those bytes keep their previous stack contents. input_ff_upload() then stores the full native structure in ff->effects[id], from where a uinput based force feedback daemon can read it back via UI_BEGIN_FF_UPLOAD, disclosing kernel stack memory to userspace.

Zero the effect before the compat copy.

Fixes 2d56f3a32c0e ("Input: refactor evdev 32bit compat to be shareable with uinput")
---
 drivers/input/input-compat.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/input/input-compat.c +2 -0
@@ -76,6 +76,8 @@ int input_ff_effect_from_user(const char
 		 */
 		compat_effect = (struct ff_effect_compat *)effect;
 
+		memset(effect, 0, sizeof(*effect));
+
 		if (copy_from_user(compat_effect, buffer,
 				   sizeof(struct ff_effect_compat)))
 			return -EFAULT;
author maintainer
#368 lore raw

PATCH 365/438 hwmon: (hp-wmi-sensors) Fix use-after-free in fungible_show()

In reply to Greg Kroah-Hartman

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

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

From: Muhammad Bilal <[email protected]>

commit e6cb0b4d4ecb8e71fd2200d907ab2e9663356f69 upstream.

nsensor->current_state is dynamically replaced as the sensor's state changes. update_numeric_sensor_from_wobj() does this by freeing the old string and installing a new one:

	if (strcmp(trimmed, nsensor->current_state)) {
		new_string = hp_wmi_strdup(dev, trimmed);
		if (new_string) {
			devm_kfree(dev, nsensor->current_state);
			nsensor->current_state = new_string;
		}
	}

This function is only ever called from hp_wmi_update_info() while state->lock is held, so the free-and-replace itself is properly serialized against concurrent updates.

fungible_show(), however, reads the same pointer after the lock has already been dropped:

	err = hp_wmi_update_info(state, info);
	if (err)
		return err;

	switch (prop) {
	...
	case HP_WMI_PROPERTY_CURRENT_STATE:
		seq_printf(seqf, "%s\n", nsensor->current_state);
		break;

hp_wmi_update_info() takes state->lock internally and releases it before returning, so by the time fungible_show() dereferences nsensor->current_state in seq_printf(), no lock is held. Two processes reading a sensor's current_state debugfs entry at overlapping times (or one reading it while another read of the same sensor triggers a refresh) can race: one thread's seq_printf() can be part-way through printing the string at the moment another thread's call into update_numeric_sensor_from_wobj() frees it with devm_kfree() and installs a new pointer, causing a use-after-free read.

Take state->lock around the read in fungible_show() as well, so it can never run concurrently with the free-and-replace in update_numeric_sensor_from_wobj().

---
 drivers/hwmon/hp-wmi-sensors.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/hwmon/hp-wmi-sensors.c +2 -0
@@ -1261,7 +1261,9 @@ static int fungible_show(struct seq_file
 		break;
 
 	case HP_WMI_PROPERTY_CURRENT_STATE:
+		mutex_lock(&state->lock);
 		seq_printf(seqf, "%s\n", nsensor->current_state);
+		mutex_unlock(&state->lock);
 		break;
 
 	case HP_WMI_PROPERTY_UNIT_MODIFIER:
author maintainer
#369 lore raw

PATCH 366/438 hwmon: (pmbus/core) increase number of phases and add new mask

In reply to Greg Kroah-Hartman

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

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

From: Nuno Sá <[email protected]>

commit 06bd6794b5fd2163880ac3bfe973d4cc61f359f3 upstream.

Increase the number of phases to 16 as a new upcoming device supports such a number.

While at it, add a new mask for controlling the source of the output voltage.

Note (groeck):

This patch was meant to prepare for support of MAX20826 and compatible devices, which support more than 10 phases per page. However, Sashiko reports that the mp2975 driver already supports up to 14 phases, and the mp2856 driver supports up to 12 phases. This already has the potential for out-of-bounds writes when probing the affected chips, making this patch a bug fix.

Fixes 2c6fcbb21149 ("hwmon: (pmbus) Add support for MPS Multi-phase mp2975 controller")
Fixes f9e5f289b686 ("hwmon: (pmbus) Add support for MPS Multi-phase mp2856/mp2857 controller")
---
 drivers/hwmon/pmbus/pmbus.h |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/hwmon/pmbus/pmbus.h +2 -1
@@ -242,6 +242,7 @@ enum pmbus_regs {
 /*
  * OPERATION
  */
+#define PB_OPERATION_CONTROL_V_SRC	GENMASK(5, 4)
 #define PB_OPERATION_CONTROL_ON		BIT(7)
 
 /*
@@ -386,7 +387,7 @@ enum pmbus_sensor_classes {
 };
 
 #define PMBUS_PAGES	32	/* Per PMBus specification */
-#define PMBUS_PHASES	10	/* Maximum number of phases per page */
+#define PMBUS_PHASES	16	/* Maximum number of phases per page */
 
 /* Functionality bit mask */
 #define PMBUS_HAVE_VIN		BIT(0)
author maintainer
#370 lore raw

PATCH 367/438 hwmon: (pmbus/tps53679) Fix TPS53676 phase page decoding

In reply to Greg Kroah-Hartman

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

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

From: Sanman Pradhan <[email protected]>

commit 1d12fb94ac0975566545871dda100df34df5f845 upstream.

tps53676_identify() reads the USER_DATA_03 phase configuration to count the phases assigned to each channel and derive the number of PMBus pages. In each 16-bit phase descriptor the channel (PAGE) is encoded in bit 4 and the firing order in bits 3:0, but the code tested bit 3 (0x08), which is part of the firing-order field.

TPS53676 supports up to seven phases, so firing-order bit 3 is never set. As a result the existing test classifies every enabled phase as channel A. On a dual-channel configuration the phases assigned to channel B are therefore miscounted as channel A and page 1 is not exposed.

Test the PAGE field (bit 4) instead.

Fixes cb3d37b59012 ("hwmon: (pmbus/tps53679) Add support for TI TPS53676")
---
 drivers/hwmon/pmbus/tps53679.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/pmbus/tps53679.c +1 -1
@@ -187,7 +187,7 @@ static int tps53676_identify(struct i2c_
 		return -EIO;
 	for (i = 0; i < 2 * TPS53676_MAX_PHASES; i += 2) {
 		if (buf[i + 1] & 0x80) {
-			if (buf[i] & 0x08)
+			if (buf[i] & BIT(4))
 				phases_b++;
 			else
 				phases_a++;
author maintainer
#371 lore raw

PATCH 368/438 hwmon: (pmbus/tps53679) Select page 0 for single-page TPS53676

In reply to Greg Kroah-Hartman

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

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

From: Sanman Pradhan <[email protected]>

commit 089070b51ccbac411462a30a454690274c6e4270 upstream.

tps53676_identify() derives the number of PMBus pages but does not ensure that page 0 is selected for single-page configurations. pmbus_set_page() does not update the PAGE register when info->pages is 1, so if boot firmware leaves PAGE set to another value subsequent register accesses may target the wrong page.

For single-page devices, select page 0 explicitly.

Fixes cb3d37b59012 ("hwmon: (pmbus/tps53679) Add support for TI TPS53676")
---
 drivers/hwmon/pmbus/tps53679.c |    9 +++++++++
 1 file changed, 9 insertions(+)
drivers/hwmon/pmbus/tps53679.c +9 -0
@@ -200,6 +200,15 @@ static int tps53676_identify(struct i2c_
 	if (phases_b > 0) {
 		info->pages = 2;
 		info->phases[1] = phases_b;
+	} else {
+		/*
+		 * pmbus_set_page() does not update the PAGE register on
+		 * single-page devices, so select page 0 explicitly in case
+		 * the boot firmware left the device on another page.
+		 */
+		ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+		if (ret < 0)
+			return ret;
 	}
 	return 0;
 }
author maintainer
#372 lore raw

PATCH 369/438 hwmon: (pwm-fan) Stop RPM timer before freeing tach data

In reply to Greg Kroah-Hartman

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

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

From: Yibo Tan <[email protected]>

commit 26d5ff79768548efb1e604bb6e8697c101e06269 upstream.

sample_timer() rearms the RPM timer and accesses the devm-managed ctx->tachs and ctx->pulses_per_revolution arrays. The cleanup action which stops the timer is registered before those arrays are allocated.

Since devres releases entries in reverse order, driver detach can free the arrays before pwm_fan_cleanup() shuts down the timer. A timer expiry in that window accesses the freed tach data.

With a KASAN kernel, a test-only kprobe delayed entry to pwm_fan_cleanup() while normal sysfs unbind ran. Each of three runs reported three four-byte reads and two four-byte writes in sample_timer() after its backing devm allocations had been freed. The helper did not invoke the timer callback, cleanup actions or free functions.

With the fix, three matching unbind runs completed without KASAN, BUG, WARNING, Oops or panic. Instrumentation confirmed that timer retirement completed before the first timer backing allocation was released.

Split timer retirement from the power cleanup and register its devres action after the timer backing data and IRQ actions are installed. This preserves the early power rollback action while ensuring the timer is retired before its backing data is released. Use timer_shutdown_sync() because the callback can rearm itself.

Fixes 01695410d452 ("hwmon: (pwm-fan) Store tach data separately")
Assisted-by Codex:GPT-5
---
 drivers/hwmon/pwm-fan.c |   13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/hwmon/pwm-fan.c +12 -1
@@ -483,7 +483,6 @@ static void pwm_fan_cleanup(void *__ctx)
 {
 	struct pwm_fan_ctx *ctx = __ctx;
 
-	timer_delete_sync(&ctx->rpm_timer);
 	if (ctx->pwm_shutdown) {
 		ctx->enable_mode = pwm_enable_reg_enable;
 		__set_pwm(ctx, ctx->pwm_shutdown);
@@ -494,6 +493,13 @@ static void pwm_fan_cleanup(void *__ctx)
 	}
 }
 
+static void pwm_fan_timer_cleanup(void *__ctx)
+{
+	struct pwm_fan_ctx *ctx = __ctx;
+
+	timer_shutdown_sync(&ctx->rpm_timer);
+}
+
 static int pwm_fan_probe(struct platform_device *pdev)
 {
 	struct thermal_cooling_device *cdev;
@@ -648,6 +654,10 @@ static int pwm_fan_probe(struct platform
 	}
 
 	if (ctx->tach_count > 0) {
+		ret = devm_add_action_or_reset(dev, pwm_fan_timer_cleanup, ctx);
+		if (ret)
+			return ret;
+
 		ctx->sample_start = ktime_get();
 		mod_timer(&ctx->rpm_timer, jiffies + HZ);
 
@@ -704,6 +714,7 @@ static void pwm_fan_shutdown(struct plat
 {
 	struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev);
 
+	pwm_fan_timer_cleanup(ctx);
 	pwm_fan_cleanup(ctx);
 }
 
author maintainer
#373 lore raw

PATCH 370/438 hwmon: (w83791d) remove fan/pwm 4-5 sysfs group on remove

In reply to Greg Kroah-Hartman

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

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

From: Guangshuo Li <[email protected]>

commit 0ff9c7775e51ac6d47b1bb5c46f06b1434fe58a8 upstream.

When the fan/pwm 4-5 pins are not used as GPIO, w83791d_probe() creates the w83791d_group_fanpwm45 sysfs group on the I2C client device.

The probe error path removes this group when a later initialization step fails, but the normal remove path only removes w83791d_group. As a result, the optional fan/pwm 4-5 sysfs files can remain after the driver is unbound.

The callbacks associated with these files access the driver data, which is devm allocated and released after driver unbind. Leaving the sysfs files behind can therefore result in accesses to stale driver data.

Remove w83791d_group_fanpwm45 during normal teardown as well.

This issue was found by manual code inspection.

Fixes 6e1ecd9b8f13 ("hwmon: (w83791d) fan 4/5 pins can also be used for gpio")
---
 drivers/hwmon/w83791d.c |    1 +
 1 file changed, 1 insertion(+)
drivers/hwmon/w83791d.c +1 -0
@@ -1415,6 +1415,7 @@ static void w83791d_remove(struct i2c_cl
 	struct w83791d_data *data = i2c_get_clientdata(client);
 
 	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &w83791d_group_fanpwm45);
 	sysfs_remove_group(&client->dev.kobj, &w83791d_group);
 }
 
author maintainer
#374 lore raw

PATCH 371/438 hwmon: (w83793) release probe data through kref

In reply to Greg Kroah-Hartman

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

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

From: Guangshuo Li <[email protected]>

commit c702a5f18b780e477eccbbab558e590e9673e4cb upstream.

w83793_probe() initializes data->kref to manage the lifetime of the driver data. The normal remove path drops the driver-owned reference with kref_put(), while watchdog users take and release additional references through the same kref.

However, the probe error path still frees data directly with kfree(). This bypasses the kref-managed lifetime and discards the initial reference without a matching kref_put(), leaving the reference accounting unbalanced.

Drop the probe-owned reference with kref_put() instead and let w83793_release_resources() perform the final free, matching the normal remove path.

This issue was found by manual code inspection.

---
 drivers/hwmon/w83793.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hwmon/w83793.c +3 -1
@@ -1928,7 +1928,9 @@ exit_remove:
 	for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
 		device_remove_file(dev, &w83793_temp[i].dev_attr);
 free_mem:
-	kfree(data);
+	mutex_lock(&watchdog_data_mutex);
+	kref_put(&data->kref, w83793_release_resources);
+	mutex_unlock(&watchdog_data_mutex);
 exit:
 	return err;
 }
author maintainer
#375 lore raw

PATCH 372/438 hwmon: (cgbc-hwmon) Fix current sensors ID lookup

In reply to Greg Kroah-Hartman

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

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

From: Thomas Richard (congatec GmbH) <[email protected]>

commit 7bae83ffb133bc373d098fa6828cef2ef4da49fe upstream.

Current sensors on the Congatec Board Controller don't use consecutive IDs, unlike other sensor types (voltage, temperature, fan). The driver assumed consecutive IDs and performed a simple lookup, which caused an unknown sensor warning. Define current sensor IDs explicitly.

Changes the warning on conga-SA7 (type and channel are correct now). Before:
Board Controller returned an unknown sensor (type=2, channel=17), ignore it
After:
Board Controller returned an unknown sensor (bc_type=1, bc_id=11), ignore it

---
 drivers/hwmon/cgbc-hwmon.c |   93 ++++++++++++++++++++++++++-------------------
 1 file changed, 54 insertions(+), 39 deletions(-)
drivers/hwmon/cgbc-hwmon.c +54 -39
@@ -52,31 +52,36 @@ static const char * const cgbc_hwmon_lab
 	"BOTTOMDIM Temperature",
 };
 
+static const char * const cgbc_hwmon_labels_in[] = {
+	"CPU Voltage",
+	"DC Runtime Voltage",
+	"DC Standby Voltage",
+	"CMOS Battery Voltage",
+	"Battery Voltage",
+	"AC Voltage",
+	"Other Voltage",
+	"5V Voltage",
+	"5V Standby Voltage",
+	"3V3 Voltage",
+	"3V3 Standby Voltage",
+	"VCore A Voltage",
+	"VCore B Voltage",
+	"12V Voltage",
+};
+
+/*
+ * Current sensors are a bit special, they don't have consecutive IDs like
+ * other types of sensors. So they need to be defined explicitly.
+ */
 static const struct {
-	enum hwmon_sensor_types type;
 	const char *label;
-} cgbc_hwmon_labels_in[] = {
-	{ hwmon_in, "CPU Voltage" },
-	{ hwmon_in, "DC Runtime Voltage" },
-	{ hwmon_in, "DC Standby Voltage" },
-	{ hwmon_in, "CMOS Battery Voltage" },
-	{ hwmon_in, "Battery Voltage" },
-	{ hwmon_in, "AC Voltage" },
-	{ hwmon_in, "Other Voltage" },
-	{ hwmon_in, "5V Voltage" },
-	{ hwmon_in, "5V Standby Voltage" },
-	{ hwmon_in, "3V3 Voltage" },
-	{ hwmon_in, "3V3 Standby Voltage" },
-	{ hwmon_in, "VCore A Voltage" },
-	{ hwmon_in, "VCore B Voltage" },
-	{ hwmon_in, "12V Voltage" },
-	{ hwmon_curr, "DC Current" },
-	{ hwmon_curr, "5V Current" },
-	{ hwmon_curr, "12V Current" },
+	int id;
+} cgbc_hwmon_labels_curr[] = {
+	{ "DC Current", 0x12 },
+	{ "5V Current", 0x18 },
+	{ "12V Current", 0x1E },
 };
 
-#define CGBC_HWMON_NB_IN_SENSORS	14
-
 static const char * const cgbc_hwmon_labels_fan[] = {
 	"CPU Fan",
 	"Box Fan",
@@ -114,7 +119,8 @@ static int cgbc_hwmon_probe_sensors(stru
 
 	for (i = 0; i < nb_sensors; i++) {
 		enum cgbc_sensor_types type;
-		unsigned int channel;
+		unsigned int channel, id;
+		int j;
 
 		/*
 		 * No need to request data for the first sensor.
@@ -128,32 +134,49 @@ static int cgbc_hwmon_probe_sensors(stru
 		}
 
 		type = FIELD_GET(CGBC_HWMON_TYPE_MASK, data[1]);
-		channel = FIELD_GET(CGBC_HWMON_ID_MASK, data[1]) - 1;
+		id = FIELD_GET(CGBC_HWMON_ID_MASK, data[1]);
+		channel = id - 1;
 
 		if (type == CGBC_HWMON_TYPE_TEMP && channel < ARRAY_SIZE(cgbc_hwmon_labels_temp)) {
 			sensor->type = hwmon_temp;
 			sensor->label = cgbc_hwmon_labels_temp[channel];
-		} else if (type == CGBC_HWMON_TYPE_IN &&
-			   channel < ARRAY_SIZE(cgbc_hwmon_labels_in)) {
+		} else if (type == CGBC_HWMON_TYPE_IN) {
 			/*
 			 * The Board Controller doesn't differentiate current and voltage sensors.
-			 * Get the sensor type from cgbc_hwmon_labels_in[channel].type instead.
+			 * First check if it is a current sensor.
 			 */
-			sensor->type = cgbc_hwmon_labels_in[channel].type;
-			sensor->label = cgbc_hwmon_labels_in[channel].label;
+			for (j = 0; j < ARRAY_SIZE(cgbc_hwmon_labels_curr); j++) {
+				if (id == cgbc_hwmon_labels_curr[j].id) {
+					sensor->type = hwmon_curr;
+					sensor->label = cgbc_hwmon_labels_curr[j].label;
+					channel = j;
+				}
+			}
+
+			/* If it's not a current sensor, it may be a voltage sensor. */
+			if (!sensor->label && channel < ARRAY_SIZE(cgbc_hwmon_labels_in)) {
+				sensor->type = hwmon_in;
+				sensor->label = cgbc_hwmon_labels_in[channel];
+			}
 		} else if (type == CGBC_HWMON_TYPE_FAN &&
 			   channel < ARRAY_SIZE(cgbc_hwmon_labels_fan)) {
 			sensor->type = hwmon_fan;
 			sensor->label = cgbc_hwmon_labels_fan[channel];
-		} else {
-			dev_warn(dev, "Board Controller returned an unknown sensor (type=%d, channel=%d), ignore it",
-				 type, channel);
+		}
+
+		if (!sensor->label) {
+			dev_warn(dev, "Board Controller returned an unknown sensor (bc_type=%d, bc_id=%d), ignore it",
+				 type, id);
 			continue;
 		}
 
 		sensor->active = FIELD_GET(CGBC_HWMON_ACTIVE_BIT, data[1]);
 		sensor->channel = channel;
 		sensor->index = i;
+
+		dev_dbg(dev, "Found sensor: bc_type=%d, bc_id=%d, hwmon_type=%d, hwmon_channel=%d, hwmon_label='%s', active=%d\n",
+			type, id, sensor->type, sensor->channel, sensor->label, sensor->active);
+
 		sensor++;
 		hwmon->nb_sensors++;
 	}
@@ -167,14 +190,6 @@ static struct cgbc_hwmon_sensor *cgbc_hw
 	struct cgbc_hwmon_sensor *sensor = NULL;
 	int i;
 
-	/*
-	 * The Board Controller doesn't differentiate current and voltage sensors.
-	 * The channel value (from the Board Controller point of view) shall be computed for current
-	 * sensors.
-	 */
-	if (type == hwmon_curr)
-		channel += CGBC_HWMON_NB_IN_SENSORS;
-
 	for (i = 0; i < hwmon->nb_sensors; i++) {
 		if (hwmon->sensors[i].type == type && hwmon->sensors[i].channel == channel) {
 			sensor = &hwmon->sensors[i];
author maintainer
#376 lore raw

PATCH 373/438 hwmon: (cgbc-hwmon) Add missing sensors

In reply to Greg Kroah-Hartman

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

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

From: Thomas Richard (congatec GmbH) <[email protected]>

commit 3550d1dbbcb9f51b77e077e8958423ee2c401c6c upstream.

Add the following sensors:
- Alternate Board Temperature (temp11_input)
- Top DIMM 1-7 Temperature (temp12_input to temp18_input)
- Bottom DIMM 1 Temperature (temp19_input)
- 12V Standby Voltage (in14_input)

This fixes the following warning on conga-SA7:

Board Controller returned an unknown sensor (bc_type=1, bc_id=11), ignore it

Also update existing labels to match Congatec documentation.

---
 Documentation/hwmon/cgbc-hwmon.rst |   42 ++++++++++++++++++-----------
 drivers/hwmon/cgbc-hwmon.c         |   52 ++++++++++++++++++++++++-------------
 2 files changed, 60 insertions(+), 34 deletions(-)
Documentation/hwmon/cgbc-hwmon.rst +26 -16
@@ -28,34 +28,44 @@ system.
 Name          Description
 ============= ======================
 temp1_input   CPU temperature
-temp2_input   Box temperature
+temp2_input   Case temperature
 temp3_input   Ambient temperature
-temp4_input   Board temperature
-temp5_input   Carrier temperature
-temp6_input   Chipset temperature
-temp7_input   Video temperature
+temp4_input   CPU Board temperature
+temp5_input   Carrier Board temperature
+temp6_input   System Chipset temperature
+temp7_input   Video Controller/Board temperature
 temp8_input   Other temperature
-temp9_input   TOPDIM temperature
-temp10_input  BOTTOMDIM temperature
-in0_input     CPU voltage
+temp9_input   Top DIMM 0 temperature
+temp10_input  Bottom DIMM 0 temperature
+temp11_input  Alternate Board temperature
+temp12_input  Top DIMM 1 temperature
+temp13_input  Top DIMM 2 temperature
+temp14_input  Top DIMM 3 temperature
+temp15_input  Top DIMM 4 temperature
+temp16_input  Top DIMM 5 temperature
+temp17_input  Top DIMM 6 temperature
+temp18_input  Top DIMM 7 temperature
+temp19_input  Bottom DIMM 1 temperature
+in0_input     CPU Core voltage
 in1_input     DC Runtime voltage
 in2_input     DC Standby voltage
 in3_input     CMOS Battery voltage
-in4_input     Battery voltage
+in4_input     Battery Supply voltage
 in5_input     AC voltage
 in6_input     Other voltage
-in7_input     5V voltage
+in7_input     5V Runtime voltage
 in8_input     5V Standby voltage
-in9_input     3V3 voltage
+in9_input     3V3 Runtime voltage
 in10_input    3V3 Standby voltage
 in11_input    VCore A voltage
 in12_input    VCore B voltage
-in13_input    12V voltage
-curr1_input   DC current
-curr2_input   5V current
-curr3_input   12V current
+in13_input    12V Runtime voltage
+in14_input    12V Standby voltage
+curr1_input   DC Runtime current
+curr2_input   5V Runtime current
+curr3_input   12V Runtime current
 fan1_input    CPU fan
-fan2_input    Box fan
+fan2_input    Case fan
 fan3_input    Ambient fan
 fan4_input    Chiptset fan
 fan5_input    Video fan
drivers/hwmon/cgbc-hwmon.c +34 -18

94 lines not on this page · raw message

author maintainer
#377 lore raw

PATCH 374/438 watchdog: da9063: fix suspend/resume handling of HW_RUNNING watchdog

In reply to Greg Kroah-Hartman

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

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

From: Li Jun <[email protected]>

commit 7cb575b71ab98194d2e040bded3a7281e089c5ed upstream.

da9063_wdt_suspend() and da9063_wdt_resume() only check watchdog_active(), when the watchdog is left running by the driver sets WDOG_HW_RUNNING in da9063_wdt_probe() but userspace never opens the device, so WDOG_ACTIVE remains cleared, the wdt_disable() will not be executed in da9063_wdt_suspend. In this case, the suspend callback is a no-op and the watchdog keeps counting during system suspend, leading to an unexpected system reset.
Check WDOG_HW_RUNNING and wdd,can fix this issue.

Fixes a7ceca4398bc8 ("watchdog: da9063: optionally disable watchdog during suspend")
---
 drivers/watchdog/da9063_wdt.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/watchdog/da9063_wdt.c +2 -2
@@ -271,7 +271,7 @@ static int da9063_wdt_suspend(struct dev
 	if (!da9063->use_sw_pm)
 		return 0;
 
-	if (watchdog_active(wdd))
+	if (watchdog_active(wdd) || watchdog_hw_running(wdd))
 		return da9063_wdt_stop(wdd);
 
 	return 0;
@@ -285,7 +285,7 @@ static int da9063_wdt_resume(struct devi
 	if (!da9063->use_sw_pm)
 		return 0;
 
-	if (watchdog_active(wdd))
+	if (watchdog_active(wdd) || watchdog_hw_running(wdd))
 		return da9063_wdt_start(wdd);
 
 	return 0;
author maintainer
#378 lore raw

PATCH 375/438 watchdog: digicolor: Avoid division by zero

In reply to Greg Kroah-Hartman

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

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

From: Tzung-Bi Shih <[email protected]>

commit 400cb663ca019bae6eb878f06f1094ddf7c0b0df upstream.

clk_get_rate() could return 0. Avoid a division by zero panic.

Since get_timeleft() cannot propagate errors, check the clock rate early in probe() and cache the rate in the driver data as it is unlikely to change at runtime.

Fixes 336694a01dae ("watchdog: digicolor: driver for Conexant Digicolor CX92755 SoC")
---
 drivers/watchdog/digicolor_wdt.c |   13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/watchdog/digicolor_wdt.c +9 -4
@@ -25,6 +25,7 @@ struct dc_wdt {
 	void __iomem		*base;
 	struct clk		*clk;
 	spinlock_t		lock;
+	unsigned long		rate;
 };
 
 static unsigned timeout;
@@ -61,7 +62,7 @@ static int dc_wdt_start(struct watchdog_
 {
 	struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
 
-	dc_wdt_set(wdt, wdog->timeout * clk_get_rate(wdt->clk));
+	dc_wdt_set(wdt, wdog->timeout * wdt->rate);
 
 	return 0;
 }
@@ -79,7 +80,7 @@ static int dc_wdt_set_timeout(struct wat
 {
 	struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
 
-	dc_wdt_set(wdt, t * clk_get_rate(wdt->clk));
+	dc_wdt_set(wdt, t * wdt->rate);
 	wdog->timeout = t;
 
 	return 0;
@@ -90,7 +91,7 @@ static unsigned int dc_wdt_get_timeleft(
 	struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
 	uint32_t count = readl_relaxed(wdt->base + TIMER_A_COUNT);
 
-	return count / clk_get_rate(wdt->clk);
+	return count / wdt->rate;
 }
 
 static const struct watchdog_ops dc_wdt_ops = {
@@ -130,7 +131,11 @@ static int dc_wdt_probe(struct platform_
 	wdt->clk = devm_clk_get(dev, NULL);
 	if (IS_ERR(wdt->clk))
 		return PTR_ERR(wdt->clk);
-	dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk);
+
+	wdt->rate = clk_get_rate(wdt->clk);
+	if (!wdt->rate)
+		return -EINVAL;
+	dc_wdt_wdd.max_timeout = U32_MAX / wdt->rate;
 	dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout;
 	dc_wdt_wdd.parent = dev;
 
author maintainer
#379 lore raw

PATCH 376/438 watchdog: msc313e: Fix premature reset during timeout update

In reply to Greg Kroah-Hartman

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

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

From: Tzung-Bi Shih <[email protected]>

commit 22737cfced627ffcb4b5c36d63bb3d4476f63213 upstream.

Updating the 32-bit hardware timeout requires writing to two 16-bit registers sequentially. If the watchdog is actively running, this non-atomic update might trigger a premature system reset.

Clear the watchdog counter before updating the registers to prevent the timer from timing out prematurely against an intermediate threshold.

---
 drivers/watchdog/msc313e_wdt.c |    6 ++++++
 1 file changed, 6 insertions(+)
drivers/watchdog/msc313e_wdt.c +6 -0
@@ -46,6 +46,9 @@ static void msc313e_wdt_set_hw_timeout(s
 {
 	u32 t = timeout * clk_get_rate(priv->clk);
 
+	/* Clear before to prevent premature reset during non-atomic updates. */
+	writew(1, priv->base + REG_WDT_CLR);
+
 	writew(t & 0xffff, priv->base + REG_WDT_MAX_PRD_L);
 	writew((t >> 16) & 0xffff, priv->base + REG_WDT_MAX_PRD_H);
 	writew(1, priv->base + REG_WDT_CLR);
@@ -76,6 +79,9 @@ static int msc313e_wdt_stop(struct watch
 {
 	struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev);
 
+	/* Clear before to prevent premature reset during non-atomic updates. */
+	writew(1, priv->base + REG_WDT_CLR);
+
 	writew(0, priv->base + REG_WDT_MAX_PRD_L);
 	writew(0, priv->base + REG_WDT_MAX_PRD_H);
 	writew(0, priv->base + REG_WDT_CLR);
author maintainer
#380 lore raw

PATCH 377/438 watchdog: msc313e: Propagate error code in resume()

In reply to Greg Kroah-Hartman

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

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

From: Tzung-Bi Shih <[email protected]>

commit 1d9763f34a85680db1e8233d654fdb85e5f897cc upstream.

If msc313e_wdt_start() fails during system resume, the error is currently ignored. Consequently, the watchdog isn't running without the user's knowledge.

Propagate the error code and print a message if msc313e_wdt_start() fails.

---
 drivers/watchdog/msc313e_wdt.c |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/watchdog/msc313e_wdt.c +7 -3
@@ -197,11 +197,15 @@ static int __maybe_unused msc313e_wdt_su
 static int __maybe_unused msc313e_wdt_resume(struct device *dev)
 {
 	struct msc313e_wdt_priv *priv = dev_get_drvdata(dev);
+	int ret = 0;
 
-	if (watchdog_active(&priv->wdev) || watchdog_hw_running(&priv->wdev))
-		msc313e_wdt_start(&priv->wdev);
+	if (watchdog_active(&priv->wdev) || watchdog_hw_running(&priv->wdev)) {
+		ret = msc313e_wdt_start(&priv->wdev);
+		if (ret)
+			dev_err(dev, "Failed to restart watchdog (err=%d)\n", ret);
+	}
 
-	return 0;
+	return ret;
 }
 
 static SIMPLE_DEV_PM_OPS(msc313e_wdt_pm_ops, msc313e_wdt_suspend, msc313e_wdt_resume);
author maintainer
#381 lore raw

PATCH 378/438 watchdog: rtd119x: Avoid division by zero

In reply to Greg Kroah-Hartman

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

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

From: Tzung-Bi Shih <[email protected]>

commit 5af7d2cbd20f893def03c8310a460ade66a5d822 upstream.

clk_get_rate() could return 0. Avoid a division by zero panic.

---
 drivers/watchdog/rtd119x_wdt.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/watchdog/rtd119x_wdt.c +6 -1
@@ -98,6 +98,7 @@ static int rtd119x_wdt_probe(struct plat
 {
 	struct device *dev = &pdev->dev;
 	struct rtd119x_watchdog_device *data;
+	unsigned long rate;
 
 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
@@ -111,10 +112,14 @@ static int rtd119x_wdt_probe(struct plat
 	if (IS_ERR(data->clk))
 		return PTR_ERR(data->clk);
 
+	rate = clk_get_rate(data->clk);
+	if (!rate)
+		return -EINVAL;
+
 	data->wdt_dev.info = &rtd119x_wdt_info;
 	data->wdt_dev.ops = &rtd119x_wdt_ops;
 	data->wdt_dev.timeout = 120;
-	data->wdt_dev.max_timeout = 0xffffffff / clk_get_rate(data->clk);
+	data->wdt_dev.max_timeout = 0xffffffff / rate;
 	data->wdt_dev.min_timeout = 1;
 	data->wdt_dev.parent = dev;
 
author maintainer
#382 lore raw

PATCH 379/438 watchdog: rzv2h: Avoid division by zero

In reply to Greg Kroah-Hartman

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

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

From: Tzung-Bi Shih <[email protected]>

commit 6274281c41efa8dd1aa5234c59ad904ff89d7af4 upstream.

clk_get_rate() could return 0. Avoid a division by zero panic.

Fixes f6febd0a30b6 ("watchdog: Add Watchdog Timer driver for RZ/V2H(P)")
---
 drivers/watchdog/rzv2h_wdt.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/watchdog/rzv2h_wdt.c +6 -1
@@ -278,6 +278,7 @@ static int rzv2h_wdt_probe(struct platfo
 	struct device *dev = &pdev->dev;
 	struct rzv2h_wdt_priv *priv;
 	struct clk *count_clk;
+	unsigned long rate;
 	int ret;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -314,8 +315,12 @@ static int rzv2h_wdt_probe(struct platfo
 		return dev_err_probe(dev, -EINVAL, "Invalid count source\n");
 	}
 
+	rate = clk_get_rate(count_clk);
+	if (!rate)
+		return dev_err_probe(dev, -EINVAL, "Invalid clock rate\n");
+
 	priv->wdev.max_hw_heartbeat_ms = (MILLI * priv->of_data->timeout_cycles *
-					  priv->of_data->cks_div) / clk_get_rate(count_clk);
+					  priv->of_data->cks_div) / rate;
 	dev_dbg(dev, "max hw timeout of %dms\n", priv->wdev.max_hw_heartbeat_ms);
 
 	ret = devm_pm_runtime_enable(dev);
author maintainer
#383 lore raw

PATCH 380/438 watchdog: sp5100_tco: Fix pci_dev reference leak in sp5100_tco_init()

In reply to Greg Kroah-Hartman

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

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

From: Wentao Liang <[email protected]>

commit 88f113634028ca90a857031837d8061d1a9e1a7b upstream.

sp5100_tco_init() stores the PCI device matched by for_each_pci_dev() in the global sp5100_tco_pci and keeps its reference for the lifetime of the driver, but neither sp5100_tco_exit() nor the error paths of sp5100_tco_init() call pci_dev_put(), leaking the reference on driver registration failure and on every module load/unload cycle.

Drop the reference when the platform driver or device registration fails and when the module is unloaded.

Fixes 15e28bf13008 ("watchdog: Add support for sp5100 chipset TCO")
---
 drivers/watchdog/sp5100_tco.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/watchdog/sp5100_tco.c +5 -1
@@ -605,8 +605,10 @@ static int __init sp5100_tco_init(void)
 	pr_info("SP5100/SB800 TCO WatchDog Timer Driver\n");
 
 	err = platform_driver_register(&sp5100_tco_driver);
-	if (err)
+	if (err) {
+		pci_dev_put(sp5100_tco_pci);
 		return err;
+	}
 
 	sp5100_tco_platform_device =
 		platform_device_register_simple(TCO_DRIVER_NAME, -1, NULL, 0);
@@ -619,6 +621,7 @@ static int __init sp5100_tco_init(void)
 
 unreg_platform_driver:
 	platform_driver_unregister(&sp5100_tco_driver);
+	pci_dev_put(sp5100_tco_pci);
 	return err;
 }
 
@@ -626,6 +629,7 @@ static void __exit sp5100_tco_exit(void)
 {
 	platform_device_unregister(sp5100_tco_platform_device);
 	platform_driver_unregister(&sp5100_tco_driver);
+	pci_dev_put(sp5100_tco_pci);
 }
 
 module_init(sp5100_tco_init);
author maintainer
#384 lore raw

PATCH 381/438 watchdog: starfive-wdt: Fix runtime PM leak in starfive_wdt_pm_start()

In reply to Greg Kroah-Hartman

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

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

From: Wentao Liang <[email protected]>

commit 8f0ca55016a7647109ae2bc91bcb346fc8b13785 upstream.

starfive_wdt_pm_start() takes a runtime PM reference with pm_runtime_get_sync(), which increments the usage counter even when it fails, and returns the error without dropping it again. The watchdog core does not invoke the stop callback when start fails, so the reference taken on the error path is leaked.

Use pm_runtime_resume_and_get() instead, which keeps the usage counter balanced when the resume fails.

Fixes db728ea9c7be ("drivers: watchdog: Add StarFive Watchdog driver")
---
 drivers/watchdog/starfive-wdt.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/watchdog/starfive-wdt.c +1 -1
@@ -371,7 +371,7 @@ static void starfive_wdt_stop(struct sta
 static int starfive_wdt_pm_start(struct watchdog_device *wdd)
 {
 	struct starfive_wdt *wdt = watchdog_get_drvdata(wdd);
-	int ret = pm_runtime_get_sync(wdd->parent);
+	int ret = pm_runtime_resume_and_get(wdd->parent);
 
 	if (ret < 0)
 		return ret;
author maintainer
#385 lore raw

PATCH 382/438 wifi: brcmsmac: fix UAF in brcms_free_timer()

In reply to Greg Kroah-Hartman

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

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

From: Jiangshan Yi <[email protected]>

commit 1eeca1d5e0920fbdad6449768fd2d4364e714180 upstream.

brcms_free_timer() calls brcms_del_timer() which uses the non-synchronous cancel_delayed_work() to cancel the timer's underlying delayed work. If the work callback (_brcms_timer) is already running, cancel_delayed_work() returns false without waiting, and brcms_free_timer() proceeds to kfree(t) while the callback still accesses t through container_of().

Add an explicit cancel_delayed_work_sync() after brcms_del_timer() to guarantee that any in-flight callback has completed before the timer structure is freed.

---
 drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c |    4 ++++
 1 file changed, 4 insertions(+)
drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +4 -0
@@ -1571,6 +1571,10 @@ void brcms_free_timer(struct brcms_timer
 
 	/* delete the timer in case it is active */
 	brcms_del_timer(t);
+	/* Ensure the callback has finished before freeing the timer
+	 * structure, since brcms_del_timer() uses non-synchronous cancel.
+	 */
+	cancel_delayed_work_sync(&t->dly_wrk);
 
 	if (wl->timers == t) {
 		wl->timers = wl->timers->next;
author maintainer
#386 lore raw

PATCH 383/438 wifi: iwlegacy: fix broadcast stations deallocation

In reply to Greg Kroah-Hartman

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

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

From: Stanislaw Gruszka <[email protected]>

commit b5526b780f8b297a76030410b96ba29153afb98f upstream.

On the error path of __il4965_up(), il_dealloc_bcast_stations() clears only IL_STA_UCODE_ACTIVE, leaving IL_STA_BCAST set. This causes the same broadcast stations to be deallocated again by __il4965_down().

This can occur when RF_KILL is toggled during driver startup.

To fix clear the entire 'used' field, since we will not do any other operations on the station.

Fixes c2fd34469d16 ("iwl4965: Fix a memory leak in error handling code of __il4965_up")
Cc <[email protected]> # 7.1.x: 57aa1718d595 wifi: iwlegacy: replace BUG_ON() with WARN_ON() on num_stations check
Cc <[email protected]> # 6.x.x: 57aa1718d595 wifi: iwlegacy: replace BUG_ON() with WARN_ON() on num_stations check
Cc <[email protected]> # 5.x.x: 57aa1718d595 wifi: iwlegacy: replace BUG_ON() with WARN_ON() on num_stations check
---
 drivers/net/wireless/intel/iwlegacy/common.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/intel/iwlegacy/common.c +1 -1
@@ -2326,7 +2326,7 @@ il_dealloc_bcast_stations(struct il_priv
 		if (!(il->stations[i].used & IL_STA_BCAST))
 			continue;
 
-		il->stations[i].used &= ~IL_STA_UCODE_ACTIVE;
+		il->stations[i].used = 0;
 		il->num_stations--;
 		if (WARN_ON(il->num_stations < 0))
 			il->num_stations = 0;
author maintainer
#387 lore raw

PATCH 384/438 wifi: libertas_tf: fix UAF in lbtf_free_adapter()

In reply to Greg Kroah-Hartman

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

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

From: Jiangshan Yi <[email protected]>

commit bbb9a0ab96d44a64529aafc7a16de460a1712f6a upstream.

lbtf_free_adapter() calls lbtf_free_cmd_buffer() to free the command buffers before calling timer_delete_sync() to wait for the command timer callback. If the timer callback (command_timer_fn) is already running when lbtf_free_cmd_buffer() frees the command array, the callback dereferences priv->cur_cmd->cmdbuf which points to freed memory.

Swap the order so that timer_delete_sync() runs first, ensuring any in-flight callback has completed before the command buffers are freed.

Fixes 06b16ae53192 ("libertas_tf: main.c, data paths and mac80211 handlers")
---
 drivers/net/wireless/marvell/libertas_tf/main.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/marvell/libertas_tf/main.c +1 -1
@@ -173,8 +173,8 @@ static int lbtf_init_adapter(struct lbtf
 static void lbtf_free_adapter(struct lbtf_private *priv)
 {
 	lbtf_deb_enter(LBTF_DEB_MAIN);
-	lbtf_free_cmd_buffer(priv);
 	timer_delete_sync(&priv->command_timer);
+	lbtf_free_cmd_buffer(priv);
 	lbtf_deb_leave(LBTF_DEB_MAIN);
 }
 
author maintainer
#388 lore raw

PATCH 385/438 wifi: libipw: reject TKIP frames without a full MIC

In reply to Greg Kroah-Hartman

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

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

From: Daehyeon Ko <[email protected]>

commit 06f42accaf3c6aecab1dcc57f68dde6c06c8b380 upstream.

libipw_michael_mic_verify() assumes that an skb contains an eight-byte Michael MIC. A short TKIP frame makes the unsigned payload length wrap, causing michael_mic() to read past the skb.

Check that the MIC is present before verifying it, and use the existing MICHAEL_MIC_LEN constant for all MIC lengths in the verifier.

---
 drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c |   12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c +7 -5
@@ -474,14 +474,16 @@ static int libipw_michael_mic_verify(str
 					int hdr_len, void *priv)
 {
 	struct libipw_tkip_data *tkey = priv;
-	u8 mic[8];
+	u8 mic[MICHAEL_MIC_LEN];
 
-	if (!tkey->key_set)
+	if (!tkey->key_set || skb->len < hdr_len + MICHAEL_MIC_LEN)
 		return -1;
 
 	michael_mic(&tkey->key[24], (struct ieee80211_hdr *)skb->data,
-		    skb->data + hdr_len, skb->len - 8 - hdr_len, mic);
-	if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
+		    skb->data + hdr_len,
+		    skb->len - MICHAEL_MIC_LEN - hdr_len, mic);
+	if (memcmp(mic, skb->data + skb->len - MICHAEL_MIC_LEN,
+		   MICHAEL_MIC_LEN) != 0) {
 		struct ieee80211_hdr *hdr;
 		hdr = (struct ieee80211_hdr *)skb->data;
 		printk(KERN_DEBUG "%s: Michael MIC verification failed for "
@@ -499,7 +501,7 @@ static int libipw_michael_mic_verify(str
 	tkey->rx_iv32 = tkey->rx_iv32_new;
 	tkey->rx_iv16 = tkey->rx_iv16_new;
 
-	skb_trim(skb, skb->len - 8);
+	skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
 
 	return 0;
 }
author maintainer
#389 lore raw

PATCH 386/438 wifi: rsi: fix heap OOB write on key removal

In reply to Greg Kroah-Hartman

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

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

From: Tianchu Chen <[email protected]>

commit e6c5ed7a98d7bc8b0f7918246f1c90ddb3f79dfa upstream.

When a key is removed (data == NULL), rsi_hal_load_key() runs:

	memset(&set_key[FRAME_DESC_SZ], 0, frame_len - FRAME_DESC_SZ);

set_key is a struct rsi_set_key *, so the subscript is scaled by sizeof(struct rsi_set_key) (160 bytes): &set_key[FRAME_DESC_SZ] is skb->data + 2560, and the memset writes 144 zero bytes starting 2.4KB past the end of the 160-byte skb data buffer, corrupting unrelated heap objects. The intended byte offset would have been (u8 *)set_key + FRAME_DESC_SZ.

The write fires on every DISABLE_KEY callback, so plain disconnects, roams and interface teardowns trigger it on real networks.

The memset is redundant: the whole buffer is zeroed right after allocation, so the frame sent to the device is byte-identical without it. Drop the else branch; normal operation is unaffected.

Discovered by Atuin - Automated Vulnerability Discovery Engine.

Fixes dad0d04fa7ba ("rsi: Add RS9113 wireless driver")
Assisted-by LLM
---
 drivers/net/wireless/rsi/rsi_91x_mgmt.c |    2 --
 1 file changed, 2 deletions(-)
drivers/net/wireless/rsi/rsi_91x_mgmt.c +0 -2
@@ -852,8 +852,6 @@ int rsi_hal_load_key(struct rsi_common *
 			memcpy(set_key->tx_mic_key, &data[16], 8);
 			memcpy(set_key->rx_mic_key, &data[24], 8);
 		}
-	} else {
-		memset(&set_key[FRAME_DESC_SZ], 0, frame_len - FRAME_DESC_SZ);
 	}
 
 	skb_put(skb, frame_len);
author maintainer
#390 lore raw

PATCH 387/438 wifi: wcn36xx: Fix potential use-after-free in TX ack timer teardown

In reply to Greg Kroah-Hartman

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

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

From: Fan Wu <[email protected]>

commit d9be5e75530772fc31637070d51e5717d6aeaa2a upstream.

wcn36xx_dxe_deinit() tears down the TX ack timer with timer_delete(), which only dequeues the timer and does not wait for a callback that is already executing; the preceding free_irq() calls synchronize the interrupt handlers only. The callback, wcn36xx_dxe_tx_timer(), can therefore be running past the teardown and use the wcn freed along with the ieee80211_hw in wcn36xx_remove(): it takes wcn->dxe_lock, reads wcn->tx_ack_skb and passes wcn->hw to ieee80211_tx_status_irqsafe().

Fix this by using timer_shutdown_sync(), which waits for a running callback and also prevents the timer from being rearmed again. The timer is set up again by wcn36xx_dxe_init() on the next start, so the start/stop cycle is unaffected.

This issue was found by an in-house static analysis tool.

---
 drivers/net/wireless/ath/wcn36xx/dxe.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/wireless/ath/wcn36xx/dxe.c +1 -1
@@ -1055,7 +1055,7 @@ void wcn36xx_dxe_deinit(struct wcn36xx *
 
 	free_irq(wcn->tx_irq, wcn);
 	free_irq(wcn->rx_irq, wcn);
-	timer_delete(&wcn->tx_ack_timer);
+	timer_shutdown_sync(&wcn->tx_ack_timer);
 
 	if (wcn->tx_ack_skb) {
 		ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb);
author maintainer
#391 lore raw

PATCH 388/438 wifi: wlcore: release runtime PM ref on regdomain config failure

In reply to Greg Kroah-Hartman

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

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

From: Runyu Xiao <[email protected]>

commit 8a1f3cf89ddcc700e25afe42cfad333059adcc94 upstream.

wlcore_regdomain_config() gets a runtime PM reference before sending the regulatory-domain command. When wlcore_cmd_regdomain_config_locked() fails, the function queues recovery and returns without dropping that reference.

Release the reference after handling the command result so both success and failure paths balance the preceding pm_runtime_resume_and_get(). The recovery worker takes a separate runtime PM reference and cannot release the reference held here.

---
 drivers/net/wireless/ti/wlcore/main.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/net/wireless/ti/wlcore/main.c +1 -3
@@ -3724,10 +3724,8 @@ void wlcore_regdomain_config(struct wl12
 		goto out;
 
 	ret = wlcore_cmd_regdomain_config_locked(wl);
-	if (ret < 0) {
+	if (ret < 0)
 		wl12xx_queue_recovery_work(wl);
-		goto out;
-	}
 
 	pm_runtime_put_autosuspend(wl->dev);
 out:
author maintainer
#392 lore raw

PATCH 389/438 wifi: wilc1000: fix out-of-bounds read in P2P public action frames

In reply to Greg Kroah-Hartman

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

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

From: Ali Ahmet Memis <[email protected]>

commit ba6cb7c0868a412c2eb68e8efd5aa38bfb258a14 upstream.

wilc_wfi_p2p_rx() and mgmt_tx() start parsing a frame once ieee80211_is_public_action() returns true. That helper only verifies the frame is long enough for the action category field, that is offsetofend(struct ieee80211_mgmt, u.action.category), 25 bytes. Both functions then read the P2P public action header up to oui_subtype at offset 30 and pass "size - ie_offset" to cfg80211_find_vendor_ie(), where ie_offset is offsetof(struct ieee80211_mgmt, u) + sizeof(*d), i.e. 32.

A public action frame of 25 to 31 bytes passes the check but is shorter than that 32 byte header, so oui_subtype can be read out of bounds, and because the length is unsigned, "size - ie_offset" underflows to a value close to 4 GiB. cfg80211_find_vendor_ie() takes an unsigned int length, so even the size_t subtraction in mgmt_tx() is truncated to the same value. It then walks far past the buffer searching for a vendor element until it reaches unmapped memory.

In the receive path the frame arrives over the air and needs no association, so a nearby unauthenticated device can crash the host while it is in P2P listen. Reject frames shorter than the P2P public action header in both paths before dereferencing it.

Fixes 4fb8b5aa2a11 ("staging: wilc1000: refactor p2p action frames handling API's")
---
 drivers/net/wireless/microchip/wilc1000/cfg80211.c |   14 ++++++++++++++
 1 file changed, 14 insertions(+)
drivers/net/wireless/microchip/wilc1000/cfg80211.c +14 -0
@@ -1058,6 +1058,13 @@ void wilc_wfi_p2p_rx(struct wilc_vif *vi
 	if (!ieee80211_is_public_action((struct ieee80211_hdr *)buff, size))
 		goto out_rx_mgmt;
 
+	/* ieee80211_is_public_action() only validates up to the category
+	 * byte, so reject frames too short for the P2P public action header
+	 * before dereferencing it or computing size - ie_offset.
+	 */
+	if (size < ie_offset)
+		goto out_rx_mgmt;
+
 	d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
 	if (d->oui_subtype != GO_NEG_REQ && d->oui_subtype != GO_NEG_RSP &&
 	    d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP)
@@ -1207,6 +1214,13 @@ static int mgmt_tx(struct wiphy *wiphy,
 		goto out_set_timeout;
 	}
 
+	/* ieee80211_is_public_action() only validates up to the category
+	 * byte, so reject frames too short for the P2P public action header
+	 * before dereferencing it or computing len - ie_offset.
+	 */
+	if (len < ie_offset)
+		goto out_set_timeout;
+
 	d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
 	if (d->oui_type != WLAN_OUI_TYPE_WFA_P2P ||
 	    d->oui_subtype != GO_NEG_CONF) {
author maintainer
#393 lore raw

PATCH 390/438 wifi: wilc1000: fix RX buffer OOB-write in wilc_wlan_handle_isr_ext()

In reply to Greg Kroah-Hartman

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

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

From: Tianchu Chen <[email protected]>

commit c1ba7f7f18465e259cf1b4d9c73fc73853d7f790 upstream.

wilc_wlan_handle_isr_ext() takes the RX transfer size from the device-reported interrupt status register (a 15-bit field shifted left by 2, up to 131068 bytes) and reads that many bytes from the device into rx_buffer, which is only WILC_RX_BUFF_SIZE (96K) large. The wrap check only handles the current offset; the size itself is never compared against the buffer, so a bogus SDIO device can make the driver OOB-write rx_buffer by up to ~32K with data it controls.

The oversized transfer also leaves rx_buffer_offset past the end of the buffer, after which the unsigned wrap check stops working and the overflow can repeat.

Drop any transfer whose size exceeds the RX buffer, acknowledging the data interrupt and re-arming the RX engine so the bogus frame is discarded and reception can continue. This also restores the rx_buffer_offset <= WILC_RX_BUFF_SIZE invariant the wrap check relies on.

This is not expected to change driver behavior in most cases:
without this check, an oversized transfer would most likely corrupt neighboring kernel memory instead of completing anyway, and the drop path performs the same interrupt acknowledgment and RX engine re-arming as the normal path, so subsequent transfers are received unaffected.

Discovered by Atuin - Automated Vulnerability Discovery Engine.

Fixes c5c77ba18ea6 ("staging: wilc1000: Add SDIO/SPI 802.11 driver")
Assisted-by LLM
---
 drivers/net/wireless/microchip/wilc1000/wlan.c |    9 +++++++++
 1 file changed, 9 insertions(+)
drivers/net/wireless/microchip/wilc1000/wlan.c +9 -0
@@ -1197,6 +1197,15 @@ static void wilc_wlan_handle_isr_ext(str
 	if (size <= 0)
 		return;
 
+	/* A size exceeding the RX buffer is bogus; drop the transfer
+	 * instead of overflowing the buffer.
+	 */
+	if (size > WILC_RX_BUFF_SIZE) {
+		wilc->hif_func->hif_clear_int_ext(wilc,
+						  DATA_INT_CLR | ENABLE_RX_VMM);
+		return;
+	}
+
 	if (WILC_RX_BUFF_SIZE - offset < size)
 		offset = 0;
 
author maintainer
#394 lore raw

PATCH 391/438 wifi: p54: validate curve data length in the calibration curve converters

In reply to Greg Kroah-Hartman

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

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

From: Shengzhuo Wei <[email protected]>

commit ce858fa6b8a214dee5adb82358885fa024cdd887 upstream.

p54_convert_rev0() and p54_convert_rev1() read calibration curve data from the device-supplied EEPROM entry using channel and points-per-channel counts taken verbatim from that same entry, so an entry that declares more data than it carries drives an out-of-bounds read past the EEPROM buffer (verified with a KASAN reproducer of the conversion loop). The sibling converters p54_convert_output_limits() and p54_convert_db() already validate their counts against the entry length; this path was missed.

Reject the entry when the counts do not fit in the entry data.

Fixes eff1a59c48e3 ("[P54]: add mac80211-based driver for prism54 softmac hardware")
Assisted-by GLM:5.3
---
 drivers/net/wireless/intersil/p54/eeprom.c |   19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
drivers/net/wireless/intersil/p54/eeprom.c +15 -4
@@ -414,17 +414,22 @@ free:
 }
 
 static int p54_convert_rev0(struct ieee80211_hw *dev,
-			    struct pda_pa_curve_data *curve_data)
+			    struct pda_pa_curve_data *curve_data, size_t len)
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_pa_curve_data_sample *dst;
 	struct pda_pa_curve_data_sample_rev0 *src;
+	size_t needed = curve_data->channels *
+		(sizeof(*src) * curve_data->points_per_channel + 2);
 	size_t cd_len = sizeof(*curve_data) +
 		(curve_data->points_per_channel*sizeof(*dst) + 2) *
 		 curve_data->channels;
 	unsigned int i, j;
 	void *source, *target;
 
+	if (len < sizeof(*curve_data) + needed)
+		return -EINVAL;
+
 	priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
 				   GFP_KERNEL);
 	if (!priv->curve_data)
@@ -466,17 +471,22 @@ static int p54_convert_rev0(struct ieee8
 }
 
 static int p54_convert_rev1(struct ieee80211_hw *dev,
-			    struct pda_pa_curve_data *curve_data)
+			    struct pda_pa_curve_data *curve_data, size_t len)
 {
 	struct p54_common *priv = dev->priv;
 	struct p54_pa_curve_data_sample *dst;
 	struct pda_pa_curve_data_sample_rev1 *src;
+	size_t needed = curve_data->channels *
+		(sizeof(*src) * curve_data->points_per_channel + 3);
 	size_t cd_len = sizeof(*curve_data) +
 		(curve_data->points_per_channel*sizeof(*dst) + 2) *
 		 curve_data->channels;
 	unsigned int i, j;
 	void *source, *target;
 
+	if (len < sizeof(*curve_data) + needed)
+		return -EINVAL;
+
 	priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
 				   GFP_KERNEL);
 	if (!priv->curve_data)
@@ -763,6 +773,7 @@ int p54_parse_eeprom(struct ieee80211_hw
 		case PDR_PRISM_PA_CAL_CURVE_DATA: {
 			struct pda_pa_curve_data *curve_data =
 				(struct pda_pa_curve_data *)entry->data;
+
 			if (data_len < sizeof(*curve_data)) {
 				err = -EINVAL;
 				goto err;
@@ -770,10 +781,10 @@ int p54_parse_eeprom(struct ieee80211_hw
 
 			switch (curve_data->cal_method_rev) {
 			case 0:
-				err = p54_convert_rev0(dev, curve_data);
+				err = p54_convert_rev0(dev, curve_data, data_len);
 				break;
 			case 1:
-				err = p54_convert_rev1(dev, curve_data);
+				err = p54_convert_rev1(dev, curve_data, data_len);
 				break;
 			default:
 				wiphy_err(dev->wiphy,
author maintainer
#395 lore raw

PATCH 392/438 wifi: p54: require a full exp_if record in PDR_INTERFACE_LIST

In reply to Greg Kroah-Hartman

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

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

From: Shengzhuo Wei <[email protected]>

commit d8efd84f49379ed28624098821f80e992657d935 upstream.

The PDR_INTERFACE_LIST loop only checks that the record start is within the entry before reading an entire struct exp_if from it. A truncated trailing record makes the if_id/variant reads cross the entry boundary into the heap beyond the EEPROM buffer (verified with a KASAN reproducer of the loop). The variant also feeds the synth front-end selection, so this is not only a leak.

Advance only while a full record still fits in the entry.

Fixes eff1a59c48e3 ("[P54]: add mac80211-based driver for prism54 softmac hardware")
Assisted-by GLM:5.3
---
 drivers/net/wireless/intersil/p54/eeprom.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/wireless/intersil/p54/eeprom.c +2 -1
@@ -812,7 +812,8 @@ int p54_parse_eeprom(struct ieee80211_hw
 			break;
 		case PDR_INTERFACE_LIST:
 			tmp = entry->data;
-			while ((u8 *)tmp < entry->data + data_len) {
+			while ((u8 *)tmp + sizeof(struct exp_if) <=
+			       entry->data + data_len) {
 				struct exp_if *exp_if = tmp;
 				if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
 					synth = le16_to_cpu(exp_if->variant);
author maintainer
#396 lore raw

PATCH 393/438 wifi: mwifiex: bound the pairwise-cipher OUI walk to the IE length

In reply to Greg Kroah-Hartman

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

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

From: Doruk Tan Ozturk <[email protected]>

commit e667aee1c192d67d27c803007bfa9c6e0873e959 upstream.

mwifiex_search_oui_in_ie() reads a pairwise-cipher (PTK) count from a beacon/probe-response RSN or WPA information element and then walks that many 4-byte OUIs, comparing each with memcmp(). The count comes straight from the (attacker-supplied) IE and is never checked against the element's own length, and the callers admit the element on element_id alone (has_ieee_hdr() / has_vendor_hdr(), no length check). A crafted RSN/WPA IE with a large pairwise count therefore makes the walk read up to 255 * 4 bytes past the element -- an out-of-bounds read of the kmemdup()'d beacon buffer, reachable from any AP whose beacon/probe response is processed during scan-result parsing.

Pass the number of IE bytes available at the OUI list and bound the walk to the element. Keep the length signed and reject a negative value before any unsigned arithmetic, so a small or zero IE length cannot underflow to a large size_t and defeat the bound.

Found by 0sec automated security-research tooling (https://0sec.ai).

Fixes 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver")
Assisted-by 0sec:multi-model
---
 drivers/net/wireless/marvell/mwifiex/scan.c |   25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)
drivers/net/wireless/marvell/mwifiex/scan.c +22 -3
@@ -104,12 +104,24 @@ has_vendor_hdr(struct ieee_types_vendor_
  * a given oui in PTK.
  */
 static u8
-mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui)
+mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui, int ie_len)
 {
+	const size_t ptk_body_offset = offsetof(struct ie_body, ptk_body);
 	u8 count;
 
+	/* ie_len is the number of bytes available at iebody. Keep it signed
+	 * and reject a negative (underflowed) length before the unsigned
+	 * comparisons below, so a small or zero IE length cannot wrap.
+	 */
+	if (ie_len < 0 || (size_t)ie_len < ptk_body_offset)
+		return MWIFIEX_OUI_NOT_PRESENT;
+
 	count = iebody->ptk_cnt[0];
 
+	/* Reject an OUI count whose list would run past the element. */
+	if (ptk_body_offset + count * sizeof(iebody->ptk_body) > (size_t)ie_len)
+		return MWIFIEX_OUI_NOT_PRESENT;
+
 	/* There could be multiple OUIs for PTK hence
 	   1) Take the length.
 	   2) Check all the OUIs for AES.
@@ -143,11 +155,14 @@ mwifiex_is_rsn_oui_present(struct mwifie
 	u8 ret = MWIFIEX_OUI_NOT_PRESENT;
 
 	if (has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) {
+		int ie_len = (int)bss_desc->bcn_rsn_ie->ieee_hdr.len -
+			RSN_GTK_OUI_OFFSET;
+
 		iebody = (struct ie_body *)
 			 (((u8 *) bss_desc->bcn_rsn_ie->data) +
 			  RSN_GTK_OUI_OFFSET);
 		oui = &mwifiex_rsn_oui[cipher][0];
-		ret = mwifiex_search_oui_in_ie(iebody, oui);
+		ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len);
 		if (ret)
 			return ret;
 	}
@@ -169,10 +184,14 @@ mwifiex_is_wpa_oui_present(struct mwifie
 	u8 ret = MWIFIEX_OUI_NOT_PRESENT;
 
 	if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) {
+		int ie_len = (int)bss_desc->bcn_wpa_ie->vend_hdr.len -
+			(int)sizeof(bss_desc->bcn_wpa_ie->vend_hdr.oui) -
+			WPA_GTK_OUI_OFFSET;
+
 		iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data +
 					    WPA_GTK_OUI_OFFSET);
 		oui = &mwifiex_wpa_oui[cipher][0];
-		ret = mwifiex_search_oui_in_ie(iebody, oui);
+		ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len);
 		if (ret)
 			return ret;
 	}
author maintainer
#397 lore raw

PATCH 394/438 wifi: mwifiex: validate scan response extents

In reply to Greg Kroah-Hartman

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

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

From: Pengpeng Hou <[email protected]>

commit 3687d7d48070838cc2953431b3a27717cab0aaf6 upstream.

mwifiex_ret_802_11_scan() subtracts the fixed response fields and the firmware-provided BSS length from resp->size without first proving that either extent fits. A short response or oversized BSS length can therefore underflow tlv_buf_size and make the TLV parser walk beyond the command response.

Compute the fixed extent from the selected normal or background scan response. Validate that the fixed fields and BSS data fit before deriving the TLV extent and entering the parser.

Fixes 5e6e3a92b9a4 ("wireless: mwifiex: initial commit for Marvell mwifiex driver")
Assisted-by Codex:gpt-5
---
 drivers/net/wireless/marvell/mwifiex/scan.c |   29 ++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)
drivers/net/wireless/marvell/mwifiex/scan.c +19 -10
@@ -2115,6 +2115,7 @@ int mwifiex_ret_802_11_scan(struct mwifi
 	u32 bytes_left;
 	u32 idx;
 	u32 tlv_buf_size;
+	size_t fixed_size;
 	struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
 	struct chan_band_param_set *chan_band;
 	u8 is_bgscan_resp;
@@ -2130,6 +2131,14 @@ int mwifiex_ret_802_11_scan(struct mwifi
 	else
 		scan_rsp = &resp->params.scan_resp;
 
+	scan_resp_size = le16_to_cpu(resp->size);
+	fixed_size = scan_rsp->bss_desc_and_tlv_buffer - (u8 *)resp;
+	if (scan_resp_size < fixed_size) {
+		mwifiex_dbg(adapter, ERROR,
+			    "SCAN_RESP: response is too short\n");
+		ret = -1;
+		goto check_next_scan;
+	}
 
 	if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) {
 		mwifiex_dbg(adapter, ERROR,
@@ -2147,8 +2156,6 @@ int mwifiex_ret_802_11_scan(struct mwifi
 		    "info: SCAN_RESP: bss_descript_size %d\n",
 		    bytes_left);
 
-	scan_resp_size = le16_to_cpu(resp->size);
-
 	mwifiex_dbg(adapter, INFO,
 		    "info: SCAN_RESP: returned %d APs before parsing\n",
 		    scan_rsp->number_of_sets);
@@ -2156,15 +2163,17 @@ int mwifiex_ret_802_11_scan(struct mwifi
 	bss_info = scan_rsp->bss_desc_and_tlv_buffer;
 
 	/*
-	 * The size of the TLV buffer is equal to the entire command response
-	 *   size (scan_resp_size) minus the fixed fields (sizeof()'s), the
-	 *   BSS Descriptions (bss_descript_size as bytesLef) and the command
-	 *   response header (S_DS_GEN)
+	 * The TLV buffer follows the command-specific fixed fields and the BSS
+	 * descriptions. Background-scan responses have an additional fixed
+	 * field before scan_rsp, which is included in fixed_size.
 	 */
-	tlv_buf_size = scan_resp_size - (bytes_left
-					 + sizeof(scan_rsp->bss_descript_size)
-					 + sizeof(scan_rsp->number_of_sets)
-					 + S_DS_GEN);
+	if (bytes_left > scan_resp_size - fixed_size) {
+		mwifiex_dbg(adapter, ERROR,
+			    "SCAN_RESP: BSS data exceeds response\n");
+		ret = -1;
+		goto check_next_scan;
+	}
+	tlv_buf_size = scan_resp_size - fixed_size - bytes_left;
 
 	tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp->
 						 bss_desc_and_tlv_buffer +
author maintainer
#398 lore raw

PATCH 395/438 wifi: mwifiex: prevent authentication frame length truncation

In reply to Greg Kroah-Hartman

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

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

From: Linmao Li <[email protected]>

commit fa00193eb991f92b007aefe7afb6a7566976dacf upstream.

mwifiex_cfg80211_authenticate() derives the authentication frame length from req->ie_len and req->auth_data_len, both of type size_t, but stores it in a u16.

NL80211_ATTR_AUTH_DATA only has a minimum length policy. Since nla_len is a u16, a single attribute can carry up to 65531 bytes of payload, so the sum can exceed U16_MAX before it is assigned to pkt_len. The truncated pkt_len determines the skb frame area, while the copy length remains req->auth_data_len - 4, resulting in a heap buffer overflow.

For example, with auth_data_len equal to 65510 and no IEs, the sum is 65546. It is truncated to 10 and then reduced by four to 6. The driver appends only six bytes to the skb with skb_put(), but then copies 65506 user-provided bytes into the authentication body.

Reaching this path requires CAP_NET_ADMIN in the user namespace owning the network namespace, an up station netdev, and a suitable BSS/SAE authentication request.

Compute the length in size_t, reject values that cannot be represented by the firmware's u16 frame length field, and only then assign it to pkt_len.

Fixes 36995892c271 ("wifi: mwifiex: add host mlme for client mode")
---
 drivers/net/wireless/marvell/mwifiex/cfg80211.c |   12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/net/wireless/marvell/mwifiex/cfg80211.c +10 -2
@@ -4279,6 +4279,7 @@ mwifiex_cfg80211_authenticate(struct wip
 	struct mwifiex_adapter *adapter = priv->adapter;
 	struct sk_buff *skb;
 	u16 pkt_len, auth_alg;
+	size_t frame_len;
 	int ret;
 	struct mwifiex_ieee80211_mgmt *mgmt;
 	struct mwifiex_txinfo *tx_info;
@@ -4351,10 +4352,17 @@ mwifiex_cfg80211_authenticate(struct wip
 
 	mwifiex_cancel_scan(adapter);
 
-	pkt_len = (u16)req->ie_len + req->auth_data_len +
+	frame_len = req->ie_len + req->auth_data_len +
 		MWIFIEX_MGMT_HEADER_LEN + MWIFIEX_AUTH_BODY_LEN;
 	if (req->auth_data_len >= 4)
-		pkt_len -= 4;
+		frame_len -= 4;
+
+	if (frame_len > U16_MAX) {
+		mwifiex_dbg(priv->adapter, ERROR,
+			    "auth frame too long: %zu bytes\n", frame_len);
+		return -EINVAL;
+	}
+	pkt_len = frame_len;
 
 	skb = dev_alloc_skb(MWIFIEX_MIN_DATA_HEADER_LEN +
 			    MWIFIEX_MGMT_FRAME_HEADER_SIZE +
author maintainer
#399 lore raw

PATCH 396/438 wifi: mwifiex: validate action frame fixed fields

In reply to Greg Kroah-Hartman

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

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

From: Zhao Li <[email protected]>

commit 1c25bfad93e69ce13f744a2fb919f02ea396a985 upstream.

mwifiex_process_mgmt_packet() accepts an rx_pkt_length as small as a four-address struct ieee80211_hdr plus the two-byte firmware length prefix. After stripping the prefix, mwifiex_parse_mgmt_packet() can receive a frame equal to sizeof(struct ieee80211_hdr).

For action frames, the parser reads the category byte immediately after that header and, for a public action frame, reads the following action code byte without verifying that either field is present. A truncated frame can therefore make the parser consume up to two bytes past the firmware-declared frame length. If those bytes look like a TDLS discovery response, the malformed frame can spuriously update peer signal state.

Require the category and public action-code fields before reading them. Use sizeof(*ieee_hdr) so the checks and field accesses directly match the firmware four-address layout being parsed before address4 is removed.

---
 drivers/net/wireless/marvell/mwifiex/util.c |   10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/wireless/marvell/mwifiex/util.c +8 -2
@@ -317,10 +317,16 @@ mwifiex_parse_mgmt_packet(struct mwifiex
 
 	switch (stype) {
 	case IEEE80211_STYPE_ACTION:
-		category = *(payload + sizeof(struct ieee80211_hdr));
+		if (len < sizeof(*ieee_hdr) + 1)
+			return -1;
+
+		category = *(payload + sizeof(*ieee_hdr));
 		switch (category) {
 		case WLAN_CATEGORY_PUBLIC:
-			action_code = *(payload + sizeof(struct ieee80211_hdr)
+			if (len < sizeof(*ieee_hdr) + 2)
+				return -1;
+
+			action_code = *(payload + sizeof(*ieee_hdr)
 					+ 1);
 			if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
 				addr2 = ieee_hdr->addr2;
author maintainer
#400 lore raw

PATCH 397/438 wifi: mac80211: avoid WARN in set_bitrate_mask when sdata not in driver

In reply to Greg Kroah-Hartman

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

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

From: Rik van Riel <[email protected]>

commit da2ca406f45a6e21760243152ed8d2e8e72915c2 upstream.

ieee80211_set_bitrate_mask() checks if the interface is running via ieee80211_sdata_running(), but it does not check if the interface is still present in the driver.

When sdata is running but IEEE80211_SDATA_IN_DRIVER is not set, the call reaches drv_set_bitrate_mask() in driver-ops.h which hits

wlan1: Failed check-sdata-in-driver check, flags: 0x0

  WARNING: net/mac80211/driver-ops.h:884 at drv_set_bitrate_mask

Syzkaller triggers this via wext SIOCSIWRATE ioctl. The Call Trace shows wext_ioctl_dispatch() in wext-core.c dispatching the ioctl, calling ioctl_standard_call() for SIOCSIWRATE, which calls cfg80211_wext_siwrate() in wext-compat.c. That builds a bitrate mask and calls rdev_set_bitrate_mask() which ends up in ieee80211_set_bitrate_mask() in cfg.c. The interface is marked running via SDATA_STATE_RUNNING but flags is 0, so check_sdata_in_driver() fails.

When the interface is being torn down, or when wext ioctl is issued during interface bringup before drv_add_interface() sets IN_DRIVER, the running check passes while IN_DRIVER is clear.

Check IEEE80211_SDATA_IN_DRIVER in ieee80211_set_bitrate_mask() before calling the driver, returning -ENETDOWN. This avoids the WARN_ONCE in driver-ops.h and matches other cfg.c operations that bail early when not in driver.

This change should be safe because wiphy mutex is held in cfg80211_wext_siwrate() via guard(wiphy), and IN_DRIVER is set/cleared under RTNL and wiphy paths in drv_add_interface() and drv_remove_interface() in driver-ops.c, so the check is race-free against driver add/remove. Returning -ENETDOWN is the same error other not-running paths use and does not introduce new locking.

---
 net/mac80211/cfg.c |    3 +++
 1 file changed, 3 insertions(+)
net/mac80211/cfg.c +3 -0
@@ -4120,6 +4120,9 @@ static int ieee80211_set_bitrate_mask(st
 	if (!ieee80211_sdata_running(sdata))
 		return -ENETDOWN;
 
+	if (!(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+		return -ENETDOWN;
+
 	/*
 	 * If active validate the setting and reject it if it doesn't leave
 	 * at least one basic rate usable, since we really have to be able
author maintainer
#401 lore raw

PATCH 398/438 wifi: mac80211: avoid out-of-bounds read for empty PREQ elements

In reply to Greg Kroah-Hartman

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

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

From: Ivan Pustogarov <[email protected]>

commit e6031f02269c0f51cf67886d177f02bc300b47cd upstream.

ieee80211_mesh_preq_size_ok() derives the location of the PREQ bottom fields before checking whether the element contains even the fixed header. ieee80211_mesh_hwmp_preq_get_bottom() reads the flags byte to account for the optional Address Extension field. Consequently, an empty PREQ element causes a one-byte read beyond its declared payload.

Move the helper call after both size checks, so the bottom fields are only accessed when they are present.

Fixes 8b40b1d24a60 ("wifi: mac80211: Fix overread in PREQ frame processing")
---
 include/linux/ieee80211-mesh.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
include/linux/ieee80211-mesh.h +2 -2
index 7eb15834531c..9e548b9173df 100644
@@ -361,8 +361,7 @@ ieee80211_mesh_hwmp_perr_get_rcode(const u8 *ie, u8 dst_idx)
 /* IEEE Std 802.11-2016 9.4.2.113 PREQ element */
 static inline bool ieee80211_mesh_preq_size_ok(const u8 *pos, u8 elen)
 {
-	struct ieee80211_mesh_hwmp_preq_bottom *preq_elem_bottom =
-		ieee80211_mesh_hwmp_preq_get_bottom(pos);
+	struct ieee80211_mesh_hwmp_preq_bottom *preq_elem_bottom;
 	u8 target_count;
 	int needed;
 
@@ -378,6 +377,7 @@ static inline bool ieee80211_mesh_preq_size_ok(const u8 *pos, u8 elen)
 	if (elen < needed)
 		return false;
 
+	preq_elem_bottom = ieee80211_mesh_hwmp_preq_get_bottom(pos);
 	target_count = preq_elem_bottom->target_count;
 	/* IEEE Std 802.11-2016 Table 14-10 to 14-16 */
 	if (target_count < 1)
Signature · 1 line
2.55.0
author maintainer
#402 lore raw

PATCH 399/438 wifi: mac80211: refuse to make a monitor active when it has no queue

In reply to Greg Kroah-Hartman

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

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

From: Devin Wittmayer <[email protected]>

commit 2b04d6556964ae9f89819b86a0a7801e39c3aae5 upstream.

A monitor interface only gets a TXQ if it's created active, and one can't be added later. Setting the flag on a down interface is still allowed, so the driver is handed a monitor with no queue. ath9k dereferences it:

  BUG: kernel NULL pointer dereference, address: 0000000000000066
  RIP: 0010:ath_tx_node_init+0x49/0x170 [ath9k]
   ath9k_add_interface+0x10c/0x140 [ath9k]
   drv_add_interface+0x54/0x250 [mac80211]
   ieee80211_do_open+0x32f/0x800 [mac80211]

Reached with CAP_NET_ADMIN by "iw dev X set monitor active" followed by "ip link set X up". RTNL is held, so netlink operations block behind it.

Refuse the flag when there is no queue to give.

Fixes 79af1f866193 ("mac80211: avoid allocating TXQs that won't be used")
---
 net/mac80211/cfg.c |    4 ++++
 1 file changed, 4 insertions(+)
net/mac80211/cfg.c +4 -0
@@ -115,6 +115,10 @@ static int ieee80211_set_mon_options(str
 			return -EBUSY;
 	}
 
+	/* TXQs are reserved in ieee80211_if_add() and cannot be added later */
+	if ((params->flags & MONITOR_FLAG_ACTIVE) && !sdata->vif.txq)
+		return -EOPNOTSUPP;
+
 	/* validate whether MU-MIMO can be configured */
 	if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
 	    !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
author maintainer
#403 lore raw

PATCH 400/438 drm/gud: fix out-of-bounds write in gud_plane_atomic_check()

In reply to Greg Kroah-Hartman

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

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

From: Sajal Gupta <[email protected]>

commit 59ced288fcba9e91bd38e61a972ad782c4edb7d0 upstream.

The plane property loop uses req->properties[num_properties + i] as write index while simultaneously incrementing num_properties inside the loop. At iteration i, num_properties has also incremented by i, so the write is done at initial_num_properties + 2*i, skipping every other index and advancing by 2 per iteration.

With just 2 connector and 32 plane properties the last write happens at index 64, one slot past the end of the 64-slot (indices 0–63) allocation. A USB device can trigger OOB by advertising the maximum number of properties.

Fix by dropping the redundant + i; num_properties is already the correct running index, as gud_connector_fill_properties() fills the preceding slots.

---
 drivers/gpu/drm/gud/gud_pipe.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/gud/gud_pipe.c +2 -2
@@ -562,8 +562,8 @@ int gud_plane_atomic_check(struct drm_pl
 			goto out;
 		}
 
-		req->properties[num_properties + i].prop = cpu_to_le16(prop);
-		req->properties[num_properties + i].val = cpu_to_le64(val);
+		req->properties[num_properties].prop = cpu_to_le16(prop);
+		req->properties[num_properties].val = cpu_to_le64(val);
 		num_properties++;
 	}
 
author maintainer
#404 lore raw

PATCH 401/438 drm/gud: Ignore damage clips in full update mode

In reply to Greg Kroah-Hartman

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

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

From: Sophie D <[email protected]>

commit effce1cb87ee0d8b3a8cbe7722968f4ea7efd360 upstream.

When running in full update mode, previously small updates (such as moving the mouse across the screen) would cause many full frames to be generated. This would bog down the bus and lower the effective framerate significantly - I was seeing a drop from 60 FPS to 2 FPS.

Set ignore_damage_clips in full update mode so the damage iterator yields a single full-plane rectangle instead of one per clip.

Fixes 73cfd166e045 ("drm/gud: Replace simple display pipe with DRM atomic helpers")
Cc <[email protected]> # 6.18.x
---
 drivers/gpu/drm/gud/gud_pipe.c |    3 +++
 1 file changed, 3 insertions(+)
drivers/gpu/drm/gud/gud_pipe.c +3 -0
@@ -482,6 +482,9 @@ int gud_plane_atomic_check(struct drm_pl
 	if (!new_plane_state->visible)
 		return 0;
 
+	if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE)
+		new_plane_state->ignore_damage_clips = true;
+
 	if (old_plane_state->rotation != new_plane_state->rotation)
 		crtc_state->mode_changed = true;
 
author maintainer
#405 lore raw

PATCH 402/438 drm/msm/adreno: fix autosuspend cleanup during teardown

In reply to Greg Kroah-Hartman

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

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

From: Guangshuo Li <[email protected]>

commit 6fbbf1e152f34ad3913e4a6476680aba672c5068 upstream.

adreno_gpu_init() calls pm_runtime_use_autosuspend(), but adreno_gpu_cleanup() does not call the matching pm_runtime_dont_use_autosuspend() during teardown.

If the autosuspend delay is set to a negative value while autosuspend is enabled, the runtime PM core increments usage_count to prevent runtime suspend. Without calling pm_runtime_dont_use_autosuspend() during teardown, this reference is not dropped and usage_count remains unbalanced.

The documentation for pm_runtime_use_autosuspend() also notes that it is important to undo it with pm_runtime_dont_use_autosuspend() at driver exit time, unless runtime PM was initially enabled with devm_pm_runtime_enable().

Add the missing pm_runtime_dont_use_autosuspend() call to adreno_gpu_cleanup().

This issue was found by manual code inspection.

Fixes eeb754746b14 ("drm/msm/gpu: use pm-runtime")

Patchwork: https://patchwork.freedesktop.org/patch/745110/

---
 drivers/gpu/drm/msm/adreno/adreno_gpu.c |    2 ++
 1 file changed, 2 insertions(+)
drivers/gpu/drm/msm/adreno/adreno_gpu.c +2 -0
@@ -1252,6 +1252,8 @@ void adreno_gpu_cleanup(struct adreno_gp
 	for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++)
 		release_firmware(adreno_gpu->fw[i]);
 
+	pm_runtime_dont_use_autosuspend(&gpu->pdev->dev);
+
 	if (priv && pm_runtime_enabled(&priv->gpu_pdev->dev))
 		pm_runtime_disable(&priv->gpu_pdev->dev);
 
author maintainer
#406 lore raw

PATCH 403/438 drm/msm/dpu: clear pending peripheral flush state

In reply to Greg Kroah-Hartman

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

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

From: Saim Shujah <[email protected]>

commit a5b5cc909931572aec446e129c035b76b3f0c1fa upstream.

dpu_hw_ctl_clear_pending_flush() resets the cached per-block state after a flush transaction, but misses pending_periph_flush_mask.

The peripheral flush updater accumulates interface bits in this mask. A later transaction which sets the top-level peripheral flush bit can write stale interface bits to CTL_PERIPH_FLUSH together with the current state.

Peripheral flush support was added after the helper started clearing every individual pending flush mask. Clear the peripheral mask together with the other cached child masks.

Fixes 64f7b81f0358 ("drm/msm/dpu: add support of new peripheral flush mechanism")

Patchwork: https://patchwork.freedesktop.org/patch/748968/

---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c |    1 +
 1 file changed, 1 insertion(+)
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +1 -0
@@ -118,6 +118,7 @@ static inline void dpu_hw_ctl_clear_pend
 	ctx->pending_intf_flush_mask = 0;
 	ctx->pending_wb_flush_mask = 0;
 	ctx->pending_cwb_flush_mask = 0;
+	ctx->pending_periph_flush_mask = 0;
 	ctx->pending_merge_3d_flush_mask = 0;
 	ctx->pending_dsc_flush_mask = 0;
 	ctx->pending_cdm_flush_mask = 0;