* [PATCH 6.12 01/77] PCI: host-generic: Fix NULL pointer dereference on 32-bit CAM systems
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 02/77] Bluetooth: RFCOMM: take rfcomm_mutex for the deferred setup accept Greg Kroah-Hartman
` (83 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Steffen Persvold,
Manivannan Sadhasivam
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steffen Persvold <spersvold@gmail.com>
commit 008cb88edb41f3c7c8e0ed763ff9f26719830984 upstream.
On 32-bit systems the config space is too large to ioremap in one go, so
pci_ecam_create() maps each bus segment separately and relies on the
->add_bus callback (pci_ecam_add_bus) to populate the per-bus mapping in
cfg->winp[]. pci_ecam_map_bus() then uses that mapping as the base for
every config access.
The generic ECAM ops (pci_generic_ecam_ops) already provide the ->add_bus
and ->remove_bus callbacks, but the CAM (legacy) ops in pci-host-generic.c
do not. As a result, on a 32-bit host using "pci-host-cam-generic" the
per-bus mapping is never set up and the first config read dereferences a
NULL base, crashing during bus enumeration:
Unable to handle kernel NULL pointer dereference at virtual address 00000800
Oops [#1]
CPU: 0 PID: 1 Comm: swapper Not tainted 6.9.7+ #43
Hardware name: Digilent Nexys-Video-A7 RV32 (DT)
epc : pci_generic_config_read+0x40/0xb0
ra : pci_generic_config_read+0x2c/0xb0
[<c038db9c>] pci_generic_config_read+0x40/0xb0
[<c038da04>] pci_bus_read_config_dword+0x50/0xb0
[<c0391e94>] pci_bus_generic_read_dev_vendor_id+0x3c/0x1ec
[<c039245c>] pci_scan_single_device+0xa4/0x11c
[<c0392570>] pci_scan_slot+0x9c/0x23c
[<c039388c>] pci_scan_child_bus_extend+0x58/0x2f4
[<c0393db0>] pci_scan_root_bus_bridge+0x64/0xe8
[<c0393e54>] pci_host_probe+0x20/0xc8
[<c03bc6f4>] pci_host_common_probe+0x144/0x1e4
Fix this by giving the CAM ops the same ->add_bus/->remove_bus callbacks.
Since pci_ecam_add_bus() and pci_ecam_remove_bus() are static to ecam.c,
move the CAM ops definition there as pci_generic_cam_ops (mirroring
pci_generic_ecam_ops) and export it for pci-host-generic.c to reference.
Fixes: 8fe55ef23387 ("PCI: Dynamically map ECAM regions")
Signed-off-by: Steffen Persvold <spersvold@gmail.com>
[mani: removed timestamp from log]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260709122446.3151899-1-spersvold@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/pci/controller/pci-host-generic.c | 11 +----------
drivers/pci/ecam.c | 13 +++++++++++++
include/linux/pci-ecam.h | 3 +++
3 files changed, 17 insertions(+), 10 deletions(-)
--- a/drivers/pci/controller/pci-host-generic.c
+++ b/drivers/pci/controller/pci-host-generic.c
@@ -14,15 +14,6 @@
#include <linux/pci-ecam.h>
#include <linux/platform_device.h>
-static const struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
- .bus_shift = 16,
- .pci_ops = {
- .map_bus = pci_ecam_map_bus,
- .read = pci_generic_config_read,
- .write = pci_generic_config_write,
- }
-};
-
static bool pci_dw_valid_device(struct pci_bus *bus, unsigned int devfn)
{
struct pci_config_window *cfg = bus->sysdata;
@@ -58,7 +49,7 @@ static const struct pci_ecam_ops pci_dw_
static const struct of_device_id gen_pci_of_match[] = {
{ .compatible = "pci-host-cam-generic",
- .data = &gen_pci_cfg_cam_bus_ops },
+ .data = &pci_generic_cam_ops },
{ .compatible = "pci-host-ecam-generic",
.data = &pci_generic_ecam_ops },
--- a/drivers/pci/ecam.c
+++ b/drivers/pci/ecam.c
@@ -208,6 +208,19 @@ const struct pci_ecam_ops pci_generic_ec
};
EXPORT_SYMBOL_GPL(pci_generic_ecam_ops);
+/* CAM ops */
+const struct pci_ecam_ops pci_generic_cam_ops = {
+ .bus_shift = 16,
+ .pci_ops = {
+ .add_bus = pci_ecam_add_bus,
+ .remove_bus = pci_ecam_remove_bus,
+ .map_bus = pci_ecam_map_bus,
+ .read = pci_generic_config_read,
+ .write = pci_generic_config_write,
+ }
+};
+EXPORT_SYMBOL_GPL(pci_generic_cam_ops);
+
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
/* ECAM ops for 32-bit access only (non-compliant) */
const struct pci_ecam_ops pci_32b_ops = {
--- a/include/linux/pci-ecam.h
+++ b/include/linux/pci-ecam.h
@@ -77,6 +77,9 @@ void __iomem *pci_ecam_map_bus(struct pc
/* default ECAM ops */
extern const struct pci_ecam_ops pci_generic_ecam_ops;
+/* default CAM ops */
+extern const struct pci_ecam_ops pci_generic_cam_ops;
+
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
extern const struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */
extern const struct pci_ecam_ops pci_32b_read_ops; /* 32-bit read only */
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 02/77] Bluetooth: RFCOMM: take rfcomm_mutex for the deferred setup accept
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 01/77] PCI: host-generic: Fix NULL pointer dereference on 32-bit CAM systems Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 03/77] ALSA: scarlett2: Use a private URB for the notification endpoint Greg Kroah-Hartman
` (82 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Ali Ahmet Memis,
Luiz Augusto von Dentz
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <ali@iusegentoo.com>
commit 43a556b2fd43f2df6dded59c2e26560a27874c24 upstream.
rfcomm_sock_recvmsg() completes a deferred setup by calling
rfcomm_dlc_accept() without holding any RFCOMM lock:
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
rfcomm_dlc_accept(d);
return 0;
}
and rfcomm_dlc_accept() dereferences the session on its first line:
struct sock *sk = d->session->sock->sk;
Every other path that touches d->session runs under rfcomm_mutex:
rfcomm_dlc_open(), rfcomm_dlc_close(), rfcomm_dlc_exists(),
rfcomm_dlc_send_rpn(), and the RFCOMM thread through
rfcomm_process_sessions(). rfcomm_connect_ind() is even documented as
"called under rfcomm_lock()". This call site is the only one that skips
it.
The RFCOMM_DEFER_SETUP bit looks like it serialises the accept against
teardown, since __rfcomm_dlc_close() returns early when it wins the
test_and_clear. But rfcomm_recv_disc() forces the state first:
d->state = BT_CLOSED;
__rfcomm_dlc_close(d, err);
and the early return only covers BT_CONNECT, BT_CONFIG, BT_OPEN and
BT_CONNECT2. With the state already BT_CLOSED that switch does not
match, the bit is never consulted, and __rfcomm_dlc_close() falls
through to rfcomm_dlc_unlink(), which sets d->session = NULL.
So a remote DISC on a deferred dlc clears the session while leaving
RFCOMM_DEFER_SETUP set. The next recvmsg() then passes the
test_and_clear and dereferences a NULL session. No timing window is
needed: once the DISC has been processed, the dereference is
unconditional.
Give rfcomm_dlc_accept() the same shape as rfcomm_dlc_open() and
rfcomm_dlc_close(): an exported wrapper that takes rfcomm_mutex and
re-checks the session, around a __rfcomm_dlc_accept() that the two
in-core callers, which already hold the mutex, keep using.
Reproduced on a KASAN + PROVE_LOCKING kernel with a BR/EDR peer emulated
over /dev/vhci: the peer brings up an ACL link, opens L2CAP on the
RFCOMM PSM, starts a session, opens a dlc on a channel bound with
BT_DEFER_SETUP, and sends DISC after the socket is accepted. recv() on
the accepted socket then hits:
Oops: general protection fault
KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
RIP: 0010:rfcomm_dlc_accept+0x54/0x350
Call Trace:
rfcomm_sock_recvmsg+0x1cd/0x230
sock_recvmsg+0x166/0x1c0
__sys_recvfrom+0x20d/0x300
0x10 is the offset of sock in struct rfcomm_session. With this patch the
same run completes with recv() returning 0 and no report, and lockdep
stays quiet, confirming rfcomm_mutex is still taken before lock_sock on
this path as it is on the thread side.
Fixes: bb23c0ab8246 ("Bluetooth: Add support for deferring RFCOMM connection setup")
Cc: stable@vger.kernel.org
Signed-off-by: Ali Ahmet Memis <ali@iusegentoo.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/bluetooth/rfcomm/core.c | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1334,7 +1334,10 @@ static struct rfcomm_session *rfcomm_rec
return s;
}
-void rfcomm_dlc_accept(struct rfcomm_dlc *d)
+/* Must be called with rfcomm_mutex held, so that the session cannot be
+ * unlinked from under us.
+ */
+static void __rfcomm_dlc_accept(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
@@ -1356,6 +1359,21 @@ void rfcomm_dlc_accept(struct rfcomm_dlc
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
}
+void rfcomm_dlc_accept(struct rfcomm_dlc *d)
+{
+ rfcomm_lock();
+
+ /* rfcomm_recv_disc() sets the dlc state to BT_CLOSED before calling
+ * __rfcomm_dlc_close(), so the RFCOMM_DEFER_SETUP handshake there is
+ * skipped and the session can already be unlinked by the time the
+ * deferred accept runs from rfcomm_sock_recvmsg().
+ */
+ if (d->session)
+ __rfcomm_dlc_accept(d);
+
+ rfcomm_unlock();
+}
+
static void rfcomm_check_accept(struct rfcomm_dlc *d)
{
if (rfcomm_check_security(d)) {
@@ -1368,7 +1386,7 @@ static void rfcomm_check_accept(struct r
d->state_change(d, 0);
rfcomm_dlc_unlock(d);
} else
- rfcomm_dlc_accept(d);
+ __rfcomm_dlc_accept(d);
} else {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
@@ -1953,7 +1971,7 @@ static void rfcomm_process_dlcs(struct r
d->state_change(d, 0);
rfcomm_dlc_unlock(d);
} else
- rfcomm_dlc_accept(d);
+ __rfcomm_dlc_accept(d);
}
continue;
} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 03/77] ALSA: scarlett2: Use a private URB for the notification endpoint
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 01/77] PCI: host-generic: Fix NULL pointer dereference on 32-bit CAM systems Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 02/77] Bluetooth: RFCOMM: take rfcomm_mutex for the deferred setup accept Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 04/77] rndis_host: add overflow check in rndis_rx_fixup() Greg Kroah-Hartman
` (81 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Geoffrey D. Bennett, Takashi Iwai
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geoffrey D. Bennett <g@b4.vu>
commit cd17d6ff7b7d2b1dd9bcc80ae7b4a83773f918c6 upstream.
scarlett2_init_notify() used mixer->urb, which
snd_usb_mixer_status_create() allocates for the UAC2 status interrupt
endpoint and mixer.c manages. On a device with that endpoint, the
"already in use" check fires on the status URB and returns 0 for
success without doing anything. No notification URB is submitted, and
cmd_done is left zeroed because it is initialised past that check and
nowhere else. scarlett2_usb_init() then issues SCARLETT2_USB_INIT_1
and wait_for_completion_timeout() would crash adding to the zeroed
wait.head.
Use a separate URB in scarlett2_data, as done for FCP, and initialise
cmd_done in scarlett2_init_private(). mixer.c was also freeing the URB
in snd_usb_mixer_free() and resubmitting it in
snd_usb_mixer_activate(), so scarlett2 must now do both: add
scarlett2_cleanup_urb(), called from private_free and private_suspend,
and a private_resume callback to re-establish the URB after resume.
scarlett2_init_notify() is reached from there, and the URB kill path
in scarlett2_notify() completes cmd_done, leaving a stale count that
would satisfy the next command's wait before the device ACKs. Use
reinit_completion() to clear it.
Also free the URB if the transfer buffer allocation fails, and both if
usb_submit_urb() fails. Move scarlett2_init_notify() up next to
scarlett2_cleanup_urb() so scarlett2_init_private() can reference it
without a forward declaration.
Fixes: 1b65088958ca ("ALSA: scarlett2: Implement handling of the ACK notification")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-5
Signed-off-by: Geoffrey D. Bennett <g@b4.vu>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/ffb8ba37d5d605dfdfd8576949d67098651f9349.1786290885.git.g@b4.vu
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
sound/usb/mixer.c | 6 ++
sound/usb/mixer.h | 2
sound/usb/mixer_scarlett2.c | 98 ++++++++++++++++++++++++++++----------------
3 files changed, 71 insertions(+), 35 deletions(-)
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -3736,6 +3736,12 @@ int snd_usb_mixer_resume(struct usb_mixe
struct usb_mixer_elem_list *list;
int id, err;
+ if (mixer->private_resume) {
+ err = mixer->private_resume(mixer);
+ if (err < 0)
+ return err;
+ }
+
/* restore cached mixer values */
for (id = 0; id < MAX_ID_ELEMS; id++) {
for_each_mixer_elem(list, mixer, id) {
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -18,6 +18,7 @@ struct usb_mixer_interface {
struct usb_host_interface *hostif;
struct list_head list;
unsigned int ignore_ctl_error;
+ /* UAC2 status interrupt endpoint; owned by mixer.c */
struct urb *urb;
/* array[MAX_ID_ELEMS], indexed by unit id */
struct usb_mixer_elem_list **id_elems;
@@ -42,6 +43,7 @@ struct usb_mixer_interface {
void *private_data;
void (*private_free)(struct usb_mixer_interface *mixer);
void (*private_suspend)(struct usb_mixer_interface *mixer);
+ int (*private_resume)(struct usb_mixer_interface *mixer);
};
#define MAX_CHANNELS 16 /* max logical channels */
--- a/sound/usb/mixer_scarlett2.c
+++ b/sound/usb/mixer_scarlett2.c
@@ -1259,6 +1259,7 @@ struct scarlett2_data {
struct usb_mixer_interface *mixer;
struct mutex usb_mutex; /* prevent sending concurrent USB requests */
struct completion cmd_done;
+ struct urb *urb; /* notification endpoint */
struct mutex data_mutex; /* lock access to this data */
u8 running;
u8 hwdep_in_use;
@@ -8641,13 +8642,70 @@ requeue:
}
}
-/*** Cleanup/Suspend Callbacks ***/
+/*** Notification URB and Cleanup/Suspend Callbacks ***/
+
+/* Submit a URB to receive notifications from the device */
+static int scarlett2_init_notify(struct usb_mixer_interface *mixer)
+{
+ struct usb_device *dev = mixer->chip->dev;
+ struct scarlett2_data *private = mixer->private_data;
+ unsigned int pipe = usb_rcvintpipe(dev, private->bEndpointAddress);
+ void *transfer_buffer;
+ int err;
+
+ /* Already set up */
+ if (private->urb)
+ return 0;
+
+ if (usb_pipe_type_check(dev, pipe))
+ return -EINVAL;
+
+ private->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!private->urb)
+ return -ENOMEM;
+
+ transfer_buffer = kmalloc(private->wMaxPacketSize, GFP_KERNEL);
+ if (!transfer_buffer) {
+ usb_free_urb(private->urb);
+ private->urb = NULL;
+ return -ENOMEM;
+ }
+
+ usb_fill_int_urb(private->urb, dev, pipe,
+ transfer_buffer, private->wMaxPacketSize,
+ scarlett2_notify, mixer, private->bInterval);
+
+ reinit_completion(&private->cmd_done);
+
+ err = usb_submit_urb(private->urb, GFP_KERNEL);
+ if (err) {
+ kfree(transfer_buffer);
+ usb_free_urb(private->urb);
+ private->urb = NULL;
+ }
+
+ return err;
+}
+
+static void scarlett2_cleanup_urb(struct usb_mixer_interface *mixer)
+{
+ struct scarlett2_data *private = mixer->private_data;
+
+ if (!private->urb)
+ return;
+
+ usb_kill_urb(private->urb);
+ kfree(private->urb->transfer_buffer);
+ usb_free_urb(private->urb);
+ private->urb = NULL;
+}
static void scarlett2_private_free(struct usb_mixer_interface *mixer)
{
struct scarlett2_data *private = mixer->private_data;
cancel_delayed_work_sync(&private->work);
+ scarlett2_cleanup_urb(mixer);
kfree(private);
mixer->private_data = NULL;
}
@@ -8658,6 +8716,8 @@ static void scarlett2_private_suspend(st
if (cancel_delayed_work_sync(&private->work))
scarlett2_config_save(private->mixer);
+
+ scarlett2_cleanup_urb(mixer);
}
/*** Initialisation ***/
@@ -8778,11 +8838,13 @@ static int scarlett2_init_private(struct
mutex_init(&private->usb_mutex);
mutex_init(&private->data_mutex);
+ init_completion(&private->cmd_done);
INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work);
mixer->private_data = private;
mixer->private_free = scarlett2_private_free;
mixer->private_suspend = scarlett2_private_suspend;
+ mixer->private_resume = scarlett2_init_notify;
private->info = entry->info;
@@ -8799,40 +8861,6 @@ static int scarlett2_init_private(struct
return scarlett2_find_fc_interface(mixer->chip->dev, private);
}
-/* Submit a URB to receive notifications from the device */
-static int scarlett2_init_notify(struct usb_mixer_interface *mixer)
-{
- struct usb_device *dev = mixer->chip->dev;
- struct scarlett2_data *private = mixer->private_data;
- unsigned int pipe = usb_rcvintpipe(dev, private->bEndpointAddress);
- void *transfer_buffer;
-
- if (mixer->urb) {
- usb_audio_err(mixer->chip,
- "%s: mixer urb already in use!\n", __func__);
- return 0;
- }
-
- if (usb_pipe_type_check(dev, pipe))
- return -EINVAL;
-
- mixer->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!mixer->urb)
- return -ENOMEM;
-
- transfer_buffer = kmalloc(private->wMaxPacketSize, GFP_KERNEL);
- if (!transfer_buffer)
- return -ENOMEM;
-
- usb_fill_int_urb(mixer->urb, dev, pipe,
- transfer_buffer, private->wMaxPacketSize,
- scarlett2_notify, mixer, private->bInterval);
-
- init_completion(&private->cmd_done);
-
- return usb_submit_urb(mixer->urb, GFP_KERNEL);
-}
-
/* Cargo cult proprietary initialisation sequence */
static int scarlett2_usb_init(struct usb_mixer_interface *mixer)
{
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 04/77] rndis_host: add overflow check in rndis_rx_fixup()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (2 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 03/77] ALSA: scarlett2: Use a private URB for the notification endpoint Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 05/77] gpio: ml-ioh: use raw_spinlock_t for the register lock Greg Kroah-Hartman
` (80 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Andrew Lunn, Shaoxu Liu,
Griffin Kroah-Hartman, Simon Horman, Jakub Kicinski
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Griffin Kroah-Hartman <griffin@kroah.com>
commit 965a251f23ff69cfb4486974d4532e9bb551c7fc upstream.
Add an overflow check to ensure that data_offset + data_len + 8 does not
wrap, which would enable an OOB read of the USB data buffer.
Cc: Andrew Lunn <andrew+netdev@lunn.ch>
Cc: Shaoxu Liu <shaoxul@foxmail.com>
Signed-off-by: Griffin Kroah-Hartman <griffin@kroah.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/2026070900-denim-brook-52d4@gregkh
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/usb/rndis_host.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -14,6 +14,7 @@
#include <linux/usb/cdc.h>
#include <linux/usb/usbnet.h>
#include <linux/usb/rndis_host.h>
+#include <linux/overflow.h>
/*
@@ -506,6 +507,7 @@ int rndis_rx_fixup(struct usbnet *dev, s
struct rndis_data_hdr *hdr = (void *)skb->data;
struct sk_buff *skb2;
u32 msg_type, msg_len, data_offset, data_len;
+ u32 overflow_check;
msg_type = le32_to_cpu(hdr->msg_type);
msg_len = le32_to_cpu(hdr->msg_len);
@@ -514,7 +516,9 @@ int rndis_rx_fixup(struct usbnet *dev, s
/* don't choke if we see oob, per-packet data, etc */
if (unlikely(msg_type != RNDIS_MSG_PACKET || skb->len < msg_len
- || (data_offset + data_len + 8) > msg_len)) {
+ || (data_offset + data_len + 8) > msg_len
+ || check_add_overflow(data_offset, data_len, &overflow_check)
+ || check_add_overflow(overflow_check, 8, &overflow_check))) {
dev->net->stats.rx_frame_errors++;
netdev_dbg(dev->net, "bad rndis message %d/%d/%d/%d, len %d\n",
le32_to_cpu(hdr->msg_type),
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 05/77] gpio: ml-ioh: use raw_spinlock_t for the register lock
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (3 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 04/77] rndis_host: add overflow check in rndis_rx_fixup() Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 06/77] gve: fix zero-length skb frag with header-split Greg Kroah-Hartman
` (79 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Linus Walleij, Junjie Cao
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junjie Cao <junjie.cao@intel.com>
commit 600411ea1f2443fdf5b1af9b6480f616d7aff9d0 upstream.
ioh_irq_type() is registered as the irq_chip .irq_set_type callback and
takes chip->spinlock with spin_lock_irqsave(). This callback is reached
from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while
the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled.
That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is
an rtmutex-backed sleeping lock, so acquiring it there is invalid.
ioh_irq_enable() and ioh_irq_disable() take the same lock from the
.irq_enable/.irq_disable callbacks, which are likewise invoked with
desc->lock held.
Convert the register lock to raw_spinlock_t. The same lock also
serializes the GPIO direction/value callbacks and the suspend/resume
register save/restore, and those critical sections only perform short
sequences of MMIO register accesses (ioread32()/iowrite32()); the
.irq_set_type callback additionally emits a dev_warn() on an unsupported
type. None of these are sleepable operations, so keeping this register
lock non-sleeping is appropriate for the irqchip callbacks and does not
change the GPIO-side locking contract.
This is the same fix as commit a02b8950d619 ("gpio: pch: use
raw_spinlock_t for the register lock"); this driver shares the same
structure as gpio-pch.
Fixes: 54be566317b6 ("gpio-ml-ioh: Support interrupt function")
Cc: stable@vger.kernel.org
Reviewed-by: Linus Walleij <linusw@kernel.org>
Link: https://patch.msgid.link/20260731032747.2987292-1-junjie.cao@intel.com
Signed-off-by: Junjie Cao <junjie.cao@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/gpio/gpio-ml-ioh.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -84,7 +84,7 @@ struct ioh_gpio {
u32 gpio_use_sel;
int ch;
int irq_base;
- spinlock_t spinlock;
+ raw_spinlock_t spinlock;
};
static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
@@ -95,7 +95,7 @@ static void ioh_gpio_set(struct gpio_chi
struct ioh_gpio *chip = gpiochip_get_data(gpio);
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
reg_val = ioread32(&chip->reg->regs[chip->ch].po);
if (val)
reg_val |= BIT(nr);
@@ -103,7 +103,7 @@ static void ioh_gpio_set(struct gpio_chi
reg_val &= ~BIT(nr);
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
}
static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr)
@@ -121,7 +121,7 @@ static int ioh_gpio_direction_output(str
u32 reg_val;
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
pm = ioread32(&chip->reg->regs[chip->ch].pm);
pm &= BIT(num_ports[chip->ch]) - 1;
pm |= BIT(nr);
@@ -134,7 +134,7 @@ static int ioh_gpio_direction_output(str
reg_val &= ~BIT(nr);
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@@ -145,12 +145,12 @@ static int ioh_gpio_direction_input(stru
u32 pm;
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
pm = ioread32(&chip->reg->regs[chip->ch].pm);
pm &= BIT(num_ports[chip->ch]) - 1;
pm &= ~BIT(nr);
iowrite32(pm, &chip->reg->regs[chip->ch].pm);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@@ -254,7 +254,7 @@ static int ioh_irq_type(struct irq_data
dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d type=%d\n",
__func__, irq, type, ch, im_pos, type);
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
switch (type) {
case IRQ_TYPE_EDGE_RISING:
@@ -294,7 +294,7 @@ static int ioh_irq_type(struct irq_data
ien = ioread32(&chip->reg->regs[chip->ch].ien);
iowrite32(ien | BIT(ch), &chip->reg->regs[chip->ch].ien);
end:
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@@ -324,11 +324,11 @@ static void ioh_irq_disable(struct irq_d
unsigned long flags;
u32 ien;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
ien = ioread32(&chip->reg->regs[chip->ch].ien);
ien &= ~BIT(d->irq - chip->irq_base);
iowrite32(ien, &chip->reg->regs[chip->ch].ien);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
}
static void ioh_irq_enable(struct irq_data *d)
@@ -338,11 +338,11 @@ static void ioh_irq_enable(struct irq_da
unsigned long flags;
u32 ien;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
ien = ioread32(&chip->reg->regs[chip->ch].ien);
ien |= BIT(d->irq - chip->irq_base);
iowrite32(ien, &chip->reg->regs[chip->ch].ien);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
}
static irqreturn_t ioh_gpio_handler(int irq, void *dev_id)
@@ -438,7 +438,7 @@ static int ioh_gpio_probe(struct pci_dev
chip->base = base;
chip->reg = chip->base;
chip->ch = i;
- spin_lock_init(&chip->spinlock);
+ raw_spin_lock_init(&chip->spinlock);
ioh_gpio_setup(chip, num_ports[i]);
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
if (ret) {
@@ -482,9 +482,9 @@ static int __maybe_unused ioh_gpio_suspe
struct ioh_gpio *chip = dev_get_drvdata(dev);
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
ioh_gpio_save_reg_conf(chip);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
@@ -494,11 +494,11 @@ static int __maybe_unused ioh_gpio_resum
struct ioh_gpio *chip = dev_get_drvdata(dev);
unsigned long flags;
- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&chip->spinlock, flags);
iowrite32(0x01, &chip->reg->srst);
iowrite32(0x00, &chip->reg->srst);
ioh_gpio_restore_reg_conf(chip);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 06/77] gve: fix zero-length skb frag with header-split
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (4 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 05/77] gpio: ml-ioh: use raw_spinlock_t for the register lock Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 07/77] hwmon: (ltc4286) Fix symbol namespace of MODULE_IMPORT_NS() Greg Kroah-Hartman
` (78 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Praveen Kaligineedi, Ziwei Xiao,
Jordan Rhee, Harshitha Ramamurthy, Jakub Kicinski
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jordan Rhee <jordanrhee@google.com>
commit 6bf14575c65569dcded90ef78afb8a6d57323f04 upstream.
When header split is enabled and a header-only packet is
received such as a pure TCP ACK, GVE will indicate an
RX SKB with a zero-length fragment. If this SKB is then
hairpinned and sent back out, the GVE TX path will emit
a zero-length descriptor. Hardware considers this
an illegal descriptor and stops the queue, causing a
TX timeout and interface reset.
Fix it by not adding the zero-length skb frag.
Cc: stable@vger.kernel.org
Fixes: 5e37d8254e7f ("gve: Add header split data path")
Suggested-by: Praveen Kaligineedi <pkaligineedi@google.com>
Co-developed-by: Ziwei Xiao <ziweixiao@google.com>
Signed-off-by: Ziwei Xiao <ziweixiao@google.com>
Signed-off-by: Jordan Rhee <jordanrhee@google.com>
Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com>
Link: https://patch.msgid.link/20260807224315.234152-2-hramamurthy@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Harshitha Ramamurthy <hramamurthy@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/google/gve/gve_rx_dqo.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -850,6 +850,12 @@ static int gve_rx_dqo(struct napi_struct
rx->rx_hsplit_unsplit_pkt += unsplit;
rx->rx_hsplit_bytes += hdr_len;
u64_stats_update_end(&rx->statss);
+
+ if (!buf_len) {
+ gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states,
+ buf_state);
+ return 0;
+ }
}
/* Sync the portion of dma buffer for CPU to read. */
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 07/77] hwmon: (ltc4286) Fix symbol namespace of MODULE_IMPORT_NS()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (5 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 06/77] gve: fix zero-length skb frag with header-split Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 08/77] netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages() Greg Kroah-Hartman
` (77 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Nobuhiro Iwamatsu (CIP)
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.x90@mail.toshiba>
In 6.12.y, the namespace specified in MODULE_IMPORT_NS() does not require
a string. This removes the quotes from the namespace name.
Fixes: 7fd4a5682c78 ("hwmon: (ltc4286) Add missing MODULE_IMPORT_NS("PMBUS")")
Signed-off-by: Nobuhiro Iwamatsu (CIP) <nobuhiro.iwamatsu.x90@mail.toshiba>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hwmon/pmbus/ltc4286.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/hwmon/pmbus/ltc4286.c
+++ b/drivers/hwmon/pmbus/ltc4286.c
@@ -173,4 +173,4 @@ module_i2c_driver(ltc4286_driver);
MODULE_AUTHOR("Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>");
MODULE_DESCRIPTION("PMBUS driver for LTC4286 and compatibles");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS("PMBUS");
+MODULE_IMPORT_NS(PMBUS);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 08/77] netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (6 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 07/77] hwmon: (ltc4286) Fix symbol namespace of MODULE_IMPORT_NS() Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 09/77] inet: frags: add inet_frag_putn() helper Greg Kroah-Hartman
` (76 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Howells, Paulo Alcantara,
Viacheslav Dubeyko, Matthew Wilcox, netfs, linux-fsdevel,
Christian Brauner, Shishkin Aleksey
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <dhowells@redhat.com>
commit dbe556972100fabb8e5a1b3d2163831ff07b1e8e upstream.
netfs_unlock_abandoned_read_pages(rreq) accesses the index of the folios it
is wanting to unlock and compares that to rreq->no_unlock_folio so that it
doesn't unlock a folio being read for netfs_perform_write() or
netfs_write_begin().
However, given that netfs_unlock_abandoned_read_pages() is called _after_
NETFS_RREQ_IN_PROGRESS is cleared, the one folio that it's not allowed to
dereference is the one specified by ->no_unlock_folio as ownership
immediately reverts to the caller.
Fix this by storing the folio pointer instead and using that rather than
the index. Also fix netfs_unlock_read_folio() where the same applies.
Fixes: ee4cdf7ba857 ("netfs: Speed up buffered reading")
Closes: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260512123404.719402-20-dhowells@redhat.com
cc: Paulo Alcantara <pc@manguebit.org>
cc: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
cc: Matthew Wilcox <willy@infradead.org>
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Shishkin Aleksey <demonaxsh@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/netfs/buffered_read.c | 4 ++--
fs/netfs/read_collect.c | 2 +-
fs/netfs/read_retry.c | 2 +-
include/linux/netfs.h | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
--- a/fs/netfs/buffered_read.c
+++ b/fs/netfs/buffered_read.c
@@ -734,7 +734,7 @@ retry:
ret = PTR_ERR(rreq);
goto error;
}
- rreq->no_unlock_folio = folio->index;
+ rreq->no_unlock_folio = folio;
__set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags);
ret = netfs_begin_cache_read(rreq, ctx);
@@ -800,7 +800,7 @@ int netfs_prefetch_for_write(struct file
goto error;
}
- rreq->no_unlock_folio = folio->index;
+ rreq->no_unlock_folio = folio;
__set_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags);
ret = netfs_begin_cache_read(rreq, ctx);
if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS)
--- a/fs/netfs/read_collect.c
+++ b/fs/netfs/read_collect.c
@@ -73,7 +73,7 @@ static void netfs_unlock_read_folio(stru
}
if (!test_bit(NETFS_RREQ_DONT_UNLOCK_FOLIOS, &rreq->flags)) {
- if (folio->index == rreq->no_unlock_folio &&
+ if (folio == rreq->no_unlock_folio &&
test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags)) {
_debug("no unlock");
} else {
--- a/fs/netfs/read_retry.c
+++ b/fs/netfs/read_retry.c
@@ -249,7 +249,7 @@ void netfs_unlock_abandoned_read_pages(s
struct folio *folio = folioq_folio(p, slot);
if (folio && !folioq_is_marked2(p, slot)) {
- if (folio->index == rreq->no_unlock_folio &&
+ if (folio == rreq->no_unlock_folio &&
test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO,
&rreq->flags)) {
_debug("no unlock");
--- a/include/linux/netfs.h
+++ b/include/linux/netfs.h
@@ -266,7 +266,7 @@ struct netfs_io_request {
atomic64_t issued_to; /* Write issuer folio cursor */
unsigned long long collected_to; /* Point we've collected to */
unsigned long long cleaned_to; /* Position we've cleaned folios to */
- pgoff_t no_unlock_folio; /* Don't unlock this folio after read */
+ const struct folio *no_unlock_folio; /* Don't unlock this folio after read */
size_t prev_donated; /* Fallback for subreq->prev_donated */
refcount_t ref;
unsigned long flags;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 09/77] inet: frags: add inet_frag_putn() helper
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (7 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 08/77] netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages() Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 10/77] ipv4: frags: remove ipq_put() Greg Kroah-Hartman
` (75 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Paolo Abeni,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit ae2d90355aa5592b0e99c8bbb4c3fa1d8e205f1b ]
inet_frag_putn() can release multiple references
in one step.
Use it in inet_frags_free_cb().
Replace inet_frag_put(X) with inet_frag_putn(X, 1)
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250312082250.1803501-2-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: 653d7ddf6cba ("inet: frags: publish queues before arming timer")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/net/inet_frag.h | 4 ++--
include/net/ipv6_frag.h | 3 ++-
net/ieee802154/6lowpan/reassembly.c | 7 ++++---
net/ipv4/inet_fragment.c | 3 +--
net/ipv4/ip_fragment.c | 2 +-
net/ipv6/netfilter/nf_conntrack_reasm.c | 3 ++-
net/ipv6/reassembly.c | 4 ++--
7 files changed, 14 insertions(+), 12 deletions(-)
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -133,9 +133,9 @@ struct inet_frag_queue *inet_frag_find(s
void inet_frag_queue_flush(struct inet_frag_queue *q,
enum skb_drop_reason reason);
-static inline void inet_frag_put(struct inet_frag_queue *q)
+static inline void inet_frag_putn(struct inet_frag_queue *q, int refs)
{
- if (refcount_dec_and_test(&q->refcnt))
+ if (refs && refcount_sub_and_test(refs, &q->refcnt))
inet_frag_destroy(q);
}
--- a/include/net/ipv6_frag.h
+++ b/include/net/ipv6_frag.h
@@ -66,6 +66,7 @@ ip6frag_expire_frag_queue(struct net *ne
{
struct net_device *dev = NULL;
struct sk_buff *head;
+ int refs = 1;
rcu_read_lock();
spin_lock(&fq->q.lock);
@@ -112,7 +113,7 @@ out:
spin_unlock(&fq->q.lock);
out_rcu_unlock:
rcu_read_unlock();
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
}
/* Check if the upper layer header is truncated in the first fragment. */
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -45,6 +45,7 @@ static void lowpan_frag_expire(struct ti
{
struct inet_frag_queue *frag = from_timer(frag, t, timer);
struct frag_queue *fq;
+ int refs = 1;
fq = container_of(frag, struct frag_queue, q);
@@ -56,7 +57,7 @@ static void lowpan_frag_expire(struct ti
inet_frag_kill(&fq->q);
out:
spin_unlock(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
}
static inline struct lowpan_frag_queue *
@@ -302,13 +303,13 @@ int lowpan_frag_rcv(struct sk_buff *skb,
fq = fq_find(net, cb, &hdr.source, &hdr.dest);
if (fq != NULL) {
- int ret;
+ int ret, refs = 1;
spin_lock(&fq->q.lock);
ret = lowpan_frag_queue(fq, skb, frag_type);
spin_unlock(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
return ret;
}
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -145,8 +145,7 @@ static void inet_frags_free_cb(void *ptr
}
spin_unlock_bh(&fq->lock);
- if (refcount_sub_and_test(count, &fq->refcnt))
- inet_frag_destroy(fq);
+ inet_frag_putn(fq, count);
}
static LLIST_HEAD(fqdir_free_list);
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -112,7 +112,7 @@ static void ip4_frag_free(struct inet_fr
static void ipq_put(struct ipq *ipq)
{
- inet_frag_put(&ipq->q);
+ inet_frag_putn(&ipq->q, 1);
}
/* Kill ipq entry. It is not destroyed immediately,
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -448,6 +448,7 @@ int nf_ct_frag6_gather(struct net *net,
struct frag_hdr *fhdr;
struct frag_queue *fq;
struct ipv6hdr *hdr;
+ int refs = 1;
u8 prevhdr;
/* Jumbo payload inhibits frag. header */
@@ -490,7 +491,7 @@ int nf_ct_frag6_gather(struct net *net,
}
spin_unlock_bh(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
return ret;
}
EXPORT_SYMBOL_GPL(nf_ct_frag6_gather);
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -380,7 +380,7 @@ static int ipv6_frag_rcv(struct sk_buff
fq = fq_find(net, fhdr->identification, hdr, iif);
if (fq) {
u32 prob_offset = 0;
- int ret;
+ int ret, refs = 1;
spin_lock(&fq->q.lock);
@@ -389,7 +389,7 @@ static int ipv6_frag_rcv(struct sk_buff
&prob_offset);
spin_unlock(&fq->q.lock);
- inet_frag_put(&fq->q);
+ inet_frag_putn(&fq->q, refs);
if (prob_offset) {
__IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
IPSTATS_MIB_INHDRERRORS);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 10/77] ipv4: frags: remove ipq_put()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (8 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 09/77] inet: frags: add inet_frag_putn() helper Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 11/77] inet: frags: change inet_frag_kill() to defer refcount updates Greg Kroah-Hartman
` (74 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Paolo Abeni,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit a2fb987c0ecf0498cc17056339cb11d128c46ab7 ]
Replace ipq_put() with inet_frag_putn()
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250312082250.1803501-3-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: 653d7ddf6cba ("inet: frags: publish queues before arming timer")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/ipv4/ip_fragment.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -107,14 +107,6 @@ static void ip4_frag_free(struct inet_fr
inet_putpeer(qp->peer);
}
-
-/* Destruction primitives. */
-
-static void ipq_put(struct ipq *ipq)
-{
- inet_frag_putn(&ipq->q, 1);
-}
-
/* Kill ipq entry. It is not destroyed immediately,
* because caller (and someone more) holds reference count.
*/
@@ -142,6 +134,7 @@ static void ip_expire(struct timer_list
struct sk_buff *head = NULL;
struct net *net;
struct ipq *qp;
+ int refs = 1;
int err;
qp = container_of(frag, struct ipq, q);
@@ -203,7 +196,7 @@ out:
out_rcu_unlock:
rcu_read_unlock();
kfree_skb_reason(head, SKB_DROP_REASON_FRAG_REASM_TIMEOUT);
- ipq_put(qp);
+ inet_frag_putn(&qp->q, refs);
}
/* Find the correct entry in the "incomplete datagrams" queue for
@@ -492,14 +485,14 @@ int ip_defrag(struct net *net, struct sk
/* Lookup (or create) queue header */
qp = ip_find(net, ip_hdr(skb), user, vif);
if (qp) {
- int ret;
+ int ret, refs = 1;
spin_lock(&qp->q.lock);
ret = ip_frag_queue(qp, skb);
spin_unlock(&qp->q.lock);
- ipq_put(qp);
+ inet_frag_putn(&qp->q, refs);
return ret;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 11/77] inet: frags: change inet_frag_kill() to defer refcount updates
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (9 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 10/77] ipv4: frags: remove ipq_put() Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 12/77] inet: frags: save a pair of atomic operations in reassembly Greg Kroah-Hartman
` (73 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Paolo Abeni,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit eb0dfc0ef195a04e519b15d73cf25d8c25ee8df7 ]
In the following patch, we no longer assume inet_frag_kill()
callers own a reference.
Consuming two refcounts from inet_frag_kill() would lead in UAF.
Propagate the pointer to the refs that will be consumed later
by the final inet_frag_putn() call.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250312082250.1803501-4-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: 653d7ddf6cba ("inet: frags: publish queues before arming timer")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/net/inet_frag.h | 2 +-
include/net/ipv6_frag.h | 2 +-
net/ieee802154/6lowpan/reassembly.c | 17 ++++++++++-------
net/ipv4/inet_fragment.c | 12 +++++++-----
net/ipv4/ip_fragment.c | 30 ++++++++++++------------------
net/ipv6/netfilter/nf_conntrack_reasm.c | 21 ++++++++++++---------
net/ipv6/reassembly.c | 18 ++++++++++--------
7 files changed, 53 insertions(+), 49 deletions(-)
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -126,7 +126,7 @@ int fqdir_init(struct fqdir **fqdirp, st
void fqdir_pre_exit(struct fqdir *fqdir);
void fqdir_exit(struct fqdir *fqdir);
-void inet_frag_kill(struct inet_frag_queue *q);
+void inet_frag_kill(struct inet_frag_queue *q, int *refs);
void inet_frag_destroy(struct inet_frag_queue *q);
struct inet_frag_queue *inet_frag_find(struct fqdir *fqdir, void *key);
--- a/include/net/ipv6_frag.h
+++ b/include/net/ipv6_frag.h
@@ -75,7 +75,7 @@ ip6frag_expire_frag_queue(struct net *ne
goto out;
fq->q.flags |= INET_FRAG_DROP;
- inet_frag_kill(&fq->q);
+ inet_frag_kill(&fq->q, &refs);
/* Paired with the WRITE_ONCE() in fqdir_pre_exit(). */
if (READ_ONCE(fq->q.fqdir->dead)) {
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -31,7 +31,8 @@ static const char lowpan_frags_cache_nam
static struct inet_frags lowpan_frags;
static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *skb,
- struct sk_buff *prev, struct net_device *ldev);
+ struct sk_buff *prev, struct net_device *ldev,
+ int *refs);
static void lowpan_frag_init(struct inet_frag_queue *q, const void *a)
{
@@ -54,7 +55,7 @@ static void lowpan_frag_expire(struct ti
if (fq->q.flags & INET_FRAG_COMPLETE)
goto out;
- inet_frag_kill(&fq->q);
+ inet_frag_kill(&fq->q, &refs);
out:
spin_unlock(&fq->q.lock);
inet_frag_putn(&fq->q, refs);
@@ -83,7 +84,8 @@ fq_find(struct net *net, const struct lo
}
static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
- struct sk_buff *skb, u8 frag_type)
+ struct sk_buff *skb, u8 frag_type,
+ int *refs)
{
struct sk_buff *prev_tail;
struct net_device *ldev;
@@ -144,7 +146,7 @@ static int lowpan_frag_queue(struct lowp
unsigned long orefdst = skb->_skb_refdst;
skb->_skb_refdst = 0UL;
- res = lowpan_frag_reasm(fq, skb, prev_tail, ldev);
+ res = lowpan_frag_reasm(fq, skb, prev_tail, ldev, refs);
skb->_skb_refdst = orefdst;
return res;
}
@@ -163,11 +165,12 @@ err:
* the last and the first frames arrived and all the bits are here.
*/
static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *skb,
- struct sk_buff *prev_tail, struct net_device *ldev)
+ struct sk_buff *prev_tail, struct net_device *ldev,
+ int *refs)
{
void *reasm_data;
- inet_frag_kill(&fq->q);
+ inet_frag_kill(&fq->q, refs);
reasm_data = inet_frag_reasm_prepare(&fq->q, skb, prev_tail);
if (!reasm_data)
@@ -306,7 +309,7 @@ int lowpan_frag_rcv(struct sk_buff *skb,
int ret, refs = 1;
spin_lock(&fq->q.lock);
- ret = lowpan_frag_queue(fq, skb, frag_type);
+ ret = lowpan_frag_queue(fq, skb, frag_type, &refs);
spin_unlock(&fq->q.lock);
inet_frag_putn(&fq->q, refs);
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -260,10 +260,10 @@ void fqdir_exit(struct fqdir *fqdir)
}
EXPORT_SYMBOL(fqdir_exit);
-void inet_frag_kill(struct inet_frag_queue *fq)
+void inet_frag_kill(struct inet_frag_queue *fq, int *refs)
{
if (del_timer(&fq->timer))
- refcount_dec(&fq->refcnt);
+ (*refs)++;
if (!(fq->flags & INET_FRAG_COMPLETE)) {
struct fqdir *fqdir = fq->fqdir;
@@ -278,7 +278,7 @@ void inet_frag_kill(struct inet_frag_que
if (!READ_ONCE(fqdir->dead)) {
rhashtable_remove_fast(&fqdir->rhashtable, &fq->node,
fqdir->f->rhash_params);
- refcount_dec(&fq->refcnt);
+ (*refs)++;
} else {
fq->flags |= INET_FRAG_HASH_DEAD;
}
@@ -397,9 +397,11 @@ static struct inet_frag_queue *inet_frag
*prev = rhashtable_lookup_get_insert_key(&fqdir->rhashtable, &q->key,
&q->node, f->rhash_params);
if (*prev) {
+ int refs = 2;
+
q->flags |= INET_FRAG_COMPLETE;
- inet_frag_kill(q);
- inet_frag_destroy(q);
+ inet_frag_kill(q, &refs);
+ inet_frag_putn(q, refs);
return NULL;
}
return q;
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -76,7 +76,8 @@ static u8 ip4_frag_ecn(u8 tos)
static struct inet_frags ip4_frags;
static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
- struct sk_buff *prev_tail, struct net_device *dev);
+ struct sk_buff *prev_tail, struct net_device *dev,
+ int *refs);
static void ip4_frag_init(struct inet_frag_queue *q, const void *a)
@@ -107,14 +108,6 @@ static void ip4_frag_free(struct inet_fr
inet_putpeer(qp->peer);
}
-/* Kill ipq entry. It is not destroyed immediately,
- * because caller (and someone more) holds reference count.
- */
-static void ipq_kill(struct ipq *ipq)
-{
- inet_frag_kill(&ipq->q);
-}
-
static bool frag_expire_skip_icmp(u32 user)
{
return user == IP_DEFRAG_AF_PACKET ||
@@ -147,7 +140,7 @@ static void ip_expire(struct timer_list
goto out;
qp->q.flags |= INET_FRAG_DROP;
- ipq_kill(qp);
+ inet_frag_kill(&qp->q, &refs);
/* Paired with WRITE_ONCE() in fqdir_pre_exit(). */
if (READ_ONCE(qp->q.fqdir->dead)) {
@@ -265,7 +258,7 @@ static int ip_frag_reinit(struct ipq *qp
}
/* Add new segment to existing queue. */
-static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
+static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb, int *refs)
{
struct net *net = qp->q.fqdir->net;
int ihl, end, flags, offset;
@@ -285,7 +278,7 @@ static int ip_frag_queue(struct ipq *qp,
if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) &&
unlikely(ip_frag_too_far(qp)) &&
unlikely(err = ip_frag_reinit(qp))) {
- ipq_kill(qp);
+ inet_frag_kill(&qp->q, refs);
goto err;
}
@@ -369,10 +362,10 @@ static int ip_frag_queue(struct ipq *qp,
unsigned long orefdst = skb->_skb_refdst;
skb->_skb_refdst = 0UL;
- err = ip_frag_reasm(qp, skb, prev_tail, dev);
+ err = ip_frag_reasm(qp, skb, prev_tail, dev, refs);
skb->_skb_refdst = orefdst;
if (err)
- inet_frag_kill(&qp->q);
+ inet_frag_kill(&qp->q, refs);
return err;
}
@@ -389,7 +382,7 @@ insert_error:
err = -EINVAL;
__IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS);
discard_qp:
- inet_frag_kill(&qp->q);
+ inet_frag_kill(&qp->q, refs);
__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
err:
kfree_skb_reason(skb, reason);
@@ -403,7 +396,8 @@ static bool ip_frag_coalesce_ok(const st
/* Build a new IP datagram from all its fragments. */
static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
- struct sk_buff *prev_tail, struct net_device *dev)
+ struct sk_buff *prev_tail, struct net_device *dev,
+ int *refs)
{
struct net *net = qp->q.fqdir->net;
struct iphdr *iph;
@@ -411,7 +405,7 @@ static int ip_frag_reasm(struct ipq *qp,
int len, err;
u8 ecn;
- ipq_kill(qp);
+ inet_frag_kill(&qp->q, refs);
ecn = ip_frag_ecn_table[qp->ecn];
if (unlikely(ecn == 0xff)) {
@@ -489,7 +483,7 @@ int ip_defrag(struct net *net, struct sk
spin_lock(&qp->q.lock);
- ret = ip_frag_queue(qp, skb);
+ ret = ip_frag_queue(qp, skb, &refs);
spin_unlock(&qp->q.lock);
inet_frag_putn(&qp->q, refs);
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -123,7 +123,8 @@ static void __net_exit nf_ct_frags6_sysc
#endif
static int nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *skb,
- struct sk_buff *prev_tail, struct net_device *dev);
+ struct sk_buff *prev_tail, struct net_device *dev,
+ int *refs);
static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h)
{
@@ -167,7 +168,8 @@ static struct frag_queue *fq_find(struct
static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
- const struct frag_hdr *fhdr, int nhoff)
+ const struct frag_hdr *fhdr, int nhoff,
+ int *refs)
{
unsigned int payload_len;
struct net_device *dev;
@@ -221,7 +223,7 @@ static int nf_ct_frag6_queue(struct frag
* this case. -DaveM
*/
pr_debug("end of fragment not rounded to 8 bytes.\n");
- inet_frag_kill(&fq->q);
+ inet_frag_kill(&fq->q, refs);
return -EPROTO;
}
if (end > fq->q.len) {
@@ -287,7 +289,7 @@ static int nf_ct_frag6_queue(struct frag
unsigned long orefdst = skb->_skb_refdst;
skb->_skb_refdst = 0UL;
- err = nf_ct_frag6_reasm(fq, skb, prev, dev);
+ err = nf_ct_frag6_reasm(fq, skb, prev, dev, refs);
skb->_skb_refdst = orefdst;
/* After queue has assumed skb ownership, only 0 or
@@ -301,7 +303,7 @@ static int nf_ct_frag6_queue(struct frag
return -EINPROGRESS;
insert_error:
- inet_frag_kill(&fq->q);
+ inet_frag_kill(&fq->q, refs);
err:
skb_dst_drop(skb);
return -EINVAL;
@@ -315,13 +317,14 @@ err:
* the last and the first frames arrived and all the bits are here.
*/
static int nf_ct_frag6_reasm(struct frag_queue *fq, struct sk_buff *skb,
- struct sk_buff *prev_tail, struct net_device *dev)
+ struct sk_buff *prev_tail, struct net_device *dev,
+ int *refs)
{
void *reasm_data;
int payload_len;
u8 ecn;
- inet_frag_kill(&fq->q);
+ inet_frag_kill(&fq->q, refs);
ecn = ip_frag_ecn_table[fq->ecn];
if (unlikely(ecn == 0xff))
@@ -373,7 +376,7 @@ static int nf_ct_frag6_reasm(struct frag
return 0;
err:
- inet_frag_kill(&fq->q);
+ inet_frag_kill(&fq->q, refs);
return -EINVAL;
}
@@ -484,7 +487,7 @@ int nf_ct_frag6_gather(struct net *net,
spin_lock_bh(&fq->q.lock);
- ret = nf_ct_frag6_queue(fq, skb, fhdr, nhoff);
+ ret = nf_ct_frag6_queue(fq, skb, fhdr, nhoff, &refs);
if (ret == -EPROTO) {
skb->transport_header = savethdr;
ret = 0;
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -68,7 +68,8 @@ static u8 ip6_frag_ecn(const struct ipv6
static struct inet_frags ip6_frags;
static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
- struct sk_buff *prev_tail, struct net_device *dev);
+ struct sk_buff *prev_tail, struct net_device *dev,
+ int *refs);
static void ip6_frag_expire(struct timer_list *t)
{
@@ -105,7 +106,7 @@ fq_find(struct net *net, __be32 id, cons
static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
struct frag_hdr *fhdr, int nhoff,
- u32 *prob_offset)
+ u32 *prob_offset, int *refs)
{
struct net *net = dev_net(skb_dst(skb)->dev);
int offset, end, fragsize;
@@ -220,7 +221,7 @@ static int ip6_frag_queue(struct frag_qu
unsigned long orefdst = skb->_skb_refdst;
skb->_skb_refdst = 0UL;
- err = ip6_frag_reasm(fq, skb, prev_tail, dev);
+ err = ip6_frag_reasm(fq, skb, prev_tail, dev, refs);
skb->_skb_refdst = orefdst;
return err;
}
@@ -238,7 +239,7 @@ insert_error:
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_REASM_OVERLAPS);
discard_fq:
- inet_frag_kill(&fq->q);
+ inet_frag_kill(&fq->q, refs);
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_REASMFAILS);
err:
@@ -254,7 +255,8 @@ err:
* the last and the first frames arrived and all the bits are here.
*/
static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
- struct sk_buff *prev_tail, struct net_device *dev)
+ struct sk_buff *prev_tail, struct net_device *dev,
+ int *refs)
{
struct net *net = fq->q.fqdir->net;
unsigned int nhoff;
@@ -262,7 +264,7 @@ static int ip6_frag_reasm(struct frag_qu
int payload_len;
u8 ecn;
- inet_frag_kill(&fq->q);
+ inet_frag_kill(&fq->q, refs);
ecn = ip_frag_ecn_table[fq->ecn];
if (unlikely(ecn == 0xff))
@@ -320,7 +322,7 @@ out_fail:
rcu_read_lock();
__IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMFAILS);
rcu_read_unlock();
- inet_frag_kill(&fq->q);
+ inet_frag_kill(&fq->q, refs);
return -1;
}
@@ -386,7 +388,7 @@ static int ipv6_frag_rcv(struct sk_buff
fq->iif = iif;
ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff,
- &prob_offset);
+ &prob_offset, &refs);
spin_unlock(&fq->q.lock);
inet_frag_putn(&fq->q, refs);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 12/77] inet: frags: save a pair of atomic operations in reassembly
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (10 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 11/77] inet: frags: change inet_frag_kill() to defer refcount updates Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 13/77] inet: frags: publish queues before arming timer Greg Kroah-Hartman
` (72 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Dumazet, Jacob Keller,
Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit ca0359df45a55a9eb4d6dc09a481064abf78320f ]
As mentioned in commit 648700f76b03 ("inet: frags:
use rhashtables for reassembly units"):
A followup patch will even remove the refcount hold/release
left from prior implementation and save a couple of atomic
operations.
This patch implements this idea, seven years later.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20250312082250.1803501-5-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Stable-dep-of: 653d7ddf6cba ("inet: frags: publish queues before arming timer")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/ieee802154/6lowpan/reassembly.c | 5 ++++-
net/ipv4/inet_fragment.c | 18 ++++++++----------
net/ipv4/ip_fragment.c | 5 ++++-
net/ipv6/netfilter/nf_conntrack_reasm.c | 5 ++++-
net/ipv6/reassembly.c | 9 ++++-----
5 files changed, 24 insertions(+), 18 deletions(-)
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -304,17 +304,20 @@ int lowpan_frag_rcv(struct sk_buff *skb,
goto err;
}
+ rcu_read_lock();
fq = fq_find(net, cb, &hdr.source, &hdr.dest);
if (fq != NULL) {
- int ret, refs = 1;
+ int ret, refs = 0;
spin_lock(&fq->q.lock);
ret = lowpan_frag_queue(fq, skb, frag_type, &refs);
spin_unlock(&fq->q.lock);
+ rcu_read_unlock();
inet_frag_putn(&fq->q, refs);
return ret;
}
+ rcu_read_unlock();
err:
kfree_skb(skb);
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -375,7 +375,8 @@ static struct inet_frag_queue *inet_frag
timer_setup(&q->timer, f->frag_expire, 0);
spin_lock_init(&q->lock);
- refcount_set(&q->refcnt, 3);
+ /* One reference for the timer, one for the hash table. */
+ refcount_set(&q->refcnt, 2);
return q;
}
@@ -397,7 +398,11 @@ static struct inet_frag_queue *inet_frag
*prev = rhashtable_lookup_get_insert_key(&fqdir->rhashtable, &q->key,
&q->node, f->rhash_params);
if (*prev) {
- int refs = 2;
+ /* We could not insert in the hash table,
+ * we need to cancel what inet_frag_alloc()
+ * anticipated.
+ */
+ int refs = 1;
q->flags |= INET_FRAG_COMPLETE;
inet_frag_kill(q, &refs);
@@ -407,7 +412,6 @@ static struct inet_frag_queue *inet_frag
return q;
}
-/* TODO : call from rcu_read_lock() and no longer use refcount_inc_not_zero() */
struct inet_frag_queue *inet_frag_find(struct fqdir *fqdir, void *key)
{
/* This pairs with WRITE_ONCE() in fqdir_pre_exit(). */
@@ -417,17 +421,11 @@ struct inet_frag_queue *inet_frag_find(s
if (!high_thresh || frag_mem_limit(fqdir) > high_thresh)
return NULL;
- rcu_read_lock();
-
prev = rhashtable_lookup(&fqdir->rhashtable, key, fqdir->f->rhash_params);
if (!prev)
fq = inet_frag_create(fqdir, key, &prev);
- if (!IS_ERR_OR_NULL(prev)) {
+ if (!IS_ERR_OR_NULL(prev))
fq = prev;
- if (!refcount_inc_not_zero(&fq->refcnt))
- fq = NULL;
- }
- rcu_read_unlock();
return fq;
}
EXPORT_SYMBOL(inet_frag_find);
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -477,18 +477,21 @@ int ip_defrag(struct net *net, struct sk
__IP_INC_STATS(net, IPSTATS_MIB_REASMREQDS);
/* Lookup (or create) queue header */
+ rcu_read_lock();
qp = ip_find(net, ip_hdr(skb), user, vif);
if (qp) {
- int ret, refs = 1;
+ int ret, refs = 0;
spin_lock(&qp->q.lock);
ret = ip_frag_queue(qp, skb, &refs);
spin_unlock(&qp->q.lock);
+ rcu_read_unlock();
inet_frag_putn(&qp->q, refs);
return ret;
}
+ rcu_read_unlock();
__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
kfree_skb(skb);
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -451,7 +451,7 @@ int nf_ct_frag6_gather(struct net *net,
struct frag_hdr *fhdr;
struct frag_queue *fq;
struct ipv6hdr *hdr;
- int refs = 1;
+ int refs = 0;
u8 prevhdr;
/* Jumbo payload inhibits frag. header */
@@ -478,9 +478,11 @@ int nf_ct_frag6_gather(struct net *net,
hdr = ipv6_hdr(skb);
fhdr = (struct frag_hdr *)skb_transport_header(skb);
+ rcu_read_lock();
fq = fq_find(net, fhdr->identification, user, hdr,
skb->dev ? skb->dev->ifindex : 0);
if (fq == NULL) {
+ rcu_read_unlock();
pr_debug("Can't find and can't create new queue\n");
return -ENOMEM;
}
@@ -494,6 +496,7 @@ int nf_ct_frag6_gather(struct net *net,
}
spin_unlock_bh(&fq->q.lock);
+ rcu_read_unlock();
inet_frag_putn(&fq->q, refs);
return ret;
}
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -305,9 +305,7 @@ static int ip6_frag_reasm(struct frag_qu
skb_postpush_rcsum(skb, skb_network_header(skb),
skb_network_header_len(skb));
- rcu_read_lock();
__IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMOKS);
- rcu_read_unlock();
fq->q.rb_fragments = RB_ROOT;
fq->q.fragments_tail = NULL;
fq->q.last_run_head = NULL;
@@ -319,9 +317,7 @@ out_oversize:
out_oom:
net_dbg_ratelimited("ip6_frag_reasm: no memory for reassembly\n");
out_fail:
- rcu_read_lock();
__IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMFAILS);
- rcu_read_unlock();
inet_frag_kill(&fq->q, refs);
return -1;
}
@@ -379,10 +375,11 @@ static int ipv6_frag_rcv(struct sk_buff
}
iif = skb->dev ? skb->dev->ifindex : 0;
+ rcu_read_lock();
fq = fq_find(net, fhdr->identification, hdr, iif);
if (fq) {
u32 prob_offset = 0;
- int ret, refs = 1;
+ int ret, refs = 0;
spin_lock(&fq->q.lock);
@@ -391,6 +388,7 @@ static int ipv6_frag_rcv(struct sk_buff
&prob_offset, &refs);
spin_unlock(&fq->q.lock);
+ rcu_read_unlock();
inet_frag_putn(&fq->q, refs);
if (prob_offset) {
__IP6_INC_STATS(net, __in6_dev_get_safely(skb->dev),
@@ -400,6 +398,7 @@ static int ipv6_frag_rcv(struct sk_buff
}
return ret;
}
+ rcu_read_unlock();
__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMFAILS);
kfree_skb(skb);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 13/77] inet: frags: publish queues before arming timer
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (11 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 12/77] inet: frags: save a pair of atomic operations in reassembly Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 14/77] serial: 8250_of: clear stuck empty-FIFO RX-timeout on LPC32xx Greg Kroah-Hartman
` (71 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vega, Zhiling Zou, Ren Wei,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <zhilinz@nebusec.ai>
[ Upstream commit 653d7ddf6cba867777a3d14c4f83ace008c5ad13 ]
inet_frag_create() arms the fragment queue timer before inserting the
queue into the fqdir rhashtable. If the namespace fragment timeout is
zero or negative, the timer can run before the queue is published.
The timer callback then marks the queue complete, tries to remove a node
that is not in the hash table yet, and drops the anticipated hash
reference. Creation can subsequently publish the completed queue without
restoring that reference, leaving a stale hash node after the caller drops
the remaining reference.
Publish the queue first and arm the timer while holding the queue lock.
This makes timer expiry wait until the queue is visible in the hash table,
so inet_frag_kill() can remove the node and balance the hash reference.
Fixes: 648700f76b03 ("inet: frags: use rhashtables for reassembly units")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
Signed-off-by: Ren Wei <enjou1224z@gmail.com>
Link: https://patch.msgid.link/bf66785e7c0c139d7a1900e2f01faeeab344b960.1784948849.git.zhilinz@nebusec.ai
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/ipv4/inet_fragment.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -393,8 +393,8 @@ static struct inet_frag_queue *inet_frag
*prev = ERR_PTR(-ENOMEM);
return NULL;
}
- mod_timer(&q->timer, jiffies + fqdir->timeout);
+ spin_lock_bh(&q->lock);
*prev = rhashtable_lookup_get_insert_key(&fqdir->rhashtable, &q->key,
&q->node, f->rhash_params);
if (*prev) {
@@ -402,13 +402,13 @@ static struct inet_frag_queue *inet_frag
* we need to cancel what inet_frag_alloc()
* anticipated.
*/
- int refs = 1;
-
q->flags |= INET_FRAG_COMPLETE;
- inet_frag_kill(q, &refs);
- inet_frag_putn(q, refs);
+ spin_unlock_bh(&q->lock);
+ inet_frag_putn(q, 2);
return NULL;
}
+ mod_timer(&q->timer, jiffies + fqdir->timeout);
+ spin_unlock_bh(&q->lock);
return q;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 14/77] serial: 8250_of: clear stuck empty-FIFO RX-timeout on LPC32xx
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (12 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 13/77] inet: frags: publish queues before arming timer Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 15/77] NTB: ntb_netdev: Preserve RX queue depth on allocation failure Greg Kroah-Hartman
` (70 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, stable, Ryan Wilbur, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Wilbur <rwilbur633@gmail.com>
[ Upstream commit 1423415471274abda87024967d7fe2206ceee0ea ]
The NXP LPC32xx UART (PORT_LPC3220) can latch an RX character-timeout
interrupt while the RX FIFO is empty: IIR reports UART_IIR_RX_TIMEOUT
(0x0c) but LSR.DR is clear. A character timeout is only cleared by
reading RHR, but serial8250_rx_chars() reads RHR only when LSR.DR is
set, so nothing ever clears the condition. The interrupt is
level-triggered and re-fires immediately, so on a single-core ARM926
the resulting interrupt storm livelocks the CPU.
It is reproducible when userspace repeatedly opens the front-panel port
(ttyS1): serial8250_do_set_termios() re-enables interrupts on unlock and
the handler then spins forever with iir=0xcc lsr=0x60 ier=0x05, tripping
the soft-lockup detector in serial8250_handle_irq_locked().
LPC32xx has no dedicated 8250 glue driver, it's driven by the generic
8250_of. Add a hardware specific handle_irq for PORT_LPC3220, wired up
in of_platform_serial_setup() the same way fsl8250_handle_irq is
installed. The handler follows dw8250_handle_irq(): on an RX timeout
with an empty FIFO (LSR.DR and LSR.BI clear) it does one throwaway RHR
read to clear the condition, then calls serial8250_handle_irq_locked().
No real received data is ever discarded, and it is a no-op on healthy
UARTs which never report a timeout with DR clear.
This is the same class of bug already worked around in other 8250 drivers;
see commit 424d79183af0 ("serial: 8250_dw: Avoid "too much work" from bogus rx timeout interrupt")
which reports the identical iir=0xcc/lsr=0x60. See also
UART_RX_TIMEOUT_QUIRK in 8250_omap, and the note in 8250_bcm7271.
Cc: stable <stable@kernel.org>
Assisted-by: Claude:Opus4.8
Signed-off-by: Ryan Wilbur <rwilbur633@gmail.com>
Link: https://patch.msgid.link/20260730193920.28954-1-rwilbur633@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/serial/8250/8250_of.c | 41 ++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -80,6 +80,44 @@ static int of_platform_serial_clk_notifi
return NOTIFY_DONE;
}
+static int lpc32xx_handle_irq(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned long flags;
+ unsigned int iir;
+ u16 status;
+ int ret;
+
+ serial8250_rpm_get(up);
+
+ iir = serial_port_in(port, UART_IIR);
+
+ /*
+ * The LPC32xx UART can assert an RX character-timeout interrupt while
+ * the RX FIFO is empty: IIR reports UART_IIR_RX_TIMEOUT but LSR.DR is
+ * clear. The timeout is only cleared by reading RHR, but the core RX
+ * path skips that read when the FIFO is empty, so the level-triggered
+ * IRQ re-fires forever and livelocks this single-core SoC. Do one
+ * throwaway RHR read to clear it; a healthy UART never reports a
+ * timeout with DR/BI clear, so no received data is ever discarded.
+ */
+ if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
+ uart_port_lock_irqsave(port, &flags);
+
+ status = serial_lsr_in(up);
+ if (!(status & (UART_LSR_DR | UART_LSR_BI)))
+ serial_port_in(port, UART_RX);
+
+ uart_port_unlock_irqrestore(port, flags);
+ }
+
+ ret = serial8250_handle_irq(port, iir);
+
+ serial8250_rpm_put(up);
+
+ return ret;
+}
+
/*
* Fill a struct uart_port for a given device node
*/
@@ -163,6 +201,9 @@ static int of_platform_serial_setup(stru
case PORT_NPCM:
ret = npcm_setup(port);
break;
+ case PORT_LPC3220:
+ port->handle_irq = lpc32xx_handle_irq;
+ break;
default:
/* Nothing to do */
ret = 0;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 15/77] NTB: ntb_netdev: Preserve RX queue depth on allocation failure
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (13 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 14/77] serial: 8250_of: clear stuck empty-FIFO RX-timeout on LPC32xx Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 16/77] serial: amba-pl011: synchronize DMA teardown Greg Kroah-Hartman
` (69 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Koichiro Den, Dave Jiang,
Paolo Abeni, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <den@valinux.co.jp>
[ Upstream commit d2121faf133ac3bf9531b53a7e21273649a08517 ]
ntb_netdev_rx_handler() hands the received skb to the network stack
before allocating its replacement. If the allocation fails, nothing is
reposted. Every failure therefore takes one buffer out of the RX queue
while the interface remains up, and enough failures eventually stall
reception.
A retry path could refill the queue later, but ntb_netdev has none.
Allocate the replacement first instead. If that fails, drop the packet
and repost the same skb. This keeps the queue full and lets packet
delivery resume as soon as memory is available again.
Fixes: 548c237c0a99 ("net: Add support for NTB virtual ethernet device")
Cc: stable@vger.kernel.org
Signed-off-by: Koichiro Den <den@valinux.co.jp>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Link: https://patch.msgid.link/20260806032537.3526498-1-den@valinux.co.jp
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
[ kept HEAD's `struct net_device *ndev = qp_data;` declaration instead of the per-queue context variables, adding only `new_skb` to the existing `skb` declaration ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ntb_netdev.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
--- a/drivers/net/ntb_netdev.c
+++ b/drivers/net/ntb_netdev.c
@@ -100,7 +100,7 @@ static void ntb_netdev_rx_handler(struct
void *data, int len)
{
struct net_device *ndev = qp_data;
- struct sk_buff *skb;
+ struct sk_buff *skb, *new_skb;
int rc;
skb = data;
@@ -115,6 +115,12 @@ static void ntb_netdev_rx_handler(struct
goto enqueue_again;
}
+ new_skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
+ if (!new_skb) {
+ ndev->stats.rx_dropped++;
+ goto enqueue_again;
+ }
+
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, ndev);
skb->ip_summed = CHECKSUM_NONE;
@@ -127,12 +133,7 @@ static void ntb_netdev_rx_handler(struct
ndev->stats.rx_bytes += len;
}
- skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
- if (!skb) {
- ndev->stats.rx_errors++;
- ndev->stats.rx_frame_errors++;
- return;
- }
+ skb = new_skb;
enqueue_again:
rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 16/77] serial: amba-pl011: synchronize DMA teardown
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (14 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 15/77] NTB: ntb_netdev: Preserve RX queue depth on allocation failure Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 17/77] serial: sc16is7xx: rename EFR mutex with generic name Greg Kroah-Hartman
` (68 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, stable, Fan Wu, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <fanwu01@zju.edu.cn>
[ Upstream commit 440915499231e9db1c361aa45bb702e8fd3b4a32 ]
dmaengine_terminate_all() does not wait for a running callback, so the TX
callback can still touch the TX buffer after it is freed. The RX poll
timer reads the RX buffers without the port lock.
Switch to dmaengine_terminate_sync() and delete the RX timer before
freeing the buffers.
Fixes: ead76f329f77 ("ARM: 6763/1: pl011: add optional RX DMA to PL011 v2")
Cc: stable <stable@kernel.org>
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Link: https://patch.msgid.link/20260731085915.326775-4-fanwu01@zju.edu.cn
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[ changed upstream's `timer_delete_sync()` deletion to match this tree's `del_timer_sync()` spelling at the old call site ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/serial/amba-pl011.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1171,7 +1171,7 @@ static void pl011_dma_shutdown(struct ua
if (uap->using_tx_dma) {
/* In theory, this should already be done by pl011_dma_flush_buffer */
- dmaengine_terminate_all(uap->dmatx.chan);
+ dmaengine_terminate_sync(uap->dmatx.chan);
if (uap->dmatx.queued) {
dma_unmap_single(uap->dmatx.chan->device->dev,
uap->dmatx.dma, uap->dmatx.len,
@@ -1184,12 +1184,12 @@ static void pl011_dma_shutdown(struct ua
}
if (uap->using_rx_dma) {
- dmaengine_terminate_all(uap->dmarx.chan);
+ if (uap->dmarx.poll_rate)
+ timer_delete_sync(&uap->dmarx.timer);
+ dmaengine_terminate_sync(uap->dmarx.chan);
/* Clean up the RX DMA */
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
- if (uap->dmarx.poll_rate)
- del_timer_sync(&uap->dmarx.timer);
uap->using_rx_dma = false;
}
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 17/77] serial: sc16is7xx: rename EFR mutex with generic name
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (15 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 16/77] serial: amba-pl011: synchronize DMA teardown Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 18/77] serial: sc16is7xx: use guards for simple mutex locks Greg Kroah-Hartman
` (67 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Hugo Villeneuve, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
[ Upstream commit d9b2d7ddbb973b981c20b21e9228581bb156f66f ]
This mutex is used as a lock when accessing registers that share the same
address space, not necessarily EFR registers.
For example, address 0x06 is shared by MSR, TCR and XOFF1 registers,
independently of EFR.
Rename the mutex with a more generic name to avoid misinterpreting its
usage.
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Link: https://patch.msgid.link/20251027142957.1032073-3-hugo@hugovil.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: 246ac114f485 ("serial: sc16is7xx: enable THRI before filling TX FIFO")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/serial/sc16is7xx.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -327,7 +327,7 @@ struct sc16is7xx_one_config {
struct sc16is7xx_one {
struct uart_port port;
struct regmap *regmap;
- struct mutex efr_lock; /* EFR registers access */
+ struct mutex lock; /* For registers sharing same address space. */
struct kthread_work tx_work;
struct kthread_work reg_work;
struct kthread_delayed_work ms_work;
@@ -433,7 +433,7 @@ static void sc16is7xx_efr_lock(struct ua
{
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- mutex_lock(&one->efr_lock);
+ mutex_lock(&one->lock);
/* Backup content of LCR. */
one->old_lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
@@ -455,7 +455,7 @@ static void sc16is7xx_efr_unlock(struct
/* Restore original content of LCR */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, one->old_lcr);
- mutex_unlock(&one->efr_lock);
+ mutex_unlock(&one->lock);
}
static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit)
@@ -590,7 +590,7 @@ static int sc16is7xx_set_baud(struct uar
SC16IS7XX_MCR_CLKSEL_BIT,
prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT);
- mutex_lock(&one->efr_lock);
+ mutex_lock(&one->lock);
/* Backup LCR and access special register set (DLL/DLH) */
lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
@@ -606,7 +606,7 @@ static int sc16is7xx_set_baud(struct uar
/* Restore LCR and access to general register set */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
- mutex_unlock(&one->efr_lock);
+ mutex_unlock(&one->lock);
return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div);
}
@@ -753,7 +753,7 @@ static void sc16is7xx_update_mlines(stru
unsigned long flags;
unsigned int status, changed;
- lockdep_assert_held_once(&one->efr_lock);
+ lockdep_assert_held_once(&one->lock);
status = sc16is7xx_get_hwmctrl(port);
changed = status ^ one->old_mctrl;
@@ -784,7 +784,7 @@ static bool sc16is7xx_port_irq(struct sc
struct uart_port *port = &s->p[portno].port;
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- mutex_lock(&one->efr_lock);
+ mutex_lock(&one->lock);
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
if (iir & SC16IS7XX_IIR_NO_INT_BIT) {
@@ -831,7 +831,7 @@ static bool sc16is7xx_port_irq(struct sc
}
out_port_irq:
- mutex_unlock(&one->efr_lock);
+ mutex_unlock(&one->lock);
return rc;
}
@@ -863,9 +863,9 @@ static void sc16is7xx_tx_proc(struct kth
(port->rs485.delay_rts_before_send > 0))
msleep(port->rs485.delay_rts_before_send);
- mutex_lock(&one->efr_lock);
+ mutex_lock(&one->lock);
sc16is7xx_handle_tx(port);
- mutex_unlock(&one->efr_lock);
+ mutex_unlock(&one->lock);
}
static void sc16is7xx_reconf_rs485(struct uart_port *port)
@@ -932,9 +932,9 @@ static void sc16is7xx_ms_proc(struct kth
struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
if (one->port.state) {
- mutex_lock(&one->efr_lock);
+ mutex_lock(&one->lock);
sc16is7xx_update_mlines(one);
- mutex_unlock(&one->efr_lock);
+ mutex_unlock(&one->lock);
kthread_queue_delayed_work(&s->kworker, &one->ms_work, HZ);
}
@@ -1604,7 +1604,7 @@ int sc16is7xx_probe(struct device *dev,
s->p[i].old_mctrl = 0;
s->p[i].regmap = regmaps[i];
- mutex_init(&s->p[i].efr_lock);
+ mutex_init(&s->p[i].lock);
ret = uart_get_rs485_mode(&s->p[i].port);
if (ret)
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 18/77] serial: sc16is7xx: use guards for simple mutex locks
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (16 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 17/77] serial: sc16is7xx: rename EFR mutex with generic name Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 19/77] serial: sc16is7xx: enable THRI before filling TX FIFO Greg Kroah-Hartman
` (66 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Hugo Villeneuve, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hugo Villeneuve <hvilleneuve@dimonoff.com>
[ Upstream commit 0f4f88bfd7e7bf3f3293045fffdc63586b0a889f ]
Guards can help to make the code more readable, so use them wherever they
do so.
In sc16is7xx_port_irq(), labels and 'rc' locals are eliminated completely.
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Link: https://patch.msgid.link/20251027142957.1032073-6-hugo@hugovil.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: 246ac114f485 ("serial: sc16is7xx: enable THRI before filling TX FIFO")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/serial/sc16is7xx.c | 23 ++++++++---------------
1 file changed, 8 insertions(+), 15 deletions(-)
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -11,6 +11,7 @@
#define DEFAULT_SYMBOL_NAMESPACE "SERIAL_NXP_SC16IS7XX"
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -779,18 +780,15 @@ static void sc16is7xx_update_mlines(stru
static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
{
- bool rc = true;
unsigned int iir, rxlen;
struct uart_port *port = &s->p[portno].port;
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- mutex_lock(&one->lock);
+ guard(mutex)(&one->lock);
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
- if (iir & SC16IS7XX_IIR_NO_INT_BIT) {
- rc = false;
- goto out_port_irq;
- }
+ if (iir & SC16IS7XX_IIR_NO_INT_BIT)
+ return false;
iir &= SC16IS7XX_IIR_ID_MASK;
@@ -830,10 +828,7 @@ static bool sc16is7xx_port_irq(struct sc
break;
}
-out_port_irq:
- mutex_unlock(&one->lock);
-
- return rc;
+ return true;
}
static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
@@ -863,9 +858,8 @@ static void sc16is7xx_tx_proc(struct kth
(port->rs485.delay_rts_before_send > 0))
msleep(port->rs485.delay_rts_before_send);
- mutex_lock(&one->lock);
+ guard(mutex)(&one->lock);
sc16is7xx_handle_tx(port);
- mutex_unlock(&one->lock);
}
static void sc16is7xx_reconf_rs485(struct uart_port *port)
@@ -932,9 +926,8 @@ static void sc16is7xx_ms_proc(struct kth
struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
if (one->port.state) {
- mutex_lock(&one->lock);
- sc16is7xx_update_mlines(one);
- mutex_unlock(&one->lock);
+ scoped_guard(mutex, &one->lock)
+ sc16is7xx_update_mlines(one);
kthread_queue_delayed_work(&s->kworker, &one->ms_work, HZ);
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 19/77] serial: sc16is7xx: enable THRI before filling TX FIFO
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (17 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 18/77] serial: sc16is7xx: use guards for simple mutex locks Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 20/77] xfs: namespace the maximum length/refcount symbols Greg Kroah-Hartman
` (65 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, stable, Luca Fresi, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luca Fresi <luca.fresi@bithiatec.com>
[ Upstream commit 246ac114f485c2affb454240f3ea4fabfce22456 ]
sc16is7xx_handle_tx() currently requests the THRI enable only after it has
filled the TX FIFO. The request is asynchronous because the IER update is
performed later by reg_work.
The SC16IS7xx generates a THRI interrupt when the TX FIFO crosses its
trigger level. If the FIFO drains past that level before reg_work enables
THRI, the chip does not generate a new interrupt. Characters remain queued
indefinitely even though the hardware FIFO is empty.
This was observed on an SC16IS752 while both UART channels were active.
During the stall the software TX buffer remained non-empty while TXLVL
reported 64 bytes free, LSR reported THR and transmitter empty, IER had
THRI enabled, and IIR reported no interrupt pending.
Enable THRI synchronously before filling the FIFO so the threshold crossing
cannot be missed.
Fixes: cc4c1d05eb10 ("sc16is7xx: Properly resume TX after stop")
Cc: stable <stable@kernel.org>
Signed-off-by: Luca Fresi <luca.fresi@bithiatec.com>
Link: https://patch.msgid.link/20260721222404.204746-1-luca.fresi@bithiatec.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/serial/sc16is7xx.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -859,6 +859,9 @@ static void sc16is7xx_tx_proc(struct kth
msleep(port->rs485.delay_rts_before_send);
guard(mutex)(&one->lock);
+ sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
+ SC16IS7XX_IER_THRI_BIT,
+ SC16IS7XX_IER_THRI_BIT);
sc16is7xx_handle_tx(port);
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 20/77] xfs: namespace the maximum length/refcount symbols
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (18 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 19/77] serial: sc16is7xx: enable THRI before filling TX FIFO Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 21/77] xfs: dont use a xfs_log_iovec for ri_buf in log recovery Greg Kroah-Hartman
` (64 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <djwong@kernel.org>
[ Upstream commit 70fcf6866578e69635399e806273376f5e0b8e2b ]
Actually namespace these variables properly, so that readers can tell
that this is an XFS symbol, and that it's for the refcount
functionality.
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Stable-dep-of: 813f8136a2ce ("xfs: bounds-check buffer log item's dirty bitmap")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/xfs/libxfs/xfs_format.h | 4 ++--
fs/xfs/libxfs/xfs_refcount.c | 18 +++++++++---------
fs/xfs/scrub/refcount.c | 2 +-
fs/xfs/scrub/refcount_repair.c | 4 ++--
4 files changed, 14 insertions(+), 14 deletions(-)
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1625,8 +1625,8 @@ struct xfs_refcount_key {
__be32 rc_startblock; /* starting block number */
};
-#define MAXREFCOUNT ((xfs_nlink_t)~0U)
-#define MAXREFCEXTLEN ((xfs_extlen_t)~0U)
+#define XFS_REFC_REFCOUNT_MAX ((xfs_nlink_t)~0U)
+#define XFS_REFC_LEN_MAX ((xfs_extlen_t)~0U)
/* btree pointer type */
typedef __be32 xfs_refcount_ptr_t;
--- a/fs/xfs/libxfs/xfs_refcount.c
+++ b/fs/xfs/libxfs/xfs_refcount.c
@@ -128,7 +128,7 @@ xfs_refcount_check_irec(
struct xfs_perag *pag,
const struct xfs_refcount_irec *irec)
{
- if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
+ if (irec->rc_blockcount == 0 || irec->rc_blockcount > XFS_REFC_LEN_MAX)
return __this_address;
if (!xfs_refcount_check_domain(irec))
@@ -138,7 +138,7 @@ xfs_refcount_check_irec(
if (!xfs_verify_agbext(pag, irec->rc_startblock, irec->rc_blockcount))
return __this_address;
- if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
+ if (irec->rc_refcount == 0 || irec->rc_refcount > XFS_REFC_REFCOUNT_MAX)
return __this_address;
return NULL;
@@ -853,9 +853,9 @@ xfs_refc_merge_refcount(
const struct xfs_refcount_irec *irec,
enum xfs_refc_adjust_op adjust)
{
- /* Once a record hits MAXREFCOUNT, it is pinned there forever */
- if (irec->rc_refcount == MAXREFCOUNT)
- return MAXREFCOUNT;
+ /* Once a record hits XFS_REFC_REFCOUNT_MAX, it is pinned forever */
+ if (irec->rc_refcount == XFS_REFC_REFCOUNT_MAX)
+ return XFS_REFC_REFCOUNT_MAX;
return irec->rc_refcount + adjust;
}
@@ -898,7 +898,7 @@ xfs_refc_want_merge_center(
* hence we need to catch u32 addition overflows here.
*/
ulen += cleft->rc_blockcount + right->rc_blockcount;
- if (ulen >= MAXREFCEXTLEN)
+ if (ulen >= XFS_REFC_LEN_MAX)
return false;
*ulenp = ulen;
@@ -933,7 +933,7 @@ xfs_refc_want_merge_left(
* hence we need to catch u32 addition overflows here.
*/
ulen += cleft->rc_blockcount;
- if (ulen >= MAXREFCEXTLEN)
+ if (ulen >= XFS_REFC_LEN_MAX)
return false;
return true;
@@ -967,7 +967,7 @@ xfs_refc_want_merge_right(
* hence we need to catch u32 addition overflows here.
*/
ulen += cright->rc_blockcount;
- if (ulen >= MAXREFCEXTLEN)
+ if (ulen >= XFS_REFC_LEN_MAX)
return false;
return true;
@@ -1196,7 +1196,7 @@ xfs_refcount_adjust_extents(
* Adjust the reference count and either update the tree
* (incr) or free the blocks (decr).
*/
- if (ext.rc_refcount == MAXREFCOUNT)
+ if (ext.rc_refcount == XFS_REFC_REFCOUNT_MAX)
goto skip;
ext.rc_refcount += adj;
trace_xfs_refcount_modify_extent(cur, &ext);
--- a/fs/xfs/scrub/refcount.c
+++ b/fs/xfs/scrub/refcount.c
@@ -421,7 +421,7 @@ xchk_refcount_mergeable(
if (r1->rc_refcount != r2->rc_refcount)
return false;
if ((unsigned long long)r1->rc_blockcount + r2->rc_blockcount >
- MAXREFCEXTLEN)
+ XFS_REFC_LEN_MAX)
return false;
return true;
--- a/fs/xfs/scrub/refcount_repair.c
+++ b/fs/xfs/scrub/refcount_repair.c
@@ -177,7 +177,7 @@ xrep_refc_stash(
if (xchk_should_terminate(sc, &error))
return error;
- irec.rc_refcount = min_t(uint64_t, MAXREFCOUNT, refcount);
+ irec.rc_refcount = min_t(uint64_t, XFS_REFC_REFCOUNT_MAX, refcount);
error = xrep_refc_check_ext(rr->sc, &irec);
if (error)
@@ -416,7 +416,7 @@ xrep_refc_find_refcounts(
/*
* Set up a bag to store all the rmap records that we're tracking to
* generate a reference count record. If the size of the bag exceeds
- * MAXREFCOUNT, we clamp rc_refcount.
+ * XFS_REFC_REFCOUNT_MAX, we clamp rc_refcount.
*/
error = rcbag_init(sc->mp, sc->xmbtp, &rcstack);
if (error)
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 21/77] xfs: dont use a xfs_log_iovec for ri_buf in log recovery
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (19 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 20/77] xfs: namespace the maximum length/refcount symbols Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 22/77] xfs: bounds-check buffer log items dirty bitmap Greg Kroah-Hartman
` (63 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christoph Hellwig, Carlos Maiolino,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christoph Hellwig <hch@lst.de>
[ Upstream commit ded74fddcaf685a9440c5612f7831d0c4c1473ca ]
ri_buf just holds a pointer/len pair and is not a log iovec used for
writing to the log. Switch to use a kvec instead.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Stable-dep-of: 813f8136a2ce ("xfs: bounds-check buffer log item's dirty bitmap")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/xfs/libxfs/xfs_log_recover.h | 4 +--
fs/xfs/xfs_attr_item.c | 32 ++++++++++++++--------------
fs/xfs/xfs_bmap_item.c | 18 ++++++++--------
fs/xfs/xfs_buf_item.c | 8 +++----
fs/xfs/xfs_buf_item.h | 2 -
fs/xfs/xfs_buf_item_recover.c | 38 ++++++++++++++++-----------------
fs/xfs/xfs_dquot_item_recover.c | 20 ++++++++---------
fs/xfs/xfs_exchmaps_item.c | 8 +++----
fs/xfs/xfs_extfree_item.c | 45 +++++++++++++++++++++-------------------
fs/xfs/xfs_icreate_item.c | 2 -
fs/xfs/xfs_inode_item.c | 6 ++---
fs/xfs/xfs_inode_item.h | 4 +--
fs/xfs/xfs_inode_item_recover.c | 26 +++++++++++------------
fs/xfs/xfs_log_recover.c | 16 +++++++-------
fs/xfs/xfs_refcount_item.c | 16 +++++++-------
fs/xfs/xfs_rmap_item.c | 16 +++++++-------
fs/xfs/xfs_trans.h | 1
17 files changed, 132 insertions(+), 130 deletions(-)
--- a/fs/xfs/libxfs/xfs_log_recover.h
+++ b/fs/xfs/libxfs/xfs_log_recover.h
@@ -98,7 +98,7 @@ struct xlog_recover_item {
struct list_head ri_list;
int ri_cnt; /* count of regions found */
int ri_total; /* total regions */
- struct xfs_log_iovec *ri_buf; /* ptr to regions buffer */
+ struct kvec *ri_buf; /* ptr to regions buffer */
const struct xlog_recover_item_ops *ri_ops;
};
@@ -111,7 +111,7 @@ struct xlog_recover {
struct list_head r_itemq; /* q for items */
};
-#define ITEM_TYPE(i) (*(unsigned short *)(i)->ri_buf[0].i_addr)
+#define ITEM_TYPE(i) (*(unsigned short *)(i)->ri_buf[0].iov_base)
#define XLOG_RECOVER_CRCPASS 0
#define XLOG_RECOVER_PASS1 1
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -952,50 +952,50 @@ static inline void *
xfs_attri_validate_name_iovec(
struct xfs_mount *mp,
struct xfs_attri_log_format *attri_formatp,
- const struct xfs_log_iovec *iovec,
+ const struct kvec *iovec,
unsigned int name_len)
{
- if (iovec->i_len != xlog_calc_iovec_len(name_len)) {
+ if (iovec->iov_len != xlog_calc_iovec_len(name_len)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
attri_formatp, sizeof(*attri_formatp));
return NULL;
}
- if (!xfs_attr_namecheck(attri_formatp->alfi_attr_filter, iovec->i_addr,
+ if (!xfs_attr_namecheck(attri_formatp->alfi_attr_filter, iovec->iov_base,
name_len)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
attri_formatp, sizeof(*attri_formatp));
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- iovec->i_addr, iovec->i_len);
+ iovec->iov_base, iovec->iov_len);
return NULL;
}
- return iovec->i_addr;
+ return iovec->iov_base;
}
static inline void *
xfs_attri_validate_value_iovec(
struct xfs_mount *mp,
struct xfs_attri_log_format *attri_formatp,
- const struct xfs_log_iovec *iovec,
+ const struct kvec *iovec,
unsigned int value_len)
{
- if (iovec->i_len != xlog_calc_iovec_len(value_len)) {
+ if (iovec->iov_len != xlog_calc_iovec_len(value_len)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
attri_formatp, sizeof(*attri_formatp));
return NULL;
}
if ((attri_formatp->alfi_attr_filter & XFS_ATTR_PARENT) &&
- !xfs_parent_valuecheck(mp, iovec->i_addr, value_len)) {
+ !xfs_parent_valuecheck(mp, iovec->iov_base, value_len)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
attri_formatp, sizeof(*attri_formatp));
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- iovec->i_addr, iovec->i_len);
+ iovec->iov_base, iovec->iov_len);
return NULL;
}
- return iovec->i_addr;
+ return iovec->iov_base;
}
STATIC int
@@ -1022,13 +1022,13 @@ xlog_recover_attri_commit_pass2(
/* Validate xfs_attri_log_format before the large memory allocation */
len = sizeof(struct xfs_attri_log_format);
- if (item->ri_buf[i].i_len != len) {
+ if (item->ri_buf[i].iov_len != len) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
- attri_formatp = item->ri_buf[i].i_addr;
+ attri_formatp = item->ri_buf[i].iov_base;
if (!xfs_attri_validate(mp, attri_formatp)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
attri_formatp, len);
@@ -1217,10 +1217,10 @@ xlog_recover_attrd_commit_pass2(
{
struct xfs_attrd_log_format *attrd_formatp;
- attrd_formatp = item->ri_buf[0].i_addr;
- if (item->ri_buf[0].i_len != sizeof(struct xfs_attrd_log_format)) {
+ attrd_formatp = item->ri_buf[0].iov_base;
+ if (item->ri_buf[0].iov_len != sizeof(struct xfs_attrd_log_format)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
--- a/fs/xfs/xfs_bmap_item.c
+++ b/fs/xfs/xfs_bmap_item.c
@@ -653,24 +653,24 @@ xlog_recover_bui_commit_pass2(
struct xfs_bui_log_format *bui_formatp;
size_t len;
- bui_formatp = item->ri_buf[0].i_addr;
+ bui_formatp = item->ri_buf[0].iov_base;
- if (item->ri_buf[0].i_len < xfs_bui_log_format_sizeof(0)) {
+ if (item->ri_buf[0].iov_len < xfs_bui_log_format_sizeof(0)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
len = xfs_bui_log_format_sizeof(bui_formatp->bui_nextents);
- if (item->ri_buf[0].i_len != len) {
+ if (item->ri_buf[0].iov_len != len) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
@@ -704,10 +704,10 @@ xlog_recover_bud_commit_pass2(
{
struct xfs_bud_log_format *bud_formatp;
- bud_formatp = item->ri_buf[0].i_addr;
- if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format)) {
+ bud_formatp = item->ri_buf[0].iov_base;
+ if (item->ri_buf[0].iov_len != sizeof(struct xfs_bud_log_format)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -35,16 +35,16 @@ static inline struct xfs_buf_log_item *B
/* Is this log iovec plausibly large enough to contain the buffer log format? */
bool
xfs_buf_log_check_iovec(
- struct xfs_log_iovec *iovec)
+ struct kvec *iovec)
{
- struct xfs_buf_log_format *blfp = iovec->i_addr;
+ struct xfs_buf_log_format *blfp = iovec->iov_base;
char *bmp_end;
char *item_end;
- if (offsetof(struct xfs_buf_log_format, blf_data_map) > iovec->i_len)
+ if (offsetof(struct xfs_buf_log_format, blf_data_map) > iovec->iov_len)
return false;
- item_end = (char *)iovec->i_addr + iovec->i_len;
+ item_end = (char *)iovec->iov_base + iovec->iov_len;
bmp_end = (char *)&blfp->blf_data_map[blfp->blf_map_size];
return bmp_end <= item_end;
}
--- a/fs/xfs/xfs_buf_item.h
+++ b/fs/xfs/xfs_buf_item.h
@@ -67,7 +67,7 @@ static inline void xfs_buf_dquot_io_fail
}
#endif /* CONFIG_XFS_QUOTA */
void xfs_buf_iodone(struct xfs_buf *);
-bool xfs_buf_log_check_iovec(struct xfs_log_iovec *iovec);
+bool xfs_buf_log_check_iovec(struct kvec *iovec);
extern struct kmem_cache *xfs_buf_item_cache;
--- a/fs/xfs/xfs_buf_item_recover.c
+++ b/fs/xfs/xfs_buf_item_recover.c
@@ -157,7 +157,7 @@ STATIC enum xlog_recover_reorder
xlog_recover_buf_reorder(
struct xlog_recover_item *item)
{
- struct xfs_buf_log_format *buf_f = item->ri_buf[0].i_addr;
+ struct xfs_buf_log_format *buf_f = item->ri_buf[0].iov_base;
if (buf_f->blf_flags & XFS_BLF_CANCEL)
return XLOG_REORDER_CANCEL_LIST;
@@ -171,7 +171,7 @@ xlog_recover_buf_ra_pass2(
struct xlog *log,
struct xlog_recover_item *item)
{
- struct xfs_buf_log_format *buf_f = item->ri_buf[0].i_addr;
+ struct xfs_buf_log_format *buf_f = item->ri_buf[0].iov_base;
xlog_buf_readahead(log, buf_f->blf_blkno, buf_f->blf_len, NULL);
}
@@ -185,11 +185,11 @@ xlog_recover_buf_commit_pass1(
struct xlog *log,
struct xlog_recover_item *item)
{
- struct xfs_buf_log_format *bf = item->ri_buf[0].i_addr;
+ struct xfs_buf_log_format *bf = item->ri_buf[0].iov_base;
if (!xfs_buf_log_check_iovec(&item->ri_buf[0])) {
- xfs_err(log->l_mp, "bad buffer log item size (%d)",
- item->ri_buf[0].i_len);
+ xfs_err(log->l_mp, "bad buffer log item size (%zd)",
+ item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
@@ -470,8 +470,8 @@ xlog_recover_do_reg_buffer(
nbits = xfs_contig_bits(buf_f->blf_data_map,
buf_f->blf_map_size, bit);
ASSERT(nbits > 0);
- ASSERT(item->ri_buf[i].i_addr != NULL);
- ASSERT(item->ri_buf[i].i_len % XFS_BLF_CHUNK == 0);
+ ASSERT(item->ri_buf[i].iov_base != NULL);
+ ASSERT(item->ri_buf[i].iov_len % XFS_BLF_CHUNK == 0);
ASSERT(BBTOB(bp->b_length) >=
((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT));
@@ -483,8 +483,8 @@ xlog_recover_do_reg_buffer(
* the log. Hence we need to trim nbits back to the length of
* the current region being copied out of the log.
*/
- if (item->ri_buf[i].i_len < (nbits << XFS_BLF_SHIFT))
- nbits = item->ri_buf[i].i_len >> XFS_BLF_SHIFT;
+ if (item->ri_buf[i].iov_len < (nbits << XFS_BLF_SHIFT))
+ nbits = item->ri_buf[i].iov_len >> XFS_BLF_SHIFT;
/*
* Do a sanity check if this is a dquot buffer. Just checking
@@ -494,18 +494,18 @@ xlog_recover_do_reg_buffer(
fa = NULL;
if (buf_f->blf_flags &
(XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
- if (item->ri_buf[i].i_addr == NULL) {
+ if (item->ri_buf[i].iov_base == NULL) {
xfs_alert(mp,
"XFS: NULL dquot in %s.", __func__);
goto next;
}
- if (item->ri_buf[i].i_len < size_disk_dquot) {
+ if (item->ri_buf[i].iov_len < size_disk_dquot) {
xfs_alert(mp,
- "XFS: dquot too small (%d) in %s.",
- item->ri_buf[i].i_len, __func__);
+ "XFS: dquot too small (%zd) in %s.",
+ item->ri_buf[i].iov_len, __func__);
goto next;
}
- fa = xfs_dquot_verify(mp, item->ri_buf[i].i_addr, -1);
+ fa = xfs_dquot_verify(mp, item->ri_buf[i].iov_base, -1);
if (fa) {
xfs_alert(mp,
"dquot corrupt at %pS trying to replay into block 0x%llx",
@@ -516,7 +516,7 @@ xlog_recover_do_reg_buffer(
memcpy(xfs_buf_offset(bp,
(uint)bit << XFS_BLF_SHIFT), /* dest */
- item->ri_buf[i].i_addr, /* source */
+ item->ri_buf[i].iov_base, /* source */
nbits<<XFS_BLF_SHIFT); /* length */
next:
i++;
@@ -652,8 +652,8 @@ xlog_recover_do_inode_buffer(
if (next_unlinked_offset < reg_buf_offset)
continue;
- ASSERT(item->ri_buf[item_index].i_addr != NULL);
- ASSERT((item->ri_buf[item_index].i_len % XFS_BLF_CHUNK) == 0);
+ ASSERT(item->ri_buf[item_index].iov_base != NULL);
+ ASSERT((item->ri_buf[item_index].iov_len % XFS_BLF_CHUNK) == 0);
ASSERT((reg_buf_offset + reg_buf_bytes) <= BBTOB(bp->b_length));
/*
@@ -661,7 +661,7 @@ xlog_recover_do_inode_buffer(
* current di_next_unlinked field. Extract its value
* and copy it to the buffer copy.
*/
- logged_nextp = item->ri_buf[item_index].i_addr +
+ logged_nextp = item->ri_buf[item_index].iov_base +
next_unlinked_offset - reg_buf_offset;
if (XFS_IS_CORRUPT(mp, *logged_nextp == 0)) {
xfs_alert(mp,
@@ -951,7 +951,7 @@ xlog_recover_buf_commit_pass2(
struct xlog_recover_item *item,
xfs_lsn_t current_lsn)
{
- struct xfs_buf_log_format *buf_f = item->ri_buf[0].i_addr;
+ struct xfs_buf_log_format *buf_f = item->ri_buf[0].iov_base;
struct xfs_mount *mp = log->l_mp;
struct xfs_buf *bp;
int error;
--- a/fs/xfs/xfs_dquot_item_recover.c
+++ b/fs/xfs/xfs_dquot_item_recover.c
@@ -34,10 +34,10 @@ xlog_recover_dquot_ra_pass2(
if (mp->m_qflags == 0)
return;
- recddq = item->ri_buf[1].i_addr;
+ recddq = item->ri_buf[1].iov_base;
if (recddq == NULL)
return;
- if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot))
+ if (item->ri_buf[1].iov_len < sizeof(struct xfs_disk_dquot))
return;
type = recddq->d_type & XFS_DQTYPE_REC_MASK;
@@ -45,7 +45,7 @@ xlog_recover_dquot_ra_pass2(
if (log->l_quotaoffs_flag & type)
return;
- dq_f = item->ri_buf[0].i_addr;
+ dq_f = item->ri_buf[0].iov_base;
ASSERT(dq_f);
ASSERT(dq_f->qlf_len == 1);
@@ -79,14 +79,14 @@ xlog_recover_dquot_commit_pass2(
if (mp->m_qflags == 0)
return 0;
- recddq = item->ri_buf[1].i_addr;
+ recddq = item->ri_buf[1].iov_base;
if (recddq == NULL) {
xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);
return -EFSCORRUPTED;
}
- if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) {
- xfs_alert(log->l_mp, "dquot too small (%d) in %s.",
- item->ri_buf[1].i_len, __func__);
+ if (item->ri_buf[1].iov_len < sizeof(struct xfs_disk_dquot)) {
+ xfs_alert(log->l_mp, "dquot too small (%zd) in %s.",
+ item->ri_buf[1].iov_len, __func__);
return -EFSCORRUPTED;
}
@@ -108,7 +108,7 @@ xlog_recover_dquot_commit_pass2(
* The other possibility, of course, is that the quota subsystem was
* removed since the last mount - ENOSYS.
*/
- dq_f = item->ri_buf[0].i_addr;
+ dq_f = item->ri_buf[0].iov_base;
ASSERT(dq_f);
fa = xfs_dquot_verify(mp, recddq, dq_f->qlf_id);
if (fa) {
@@ -147,7 +147,7 @@ xlog_recover_dquot_commit_pass2(
}
}
- memcpy(ddq, recddq, item->ri_buf[1].i_len);
+ memcpy(ddq, recddq, item->ri_buf[1].iov_len);
if (xfs_has_crc(mp)) {
xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk),
XFS_DQUOT_CRC_OFF);
@@ -192,7 +192,7 @@ xlog_recover_quotaoff_commit_pass1(
struct xlog *log,
struct xlog_recover_item *item)
{
- struct xfs_qoff_logformat *qoff_f = item->ri_buf[0].i_addr;
+ struct xfs_qoff_logformat *qoff_f = item->ri_buf[0].iov_base;
ASSERT(qoff_f);
/*
--- a/fs/xfs/xfs_exchmaps_item.c
+++ b/fs/xfs/xfs_exchmaps_item.c
@@ -558,12 +558,12 @@ xlog_recover_xmi_commit_pass2(
size_t len;
len = sizeof(struct xfs_xmi_log_format);
- if (item->ri_buf[0].i_len != len) {
+ if (item->ri_buf[0].iov_len != len) {
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
return -EFSCORRUPTED;
}
- xmi_formatp = item->ri_buf[0].i_addr;
+ xmi_formatp = item->ri_buf[0].iov_base;
if (xmi_formatp->__pad != 0) {
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
return -EFSCORRUPTED;
@@ -598,8 +598,8 @@ xlog_recover_xmd_commit_pass2(
{
struct xfs_xmd_log_format *xmd_formatp;
- xmd_formatp = item->ri_buf[0].i_addr;
- if (item->ri_buf[0].i_len != sizeof(struct xfs_xmd_log_format)) {
+ xmd_formatp = item->ri_buf[0].iov_base;
+ if (item->ri_buf[0].iov_len != sizeof(struct xfs_xmd_log_format)) {
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, log->l_mp);
return -EFSCORRUPTED;
}
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -171,15 +171,18 @@ xfs_efi_init(
* It will handle the conversion of formats if necessary.
*/
STATIC int
-xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt)
-{
- xfs_efi_log_format_t *src_efi_fmt = buf->i_addr;
- uint i;
- uint len = xfs_efi_log_format_sizeof(src_efi_fmt->efi_nextents);
- uint len32 = xfs_efi_log_format32_sizeof(src_efi_fmt->efi_nextents);
- uint len64 = xfs_efi_log_format64_sizeof(src_efi_fmt->efi_nextents);
+xfs_efi_copy_format(
+ struct kvec *buf,
+ struct xfs_efi_log_format *dst_efi_fmt)
+{
+ struct xfs_efi_log_format *src_efi_fmt = buf->iov_base;
+ uint len, len32, len64, i;
+
+ len = xfs_efi_log_format_sizeof(src_efi_fmt->efi_nextents);
+ len32 = xfs_efi_log_format32_sizeof(src_efi_fmt->efi_nextents);
+ len64 = xfs_efi_log_format64_sizeof(src_efi_fmt->efi_nextents);
- if (buf->i_len == len) {
+ if (buf->iov_len == len) {
memcpy(dst_efi_fmt, src_efi_fmt,
offsetof(struct xfs_efi_log_format, efi_extents));
for (i = 0; i < src_efi_fmt->efi_nextents; i++)
@@ -187,8 +190,8 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf
&src_efi_fmt->efi_extents[i],
sizeof(struct xfs_extent));
return 0;
- } else if (buf->i_len == len32) {
- xfs_efi_log_format_32_t *src_efi_fmt_32 = buf->i_addr;
+ } else if (buf->iov_len == len32) {
+ xfs_efi_log_format_32_t *src_efi_fmt_32 = buf->iov_base;
dst_efi_fmt->efi_type = src_efi_fmt_32->efi_type;
dst_efi_fmt->efi_size = src_efi_fmt_32->efi_size;
@@ -201,8 +204,8 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf
src_efi_fmt_32->efi_extents[i].ext_len;
}
return 0;
- } else if (buf->i_len == len64) {
- xfs_efi_log_format_64_t *src_efi_fmt_64 = buf->i_addr;
+ } else if (buf->iov_len == len64) {
+ xfs_efi_log_format_64_t *src_efi_fmt_64 = buf->iov_base;
dst_efi_fmt->efi_type = src_efi_fmt_64->efi_type;
dst_efi_fmt->efi_size = src_efi_fmt_64->efi_size;
@@ -216,8 +219,8 @@ xfs_efi_copy_format(xfs_log_iovec_t *buf
}
return 0;
}
- XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, NULL, buf->i_addr,
- buf->i_len);
+ XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, NULL, buf->iov_base,
+ buf->iov_len);
return -EFSCORRUPTED;
}
@@ -723,11 +726,11 @@ xlog_recover_efi_commit_pass2(
struct xfs_efi_log_format *efi_formatp;
int error;
- efi_formatp = item->ri_buf[0].i_addr;
+ efi_formatp = item->ri_buf[0].iov_base;
- if (item->ri_buf[0].i_len < xfs_efi_log_format_sizeof(0)) {
+ if (item->ri_buf[0].iov_len < xfs_efi_log_format_sizeof(0)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
@@ -764,9 +767,9 @@ xlog_recover_efd_commit_pass2(
xfs_lsn_t lsn)
{
struct xfs_efd_log_format *efd_formatp;
- int buflen = item->ri_buf[0].i_len;
+ int buflen = item->ri_buf[0].iov_len;
- efd_formatp = item->ri_buf[0].i_addr;
+ efd_formatp = item->ri_buf[0].iov_base;
if (buflen < sizeof(struct xfs_efd_log_format)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
@@ -774,9 +777,9 @@ xlog_recover_efd_commit_pass2(
return -EFSCORRUPTED;
}
- if (item->ri_buf[0].i_len != xfs_efd_log_format32_sizeof(
+ if (item->ri_buf[0].iov_len != xfs_efd_log_format32_sizeof(
efd_formatp->efd_nextents) &&
- item->ri_buf[0].i_len != xfs_efd_log_format64_sizeof(
+ item->ri_buf[0].iov_len != xfs_efd_log_format64_sizeof(
efd_formatp->efd_nextents)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
efd_formatp, buflen);
--- a/fs/xfs/xfs_icreate_item.c
+++ b/fs/xfs/xfs_icreate_item.c
@@ -158,7 +158,7 @@ xlog_recover_icreate_commit_pass2(
int nbufs;
int i;
- icl = (struct xfs_icreate_log *)item->ri_buf[0].i_addr;
+ icl = (struct xfs_icreate_log *)item->ri_buf[0].iov_base;
if (icl->icl_type != XFS_LI_ICREATE) {
xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad type");
return -EINVAL;
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -1180,12 +1180,12 @@ xfs_iflush_shutdown_abort(
*/
int
xfs_inode_item_format_convert(
- struct xfs_log_iovec *buf,
+ struct kvec *buf,
struct xfs_inode_log_format *in_f)
{
- struct xfs_inode_log_format_32 *in_f32 = buf->i_addr;
+ struct xfs_inode_log_format_32 *in_f32 = buf->iov_base;
- if (buf->i_len != sizeof(*in_f32)) {
+ if (buf->iov_len != sizeof(*in_f32)) {
XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL);
return -EFSCORRUPTED;
}
--- a/fs/xfs/xfs_inode_item.h
+++ b/fs/xfs/xfs_inode_item.h
@@ -46,8 +46,8 @@ extern void xfs_inode_item_init(struct x
extern void xfs_inode_item_destroy(struct xfs_inode *);
extern void xfs_iflush_abort(struct xfs_inode *);
extern void xfs_iflush_shutdown_abort(struct xfs_inode *);
-extern int xfs_inode_item_format_convert(xfs_log_iovec_t *,
- struct xfs_inode_log_format *);
+int xfs_inode_item_format_convert(struct kvec *buf,
+ struct xfs_inode_log_format *in_f);
extern struct kmem_cache *xfs_ili_cache;
--- a/fs/xfs/xfs_inode_item_recover.c
+++ b/fs/xfs/xfs_inode_item_recover.c
@@ -28,13 +28,13 @@ xlog_recover_inode_ra_pass2(
struct xlog *log,
struct xlog_recover_item *item)
{
- if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
- struct xfs_inode_log_format *ilfp = item->ri_buf[0].i_addr;
+ if (item->ri_buf[0].iov_len == sizeof(struct xfs_inode_log_format)) {
+ struct xfs_inode_log_format *ilfp = item->ri_buf[0].iov_base;
xlog_buf_readahead(log, ilfp->ilf_blkno, ilfp->ilf_len,
&xfs_inode_buf_ra_ops);
} else {
- struct xfs_inode_log_format_32 *ilfp = item->ri_buf[0].i_addr;
+ struct xfs_inode_log_format_32 *ilfp = item->ri_buf[0].iov_base;
xlog_buf_readahead(log, ilfp->ilf_blkno, ilfp->ilf_len,
&xfs_inode_buf_ra_ops);
@@ -288,8 +288,8 @@ xlog_recover_inode_commit_pass2(
int need_free = 0;
xfs_failaddr_t fa;
- if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
- in_f = item->ri_buf[0].i_addr;
+ if (item->ri_buf[0].iov_len == sizeof(struct xfs_inode_log_format)) {
+ in_f = item->ri_buf[0].iov_base;
} else {
in_f = kmalloc(sizeof(struct xfs_inode_log_format),
GFP_KERNEL | __GFP_NOFAIL);
@@ -328,7 +328,7 @@ xlog_recover_inode_commit_pass2(
error = -EFSCORRUPTED;
goto out_release;
}
- ldip = item->ri_buf[1].i_addr;
+ ldip = item->ri_buf[1].iov_base;
if (XFS_IS_CORRUPT(mp, ldip->di_magic != XFS_DINODE_MAGIC)) {
xfs_alert(mp,
"%s: Bad inode log record, rec ptr "PTR_FMT", ino %lld",
@@ -433,12 +433,12 @@ xlog_recover_inode_commit_pass2(
goto out_release;
}
isize = xfs_log_dinode_size(mp);
- if (unlikely(item->ri_buf[1].i_len > isize)) {
+ if (unlikely(item->ri_buf[1].iov_len > isize)) {
XFS_CORRUPTION_ERROR("Bad log dinode size", XFS_ERRLEVEL_LOW,
mp, ldip, sizeof(*ldip));
xfs_alert(mp,
- "Bad inode 0x%llx log dinode size 0x%x",
- in_f->ilf_ino, item->ri_buf[1].i_len);
+ "Bad inode 0x%llx log dinode size 0x%zx",
+ in_f->ilf_ino, item->ri_buf[1].iov_len);
error = -EFSCORRUPTED;
goto out_release;
}
@@ -461,8 +461,8 @@ xlog_recover_inode_commit_pass2(
if (in_f->ilf_size == 2)
goto out_owner_change;
- len = item->ri_buf[2].i_len;
- src = item->ri_buf[2].i_addr;
+ len = item->ri_buf[2].iov_len;
+ src = item->ri_buf[2].iov_base;
ASSERT(in_f->ilf_size <= 4);
ASSERT((in_f->ilf_size == 3) || (fields & XFS_ILOG_AFORK));
ASSERT(!(fields & XFS_ILOG_DFORK) ||
@@ -499,8 +499,8 @@ xlog_recover_inode_commit_pass2(
} else {
attr_index = 2;
}
- len = item->ri_buf[attr_index].i_len;
- src = item->ri_buf[attr_index].i_addr;
+ len = item->ri_buf[attr_index].iov_len;
+ src = item->ri_buf[attr_index].iov_base;
ASSERT(len == xlog_calc_iovec_len(in_f->ilf_asize));
switch (in_f->ilf_fields & XFS_ILOG_AFORK) {
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -2135,15 +2135,15 @@ xlog_recover_add_to_cont_trans(
item = list_entry(trans->r_itemq.prev, struct xlog_recover_item,
ri_list);
- old_ptr = item->ri_buf[item->ri_cnt-1].i_addr;
- old_len = item->ri_buf[item->ri_cnt-1].i_len;
+ old_ptr = item->ri_buf[item->ri_cnt-1].iov_base;
+ old_len = item->ri_buf[item->ri_cnt-1].iov_len;
ptr = kvrealloc(old_ptr, len + old_len, GFP_KERNEL);
if (!ptr)
return -ENOMEM;
memcpy(&ptr[old_len], dp, len);
- item->ri_buf[item->ri_cnt-1].i_len += len;
- item->ri_buf[item->ri_cnt-1].i_addr = ptr;
+ item->ri_buf[item->ri_cnt-1].iov_len += len;
+ item->ri_buf[item->ri_cnt-1].iov_base = ptr;
trace_xfs_log_recover_item_add_cont(log, trans, item, 0);
return 0;
}
@@ -2227,7 +2227,7 @@ xlog_recover_add_to_trans(
}
item->ri_total = in_f->ilf_size;
- item->ri_buf = kzalloc(item->ri_total * sizeof(xfs_log_iovec_t),
+ item->ri_buf = kcalloc(item->ri_total, sizeof(*item->ri_buf),
GFP_KERNEL | __GFP_NOFAIL);
}
@@ -2241,8 +2241,8 @@ xlog_recover_add_to_trans(
}
/* Description region is ri_buf[0] */
- item->ri_buf[item->ri_cnt].i_addr = ptr;
- item->ri_buf[item->ri_cnt].i_len = len;
+ item->ri_buf[item->ri_cnt].iov_base = ptr;
+ item->ri_buf[item->ri_cnt].iov_len = len;
item->ri_cnt++;
trace_xfs_log_recover_item_add(log, trans, item, 0);
return 0;
@@ -2266,7 +2266,7 @@ xlog_recover_free_trans(
/* Free the regions in the item. */
list_del(&item->ri_list);
for (i = 0; i < item->ri_cnt; i++)
- kvfree(item->ri_buf[i].i_addr);
+ kvfree(item->ri_buf[i].iov_base);
/* Free the item itself */
kfree(item->ri_buf);
kfree(item);
--- a/fs/xfs/xfs_refcount_item.c
+++ b/fs/xfs/xfs_refcount_item.c
@@ -587,18 +587,18 @@ xlog_recover_cui_commit_pass2(
struct xfs_cui_log_format *cui_formatp;
size_t len;
- cui_formatp = item->ri_buf[0].i_addr;
+ cui_formatp = item->ri_buf[0].iov_base;
- if (item->ri_buf[0].i_len < xfs_cui_log_format_sizeof(0)) {
+ if (item->ri_buf[0].iov_len < xfs_cui_log_format_sizeof(0)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
len = xfs_cui_log_format_sizeof(cui_formatp->cui_nextents);
- if (item->ri_buf[0].i_len != len) {
+ if (item->ri_buf[0].iov_len != len) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
@@ -632,10 +632,10 @@ xlog_recover_cud_commit_pass2(
{
struct xfs_cud_log_format *cud_formatp;
- cud_formatp = item->ri_buf[0].i_addr;
- if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format)) {
+ cud_formatp = item->ri_buf[0].iov_base;
+ if (item->ri_buf[0].iov_len != sizeof(struct xfs_cud_log_format)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
--- a/fs/xfs/xfs_rmap_item.c
+++ b/fs/xfs/xfs_rmap_item.c
@@ -638,18 +638,18 @@ xlog_recover_rui_commit_pass2(
struct xfs_rui_log_format *rui_formatp;
size_t len;
- rui_formatp = item->ri_buf[0].i_addr;
+ rui_formatp = item->ri_buf[0].iov_base;
- if (item->ri_buf[0].i_len < xfs_rui_log_format_sizeof(0)) {
+ if (item->ri_buf[0].iov_len < xfs_rui_log_format_sizeof(0)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
len = xfs_rui_log_format_sizeof(rui_formatp->rui_nextents);
- if (item->ri_buf[0].i_len != len) {
+ if (item->ri_buf[0].iov_len != len) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
- item->ri_buf[0].i_addr, item->ri_buf[0].i_len);
+ item->ri_buf[0].iov_base, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
@@ -683,10 +683,10 @@ xlog_recover_rud_commit_pass2(
{
struct xfs_rud_log_format *rud_formatp;
- rud_formatp = item->ri_buf[0].i_addr;
- if (item->ri_buf[0].i_len != sizeof(struct xfs_rud_log_format)) {
+ rud_formatp = item->ri_buf[0].iov_base;
+ if (item->ri_buf[0].iov_len != sizeof(struct xfs_rud_log_format)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, log->l_mp,
- rud_formatp, item->ri_buf[0].i_len);
+ rud_formatp, item->ri_buf[0].iov_len);
return -EFSCORRUPTED;
}
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -15,7 +15,6 @@ struct xfs_efd_log_item;
struct xfs_efi_log_item;
struct xfs_inode;
struct xfs_item_ops;
-struct xfs_log_iovec;
struct xfs_mount;
struct xfs_trans;
struct xfs_trans_res;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 22/77] xfs: bounds-check buffer log items dirty bitmap
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (20 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 21/77] xfs: dont use a xfs_log_iovec for ri_buf in log recovery Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 23/77] xfs: hoist per-bucket unlinked list check to helper Greg Kroah-Hartman
` (62 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ibrahim Hashimov, Darrick J. Wong,
Brian Foster, Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <security@auditcode.ai>
[ Upstream commit 813f8136a2ce1fee266d02a7df73db6e8a541604 ]
xlog_recover_do_reg_buffer() replays each dirty region described by a
buffer log item's bitmap into the buffer read for that item:
memcpy(xfs_buf_offset(bp, (uint)bit << XFS_BLF_SHIFT),
item->ri_buf[i].iov_base,
nbits << XFS_BLF_SHIFT);
The destination offset (bit/nbits, from the logged dirty bitmap) and the
buffer size (from the logged blf_len) are both attacker-controlled and
otherwise unrelated, yet the only thing bounding the copy is an ASSERT(),
which compiles away on production kernels. A crafted image logging a
small blf_len together with a bitmap bit past the end of that buffer
drives the memcpy() past the buffer's allocation, corrupting adjacent
kernel heap during mount-time log recovery. This is reachable by anyone
who can get a crafted image mounted -- the malicious-filesystem threat
model XFS already guards against elsewhere.
Turn the ASSERT() into a real XFS_IS_CORRUPT() check that aborts recovery
of the buffer with -EFSCORRUPTED, consistent with the validate-and-fail
idiom already used in xlog_recover_do_inode_buffer() and
xfs_dquot_item_recover.c. xlog_recover_do_reg_buffer() therefore becomes
STATIC int and its three callers propagate the error.
Found and confirmed with KASAN on a CONFIG_XFS_DEBUG=n build: the crafted
image trips a slab-out-of-bounds write before this change and fails
recovery cleanly with -EFSCORRUPTED after it.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/xfs/xfs_buf_item_recover.c | 57 ++++++++++++++++++++++++++++++------------
1 file changed, 41 insertions(+), 16 deletions(-)
--- a/fs/xfs/xfs_buf_item_recover.c
+++ b/fs/xfs/xfs_buf_item_recover.c
@@ -444,7 +444,7 @@ xlog_recover_validate_buf_type(
* given buffer. The bitmap in the buf log format structure indicates
* where to place the logged data.
*/
-STATIC void
+STATIC int
xlog_recover_do_reg_buffer(
struct xfs_mount *mp,
struct xlog_recover_item *item,
@@ -472,8 +472,24 @@ xlog_recover_do_reg_buffer(
ASSERT(nbits > 0);
ASSERT(item->ri_buf[i].iov_base != NULL);
ASSERT(item->ri_buf[i].iov_len % XFS_BLF_CHUNK == 0);
- ASSERT(BBTOB(bp->b_length) >=
- ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT));
+ /*
+ * The bitmap is only trustworthy to the extent that it
+ * describes a region that actually fits inside the buffer we
+ * read in based on the (attacker-controlled) blf_len. Do not
+ * rely on an ASSERT() for this -- it compiles away entirely on
+ * non-DEBUG kernels, which is exactly where this matters, so
+ * validate it for real and abort recovery of this buffer rather
+ * than copying past the end of it.
+ */
+ if (XFS_IS_CORRUPT(mp, BBTOB(bp->b_length) <
+ ((uint)bit << XFS_BLF_SHIFT) +
+ (nbits << XFS_BLF_SHIFT))) {
+ xfs_alert(mp,
+ "Bad buffer log item dirty bitmap (bit %d, nbits %d) for %d-byte buffer at daddr 0x%llx.",
+ bit, nbits, BBTOB(bp->b_length),
+ xfs_buf_daddr(bp));
+ return -EFSCORRUPTED;
+ }
/*
* The dirty regions logged in the buffer, even though
@@ -527,6 +543,7 @@ xlog_recover_do_reg_buffer(
ASSERT(i == item->ri_total);
xlog_recover_validate_buf_type(mp, bp, buf_f, current_lsn);
+ return 0;
}
/*
@@ -535,10 +552,10 @@ xlog_recover_do_reg_buffer(
* (ie. USR or GRP), then just toss this buffer away; don't recover it.
* Else, treat it as a regular buffer and do recovery.
*
- * Return false if the buffer was tossed and true if we recovered the buffer to
- * indicate to the caller if the buffer needs writing.
+ * Return 0 if the buffer was not recovered (tossed), 1 if it was recovered and
+ * needs writing, or a negative errno if recovery of the buffer failed.
*/
-STATIC bool
+STATIC int
xlog_recover_do_dquot_buffer(
struct xfs_mount *mp,
struct xlog *log,
@@ -547,6 +564,7 @@ xlog_recover_do_dquot_buffer(
struct xfs_buf_log_format *buf_f)
{
uint type;
+ int error;
trace_xfs_log_recover_buf_dquot_buf(log, buf_f);
@@ -554,7 +572,7 @@ xlog_recover_do_dquot_buffer(
* Filesystems are required to send in quota flags at mount time.
*/
if (!mp->m_qflags)
- return false;
+ return 0;
type = 0;
if (buf_f->blf_flags & XFS_BLF_UDQUOT_BUF)
@@ -567,10 +585,12 @@ xlog_recover_do_dquot_buffer(
* This type of quotas was turned off, so ignore this buffer
*/
if (log->l_quotaoffs_flag & type)
- return false;
+ return 0;
- xlog_recover_do_reg_buffer(mp, item, bp, buf_f, NULLCOMMITLSN);
- return true;
+ error = xlog_recover_do_reg_buffer(mp, item, bp, buf_f, NULLCOMMITLSN);
+ if (error)
+ return error;
+ return 1;
}
/*
@@ -706,7 +726,9 @@ xlog_recover_do_primary_sb_buffer(
xfs_agnumber_t orig_agcount = mp->m_sb.sb_agcount;
int error;
- xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
+ error = xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
+ if (error)
+ return error;
if (orig_agcount == 0) {
xfs_alert(mp, "Trying to grow file system without AGs");
@@ -1026,11 +1048,11 @@ xlog_recover_buf_commit_pass2(
goto out_release;
} else if (buf_f->blf_flags &
(XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
- bool dirty;
-
- dirty = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
- if (!dirty)
+ error = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
+ if (error <= 0)
goto out_release;
+ /* write dirty buffer */
+ error = 0;
} else if ((xfs_blft_from_flags(buf_f) & XFS_BLFT_SB_BUF) &&
xfs_buf_daddr(bp) == 0) {
error = xlog_recover_do_primary_sb_buffer(mp, item, bp, buf_f,
@@ -1038,7 +1060,10 @@ xlog_recover_buf_commit_pass2(
if (error)
goto out_writebuf;
} else {
- xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
+ error = xlog_recover_do_reg_buffer(mp, item, bp, buf_f,
+ current_lsn);
+ if (error)
+ goto out_release;
}
/*
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 23/77] xfs: hoist per-bucket unlinked list check to helper
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (21 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 22/77] xfs: bounds-check buffer log items dirty bitmap Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 24/77] xfs: dont livelock in scrub on a circular unlinked list Greg Kroah-Hartman
` (61 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <djwong@kernel.org>
[ Upstream commit 7cdafd8f10ebdf745ba6046b9fa67490c343a17f ]
In the next patch we're going to make this loop more exciting, so hoist
the code to a helper function to reduce clutter in the resulting code.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Stable-dep-of: 527eaaefddb6 ("xfs: don't livelock in scrub on a circular unlinked list")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/xfs/scrub/agheader.c | 62 +++++++++++++++++++++++++++++++-----------------
1 file changed, 41 insertions(+), 21 deletions(-)
--- a/fs/xfs/scrub/agheader.c
+++ b/fs/xfs/scrub/agheader.c
@@ -891,6 +891,42 @@ xchk_agi_xref(
}
/*
+ * Walk the incore unlinked list for a particular AGI bucket to construct
+ * the unlinked inode bitmap for later reconstruction of the unlinked list.
+ * Returns 1 if we should keep checking, or 0 to stop checking.
+ */
+static int
+xchk_iunlink_bucket(
+ struct xfs_scrub *sc,
+ unsigned int bucket,
+ xfs_agino_t agino)
+{
+ while (agino != NULLAGINO) {
+ struct xfs_inode *ip;
+
+ if (agino % XFS_AGI_UNLINKED_BUCKETS != bucket) {
+ xchk_block_set_corrupt(sc, sc->sa.agi_bp);
+ return 0;
+ }
+
+ ip = xfs_iunlink_lookup(sc->sa.pag, agino);
+ if (!ip) {
+ xchk_block_set_corrupt(sc, sc->sa.agi_bp);
+ return 0;
+ }
+
+ if (!xfs_inode_on_unlinked_list(ip)) {
+ xchk_block_set_corrupt(sc, sc->sa.agi_bp);
+ return 0;
+ }
+
+ agino = ip->i_next_unlinked;
+ }
+
+ return 1;
+}
+
+/*
* Check the unlinked buckets for links to bad inodes. We hold the AGI, so
* there cannot be any threads updating unlinked list pointers in this AG.
*/
@@ -900,30 +936,14 @@ xchk_iunlink(
struct xfs_agi *agi)
{
unsigned int i;
- struct xfs_inode *ip;
for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
- xfs_agino_t agino = be32_to_cpu(agi->agi_unlinked[i]);
+ int ret;
- while (agino != NULLAGINO) {
- if (agino % XFS_AGI_UNLINKED_BUCKETS != i) {
- xchk_block_set_corrupt(sc, sc->sa.agi_bp);
- return;
- }
-
- ip = xfs_iunlink_lookup(sc->sa.pag, agino);
- if (!ip) {
- xchk_block_set_corrupt(sc, sc->sa.agi_bp);
- return;
- }
-
- if (!xfs_inode_on_unlinked_list(ip)) {
- xchk_block_set_corrupt(sc, sc->sa.agi_bp);
- return;
- }
-
- agino = ip->i_next_unlinked;
- }
+ ret = xchk_iunlink_bucket(sc, i,
+ be32_to_cpu(agi->agi_unlinked[i]));
+ if (ret < 1)
+ return;
}
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 24/77] xfs: dont livelock in scrub on a circular unlinked list
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (22 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 23/77] xfs: hoist per-bucket unlinked list check to helper Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 25/77] ALSA: dummy: Check card index validity at probe Greg Kroah-Hartman
` (60 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Darrick J. Wong, Christoph Hellwig,
Carlos Maiolino, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <djwong@kernel.org>
[ Upstream commit 527eaaefddb6ec5c83a06c9a1559960dd6361753 ]
LOLLM points out that online fsck can livelock if an unlinked inode list
contains a loop. Use a bitmap to detect cycles.
Cc: stable@vger.kernel.org # v4.15
Fixes: a12890aebb8959 ("xfs: scrub the AGI")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/xfs/scrub/agheader.c | 44 +++++++++++++++++++++++++++++++++--------
fs/xfs/scrub/agheader_repair.c | 17 +++++++++++++--
2 files changed, 51 insertions(+), 10 deletions(-)
--- a/fs/xfs/scrub/agheader.c
+++ b/fs/xfs/scrub/agheader.c
@@ -18,6 +18,8 @@
#include "xfs_inode.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
+#include "scrub/bitmap.h"
+#include "scrub/agino_bitmap.h"
int
xchk_setup_agheader(
@@ -893,7 +895,8 @@ xchk_agi_xref(
/*
* Walk the incore unlinked list for a particular AGI bucket to construct
* the unlinked inode bitmap for later reconstruction of the unlinked list.
- * Returns 1 if we should keep checking, or 0 to stop checking.
+ * Returns 1 if we should keep checking, 0 to stop checking, or a negative
+ * errno.
*/
static int
xchk_iunlink_bucket(
@@ -901,36 +904,57 @@ xchk_iunlink_bucket(
unsigned int bucket,
xfs_agino_t agino)
{
+ struct xagino_bitmap seen;
+ int ret;
+
+ xagino_bitmap_init(&seen);
+
while (agino != NULLAGINO) {
struct xfs_inode *ip;
+ unsigned int len = 1;
if (agino % XFS_AGI_UNLINKED_BUCKETS != bucket) {
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
- return 0;
+ goto bad;
+ }
+
+ if (xagino_bitmap_test(&seen, agino, &len)) {
+ xchk_block_set_corrupt(sc, sc->sa.agi_bp);
+ goto bad;
}
ip = xfs_iunlink_lookup(sc->sa.pag, agino);
if (!ip) {
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
- return 0;
+ goto bad;
}
if (!xfs_inode_on_unlinked_list(ip)) {
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
- return 0;
+ goto bad;
}
+ ret = xagino_bitmap_set(&seen, agino, 1);
+ if (ret)
+ goto out_bitmap;
+
agino = ip->i_next_unlinked;
}
+ ret = 1;
- return 1;
+out_bitmap:
+ xagino_bitmap_destroy(&seen);
+ return ret;
+bad:
+ ret = 0;
+ goto out_bitmap;
}
/*
* Check the unlinked buckets for links to bad inodes. We hold the AGI, so
* there cannot be any threads updating unlinked list pointers in this AG.
*/
-STATIC void
+STATIC int
xchk_iunlink(
struct xfs_scrub *sc,
struct xfs_agi *agi)
@@ -943,8 +967,10 @@ xchk_iunlink(
ret = xchk_iunlink_bucket(sc, i,
be32_to_cpu(agi->agi_unlinked[i]));
if (ret < 1)
- return;
+ return ret;
}
+
+ return 0;
}
/* Scrub the AGI. */
@@ -1031,7 +1057,9 @@ xchk_agi(
if (pag->pagi_freecount != be32_to_cpu(agi->agi_freecount))
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
- xchk_iunlink(sc, agi);
+ error = xchk_iunlink(sc, agi);
+ if (error)
+ goto out;
xchk_agi_xref(sc);
out:
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -1089,18 +1089,22 @@ xrep_iunlink_walk_ondisk_bucket(
struct xrep_agi *ragi,
unsigned int bucket)
{
+ struct xagino_bitmap seen;
struct xfs_scrub *sc = ragi->sc;
struct xfs_agi *agi = ragi->agi_bp->b_addr;
xfs_agino_t prev_agino = NULLAGINO;
xfs_agino_t next_agino;
int error = 0;
+ xagino_bitmap_init(&seen);
+
next_agino = be32_to_cpu(agi->agi_unlinked[bucket]);
while (next_agino != NULLAGINO) {
xfs_agino_t agino = next_agino;
+ unsigned int len = 1;
if (xchk_should_terminate(ragi->sc, &error))
- return error;
+ goto out_bitmap;
trace_xrep_iunlink_walk_ondisk_bucket(sc->sa.pag, bucket,
prev_agino, agino);
@@ -1108,15 +1112,24 @@ xrep_iunlink_walk_ondisk_bucket(
if (bucket != agino % XFS_AGI_UNLINKED_BUCKETS)
break;
+ if (xagino_bitmap_test(&seen, agino, &len))
+ break;
+
next_agino = xrep_iunlink_next(sc, agino);
if (!next_agino)
next_agino = xrep_iunlink_reload_next(ragi, prev_agino,
agino);
+ error = xagino_bitmap_set(&seen, agino, 1);
+ if (error)
+ goto out_bitmap;
+
prev_agino = agino;
}
- return 0;
+out_bitmap:
+ xagino_bitmap_destroy(&seen);
+ return error;
}
/* Decide if this is an unlinked inode in this AG. */
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 25/77] ALSA: dummy: Check card index validity at probe
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (23 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 24/77] xfs: dont livelock in scrub on a circular unlinked list Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 26/77] ocfs2: fix missing metadata reservation for large xattrs Greg Kroah-Hartman
` (59 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+2fb5d1f7cc4c1f132bcc,
Takashi Iwai
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <tiwai@suse.de>
commit 02442d5fe8ee365a084b055d4fa81a0c1abfc3fd upstream.
snd_dummy_probe() blindly trusts that the given devptr->id value is
within the proper card index range. It's OK for the devices the
driver itself creates at the module probe time, but if the device is
bound manually via sysfs interface, this could be -1 as "none", and
this leads to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a
value out of the range.
Reported-by: syzbot+2fb5d1f7cc4c1f132bcc@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/6a73bd4d.01d0871a.3a0d52.0005.GAE@google.com
Cc: <stable@vger.kernel.org>
Link: https://patch.msgid.link/20260806100433.1287393-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
sound/drivers/dummy.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -1025,6 +1025,12 @@ static int snd_dummy_probe(struct platfo
int idx, err;
int dev = devptr->id;
+ if (dev < 0 || dev >= SNDRV_CARDS) {
+ dev_warn(&devptr->dev,
+ "Invalid card index %d, using default 0\n", dev);
+ dev = 0;
+ }
+
err = snd_devm_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_dummy), &card);
if (err < 0)
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 26/77] ocfs2: fix missing metadata reservation for large xattrs
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (24 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 25/77] ALSA: dummy: Check card index validity at probe Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 27/77] null_blk: fix UBSAN shift-out-of-bounds when zone_size is 0 or overflows Greg Kroah-Hartman
` (58 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ian Bridges,
syzbot+e538032956b1157914a3, Joseph Qi, Mark Fasheh, Joel Becker,
Junxiao Bi, Changwei Ge, Jun Piao, Heming Zhao, Andrew Morton
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Bridges <icb@fastmail.org>
commit 0cdc7dde00ec63ac714271fa8b2918d630b8da1a upstream.
[BUG]
lsetxattr() panics the kernel when setting a large xattr value on a
fragmented filesystem where the file already has an external xattr
block.
[CAUSE]
ocfs2_calc_xattr_set_need() never reserves metadata blocks for a new
xattr value's extent tree when the file already has an external xattr
block. The not_found path leaves meta_add at zero, so meta_ac is NULL
when ocfs2_xattr_extend_allocation() runs.
A new value root has room for a single extent record. On a fragmented
filesystem, the allocator cannot satisfy the xattr value in one
contiguous run, so each non-contiguous run requires its own extent
record. When the value root's extent list is full and meta_ac is NULL,
ocfs2_add_clusters_in_btree() returns RESTART_META, and
ocfs2_xattr_extend_allocation() hits BUG_ON(why == RESTART_META).
[FIX]
The case where no xattr block exists yet already calls
ocfs2_extend_meta_needed(&def_xv.xv.xr_list) to reserve value tree
metadata. Add the same reservation to the case where an xattr block
already exists, making the two cases consistent.
Replace the BUG_ON with a -ENOSPC return so that if RESTART_META is
returned despite the reservation, the error propagates to userspace
instead of panicking the kernel.
Link: https://lore.kernel.org/amLwn3i9tET8yhG7@dev
Fixes: a78f9f466894 ("ocfs2: make xattr extension work with new local alloc reservation.")
Signed-off-by: Ian Bridges <icb@fastmail.org>
Reported-by: syzbot+e538032956b1157914a3@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=e538032956b1157914a3
Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Changwei Ge <gechangwei@live.cn>
Cc: Jun Piao <piaojun@huawei.com>
Cc: Heming Zhao <heming.zhao@suse.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/ocfs2/xattr.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -736,12 +736,10 @@ static int ocfs2_xattr_extend_allocation
prev_clusters;
if (why != RESTART_NONE && clusters_to_add) {
- /*
- * We can only fail in case the alloc file doesn't give
- * up enough clusters.
- */
- BUG_ON(why == RESTART_META);
-
+ if (why == RESTART_META) {
+ status = -ENOSPC;
+ break;
+ }
credits = ocfs2_calc_extend_credits(inode->i_sb,
&vb->vb_xv->xr_list);
status = ocfs2_extend_trans(handle, credits);
@@ -3211,6 +3209,14 @@ meta_guess:
credits += OCFS2_SUBALLOC_ALLOC + 1;
/*
+ * Reserve metadata for the new xattr's value extent tree.
+ * The not_found path above adds credits for this tree but
+ * omits meta_add, leaving meta_ac NULL for large values.
+ */
+ if (xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE)
+ meta_add += ocfs2_extend_meta_needed(&def_xv.xv.xr_list);
+
+ /*
* This cluster will be used either for new bucket or for
* new xattr block.
* If the cluster size is the same as the bucket size, one
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 27/77] null_blk: fix UBSAN shift-out-of-bounds when zone_size is 0 or overflows
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (25 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 26/77] ocfs2: fix missing metadata reservation for large xattrs Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 28/77] kcov: fix data corruption and race conditions on PREEMPT_RT Greg Kroah-Hartman
` (57 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+abd6a8dca0f2b7726060,
Rik van Riel, Damien Le Moal, Jens Axboe
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rik van Riel <riel@surriel.com>
commit 95491fb05105b61050cb623a5e0227eb26aa3525 upstream.
null_zone_no() does sect >> ilog2(dev->zone_size_sects). When
zone_size_sects is 0, ilog2(0) returns -1, producing shift exponent -1
which UBSAN reports as shift-out-of-bounds.
UBSAN: shift-out-of-bounds in drivers/block/null_blk/zoned.c:21:14
shift exponent -1 is negative
Call Trace:
null_zone_no drivers/block/null_blk/zoned.c:21 [inline]
null_process_zoned_cmd+0xf76/0xf80 drivers/block/null_blk/zoned.c:728
null_handle_cmd drivers/block/null_blk/main.c:1455 [inline]
null_queue_rq+0x8bc/0xe70 drivers/block/null_blk/main.c:1703
__blk_mq_issue_directly block/blk-mq.c:2694 [inline]
blk_mq_try_issue_directly+0x3f4/0x880 block/blk-mq.c:2754
blk_mq_submit_bio+0x20c0/0x2a40 block/blk-mq.c:3208
submit_bio_noacct_nocheck+0x2f4/0xa40 block/blk-core.c:790
block_read_full_folio+0x7a6/0x810 fs/buffer.c:2463
filemap_read_folio+0x12c/0x3a0 mm/filemap.c:2510
read_part_sector+0xb6/0x2b0 block/partitions/core.c:724
adfspart_check_ICS+0xb1/0x960 block/partitions/acorn.c:357
check_partition block/partitions/core.c:143 [inline]
blk_add_partitions block/partitions/core.c:591 [inline]
bdev_disk_changed+0x851/0x17a0 block/partitions/core.c:695
blkdev_get_whole+0x372/0x510 block/bdev.c:751
add_disk_final block/genhd.c:412 [inline]
add_disk_fwnode+0x24b/0x3a0 block/genhd.c:606
null_add_dev+0x130b/0x1d70 drivers/block/null_blk/main.c:2052
nullb_device_power_store+0x240/0x380 drivers/block/null_blk/main.c:501
configfs_write_iter+0x337/0x430 fs/configfs/file.c:229
Syzkaller triggers this by creating a zoned null_blk device via
configfs. The Call Trace shows configfs_write_iter in configfs/file.c
handling a write to power file, which calls nullb_device_power_store in
main.c, which calls null_add_dev in main.c, which calls add_disk in
genhd.c, which triggers partition scan via bdev_disk_changed in
partitions/core.c.
A zoned null_blk device with zone_size 0 should not be legal. Existing
code tries to reject it via is_power_of_2() check in zoned.c and
!zone_size check in main.c, but syzkaller can still reach
null_zone_no() with zone_size_sects 0 via two paths:
1. Direct 0 via configfs: zone_size attribute store in main.c has
NULLB_DEVICE_ATTR(zone_size, ulong, NULL) with no validation callback,
so echo 0 > zone_size succeeds before power store. If zoned is false
at power store time, the !zone_size check in main.c is skipped, and
later zoned set true leaves zone_size 0.
2. Large value overflow: mb_to_sects() in zoned.c does
(sector_t)mb * SZ_1M >> SECTOR_SHIFT which is mb * 2048. If mb is
1UL << 53 (9PB), mb * 2048 overflows 64-bit to 0. The value is
power-of-two so is_power_of_2() passes, but mb_to_sects() returns 0.
Check for zero zone_size explicitly in null_init_zoned_dev() in
zoned.c, returning -EINVAL with "must be non-zero power-of-two".
Check for zero zone_size_sects after mb_to_sects() conversion,
returning -EINVAL for overflow case. Keep defensive check in
null_zone_no() returning 0 for zero sectors to avoid shift out-of-bounds
even if zero slips through.
This change should be safe because zone_size is set once in
null_init_zoned_dev() under device lock and never changes after, and 0
is never valid for a zoned device. Returning -EINVAL at init time fails
device creation early with clear error, while defensive return 0 in
null_zone_no() makes zoned command fail via offline zone check.
No new locking is introduced.
Reported-by: syzbot+abd6a8dca0f2b7726060@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=abd6a8dca0f2b7726060
Link: https://lore.kernel.org/all/6a75205c.01d0871a.3a0d52.0033.GAE@google.com/
Fixes: 8a3cf049af68 ("null_blk: add zoned block device emulation")
Cc: stable@vger.kernel.org
Assisted-by: Hermes:muse-spark-1.2 syzkaller
Signed-off-by: Rik van Riel <riel@surriel.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Link: https://patch.msgid.link/20260808114239.69167f68@fangorn
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/block/null_blk/zoned.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
--- a/drivers/block/null_blk/zoned.c
+++ b/drivers/block/null_blk/zoned.c
@@ -18,6 +18,8 @@ static inline sector_t mb_to_sects(unsig
static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
{
+ if (WARN_ON_ONCE(!dev->zone_size_sects))
+ return 0;
return sect >> ilog2(dev->zone_size_sects);
}
@@ -56,8 +58,8 @@ int null_init_zoned_dev(struct nullb_dev
sector_t sector = 0;
unsigned int i;
- if (!is_power_of_2(dev->zone_size)) {
- pr_err("zone_size must be power-of-two\n");
+ if (!dev->zone_size || !is_power_of_2(dev->zone_size)) {
+ pr_err("zone_size must be non-zero power-of-two\n");
return -EINVAL;
}
if (dev->zone_size > dev->size) {
@@ -88,6 +90,10 @@ int null_init_zoned_dev(struct nullb_dev
zone_capacity_sects = mb_to_sects(dev->zone_capacity);
dev_capacity_sects = mb_to_sects(dev->size);
dev->zone_size_sects = mb_to_sects(dev->zone_size);
+ if (!dev->zone_size_sects) {
+ pr_err("zone_size too large or too small, leads to zero sectors\n");
+ return -EINVAL;
+ }
dev->nr_zones = round_up(dev_capacity_sects, dev->zone_size_sects)
>> ilog2(dev->zone_size_sects);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 28/77] kcov: fix data corruption and race conditions on PREEMPT_RT
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (26 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 27/77] null_blk: fix UBSAN shift-out-of-bounds when zone_size is 0 or overflows Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 29/77] ext4: stop retrying saturated xattr cache entries Greg Kroah-Hartman
` (56 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, syzbot+3f51ad7ac3ae57a6fdcc,
syzbot+47cf95ca1f9dcca872c8, syzbot+8a173e13208949931dc7,
syzbot+90984d3713722683112e, Tetsuo Handa, Alexander Potapenko,
Alan Stern, Andrey Konovalov, Christoph Hellwig, Clark Williams,
Dmitry Vyukov, Marco Elver, Mark Brown, Roman Gushchin,
Sebastian Andrzej Siewior, Andrew Morton
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
commit 2eed77fdcb0cc48e8eccb2bcd4b7f2c6d650e84c upstream.
syzbot is reporting KCOV state corruption on PREEMPT_RT kernels, for the
temporary storage used for saving/restoring remote KCOV state is currently
allocated as the per-CPU area.
On PREEMPT_RT kernels, softirq handlers run as preemptible task threads
(e.g., ksoftirqd). If a softirq context preempts a task running a remote
KCOV session, it safely saves the task's state into the per-CPU area.
However, if that softirq thread is subsequently preempted by a higher-
priority softirq thread on the same CPU, the second softirq will overwrite
the same per-CPU area, permanently destroying the original task's KCOV
state.
Fix this data corruption by moving the temporary storage from the per-CPU
area to the per-thread area. Since each softirq thread now owns its own
task context, nested softirq preemption no longer causes data overwrites.
Note that while the temporary storage is now on a per-thread basis, the
per-CPU kcov_percpu_data.lock must be retained, for we need to ensure that
kcov_remote_start() and kcov_remote_stop() operate atomically without
racing against asynchronous interrupts that manipulate the current task's
KCOV state.
It is likely that GFP_KERNEL allocation by vmalloc_node() in kcov_init()
has already called panic() before returning NULL, for there will be no
OOM-killable userspace processes when __init function of built-in module
runs. But this patch also fixes crashing the kernel when vmalloc_node()
in kcov_init() returned NULL, for kcov_init() left per-CPU irq_area == NULL
but kcov_remote_start() depends on per-CPU irq_area != NULL, resulting in
(1) doing vmalloc() in kcov_remote_start() despite !in_task() context
(2) out-of-array-bounds access if (1) succeeded but
kcov->remote_size < CONFIG_KCOV_IRQ_AREA_SIZE
(3) always leak memory allocated by (1), eventually killing all
OOM-killable userspace processes
problems.
Link: https://lore.kernel.org/43552d09-2ce2-4b19-b0d3-a2d1ab952145@I-love.SAKURA.ne.jp
Reported-by: syzbot+3f51ad7ac3ae57a6fdcc@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=3f51ad7ac3ae57a6fdcc
Reported-by: syzbot+47cf95ca1f9dcca872c8@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=47cf95ca1f9dcca872c8
Reported-by: syzbot+8a173e13208949931dc7@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=8a173e13208949931dc7
Reported-by: syzbot+90984d3713722683112e@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=90984d3713722683112e
Analyzed-by: AI Mode in Google Search (no mail address)
Fixes: 5ff3b30ab57d ("kcov: collect coverage from interrupts")
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reviewed-by: Alexander Potapenko <glider@google.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrey Konovalov <andreyknvl@gmail.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Clark Williams <williams@redhat.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Marco Elver <elver@google.com>
Cc: Mark Brown <broonie@kernel.org>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
include/linux/sched.h | 8 ++++
kernel/kcov.c | 90 ++++++++++++++++++++++++++------------------------
lib/Kconfig.debug | 5 +-
3 files changed, 58 insertions(+), 45 deletions(-)
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1490,6 +1490,14 @@ struct task_struct {
/* Collect coverage from softirq context: */
unsigned int kcov_softirq;
+
+ /* Temporary storage for preempting remote coverage collection: */
+ unsigned int kcov_saved_mode;
+ unsigned int kcov_saved_size;
+ void *kcov_saved_area;
+ struct kcov *kcov_saved_kcov;
+ int kcov_saved_sequence;
+
#endif
#ifdef CONFIG_MEMCG_V1
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -86,17 +86,12 @@ struct kcov_remote {
static DEFINE_SPINLOCK(kcov_remote_lock);
static DEFINE_HASHTABLE(kcov_remote_map, 4);
-static struct list_head kcov_remote_areas = LIST_HEAD_INIT(kcov_remote_areas);
+static struct list_head kcov_remote_areas[2] = {
+ LIST_HEAD_INIT(kcov_remote_areas[0]), LIST_HEAD_INIT(kcov_remote_areas[1])
+};
struct kcov_percpu_data {
- void *irq_area;
local_lock_t lock;
-
- unsigned int saved_mode;
- unsigned int saved_size;
- void *saved_area;
- struct kcov *saved_kcov;
- int saved_sequence;
};
static DEFINE_PER_CPU(struct kcov_percpu_data, kcov_percpu_data) = {
@@ -132,12 +127,13 @@ static struct kcov_remote *kcov_remote_a
}
/* Must be called with kcov_remote_lock locked. */
-static struct kcov_remote_area *kcov_remote_area_get(unsigned int size)
+static struct kcov_remote_area *kcov_remote_area_get(unsigned int size, bool irq)
{
struct kcov_remote_area *area;
struct list_head *pos;
+ struct list_head *list = &kcov_remote_areas[irq];
- list_for_each(pos, &kcov_remote_areas) {
+ list_for_each(pos, list) {
area = list_entry(pos, struct kcov_remote_area, list);
if (area->size == size) {
list_del(&area->list);
@@ -149,11 +145,11 @@ static struct kcov_remote_area *kcov_rem
/* Must be called with kcov_remote_lock locked. */
static void kcov_remote_area_put(struct kcov_remote_area *area,
- unsigned int size)
+ unsigned int size, bool irq)
{
INIT_LIST_HEAD(&area->list);
area->size = size;
- list_add(&area->list, &kcov_remote_areas);
+ list_add(&area->list, &kcov_remote_areas[irq]);
/*
* KMSAN doesn't instrument this file, so it may not know area->list
* is initialized. Unpoison it explicitly to avoid reports in
@@ -388,6 +384,12 @@ void kcov_task_init(struct task_struct *
{
kcov_task_reset(t);
t->kcov_handle = current->kcov_handle;
+ t->kcov_softirq = 0;
+ t->kcov_saved_mode = 0;
+ t->kcov_saved_size = 0;
+ t->kcov_saved_area = NULL;
+ t->kcov_saved_kcov = NULL;
+ t->kcov_saved_sequence = 0;
}
static void kcov_reset(struct kcov *kcov)
@@ -815,34 +817,31 @@ static inline bool kcov_mode_enabled(uns
static void kcov_remote_softirq_start(struct task_struct *t)
{
- struct kcov_percpu_data *data = this_cpu_ptr(&kcov_percpu_data);
unsigned int mode;
mode = READ_ONCE(t->kcov_mode);
barrier();
if (kcov_mode_enabled(mode)) {
- data->saved_mode = mode;
- data->saved_size = t->kcov_size;
- data->saved_area = t->kcov_area;
- data->saved_sequence = t->kcov_sequence;
- data->saved_kcov = t->kcov;
+ t->kcov_saved_mode = mode;
+ t->kcov_saved_size = t->kcov_size;
+ t->kcov_saved_area = t->kcov_area;
+ t->kcov_saved_sequence = t->kcov_sequence;
+ t->kcov_saved_kcov = t->kcov;
kcov_stop(t);
}
}
static void kcov_remote_softirq_stop(struct task_struct *t)
{
- struct kcov_percpu_data *data = this_cpu_ptr(&kcov_percpu_data);
-
- if (data->saved_kcov) {
- kcov_start(t, data->saved_kcov, data->saved_size,
- data->saved_area, data->saved_mode,
- data->saved_sequence);
- data->saved_mode = 0;
- data->saved_size = 0;
- data->saved_area = NULL;
- data->saved_sequence = 0;
- data->saved_kcov = NULL;
+ if (t->kcov_saved_kcov) {
+ kcov_start(t, t->kcov_saved_kcov, t->kcov_saved_size,
+ t->kcov_saved_area, t->kcov_saved_mode,
+ t->kcov_saved_sequence);
+ t->kcov_saved_mode = 0;
+ t->kcov_saved_size = 0;
+ t->kcov_saved_area = NULL;
+ t->kcov_saved_sequence = 0;
+ t->kcov_saved_kcov = NULL;
}
}
@@ -903,17 +902,17 @@ void kcov_remote_start(u64 handle)
sequence = kcov->sequence;
if (in_task()) {
size = kcov->remote_size;
- area = kcov_remote_area_get(size);
+ area = kcov_remote_area_get(size, false);
} else {
size = CONFIG_KCOV_IRQ_AREA_SIZE;
- area = this_cpu_ptr(&kcov_percpu_data)->irq_area;
+ area = kcov_remote_area_get(size, true);
}
spin_unlock(&kcov_remote_lock);
- /* Can only happen when in_task(). */
+ /* Allocate new buffer if we can sleep. */
if (!area) {
local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
- area = vmalloc(size * sizeof(unsigned long));
+ area = in_task() ? vmalloc(size * sizeof(unsigned long)) : NULL;
if (!area) {
kcov_put(kcov);
return;
@@ -1046,11 +1045,9 @@ void kcov_remote_stop(void)
kcov_move_area(kcov->mode, kcov->area, kcov->size, area);
spin_unlock(&kcov->lock);
- if (in_task()) {
- spin_lock(&kcov_remote_lock);
- kcov_remote_area_put(area, size);
- spin_unlock(&kcov_remote_lock);
- }
+ spin_lock(&kcov_remote_lock);
+ kcov_remote_area_put(area, size, !in_task());
+ spin_unlock(&kcov_remote_lock);
local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
@@ -1096,14 +1093,21 @@ static void __init selftest(void)
static int __init kcov_init(void)
{
- int cpu;
+ int cpu = num_possible_cpus();
+
+#ifdef CONFIG_PREEMPT_RT
+ /* Allocate some extra buffers in order to prepare for softirq preemption. */
+ cpu = cpu >= 4 ? cpu * 2 : cpu + 4;
+#endif
+ while (cpu--) {
+ void *area = vmalloc(CONFIG_KCOV_IRQ_AREA_SIZE * sizeof(unsigned long));
+ unsigned long flags;
- for_each_possible_cpu(cpu) {
- void *area = vmalloc_node(CONFIG_KCOV_IRQ_AREA_SIZE *
- sizeof(unsigned long), cpu_to_node(cpu));
if (!area)
return -ENOMEM;
- per_cpu_ptr(&kcov_percpu_data, cpu)->irq_area = area;
+ spin_lock_irqsave(&kcov_remote_lock, flags);
+ kcov_remote_area_put(area, CONFIG_KCOV_IRQ_AREA_SIZE, true);
+ spin_unlock_irqrestore(&kcov_remote_lock, flags);
}
/*
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2145,10 +2145,11 @@ config KCOV_INSTRUMENT_ALL
config KCOV_IRQ_AREA_SIZE
hex "Size of interrupt coverage collection area in words"
depends on KCOV
+ range 0x80 0x1000000
default 0x40000
help
- KCOV uses preallocated per-cpu areas to collect coverage from
- soft interrupts. This specifies the size of those areas in the
+ KCOV uses preallocated areas to collect coverage from soft
+ interrupts. This specifies the size of those areas in the
number of unsigned long words.
config KCOV_SELFTEST
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 29/77] ext4: stop retrying saturated xattr cache entries
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (27 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 28/77] kcov: fix data corruption and race conditions on PREEMPT_RT Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 30/77] ext4: clear error before retrying inode xattr space fallback Greg Kroah-Hartman
` (55 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Matthias Goergens, Jan Kara,
syzbot+e68dbebd9617a9250e8d, Theodore Tso
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthias Goergens <matthias.goergens@gmail.com>
commit 54b6bd40898de7906acb2bccc9a96d1b8e6b4323 upstream.
ext4_xattr_block_set() retries when a cache entry selected for reuse
has a saturated reference count after taking the buffer lock. The retry
returns to the mbcache lookup without making that entry ineligible, so
it can select the same unusable entry indefinitely. A task spinning
there can hold the parent directory's i_rwsem and leave concurrent
rmdir callers blocked.
Normally a reusable entry has a reference count below
EXT4_XATTR_REFCOUNT_MAX because the count and MBE_REUSABLE_B are
updated under the same buffer lock. A corrupted filesystem can violate
that invariant. The syzbot reproducer reports allocator and xattr
corruption before triggering this retry loop.
Check the untrusted on-disk count before incrementing it, avoiding
overflow, and clear MBE_REUSABLE_B when it is already saturated. The
next lookup then skips the entry that was just proven unusable. This
mirrors the normal transition at EXT4_XATTR_REFCOUNT_MAX; the release
path marks the entry reusable again on the exact 1024-to-1023
transition.
Using the same QEMU harness and guest parameters, current unpatched
Linux hung in 6 of 8 420-second trials with the do_rmdir signature;
representative NMI backtraces caught the owner spinning in
ext4_xattr_block_set(). The patched kernel completed 28 of 28 trials
without a hung-task report; the final twelve trials exercised the
reviewed overflow-safe form of the change. syzbot's patch testing also
completed without reproducing the hang.
Reported-and-tested-by: syzbot+e68dbebd9617a9250e8d@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=e68dbebd9617a9250e8d
Fixes: 65f8b80053a1 ("ext4: fix race when reusing xattr blocks")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reported-by: syzbot+e68dbebd9617a9250e8d@syzkaller.appspotmail.com
Tested-by: syzbot+e68dbebd9617a9250e8d@syzkaller.appspotmail.com
Link: https://patch.msgid.link/20260802065941.1726052-1-matthias.goergens@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/ext4/xattr.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -2075,12 +2075,13 @@ inserted:
* stable so we can check the additional
* reference fits.
*/
- ref = le32_to_cpu(BHDR(new_bh)->h_refcount) + 1;
- if (ref > EXT4_XATTR_REFCOUNT_MAX) {
+ ref = le32_to_cpu(BHDR(new_bh)->h_refcount);
+ if (ref >= EXT4_XATTR_REFCOUNT_MAX) {
/*
* Undo everything and check mbcache
* again.
*/
+ clear_bit(MBE_REUSABLE_B, &ce->e_flags);
unlock_buffer(new_bh);
dquot_free_block(inode,
EXT4_C2B(EXT4_SB(sb),
@@ -2091,6 +2092,7 @@ inserted:
new_bh = NULL;
goto inserted;
}
+ ref++;
BHDR(new_bh)->h_refcount = cpu_to_le32(ref);
if (ref == EXT4_XATTR_REFCOUNT_MAX)
clear_bit(MBE_REUSABLE_B, &ce->e_flags);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 30/77] ext4: clear error before retrying inode xattr space fallback
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (28 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 29/77] ext4: stop retrying saturated xattr cache entries Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 31/77] ext4: propagate errors from fast commit range replay Greg Kroah-Hartman
` (54 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Guanghui Yang, Jan Kara,
Theodore Tso
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guanghui Yang <3497809730@qq.com>
commit 409a7f12a0933ff2c617fa814c76cef0bd1d457a upstream.
When ext4_xattr_make_inode_space() returns -ENOSPC,
ext4_expand_extra_isize_ea() can retry the expansion with
s_min_extra_isize. If that retry succeeds by finding enough ibody free
space, control jumps directly to the shift label.
The previous -ENOSPC is still stored in error in that path, so the
function can update i_extra_isize but still return -ENOSPC to the
caller. Clear error before retrying so a successful fallback expansion
returns success.
Reproduced with an ext4 image using 1 KiB blocks, project quota support,
256-byte inodes, and min_extra_isize/want_extra_isize set to 32.
FS_IOC_FSSETXATTR failures dropped from 802 to 86 after the fix.
Fixes: 69f3a3039b0d ("ext4: introduce ITAIL helper")
Cc: stable@vger.kernel.org
Signed-off-by: Guanghui Yang <3497809730@qq.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/tencent_192F8A699EFD21126E02101131C9546F3C08@qq.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/ext4/xattr.c | 1 +
1 file changed, 1 insertion(+)
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -2841,6 +2841,7 @@ retry:
s_min_extra_isize) {
tried_min_extra_isize++;
new_extra_isize = s_min_extra_isize;
+ error = 0;
goto retry;
}
goto cleanup;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 31/77] ext4: propagate errors from fast commit range replay
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (29 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 30/77] ext4: clear error before retrying inode xattr space fallback Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 32/77] xfs: validate attr entry pointer before field access Greg Kroah-Hartman
` (53 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Guanghui Yang, Jan Kara,
Theodore Tso
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guanghui Yang <3497809730@qq.com>
commit d8b8dd3530bf41e14b118702cdaf9de64bb96885 upstream.
ext4_fc_replay() stops replaying fast commit tags only when a tag
handler returns a negative error. However, ext4_fc_replay_add_range()
and ext4_fc_replay_del_range() currently return 0 from their common
exit paths even after internal failures.
This hides errors from ext4_fc_record_modified_inode(),
ext4_map_blocks(), ext4_find_extent(), ext4_ext_insert_extent(),
ext4_ext_replay_update_ex(), and ext4_ext_remove_space(). As a result,
a failed ADD_RANGE or DEL_RANGE replay can be treated as successful and
the replay code may continue with subsequent fast commit tags.
This is particularly problematic for DEL_RANGE because it may already
have marked blocks as free before ext4_ext_remove_space() fails. If the
error is swallowed, replay may continue from a partially applied range
operation.
Return the saved error from the common exit paths and make the
ERR_PTR() cases in ADD_RANGE store PTR_ERR() before jumping to out.
Fixes: 8016e29f4362 ("ext4: fast commit recovery path")
Cc: stable@vger.kernel.org
Signed-off-by: Guanghui Yang <3497809730@qq.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/tencent_E3622146846A84C75C31C7D32AC4D5AD0605@qq.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/ext4/fast_commit.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
--- a/fs/ext4/fast_commit.c
+++ b/fs/ext4/fast_commit.c
@@ -1799,8 +1799,11 @@ static int ext4_fc_replay_add_range(stru
if (ret == 0) {
/* Range is not mapped */
path = ext4_find_extent(inode, cur, path, 0);
- if (IS_ERR(path))
+ if (IS_ERR(path)) {
+ ret = PTR_ERR(path);
+ path = NULL;
goto out;
+ }
memset(&newex, 0, sizeof(newex));
newex.ee_block = cpu_to_le32(cur);
ext4_ext_store_pblock(
@@ -1812,8 +1815,11 @@ static int ext4_fc_replay_add_range(stru
path = ext4_ext_insert_extent(NULL, inode,
path, &newex, 0);
up_write((&EXT4_I(inode)->i_data_sem));
- if (IS_ERR(path))
+ if (IS_ERR(path)) {
+ ret = PTR_ERR(path);
+ path = NULL;
goto out;
+ }
goto next;
}
@@ -1860,10 +1866,11 @@ next:
}
ext4_ext_replay_shrink_inode(inode, i_size_read(inode) >>
sb->s_blocksize_bits);
+ ret = 0;
out:
ext4_free_ext_path(path);
iput(inode);
- return 0;
+ return ret;
}
/* Replay DEL_RANGE tag */
@@ -1924,9 +1931,10 @@ ext4_fc_replay_del_range(struct super_bl
ext4_ext_replay_shrink_inode(inode,
i_size_read(inode) >> sb->s_blocksize_bits);
ext4_mark_inode_dirty(NULL, inode);
+ ret = 0;
out:
iput(inode);
- return 0;
+ return ret;
}
static void ext4_fc_set_bitmaps_and_counters(struct super_block *sb)
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 32/77] xfs: validate attr entry pointer before field access
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (30 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 31/77] ext4: propagate errors from fast commit range replay Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 33/77] libceph: fix OOB read in decode_watchers() via missing bounds check Greg Kroah-Hartman
` (52 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Hongling Zeng, Darrick J. Wong,
Carlos Maiolino
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongling Zeng <zenghongling@kylinos.cn>
commit b7eea80be25f3334f131d52982b3131aba77b97d upstream.
xfs_attr3_leaf_verify_entry() accesses lentry/rentry fields (namelen,
valuelen) before checking if the entry pointer itself is within bounds.
If nameidx is crafted to point near the end of the buffer, these field
accesses can read out-of-bounds before the bounds check at
name_end > buf_end is performed.
Add explicit bounds checks for entry pointers before accessing their
fields. Use offsetof() to check that the start of the flexible array
member (nameval/name) is within bounds, which ensures all preceding
fields are safe to access.
Fixes: c84760659dcf2 ("xfs: check attribute leaf block structure")
Cc: <stable@vger.kernel.org> # v5.5
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/xfs/libxfs/xfs_attr_leaf.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -268,6 +268,13 @@ xfs_attr3_leaf_verify_entry(
*/
if (ent->flags & XFS_ATTR_LOCAL) {
lentry = xfs_attr3_leaf_name_local(leaf, idx);
+
+ /* Validate lentry pointer is within bounds before field access */
+ if ((char *)lentry >= buf_end)
+ return __this_address;
+ if ((char *)lentry + offsetof(struct xfs_attr_leaf_name_local, nameval) > buf_end)
+ return __this_address;
+
namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
be16_to_cpu(lentry->valuelen));
name_end = (char *)lentry + namesize;
@@ -275,6 +282,13 @@ xfs_attr3_leaf_verify_entry(
return __this_address;
} else {
rentry = xfs_attr3_leaf_name_remote(leaf, idx);
+
+ /* Validate rentry pointer is within bounds before field access */
+ if ((char *)rentry >= buf_end)
+ return __this_address;
+ if ((char *)rentry + offsetof(struct xfs_attr_leaf_name_remote, name) > buf_end)
+ return __this_address;
+
namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
name_end = (char *)rentry + namesize;
if (rentry->namelen == 0)
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 33/77] libceph: fix OOB read in decode_watchers() via missing bounds check
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (31 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 32/77] xfs: validate attr entry pointer before field access Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 34/77] nfc: digital: clamp SENSF_RES length to the destination buffer Greg Kroah-Hartman
` (51 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Pavitra Jha, Viacheslav Dubeyko,
Ilya Dryomov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavitra Jha <jhapavitra98@gmail.com>
[ Upstream commit 00ead17c7de137a692edee59f2772e6af687e8eb ]
ceph_start_decoding() validates that struct_len bytes remain in the
buffer after the encoding header, but accepts struct_len=0 as valid:
ceph_decode_need(p, end, 0, bad) always passes. When a malicious or
compromised OSD sends an obj_list_watch_response_t reply with
struct_len=0, ceph_start_decoding() returns success with p == end,
leaving zero bytes guaranteed for subsequent reads.
The immediately following ceph_decode_32(p) in decode_watchers() has
no preceding bounds check. With p == end this is a 4-byte read past
the validated buffer boundary. The garbage value is then passed
directly to kzalloc_objs() as the watcher count.
The sibling function decode_watcher() already uses the safe variants
(ceph_decode_copy_safe, ceph_decode_64_safe, ceph_decode_skip_32)
after its own ceph_start_decoding() call. decode_watchers() is the
only site that uses the bare variant, confirming an oversight.
Fix by replacing ceph_decode_32(p) with ceph_decode_32_safe(p, end,
*num_watchers, bad), consistent with the established pattern.
Attacker model: a malicious or compromised OSD in a multi-tenant Ceph
deployment (e.g. cloud) can trigger this against any kernel client
that calls CEPH_OSD_OP_LIST_WATCHERS, without any further privileges
beyond OSD session establishment.
[ idryomov: trim changelog ]
Cc: stable@vger.kernel.org
Fixes: a4ed38d7a180 ("libceph: support for CEPH_OSD_OP_LIST_WATCHERS")
Signed-off-by: Pavitra Jha <jhapavitra98@gmail.com>
Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
[ kept the tree's `kcalloc()` context line instead of upstream's `kzalloc_objs()` ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/ceph/osd_client.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -5090,7 +5090,7 @@ static int decode_watchers(void **p, voi
if (ret)
return ret;
- *num_watchers = ceph_decode_32(p);
+ ceph_decode_32_safe(p, end, *num_watchers, bad);
*watchers = kcalloc(*num_watchers, sizeof(**watchers), GFP_NOIO);
if (!*watchers)
return -ENOMEM;
@@ -5104,6 +5104,9 @@ static int decode_watchers(void **p, voi
}
return 0;
+
+bad:
+ return -EINVAL;
}
/*
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 34/77] nfc: digital: clamp SENSF_RES length to the destination buffer
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (32 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 33/77] libceph: fix OOB read in decode_watchers() via missing bounds check Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 35/77] nfc: fdp: bound the device-reported read length and fix an skb leak Greg Kroah-Hartman
` (50 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Doruk Tan Ozturk, Alexander Lobakin,
David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <doruk@0sec.ai>
commit 344a56d7c8e0f3cbaff0bcb1bcd95a1a1db24b16 upstream.
digital_in_recv_sensf_res() memcpy()s resp->len bytes from a remote
NFC-F device response into the NFC_SENSF_RES_MAXSIZE-byte target.sensf_res
field without an upper-bound check. A nearby malicious NFC-F device can
send an oversized SENSF_RES response to overflow the stack-local struct
nfc_target.
Clamp resp->len to NFC_SENSF_RES_MAXSIZE before the copy.
Found by 0sec automated security-research tooling (https://0sec.ai).
Fixes: 8c0695e4998d ("NFC Digital: Add NFC-F technology support")
Cc: stable@vger.kernel.org
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
Reviewed-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Link: https://patch.msgid.link/20260603141355.68156-1-doruk@0sec.ai
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/nfc/digital_technology.c | 2 ++
1 file changed, 2 insertions(+)
--- a/net/nfc/digital_technology.c
+++ b/net/nfc/digital_technology.c
@@ -778,6 +778,8 @@ static void digital_in_recv_sensf_res(st
sensf_res = (struct digital_sensf_res *)resp->data;
+ resp->len = min_t(unsigned int, resp->len, NFC_SENSF_RES_MAXSIZE);
+
memcpy(target.sensf_res, sensf_res, resp->len);
target.sensf_res_len = resp->len;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 35/77] nfc: fdp: bound the device-reported read length and fix an skb leak
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (33 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 34/77] nfc: digital: clamp SENSF_RES length to the destination buffer Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 36/77] nfc: microread: validate target discovery payload lengths Greg Kroah-Hartman
` (49 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Simon Horman, Bryam Vargas,
David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <hexlabsecurity@proton.me>
commit 7ad21dcfeb5181af0c3ee2608808c0c0a5283aa1 upstream.
fdp_nci_i2c_read() takes the next packet length from two device-supplied
bytes and never validates it. The value is a u16 used as the
i2c_master_recv() count into a 261-byte on-stack buffer: a malicious,
counterfeit or malfunctioning controller (or an i2c bus interposer) can
drive it far past the buffer for a stack out-of-bounds write that
clobbers the canary and return address, or below the minimum frame size
(directly, or by truncating the computed sum) so the header/LRC strip
and the next length read run past a short receive. Reject a length
outside [FDP_NCI_I2C_MIN_PAYLOAD, FDP_NCI_I2C_MAX_PAYLOAD], as a
corrupted packet already is, and force resynchronization.
The same loop allocates one data skb per iteration and assumes a length
packet followed by a data packet; a device that sends two data packets
in one call leaks the first skb when the second allocation overwrites
it. Free a previously allocated skb before allocating the next.
Fixes: a06347c04c13 ("NFC: Add Intel Fields Peak NFC solution driver")
Cc: stable@vger.kernel.org
Suggested-by: Simon Horman <horms@kernel.org>
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Link: https://patch.msgid.link/20260616-b4-disp-b1f8ab4c-v2-1-2d1fe5955325@proton.me
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nfc/fdp/i2c.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
--- a/drivers/nfc/fdp/i2c.c
+++ b/drivers/nfc/fdp/i2c.c
@@ -166,9 +166,36 @@ static int fdp_nci_i2c_read(struct fdp_i
/* Packet that contains a length */
if (tmp[0] == 0 && tmp[1] == 0) {
phy->next_read_size = (tmp[2] << 8) + tmp[3] + 3;
+
+ /*
+ * next_read_size is taken from the device and is used
+ * as the i2c_master_recv() count for the next packet
+ * and as the data skb size. A value above the receive
+ * buffer overflows tmp[]; one below the minimum frame
+ * size runs the header/LRC strip and the length-field
+ * read past a short receive. Either way the packet is
+ * corrupt: drop it and force resynchronization.
+ */
+ if (phy->next_read_size < FDP_NCI_I2C_MIN_PAYLOAD ||
+ phy->next_read_size > FDP_NCI_I2C_MAX_PAYLOAD) {
+ dev_dbg(&client->dev, "%s: corrupted packet\n",
+ __func__);
+ phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
+ goto flush;
+ }
} else {
phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
+ /*
+ * Only one data packet is delivered per call; if the
+ * device sends another, do not overwrite and leak the
+ * skb allocated for the previous one.
+ */
+ if (*skb) {
+ kfree_skb(*skb);
+ *skb = NULL;
+ }
+
*skb = alloc_skb(len, GFP_KERNEL);
if (*skb == NULL) {
r = -ENOMEM;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 36/77] nfc: microread: validate target discovery payload lengths
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (34 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 35/77] nfc: fdp: bound the device-reported read length and fix an skb leak Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:25 ` [PATCH 6.12 37/77] nfc: llcp: bound the connect_sn TLV walk to the skb Greg Kroah-Hartman
` (48 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Pengpeng Hou, David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <pengpeng@iscas.ac.cn>
commit 25519469972ef57c3edb1805dabd6c5612b90211 upstream.
microread_target_discovered() parses target discovery payloads from
skb->data according to the HCI gate. The fixed field offsets and UID
copies were checked only against the destination nfc_target buffers, not
against the actual skb length.
Validate that each gate-specific payload contains the fixed fields and
UID bytes before reading or copying them.
Fixes: cfad1ba87150 ("NFC: Initial support for Inside Secure microread")
Cc: stable@vger.kernel.org
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Link: https://patch.msgid.link/20260723103508.1-microread-v2-pengpeng@iscas.ac.cn
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nfc/microread/microread.c | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
--- a/drivers/nfc/microread/microread.c
+++ b/drivers/nfc/microread/microread.c
@@ -483,13 +483,19 @@ static void microread_target_discovered(
switch (gate) {
case MICROREAD_GATE_ID_MREAD_ISO_A:
+ if (skb->len <= MICROREAD_EMCF_A_LEN) {
+ r = -EINVAL;
+ goto exit_free;
+ }
+
targets->supported_protocols =
nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A_SAK]);
targets->sens_res =
be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A_ATQA]);
targets->sel_res = skb->data[MICROREAD_EMCF_A_SAK];
targets->nfcid1_len = skb->data[MICROREAD_EMCF_A_LEN];
- if (targets->nfcid1_len > sizeof(targets->nfcid1)) {
+ if (targets->nfcid1_len > sizeof(targets->nfcid1) ||
+ targets->nfcid1_len > skb->len - MICROREAD_EMCF_A_UID) {
r = -EINVAL;
goto exit_free;
}
@@ -497,13 +503,19 @@ static void microread_target_discovered(
targets->nfcid1_len);
break;
case MICROREAD_GATE_ID_MREAD_ISO_A_3:
+ if (skb->len <= MICROREAD_EMCF_A3_LEN) {
+ r = -EINVAL;
+ goto exit_free;
+ }
+
targets->supported_protocols =
nfc_hci_sak_to_protocol(skb->data[MICROREAD_EMCF_A3_SAK]);
targets->sens_res =
be16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_A3_ATQA]);
targets->sel_res = skb->data[MICROREAD_EMCF_A3_SAK];
targets->nfcid1_len = skb->data[MICROREAD_EMCF_A3_LEN];
- if (targets->nfcid1_len > sizeof(targets->nfcid1)) {
+ if (targets->nfcid1_len > sizeof(targets->nfcid1) ||
+ targets->nfcid1_len > skb->len - MICROREAD_EMCF_A3_UID) {
r = -EINVAL;
goto exit_free;
}
@@ -511,11 +523,21 @@ static void microread_target_discovered(
targets->nfcid1_len);
break;
case MICROREAD_GATE_ID_MREAD_ISO_B:
+ if (skb->len < MICROREAD_EMCF_B_UID + 4) {
+ r = -EINVAL;
+ goto exit_free;
+ }
+
targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK;
memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_B_UID], 4);
targets->nfcid1_len = 4;
break;
case MICROREAD_GATE_ID_MREAD_NFC_T1:
+ if (skb->len < MICROREAD_EMCF_T1_UID + 4) {
+ r = -EINVAL;
+ goto exit_free;
+ }
+
targets->supported_protocols = NFC_PROTO_JEWEL_MASK;
targets->sens_res =
le16_to_cpu(*(u16 *)&skb->data[MICROREAD_EMCF_T1_ATQA]);
@@ -523,6 +545,11 @@ static void microread_target_discovered(
targets->nfcid1_len = 4;
break;
case MICROREAD_GATE_ID_MREAD_NFC_T3:
+ if (skb->len < MICROREAD_EMCF_T3_UID + 8) {
+ r = -EINVAL;
+ goto exit_free;
+ }
+
targets->supported_protocols = NFC_PROTO_FELICA_MASK;
memcpy(targets->nfcid1, &skb->data[MICROREAD_EMCF_T3_UID], 8);
targets->nfcid1_len = 8;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 37/77] nfc: llcp: bound the connect_sn TLV walk to the skb
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (35 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 36/77] nfc: microread: validate target discovery payload lengths Greg Kroah-Hartman
@ 2026-08-25 13:25 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 38/77] nfc: llcp: fix OOB read and u8 offset wrap in TLV parsers Greg Kroah-Hartman
` (47 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:25 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Doruk Tan Ozturk, Simon Horman,
David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <doruk@0sec.ai>
commit 55c68ac93e7dacc0f5f608b9c39dd4ff48cf28e8 upstream.
Commit 27256cdb290e ("nfc: llcp: bound SNL TLV parsing to the skb and
add length checks") fixed the unbounded TLV walk in nfc_llcp_recv_snl(),
and commit d8bd2dedbde5 ("nfc: llcp: fix OOB read and u8 offset wrap in
TLV parsers") subsequently bounded nfc_llcp_parse_gb_tlv() and
nfc_llcp_parse_connection_tlv(). One sibling parser sharing the same
pattern remains unbounded: nfc_llcp_connect_sn().
nfc_llcp_connect_sn() walks a TLV list, reading a two-byte header
(type, length) followed by length bytes of value, without checking that
the two header bytes or the declared length stay within the buffer. It
returns a pointer to a service name of up to 255 bytes that may point
past the end of the skb; it is subsequently consumed by memcmp() in
nfc_llcp_sock_from_sn(). In addition tlv_array_len was computed as
"skb->len - LLCP_HEADER_SIZE" in size_t, so a CONNECT/CC frame shorter
than the LLCP header underflows to a huge length and the walk runs far
past the buffer.
nfc_llcp_connect_sn() is reachable from nfc_llcp_recv_connect() and
nfc_llcp_recv_cc(), i.e. from received CONNECT and CC PDUs. A nearby
NFC device can reach this without authentication; LLCP link activation
happens automatically after NFC-DEP, and the nfc_llcp_rx_skb()
dispatcher applies no minimum-length guard.
Walk the TLV list by pointer, bounded by skb_tail_pointer(skb), and
validate each declared length before use, matching the approach already
used for nfc_llcp_recv_snl(). Starting the walk at
&skb->data[LLCP_HEADER_SIZE] against the tail pointer also removes the
size_t underflow for short frames.
Found by 0sec automated security-research tooling (https://0sec.ai).
Fixes: d646960f7986 ("NFC: Initial LLCP support")
Cc: stable@vger.kernel.org
Assisted-by: 0sec:claude-opus-4-8
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260709131229.44477-1-doruk@0sec.ai
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/nfc/llcp_core.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
--- a/net/nfc/llcp_core.c
+++ b/net/nfc/llcp_core.c
@@ -847,13 +847,16 @@ static struct nfc_llcp_sock *nfc_llcp_so
static const u8 *nfc_llcp_connect_sn(const struct sk_buff *skb, size_t *sn_len)
{
u8 type, length;
- const u8 *tlv = &skb->data[2];
- size_t tlv_array_len = skb->len - LLCP_HEADER_SIZE, offset = 0;
+ const u8 *tlv = &skb->data[LLCP_HEADER_SIZE];
+ const u8 *tlv_end = skb_tail_pointer(skb);
- while (offset < tlv_array_len) {
+ while (tlv + 2 < tlv_end) {
type = tlv[0];
length = tlv[1];
+ if (tlv + 2 + length > tlv_end)
+ break;
+
pr_debug("type 0x%x length %d\n", type, length);
if (type == LLCP_TLV_SN) {
@@ -861,7 +864,6 @@ static const u8 *nfc_llcp_connect_sn(con
return &tlv[2];
}
- offset += length + 2;
tlv += length + 2;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 38/77] nfc: llcp: fix OOB read and u8 offset wrap in TLV parsers
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (36 preceding siblings ...)
2026-08-25 13:25 ` [PATCH 6.12 37/77] nfc: llcp: bound the connect_sn TLV walk to the skb Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 39/77] nfc: llcp: reject PDUs shorter than the LLCP header Greg Kroah-Hartman
` (46 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Muhammad Bilal, Simon Horman,
David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muhammad Bilal <meatuni001@gmail.com>
commit 78b20c8eeacd2e44a2d8a4cb5316d3c521d90911 upstream.
nfc_llcp_parse_gb_tlv() and nfc_llcp_parse_connection_tlv() contain
three related bugs in their TLV parsing loops:
1. 'offset' is declared u8 but tlv_array_len is u16. When TLV data
advances offset past 255 it silently wraps to zero, causing
infinite loops or double-processing of buffer data.
2. Before reading tlv[0] (type) and tlv[1] (length) there is no
check that offset+2 <= tlv_array_len. A truncated TLV causes
an OOB read of one byte past the buffer end.
3. After reading the length field, the value bytes are accessed
without checking offset+2+length <= tlv_array_len. A crafted
length=0xFF on a short buffer causes up to 255 bytes of OOB
read past the buffer end.
Both functions are reachable without authentication via
nfc_llcp_set_remote_gb() which feeds remote LLCP general bytes
directly into nfc_llcp_parse_gb_tlv() with no additional
validation.
Fix all three issues by widening offset from u8 to u16 and adding
bounds checks for both the TLV header and value field before each
access.
Fixes: 3df40eb3a2ea ("nfc: constify several pointers to u8, char and sk_buff")
Cc: stable@vger.kernel.org
Signed-off-by: Muhammad Bilal <meatuni001@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260622131802.239035-1-meatuni001@gmail.com
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/nfc/llcp_commands.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
--- a/net/nfc/llcp_commands.c
+++ b/net/nfc/llcp_commands.c
@@ -193,7 +193,8 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llc
const u8 *tlv_array, u16 tlv_array_len)
{
const u8 *tlv = tlv_array;
- u8 type, length, offset = 0;
+ u8 type, length;
+ u16 offset = 0;
pr_debug("TLV array length %d\n", tlv_array_len);
@@ -201,9 +202,15 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llc
return -ENODEV;
while (offset < tlv_array_len) {
+ if (offset + 2 > tlv_array_len)
+ return -EINVAL;
+
type = tlv[0];
length = tlv[1];
+ if (offset + 2 + length > tlv_array_len)
+ return -EINVAL;
+
pr_debug("type 0x%x length %d\n", type, length);
switch (type) {
@@ -243,7 +250,8 @@ int nfc_llcp_parse_connection_tlv(struct
const u8 *tlv_array, u16 tlv_array_len)
{
const u8 *tlv = tlv_array;
- u8 type, length, offset = 0;
+ u8 type, length;
+ u16 offset = 0;
pr_debug("TLV array length %d\n", tlv_array_len);
@@ -251,9 +259,15 @@ int nfc_llcp_parse_connection_tlv(struct
return -ENOTCONN;
while (offset < tlv_array_len) {
+ if (offset + 2 > tlv_array_len)
+ return -EINVAL;
+
type = tlv[0];
length = tlv[1];
+ if (offset + 2 + length > tlv_array_len)
+ return -EINVAL;
+
pr_debug("type 0x%x length %d\n", type, length);
switch (type) {
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 39/77] nfc: llcp: reject PDUs shorter than the LLCP header
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (37 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 38/77] nfc: llcp: fix OOB read and u8 offset wrap in TLV parsers Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 40/77] nfc: pn533: purge fragmented skbs during cleanup Greg Kroah-Hartman
` (45 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, David Laight, Doruk Tan Ozturk,
Vadim Fedorenko, David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <doruk@0sec.ai>
commit 95674f506c6376d6722a23144c9acd26609771ed upstream.
Every LLCP PDU begins with a two-byte header (DSAP/SSAP + PTYPE), but the
receive path never checked that a frame is at least LLCP_HEADER_SIZE bytes
before parsing it.
nfc_llcp_rx_skb() reads the header via nfc_llcp_ptype()/nfc_llcp_dsap()/
nfc_llcp_ssap(), which dereference pdu->data[0] and pdu->data[1], and a
CONNECT or CC PDU then computes
tlv_array_len = skb->len - LLCP_HEADER_SIZE;
as a size_t and hands it to the TLV walk. When the frame is shorter than
the header the subtraction wraps to a huge value and the walk runs far
past the buffer, an out-of-bounds read.
A nearby NFC device can reach this without authentication; LLCP link
activation happens automatically after NFC-DEP.
Guard the common receive choke point __nfc_llcp_recv(), shared by both the
target (nfc_llcp_data_received()) and initiator (nfc_llcp_recv()) paths, so
a short skb is dropped before the rx_work worker parses it. Use
pskb_may_pull() rather than a skb->len test so the two header bytes are
guaranteed to sit in the skb linear area even for a non-linear skb,
matching how the sibling NCI and HCI receive paths validate their headers.
Reproduced with a KFENCE out-of-bounds read via /dev/virtual_nci on
linux-next.
Found by 0sec automated security-research tooling (https://0sec.ai).
Fixes: d646960f7986 ("NFC: Initial LLCP support")
Cc: stable@vger.kernel.org
Suggested-by: David Laight <david.laight.linux@gmail.com>
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Link: https://patch.msgid.link/20260714164631.75068-1-doruk@0sec.ai
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/nfc/llcp_core.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/net/nfc/llcp_core.c
+++ b/net/nfc/llcp_core.c
@@ -1552,6 +1552,11 @@ static void nfc_llcp_rx_work(struct work
static void __nfc_llcp_recv(struct nfc_llcp_local *local, struct sk_buff *skb)
{
+ if (!pskb_may_pull(skb, LLCP_HEADER_SIZE)) {
+ kfree_skb(skb);
+ return;
+ }
+
local->rx_pending = skb;
del_timer(&local->link_timer);
schedule_work(&local->rx_work);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 40/77] nfc: pn533: purge fragmented skbs during cleanup
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (38 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 39/77] nfc: llcp: reject PDUs shorter than the LLCP header Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 41/77] nfc: st21nfca: validate ATR_REQ length against the received frame Greg Kroah-Hartman
` (44 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Xu Rao, David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <raoxu@uniontech.com>
commit 5718fc62198c38c2de5316020a90506f9e75e0bb upstream.
pn53x_common_clean() purges resp_q before freeing the common PN533 state,
but it leaves fragment_skb untouched. The fragmentation helpers queue
transmit fragments there while sending large initiator or target-mode
frames, and those skbs remain owned by the driver until they are sent or
discarded.
If the device is removed while fragments are still queued, the common
cleanup path frees the PN533 state without releasing the queued fragment
skbs, leaking them.
Purge fragment_skb during cleanup alongside resp_q.
Fixes: 963a82e07d4e ("NFC: pn533: Split large Tx frames in chunks")
Cc: stable@vger.kernel.org
Signed-off-by: Xu Rao <raoxu@uniontech.com>
Link: https://patch.msgid.link/2D896607CAE4408E+20260720021444.3362044-1-raoxu@uniontech.com
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nfc/pn533/pn533.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/nfc/pn533/pn533.c
+++ b/drivers/nfc/pn533/pn533.c
@@ -2803,6 +2803,7 @@ void pn53x_common_clean(struct pn533 *pr
destroy_workqueue(priv->wq);
skb_queue_purge(&priv->resp_q);
+ skb_queue_purge(&priv->fragment_skb);
list_for_each_entry_safe(cmd, n, &priv->cmd_queue, queue) {
list_del(&cmd->queue);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 41/77] nfc: st21nfca: validate ATR_REQ length against the received frame
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (39 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 40/77] nfc: pn533: purge fragmented skbs during cleanup Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 42/77] nfc: nci: fix out-of-bounds write in nci_target_auto_activated() Greg Kroah-Hartman
` (43 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Doruk Tan Ozturk, Simon Horman,
David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <doruk@0sec.ai>
commit 5cdcca5d62a66eda6b774110a44cba67bc1a8d1d upstream.
st21nfca_tm_recv_atr_req() checks that the received ATR_REQ frame is at
least ST21NFCA_ATR_REQ_MIN_SIZE and that the self-declared atr_req->length
is at least sizeof(struct st21nfca_atr_req), but never checks that
atr_req->length does not exceed the actual received length (skb->len).
st21nfca_tm_send_atr_res() then trusts the declared length:
gb_len = atr_req->length - sizeof(struct st21nfca_atr_req);
...
memcpy(atr_res->gbi, atr_req->gbi, gb_len);
so an RF peer that sends a short frame but sets atr_req->length larger
than the frame makes gb_len exceed the general bytes actually present,
and the memcpy reads out of bounds past the received skb. Those bytes are
placed in the ATR_RES and sent back to the peer (kernel-memory disclosure
to a proximity attacker); a larger declared length is an out-of-bounds
read (DoS).
Reject frames whose declared length exceeds the received length. The
adjacent nfc_tm_activated() path in the same function already derives its
general-bytes length from skb->len rather than the declared field.
Found by 0sec (https://0sec.ai) using automated source analysis; the
missing bound is evident from source. Compile-tested.
Fixes: 1892bf844ea0 ("NFC: st21nfca: Adding P2P support to st21nfca in Initiator & Target mode")
Cc: stable@vger.kernel.org
Assisted-by: 0sec:claude-opus-4-8
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260711071301.58071-1-doruk@0sec.ai
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nfc/st21nfca/dep.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/nfc/st21nfca/dep.c
+++ b/drivers/nfc/st21nfca/dep.c
@@ -207,6 +207,9 @@ static int st21nfca_tm_recv_atr_req(stru
if (atr_req->length < sizeof(struct st21nfca_atr_req))
return -EPROTO;
+ if (atr_req->length > skb->len)
+ return -EPROTO;
+
r = st21nfca_tm_send_atr_res(hdev, atr_req);
if (r)
return r;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 42/77] nfc: nci: fix out-of-bounds write in nci_target_auto_activated()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (40 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 41/77] nfc: st21nfca: validate ATR_REQ length against the received frame Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 43/77] nfc: nci: fix uninit-value in the RF discover/activated NTF handlers Greg Kroah-Hartman
` (42 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Samuel Page, Simon Horman,
David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Page <sam@bynar.io>
commit ac200079db50af81e6b04d058b33ec92901d8edd upstream.
nci_target_auto_activated() appends a target to the fixed-size array
ndev->targets[NCI_MAX_DISCOVERED_TARGETS] and increments ndev->n_targets
without first checking the array is full; unlike its sibling
nci_add_new_target(), which bails out when n_targets already equals
NCI_MAX_DISCOVERED_TARGETS.
ndev->n_targets is only cleared by nci_clear_target_list(), so an NFCC
that repeatedly re-runs discovery (RF_DISCOVER_RSP, which re-enters
NCI_DISCOVERY without clearing the target list) and reports an
auto-activated target (RF_INTF_ACTIVATED_NTF) drives n_targets past the
limit. The append then writes a struct nfc_target past the end of the
array (a slab out-of-bounds write), and nfc_targets_found() goes on to
walk the array with the inflated count:
BUG: KASAN: slab-out-of-bounds in nci_add_new_protocol+0x94/0x2ac [nci]
Write of size 2 at addr ffff0000c7299a18 by task kworker/u8:0/12
Workqueue: nfc0_nci_rx_wq nci_rx_work [nci]
Call trace:
nci_add_new_protocol+0x94/0x2ac [nci]
nci_ntf_packet+0xddc/0x11a0 [nci]
nci_rx_work+0x15c/0x1e0 [nci]
process_one_work+0x2dc/0x500
worker_thread+0x240/0x460
kthread+0x1c0/0x1d0
ret_from_fork+0x10/0x20
The buggy address belongs to the cache kmalloc-2k of size 2048
The buggy address is located 1024 bytes to the right of
allocated 1560-byte region [ffff0000c7299000, ffff0000c7299618)
Guard nci_target_auto_activated() with the same check used by
nci_add_new_target().
Fixes: 019c4fbaa790 ("NFC: Add NCI multiple targets support")
Cc: stable@vger.kernel.org
Assisted-by: Bynario AI
Signed-off-by: Samuel Page <sam@bynar.io>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260622145243.3167276-1-sam@bynar.io
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/nfc/nci/ntf.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -603,6 +603,12 @@ static void nci_target_auto_activated(st
struct nfc_target *target;
int rc;
+ /* This is a new target, check if we've enough room */
+ if (ndev->n_targets == NCI_MAX_DISCOVERED_TARGETS) {
+ pr_debug("not enough room, ignoring new target...\n");
+ return;
+ }
+
target = &ndev->targets[ndev->n_targets];
rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol,
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 43/77] nfc: nci: fix uninit-value in the RF discover/activated NTF handlers
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (41 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 42/77] nfc: nci: fix out-of-bounds write in nci_target_auto_activated() Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 44/77] nfc: nci: free destination parameters when closing a connection Greg Kroah-Hartman
` (41 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Samuel Page, David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Page <sam@bynar.io>
commit 8cbe06c1e699c0a165dae5093a2550e65f914818 upstream.
nci_rf_discover_ntf_packet() and nci_rf_intf_activated_ntf_packet() each
parse a notification into an on-stack struct (nci_rf_discover_ntf /
nci_rf_intf_activated_ntf) that is not initialised. The RF
technology-specific parameters are only extracted when
rf_tech_specific_params_len is non-zero, so a notification that reports a
zero length leaves the rf_tech_specific_params union uninitialised - and
both handlers then pass it to nci_add_new_protocol(), which reads it:
- discover: nci_add_new_target() -> nci_add_new_protocol();
- activated: nci_target_auto_activated() -> nci_add_new_protocol().
nci_add_new_protocol() uses nfca_poll->nfcid1_len as both a branch
condition and a memcpy() length and copies nfcid1/sens_res/sel_res into
ndev->targets, which is later exposed to user space via NFC_CMD_GET_TARGET.
BUG: KMSAN: uninit-value in nci_add_new_protocol+0x624/0x6c0
nci_add_new_protocol+0x624/0x6c0
nci_ntf_packet+0x25b2/0x3c30
nci_rx_work+0x318/0x5d0
process_scheduled_works+0x84b/0x17a0
worker_thread+0xc10/0x11b0
kthread+0x376/0x500
Local variable ntf.i created at:
nci_ntf_packet+0xbc2/0x3c30
Zero-initialise both on-stack notifications so the union reads back as
zero when no technology-specific parameters are present.
Fixes: 019c4fbaa790 ("NFC: Add NCI multiple targets support")
Fixes: e8c0dacd9836 ("NFC: Update names and structs to NCI spec 1.0 d18")
Link: https://lore.kernel.org/netdev/20260623172109.1105965-2-horms@kernel.org/
Cc: stable@vger.kernel.org
Assisted-by: Bynario AI
Signed-off-by: Samuel Page <sam@bynar.io>
Link: https://patch.msgid.link/20260626090301.2139500-1-sam@bynar.io
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/nfc/nci/ntf.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -440,7 +440,7 @@ void nci_clear_target_list(struct nci_de
static int nci_rf_discover_ntf_packet(struct nci_dev *ndev,
const struct sk_buff *skb)
{
- struct nci_rf_discover_ntf ntf;
+ struct nci_rf_discover_ntf ntf = {};
const __u8 *data;
bool add_target = true;
@@ -672,7 +672,7 @@ static int nci_rf_intf_activated_ntf_pac
const struct sk_buff *skb)
{
struct nci_conn_info *conn_info;
- struct nci_rf_intf_activated_ntf ntf;
+ struct nci_rf_intf_activated_ntf ntf = {};
const __u8 *data;
int err = NCI_STATUS_OK;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 44/77] nfc: nci: free destination parameters when closing a connection
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (42 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 43/77] nfc: nci: fix uninit-value in the RF discover/activated NTF handlers Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 45/77] ndisc: ndisc_send_redirect() cleanup Greg Kroah-Hartman
` (40 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Linmao Li, Vadim Fedorenko,
David Heidelberg
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <lilinmao@kylinos.cn>
commit 2e65bafdfd3a8bba972b3d17b6a57816557530fc upstream.
When a connection is closed, nci_core_conn_close_rsp_packet() frees
conn_info but not conn_info->dest_params, which is a separate devm
allocation. Each connect/close cycle leaks one dest_params until the
NFC device is removed. Free dest_params along with conn_info.
Fixes: 9b8d1a4cf2aa ("nfc: nci: Add an additional parameter to identify a connection id")
Cc: stable@vger.kernel.org
Signed-off-by: Linmao Li <lilinmao@kylinos.cn>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Link: https://patch.msgid.link/20260721023518.1697625-1-lilinmao@kylinos.cn
Signed-off-by: David Heidelberg <david@ixit.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/nfc/nci/rsp.c | 1 +
1 file changed, 1 insertion(+)
--- a/net/nfc/nci/rsp.c
+++ b/net/nfc/nci/rsp.c
@@ -336,6 +336,7 @@ static void nci_core_conn_close_rsp_pack
list_del(&conn_info->list);
if (conn_info == ndev->rf_conn_info)
ndev->rf_conn_info = NULL;
+ devm_kfree(&ndev->nfc_dev->dev, conn_info->dest_params);
devm_kfree(&ndev->nfc_dev->dev, conn_info);
}
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 45/77] ndisc: ndisc_send_redirect() cleanup
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (43 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 44/77] nfc: nci: free destination parameters when closing a connection Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 46/77] Input: byd - synchronize timer deletion before freeing private data Greg Kroah-Hartman
` (39 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Dumazet, David Ahern,
Jakub Kicinski, Li Xiasong
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
commit 0784d83df3bfc977c13252a0599be924f0afa68d upstream.
ndisc_send_redirect() is always called under rcu_read_lock().
It can use dev_net_rcu() and avoid one redundant
rcu_read_lock()/rcu_read_unlock() pair.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20250214140705.2105890-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Li Xiasong <lixiasong1@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/ipv6/ndisc.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1683,7 +1683,7 @@ static void ndisc_fill_redirect_hdr_opti
void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
{
struct net_device *dev = skb->dev;
- struct net *net = dev_net(dev);
+ struct net *net = dev_net_rcu(dev);
struct sock *sk = net->ipv6.ndisc_sk;
int optlen = 0;
struct inet_peer *peer;
@@ -1698,8 +1698,8 @@ void ndisc_send_redirect(struct sk_buff
ops_data_buf[NDISC_OPS_REDIRECT_DATA_SPACE], *ops_data = NULL;
bool ret;
- if (netif_is_l3_master(skb->dev)) {
- dev = dev_get_by_index_rcu(dev_net(skb->dev), IPCB(skb)->iif);
+ if (netif_is_l3_master(dev)) {
+ dev = dev_get_by_index_rcu(net, IPCB(skb)->iif);
if (!dev)
return;
}
@@ -1737,12 +1737,10 @@ void ndisc_send_redirect(struct sk_buff
goto release;
}
- rcu_read_lock();
peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr);
if (!peer)
goto release;
ret = inet_peer_xrlim_allow(peer, 1*HZ);
- rcu_read_unlock();
if (!ret)
goto release;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 46/77] Input: byd - synchronize timer deletion before freeing private data
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (44 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 45/77] ndisc: ndisc_send_redirect() cleanup Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 47/77] ipv4: reject undersized MTUs in ip_do_fragment() Greg Kroah-Hartman
` (38 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Linmao Li, Dmitry Torokhov,
Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <lilinmao@kylinos.cn>
commit c83e79c0842ed29860648bcce5022ef0ba5001c6 upstream.
byd_disconnect() uses timer_delete() before freeing the driver's private
data. This does not wait for a running byd_clear_touch() callback, which
dereferences the private data and its psmouse pointer. A callback racing
with disconnect can therefore access the private data after it has been
freed. The timer can also still be re-armed by byd_process_byte() while
the disconnect is in progress.
Use timer_shutdown_sync() before freeing the private data: it waits for
a running callback and turns any later re-arm attempt into a no-op.
Fixes: 2d5f5611dd0d ("Input: byd - enable absolute mode")
Cc: stable@vger.kernel.org
Signed-off-by: Linmao Li <lilinmao@kylinos.cn>
Link: https://patch.msgid.link/20260720061259.1601281-1-lilinmao@kylinos.cn
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
[ changed `del_timer()` to `timer_shutdown_sync()` since 6.12 predates the `del_timer()` → `timer_delete()` rename ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/input/mouse/byd.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/input/mouse/byd.c
+++ b/drivers/input/mouse/byd.c
@@ -426,7 +426,7 @@ static void byd_disconnect(struct psmous
struct byd_data *priv = psmouse->private;
if (priv) {
- del_timer(&priv->timer);
+ timer_shutdown_sync(&priv->timer);
kfree(psmouse->private);
psmouse->private = NULL;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 47/77] ipv4: reject undersized MTUs in ip_do_fragment()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (45 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 46/77] Input: byd - synchronize timer deletion before freeing private data Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 48/77] ipv6: fix use-after-free in ip6_finish_output2() Greg Kroah-Hartman
` (37 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vega, Yong Wang, Ren Wei,
Ido Schimmel, Jakub Kicinski
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yong Wang <edragain@163.com>
commit c0726f0caf8c6b3208552949e17d23634a2f3129 upstream.
ip_do_fragment() subtracts the IPv4 header length from the effective
MTU and passes the resulting payload MTU to ip_frag_next().
If the effective MTU is smaller than hlen + 8, ip_frag_next() rounds
the fragment payload length down to zero. The fragmentation state then
never makes forward progress: state->left, state->ptr and state->offset
stay unchanged while ip_do_fragment() keeps allocating and transmitting
header-only fragments until the softlockup detector fires.
This is reproducible with a route installed using "mtu lock 20", but it
is also reproducible without route MTU lock, for example by forwarding a
packet to a device whose MTU is 20.
Fix it in ip_do_fragment() by rejecting mtu < hlen + 8 with -EMSGSIZE,
matching the existing IPv6 fragmentation check.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Yong Wang <edragain@163.com>
Signed-off-by: Ren Wei <weir@nebusec.ai>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/8809ef6314b98913681b0b370a05a85c2b6cd579.1786599079.git.edragain@163.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/ipv4/ip_output.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -798,6 +798,10 @@ int ip_do_fragment(struct net *net, stru
*/
hlen = iph->ihl * 4;
+ if (mtu < hlen + 8) {
+ err = -EMSGSIZE;
+ goto fail;
+ }
mtu = mtu - hlen; /* Size of data space */
IPCB(skb)->flags |= IPSKB_FRAG_COMPLETE;
ll_rs = LL_RESERVED_SPACE(rt->dst.dev);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 48/77] ipv6: fix use-after-free in ip6_finish_output2()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (46 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 47/77] ipv4: reject undersized MTUs in ip_do_fragment() Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 49/77] nvmet-auth: zero the AUTH_RECEIVE response buffer Greg Kroah-Hartman
` (36 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Vega, Luxiao Xu, Ren Wei,
Vadim Fedorenko, Ido Schimmel, Jakub Kicinski
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luxiao Xu <rakukuip@gmail.com>
commit d0d48d999b0eee6bb176ef4e39d9be868fa80f7e upstream.
ip6_finish_output2() caches a pointer to the IPv6 destination
address (daddr) before invoking lwtunnel_xmit(). The LWT-BPF
transmit path or other encapsulation operations within
lwtunnel_xmit() can reallocate the skb head, freeing the memory
that daddr points to. When lwtunnel_xmit() returns
LWTUNNEL_XMIT_CONTINUE, the function continues to use the stale
daddr pointer to compute the nexthop and to look up or create the
neighbour entry. This results in a use-after-free read, which can
leak sensitive kernel data, pollute the neighbour table with
arbitrary values, misdirect traffic, or crash the system.
Fix this by re-fetching the IPv6 header and the destination
address pointer after lwtunnel_xmit() returns
LWTUNNEL_XMIT_CONTINUE, ensuring that the subsequent nexthop
computation and neighbour lookup operate on valid memory.
Fixes: e415ed3a4b8b ("ipv6: use skb_expand_head in ip6_finish_output2")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Signed-off-by: Luxiao Xu <rakukuip@gmail.com>
Signed-off-by: Ren Wei <weir@nebusec.ai>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/4aa3f53bc44e79572c6dd2340ec7b68ef1a3d87d.1786516730.git.rakukuip@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/ipv6/ip6_output.c | 2 ++
1 file changed, 2 insertions(+)
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -119,6 +119,8 @@ static int ip6_finish_output2(struct net
if (res != LWTUNNEL_XMIT_CONTINUE)
return res;
+ hdr = ipv6_hdr(skb);
+ daddr = &hdr->daddr;
}
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 49/77] nvmet-auth: zero the AUTH_RECEIVE response buffer
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (47 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 48/77] ipv6: fix use-after-free in ip6_finish_output2() Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 50/77] nvmet-fc: fix invalid free in LS IOD error path Greg Kroah-Hartman
` (35 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bryam Vargas, Christoph Hellwig,
Keith Busch
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <hexlabsecurity@proton.me>
commit 3ddcfb013322aa37eaa7a0d344b73079c38dfa21 upstream.
nvmet_execute_auth_receive() allocates the response buffer with kmalloc()
sized by the host-supplied AUTH_RECEIVE allocation length, but the
DH-HMAC-CHAP builders write only a fixed-size message into it. The full
allocation length is then copied to the wire by nvmet_copy_to_sgl(), so a
remote initiator receives the bytes past the built message -- up to nearly
a page of uninitialized slab -- during the pre-authentication handshake.
Allocate the buffer with kzalloc() so the unwritten tail is zeroed before
it is sent; conforming responses are unaffected.
Fixes: db1312dd9548 ("nvmet: implement basic In-Band Authentication")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvme/target/fabrics-cmd-auth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/nvme/target/fabrics-cmd-auth.c
+++ b/drivers/nvme/target/fabrics-cmd-auth.c
@@ -509,7 +509,7 @@ void nvmet_execute_auth_receive(struct n
return;
}
- d = kmalloc(al, GFP_KERNEL);
+ d = kzalloc(al, GFP_KERNEL);
if (!d) {
status = NVME_SC_INTERNAL;
goto done;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 50/77] nvmet-fc: fix invalid free in LS IOD error path
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (48 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 49/77] nvmet-auth: zero the AUTH_RECEIVE response buffer Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 51/77] nvmet-tcp: bound SGL data length before allocating command buffers Greg Kroah-Hartman
` (34 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Maurizio Lombardi, Jiang HongHui,
Keith Busch
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiang HongHui <jiang_hh2019@163.com>
commit ba98d6796d12258e837ece065d2ecb59d76ce4ff upstream.
nvmet_fc_alloc_ls_iodlist() advances iod while initializing the LS IOD
array. If an rqstbuf allocation or response buffer DMA mapping fails,
the unwind loop decrements iod past the start of the array. The final
kfree(iod) therefore frees an address before the allocated object.
This can be reproduced with nvme-fcloop and failslab by setting
fail-nth to 6 before creating a target port. KASAN reports:
BUG: KASAN: invalid-free in nvmet_fc_register_targetport
Free of addr ffff88816cf8ff48 by task nvmet_fail_nth/9552
Free the original allocation base stored in tgtport->iod instead. With
this fix applied, the same sysfs write with fail-nth=6 returns -ENOMEM
without any KASAN report.
Fixes: c53432030d86 ("nvme-fabrics: Add target support for FC transport")
Cc: stable@vger.kernel.org
Reviewed-by: Maurizio Lombardi <mlombard@redhat.com>
Assisted-by: Codex:gpt-5
Signed-off-by: Jiang HongHui <jiang_hh2019@163.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvme/target/fc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/nvme/target/fc.c
+++ b/drivers/nvme/target/fc.c
@@ -569,7 +569,7 @@ out_fail:
list_del(&iod->ls_rcv_list);
}
- kfree(iod);
+ kfree(tgtport->iod);
return -EFAULT;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 51/77] nvmet-tcp: bound SGL data length before allocating command buffers
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (49 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 50/77] nvmet-fc: fix invalid free in LS IOD error path Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 52/77] nvmet-tcp: Do not WARN on remotely-controlled oversized SGL allocations Greg Kroah-Hartman
` (33 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Christoph Hellwig, Ibrahim Hashimov,
Keith Busch
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <security@auditcode.ai>
commit 4a3f00262a044e8e15064b1a6860968bf0500bf4 upstream.
nvmet_tcp_map_data() reads the host-controlled 32-bit sgl->length
and, for the in-capsule offset descriptor (type 0x01), checks it
against port->inline_data_size before use. Any other SGL descriptor
type -- including the non-inline transport SGL data-block descriptor
(type (NVME_TRANSPORT_SGL_DATA_DESC << 4) | NVME_SGL_FMT_TRANSPORT_A,
the type a real host uses for out-of-capsule writes) skips that check
entirely and falls straight through to:
cmd->req.sg = sgl_alloc(len, GFP_KERNEL, &cmd->req.sg_cnt);
with len taken directly from the wire, unbounded up to 4 GiB.
nvmet_req_init() only parses the command and never inspects
sgl->length, and nvmet_check_transfer_len() -- the only other place
transfer_len is validated -- runs later, from req->execute(), after
the allocation has already happened. For a write command the target
responds with an R2T and parks the command waiting for the host to
send the data; if the host (or an unauthenticated peer that simply
never follows up) never does, the sgl_alloc() buffer stays resident
for the life of the command. NVMe/TCP has no mandatory authentication
in the default configuration, so any peer able to reach the target
portal and complete a Fabrics connect can drive this with a single
crafted command, repeatable across queues and connections for
amplification. This is unbounded kernel memory allocation
triggered by a remote, effectively unauthenticated peer.
Validate len against the same NVMET_TCP_MAXH2CDATA ceiling this file
already uses to bound per-PDU H2C data, for every SGL descriptor type,
before doing any allocation. This closes the gap for the non-inline
descriptor while leaving the existing, tighter inline_data_size check
in place for the in-capsule case.
Runtime-verified on a v6.19 KASAN stand: with this bound in place, a
crafted write command carrying an oversized non-inline SGL length is
rejected before sgl_alloc() runs, where the same request previously
drove an unbounded ~256 MiB kernel allocation (up to 4 GiB) that
stayed resident pending an R2T the host never satisfies.
Fixes: 872d26a391da ("nvmet-tcp: add NVMe over TCP target driver")
Cc: stable@vger.kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvme/target/tcp.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -441,6 +441,19 @@ static int nvmet_tcp_map_data(struct nvm
if (!len)
return 0;
+ /*
+ * inline_data_size only bounds the in-capsule (type 0x01) SGL
+ * descriptor below. A non-inline transport SGL data-block
+ * descriptor skips that check entirely and would otherwise reach
+ * sgl_alloc() with an attacker-controlled len of up to 4 GiB,
+ * pinning that much kernel memory for a command that may never
+ * complete. Bound every descriptor type here, before allocating
+ * anything, using the same ceiling this file already applies to
+ * per-PDU H2C data.
+ */
+ if (len > NVMET_TCP_MAXH2CDATA)
+ return NVME_SC_SGL_INVALID_DATA | NVME_STATUS_DNR;
+
if (sgl->type == ((NVME_SGL_FMT_DATA_DESC << 4) |
NVME_SGL_FMT_OFFSET)) {
if (!nvme_is_write(cmd->req.cmd))
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 52/77] nvmet-tcp: Do not WARN on remotely-controlled oversized SGL allocations
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (50 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 51/77] nvmet-tcp: bound SGL data length before allocating command buffers Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 53/77] selinux: require a classs permission values to cover its permission count Greg Kroah-Hartman
` (32 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, stable, Keith Busch
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
commit 737a3b535247226f6e1a7988fd9d6e63e7d6fc71 upstream.
When fuzzing the nvme target code, I tripped a kernel warning in
nvmet_tcp_map_data() because the length passed into the allocator is
controlled by the remote initiator.
A remote initiator that sends a command with an SGL claiming a huge
number, can create a scatterlist and iovec allocation of over 1 million
entries, which causes the backing kmalloc call to exceed MAX_PAGE_ORDER
and then the page allocator will trip on a WARN_ON_ONCE_GFP() message:
WARNING: mm/page_alloc.c:5280 __alloc_frozen_pages_noprof
Workqueue: nvmet_tcp_wq nvmet_tcp_io_work
...
sgl_alloc_order
nvmet_tcp_map_data
nvmet_tcp_try_recv_pdu
As it's never good to trip a kernel warning remotely due to many systems
having panic-on-warn enabled, let's silence it by just add GFP_NOWARN to
the allocation flags.
Assisted-by: gkh_clanker_2000
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvme/target/tcp.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -465,14 +465,15 @@ static int nvmet_tcp_map_data(struct nvm
}
cmd->req.transfer_len += len;
- cmd->req.sg = sgl_alloc(len, GFP_KERNEL, &cmd->req.sg_cnt);
+ cmd->req.sg = sgl_alloc(len, GFP_KERNEL | __GFP_NOWARN,
+ &cmd->req.sg_cnt);
if (!cmd->req.sg)
return NVME_SC_INTERNAL;
cmd->cur_sg = cmd->req.sg;
if (nvmet_tcp_has_data_in(cmd)) {
cmd->iov = kmalloc_array(cmd->req.sg_cnt,
- sizeof(*cmd->iov), GFP_KERNEL);
+ sizeof(*cmd->iov), GFP_KERNEL | __GFP_NOWARN);
if (!cmd->iov)
goto err;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 53/77] selinux: require a classs permission values to cover its permission count
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (51 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 52/77] nvmet-tcp: Do not WARN on remotely-controlled oversized SGL allocations Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 54/77] mptcp: pm: fix data race in add_addr timer callback Greg Kroah-Hartman
` (31 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Bryam Vargas, Stephen Smalley,
Paul Moore, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <hexlabsecurity@proton.me>
[ Upstream commit b98a8ac50775540f3804397ed08f61ef9910bcab ]
security_get_permissions() sizes an array by the class's permissions.nprim
and fills it at value - 1, from the inherited common's permission table and
then the class's own. A value no permission defines leaves a NULL that
sel_make_perm_files() passes to d_alloc_name(), an oops inside
sel_write_load() that strands selinux_state.policy_mutex and leaves every
later load in uninterruptible sleep; two permissions sharing a value
overwrite the first kstrdup(). Bounding each value by nprim catches
neither, and neither would a count: the symbol table is keyed on the
permission name, so duplicates pass.
Track the values each permission table claims and require them to cover
exactly what its count declares, rejecting a count no value can reach.
Conforming policies are unaffected.
Cc: stable@vger.kernel.org
Fixes: 55fcf09b3fe4 ("selinux: add support for querying object classes and permissions from the running policy")
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
[ folded in the missing perdatum->value guards and used `void *fp` instead of `struct policy_file *fp` in perm_read() ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
security/selinux/ss/policydb.c | 57 +++++++++++++++++++++++++++++++++++++----
1 file changed, 52 insertions(+), 5 deletions(-)
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -1132,7 +1132,18 @@ static int str_read(char **strp, gfp_t f
return 0;
}
-static int perm_read(struct policydb *p, struct symtab *s, void *fp)
+/*
+ * Bitmap of the permission values a symtab has claimed. Values are 1-based
+ * and bounded by SEL_VEC_MAX, the width of an access vector, so the whole set
+ * fits in a u32 and the callers reject an nprim past that width.
+ */
+static u32 perm_claimed_mask(u32 nprim)
+{
+ return nprim ? U32_MAX >> (SEL_VEC_MAX - nprim) : 0;
+}
+
+static int perm_read(struct policydb *p, struct symtab *s, void *fp,
+ u32 *claimed)
{
char *key = NULL;
struct perm_datum *perdatum;
@@ -1150,6 +1161,16 @@ static int perm_read(struct policydb *p,
len = le32_to_cpu(buf[0]);
perdatum->value = le32_to_cpu(buf[1]);
+ rc = -EINVAL;
+ if (perdatum->value < 1 || perdatum->value > SEL_VEC_MAX)
+ goto bad;
+ /* indexes an nprim-sized array in security_get_permissions() */
+ if (perdatum->value > s->nprim)
+ goto bad;
+ /* two permissions cannot share one slot of that array */
+ if (*claimed & (1U << (perdatum->value - 1)))
+ goto bad;
+ *claimed |= 1U << (perdatum->value - 1);
rc = str_read(&key, GFP_KERNEL, fp, len);
if (rc)
@@ -1170,7 +1191,7 @@ static int common_read(struct policydb *
char *key = NULL;
struct common_datum *comdatum;
__le32 buf[4];
- u32 i, len, nel;
+ u32 i, len, nel, claimed = 0;
int rc;
comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL);
@@ -1189,17 +1210,28 @@ static int common_read(struct policydb *
if (rc)
goto bad;
comdatum->permissions.nprim = le32_to_cpu(buf[2]);
+ /* no permission value can reach a slot past SEL_VEC_MAX */
+ rc = -EINVAL;
+ if (comdatum->permissions.nprim > SEL_VEC_MAX)
+ goto bad;
rc = str_read(&key, GFP_KERNEL, fp, len);
if (rc)
goto bad;
for (i = 0; i < nel; i++) {
- rc = perm_read(p, &comdatum->permissions, fp);
+ rc = perm_read(p, &comdatum->permissions, fp, &claimed);
if (rc)
goto bad;
}
+ rc = -EINVAL;
+ if (claimed != perm_claimed_mask(comdatum->permissions.nprim)) {
+ pr_err("SELinux: common %s does not define every permission it declares\n",
+ key);
+ goto bad;
+ }
+
hash_eval(&comdatum->permissions.table, "common_permissions", key);
rc = symtab_insert(s, key, comdatum);
@@ -1335,7 +1367,7 @@ static int class_read(struct policydb *p
char *key = NULL;
struct class_datum *cladatum;
__le32 buf[6];
- u32 i, len, len2, ncons, nel;
+ u32 i, len, len2, ncons, nel, claimed = 0, inherited = 0;
int rc;
cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL);
@@ -1355,6 +1387,10 @@ static int class_read(struct policydb *p
if (rc)
goto bad;
cladatum->permissions.nprim = le32_to_cpu(buf[3]);
+ /* no permission value can reach a slot past SEL_VEC_MAX */
+ rc = -EINVAL;
+ if (cladatum->permissions.nprim > SEL_VEC_MAX)
+ goto bad;
ncons = le32_to_cpu(buf[5]);
@@ -1389,11 +1425,22 @@ static int class_read(struct policydb *p
}
}
for (i = 0; i < nel; i++) {
- rc = perm_read(p, &cladatum->permissions, fp);
+ rc = perm_read(p, &cladatum->permissions, fp, &claimed);
if (rc)
goto bad;
}
+ /* the class's own permissions must claim the slots the common leaves */
+ if (cladatum->comdatum)
+ inherited = cladatum->comdatum->permissions.nprim;
+ rc = -EINVAL;
+ if (claimed != (perm_claimed_mask(cladatum->permissions.nprim) &
+ ~perm_claimed_mask(inherited))) {
+ pr_err("SELinux: class %s does not define every permission it declares\n",
+ key);
+ goto bad;
+ }
+
hash_eval(&cladatum->permissions.table, "class_permissions", key);
rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 54/77] mptcp: pm: fix data race in add_addr timer callback
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (52 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 53/77] selinux: require a classs permission values to cover its permission count Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 55/77] ASoC: codecs: lpass-tx-macro: Fix enum kcontrol accesses Greg Kroah-Hartman
` (30 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Qing Luo, Matthieu Baerts (NGI0),
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qing Luo <luoqing@kylinos.cn>
[ Upstream commit a7aad5b69d3bdaec20a3ed9284e184502450c0cd ]
The timer callback reads entry->retrans_times outside pm.lock to decide
whether to call mptcp_pm_subflow_established(). Since
mptcp_pm_announced_del_timer() can concurrently set retrans_times =
ADD_ADDR_RETRANS_MAX under pm.lock, a race condition exists.
I discovered this issue while studying the code. AI tools helped me to
verify the issue can potentially happen under race conditions.
Use a local 'retransmit' flag set inside pm.lock to capture whether
retransmission is still possible when the lock is taken. This allows to
call mptcp_pm_subflow_established() accordingly, and not depending on
the situation that can be different when checked outside the pm.lock.
Fixes: 348d5c1dec60 ("mptcp: move to next addr when timeout")
Cc: stable@vger.kernel.org
Signed-off-by: Qing Luo <luoqing@kylinos.cn>
Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20260803-net-mptcp-misc-fixes-7-2-rc6-v2-4-b8f496d71664@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ applied to mptcp_pm_add_timer() in pm_netlink.c instead of pm.c and collapsed the adaptive backoff branch to `if (!retransmit) timeout = 0;` since the tree lacks exponential ADD_ADDR retransmission timeouts ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/mptcp/pm_netlink.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -296,6 +296,7 @@ static void mptcp_pm_add_timer(struct ti
struct mptcp_sock *msk = entry->sock;
struct sock *sk = (struct sock *)msk;
unsigned int timeout = 0;
+ bool retransmit;
pr_debug("msk=%p\n", msk);
@@ -333,12 +334,13 @@ static void mptcp_pm_add_timer(struct ti
entry->retrans_times++;
}
- if (entry->retrans_times >= ADD_ADDR_RETRANS_MAX)
+ retransmit = entry->retrans_times < ADD_ADDR_RETRANS_MAX;
+ if (!retransmit)
timeout = 0;
spin_unlock_bh(&msk->pm.lock);
- if (entry->retrans_times == ADD_ADDR_RETRANS_MAX)
+ if (!retransmit)
mptcp_pm_subflow_established(msk);
out:
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 55/77] ASoC: codecs: lpass-tx-macro: Fix enum kcontrol accesses
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (53 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 54/77] mptcp: pm: fix data race in add_addr timer callback Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 56/77] drm/xe: Fix DPT allocation paths Greg Kroah-Hartman
` (29 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Dawid Wróbel,
Srinivas Kandagatla, Mark Brown, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dawid Wróbel <me@dawidwrobel.com>
[ Upstream commit 1ba381759e45d5d0442452cfa5c42e836191a568 ]
The "DEC0 MODE" to "DEC7 MODE" controls are enumerated, but
tx_macro_dec_mode_get() and tx_macro_dec_mode_put() access their
value through ucontrol->value.integer.value[0] (a long) instead of
ucontrol->value.enumerated.item[0] (an unsigned int).
This same pattern was fixed in the sibling drivers by
commit bcfe5f76cc40 ("ASoC: codecs: rx-macro: fix accessing array
out of bounds for enum type") and
commit 0ea5eff7c606 ("ASoC: codecs: va-macro: fix accessing array
out of bounds for enum type"), but tx-macro was missed.
On 64-bit kernels built with CONFIG_SND_CTL_DEBUG, the elem value
sanity check catches the 4 bytes written past the enumerated item
and every read of these controls fails with -EINVAL:
snd-sm8250 sound: control 2:0:0:DEC0 MODE:0: access overflow
Fixes: c39667ddcfc5 ("ASoC: codecs: lpass-tx-macro: add support for lpass tx macro")
Assisted-by: Claude:claude-fable-5
Cc: stable@vger.kernel.org
Signed-off-by: Dawid Wróbel <me@dawidwrobel.com>
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
Link: https://patch.msgid.link/20260730-worktree-lpass-tx-macro-enum-fix-v2-1-6d091c736116@dawidwrobel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
[ kept `snd_soc_kcontrol_component()` context line instead of upstream's renamed `snd_kcontrol_chip()` ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
sound/soc/codecs/lpass-tx-macro.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -1076,7 +1076,7 @@ static int tx_macro_dec_mode_get(struct
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int path = e->shift_l;
- ucontrol->value.integer.value[0] = tx->dec_mode[path];
+ ucontrol->value.enumerated.item[0] = tx->dec_mode[path];
return 0;
}
@@ -1085,7 +1085,7 @@ static int tx_macro_dec_mode_put(struct
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- int value = ucontrol->value.integer.value[0];
+ int value = ucontrol->value.enumerated.item[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
int path = e->shift_l;
struct tx_macro *tx = snd_soc_component_get_drvdata(component);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 56/77] drm/xe: Fix DPT allocation paths.
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (54 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 55/77] ASoC: codecs: lpass-tx-macro: Fix enum kcontrol accesses Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 57/77] HID: magicmouse: fix battery reporting for Bluetooth Magic Trackpad USB-C Greg Kroah-Hartman
` (28 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Matthew Auld, Maarten Lankhorst,
Thomas Hellström, Sasha Levin, Matthew Brost
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maarten Lankhorst <dev@lankhorst.se>
[ Upstream commit fc648757908304aedbad74f74bf58192aec383db ]
Remove the fallback for VRAM to system memory, I tested it and that
doesn't work at all, only a black screen with pipe fault errors were
observed.
On systems with media GT, extra latency is added when accessing stolen
memory when the GT is in MC6. Since we additionally aren't counting how
much memory is used for stolen and we could in theory fill up the
entire stolen area with DPT's, avoid using stolen and only use the
default memory region.
Using stolen may also result in random system hangs under load.
Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7513
Fixes: 775d0adc01a5 ("drm/xe/fbdev: Limit the usage of stolen for LNL+")
Cc: <stable@vger.kernel.org> # v6.12+
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Link: https://patch.msgid.link/20260630135523.1775379-2-dev@lankhorst.se
Signed-off-by: Maarten Lankhorst <dev@lankhorst.se>
Acked-by: Matthew Brost <matthew.brost@intel.com> #teams
(cherry picked from commit a196406a3831291598fe8e73245914f7acffdfe0)
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
[ Replaced `xe_bo_create_pin_map_at_novm()` with `xe_bo_create_pin_map()`, dropped the alignment argument, and renamed `XE_BO_FLAG_FORCE_WC` to `XE_BO_FLAG_SCANOUT`. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/gpu/drm/xe/display/xe_fb_pin.c | 24 ++++++------------------
1 file changed, 6 insertions(+), 18 deletions(-)
--- a/drivers/gpu/drm/xe/display/xe_fb_pin.c
+++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c
@@ -97,24 +97,12 @@ static int __xe_pin_fb_vma_dpt(const str
dpt_size = ALIGN(intel_rotation_info_size(&view->rotated) * 8,
XE_PAGE_SIZE);
- if (IS_DGFX(xe))
- dpt = xe_bo_create_pin_map(xe, tile0, NULL, dpt_size,
- ttm_bo_type_kernel,
- XE_BO_FLAG_VRAM0 |
- XE_BO_FLAG_GGTT |
- XE_BO_FLAG_PAGETABLE);
- else
- dpt = xe_bo_create_pin_map(xe, tile0, NULL, dpt_size,
- ttm_bo_type_kernel,
- XE_BO_FLAG_STOLEN |
- XE_BO_FLAG_GGTT |
- XE_BO_FLAG_PAGETABLE);
- if (IS_ERR(dpt))
- dpt = xe_bo_create_pin_map(xe, tile0, NULL, dpt_size,
- ttm_bo_type_kernel,
- XE_BO_FLAG_SYSTEM |
- XE_BO_FLAG_GGTT |
- XE_BO_FLAG_PAGETABLE);
+ dpt = xe_bo_create_pin_map(xe, tile0, NULL, dpt_size,
+ ttm_bo_type_kernel,
+ XE_BO_FLAG_VRAM_IF_DGFX(tile0) |
+ XE_BO_FLAG_GGTT |
+ XE_BO_FLAG_PAGETABLE |
+ XE_BO_FLAG_SCANOUT);
if (IS_ERR(dpt))
return PTR_ERR(dpt);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 57/77] HID: magicmouse: fix battery reporting for Bluetooth Magic Trackpad USB-C
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (55 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 56/77] drm/xe: Fix DPT allocation paths Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 58/77] HID: magicmouse: re-enable multitouch after reset-resume Greg Kroah-Hartman
` (27 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Andrei Fed, Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrei Fed <andfed.net@gmail.com>
commit a1556b48efc157fdda07b52ecc56c7bd1e1786f0 upstream.
The Apple Magic Trackpad 2 (USB-C) reports a wildly wrong battery
capacity over Bluetooth, for example a constant 4% for a pack that is
actually at 74%.
The device's battery input report (0x90) is laid out as
[report-id][status][charge]. hid-input's synchronous capacity query,
hidinput_query_battery_capacity(), assumes the common
[report-id][capacity] layout and returns buf[1], which for this device
is the status byte rather than the charge (buf[2]).
magicmouse_fetch_battery(), which requests the battery report through
hid_hw_request() so the reply is decoded via the report descriptor at
the correct field offset, is gated to the USB models and never runs
over Bluetooth. The device does not push battery reports on its own
either, except a single one at connect time, which is delivered while
probe holds driver_input_lock and is silently dropped. All userspace
reads therefore go through the misparsing query, and the device is
stuck reporting its status byte as the capacity.
Enabling the fetch for Bluetooth is not sufficient on its own: user
space reacts to the power_supply registration immediately, so a query
is typically already in flight when the fetch reply is parsed.
hidinput_get_battery_property() stores the query result and marks the
battery as queried without rechecking whether a report arrived while
it was waiting, clobbering the just-reported correct value with the
misparsed one.
Fix this by adding HID_BATTERY_QUIRK_AVOID_QUERY for the Bluetooth
Magic Trackpad USB-C so the misparsing query path is never used, and
by fetching the battery at the end of probe for this device. hidp has
no asynchronous request() callback, so the fetch is serviced
synchronously via __hid_request() while probe still holds
driver_input_lock; call hid_device_io_start() first so the reply is
processed instead of being discarded.
Tested with a Magic Trackpad USB-C (004c:0324) over Bluetooth on
6.18.37: the reported capacity now matches the device (verified against
a raw GET_REPORT of report 0x90) and updates on reconnect.
Fixes: 87a2f10395c8 ("HID: magicmouse: Apple Magic Trackpad 2 USB-C driver support")
Cc: stable@vger.kernel.org
Signed-off-by: Andrei Fed <andfed.net@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-input.c | 3 +++
drivers/hid/hid-magicmouse.c | 19 ++++++++++++++++++-
2 files changed, 21 insertions(+), 1 deletion(-)
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -361,6 +361,9 @@ static const struct hid_device_id hid_ba
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_MAGICTRACKPAD),
HID_BATTERY_QUIRK_IGNORE },
+ { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC),
+ HID_BATTERY_QUIRK_AVOID_QUERY },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM,
USB_DEVICE_ID_ELECOM_BM084),
HID_BATTERY_QUIRK_IGNORE },
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -795,6 +795,12 @@ static bool is_usb_magictrackpad2(__u32
product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC;
}
+static bool is_bt_magictrackpad2(__u32 vendor, __u32 product)
+{
+ return vendor == BT_VENDOR_ID_APPLE &&
+ product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC;
+}
+
static int magicmouse_fetch_battery(struct hid_device *hdev)
{
#ifdef CONFIG_HID_BATTERY_STRENGTH
@@ -803,7 +809,8 @@ static int magicmouse_fetch_battery(stru
if (!hdev->battery ||
(!is_usb_magicmouse2(hdev->vendor, hdev->product) &&
- !is_usb_magictrackpad2(hdev->vendor, hdev->product)))
+ !is_usb_magictrackpad2(hdev->vendor, hdev->product) &&
+ !is_bt_magictrackpad2(hdev->vendor, hdev->product)))
return -1;
report_enum = &hdev->report_enum[hdev->battery_report_type];
@@ -929,6 +936,16 @@ static int magicmouse_probe(struct hid_d
schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
}
+ /*
+ * Query the Bluetooth Magic Trackpad USB-C battery as done for USB.
+ * Start io first: probe holds driver_input_lock and the synchronous
+ * GET_REPORT reply would otherwise be dropped.
+ */
+ if (is_bt_magictrackpad2(id->vendor, id->product)) {
+ hid_device_io_start(hdev);
+ magicmouse_fetch_battery(hdev);
+ }
+
return 0;
err_stop_hw:
if (is_usb_magicmouse2(id->vendor, id->product) ||
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 58/77] HID: magicmouse: re-enable multitouch after reset-resume
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (56 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 57/77] HID: magicmouse: fix battery reporting for Bluetooth Magic Trackpad USB-C Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 59/77] HID: magicmouse: do not keep a stale msc->input if no input is claimed Greg Kroah-Hartman
` (26 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Christopher Kodama, Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christopher Kodama <ckhordiasma@gmail.com>
commit 4253fe22b137c4ee68f36b707fdb1b44b191edc4 upstream.
When the Apple Magic Trackpad 2 (USB) is reset across a power transition
(e.g. resume from hibernation) it drops out of multitouch mode: it keeps
sending report ID 0x02 on its HID_TYPE_USBMOUSE interface, but the packet
shrinks from 21 to 8 bytes and the trackpad2 handler drops it (size < 12).
Clicks still work but pointer motion is lost until the device is re-plugged
or the driver reloaded.
Re-enable multitouch from .reset_resume via the workqueue. Only
.reset_resume is needed; suspend-to-idle keeps the device powered and
retains multitouch.
Fixes: 87a2f10395c8 ("HID: magicmouse: Apple Magic Trackpad 2 USB-C driver support")
Cc: stable@vger.kernel.org
Assisted-by: Claude-Code:claude-opus-4-8
Signed-off-by: Christopher Kodama <ckhordiasma@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-magicmouse.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -970,6 +970,22 @@ static void magicmouse_remove(struct hid
hid_hw_stop(hdev);
}
+#ifdef CONFIG_PM
+static int magicmouse_reset_resume(struct hid_device *hdev)
+{
+ struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+
+ /* The device drops out of multitouch mode on resume; re-send the
+ * enable report. Only the HID_TYPE_USBMOUSE interface accepts it, and
+ * it must be deferred. Sending it inline here is too early.
+ */
+ if (msc && hdev->type == HID_TYPE_USBMOUSE)
+ schedule_delayed_work(&msc->work, msecs_to_jiffies(500));
+
+ return 0;
+}
+#endif
+
static const __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
@@ -1029,6 +1045,9 @@ static struct hid_driver magicmouse_driv
.event = magicmouse_event,
.input_mapping = magicmouse_input_mapping,
.input_configured = magicmouse_input_configured,
+#ifdef CONFIG_PM
+ .reset_resume = magicmouse_reset_resume,
+#endif
};
module_hid_driver(magicmouse_driver);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 59/77] HID: magicmouse: do not keep a stale msc->input if no input is claimed
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (57 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 58/77] HID: magicmouse: re-enable multitouch after reset-resume Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 60/77] HID: magicmouse: Prevent out-of-bounds (OOB) read during DOUBLE_REPORT_ID Greg Kroah-Hartman
` (25 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Jose Villaseñor Montfort,
Alec Hall, Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jose Villaseñor Montfort <pepemontfort@gmail.com>
commit 0af3b89705688af01aa06025b84fa7a1e06ba6cc upstream.
magicmouse_input_mapping() caches the first hid_input's input_dev in
msc->input while the report descriptor is parsed, and the rest of the
driver treats a non-NULL msc->input as proof that an input device was
registered.
That does not hold on the hid-input error path. If hidinput_connect()
fails -- for instance because input_register_device() returns an error --
it unwinds through hidinput_disconnect(), which frees every input_dev it
created, including the one cached in msc->input.
The failure does not abort the probe. hid_connect() only skips the claim:
if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
connect_mask & HID_CONNECT_HIDINPUT_FORCE))
hdev->claimed |= HID_CLAIMED_INPUT;
and the "device has no listeners" bailout below it does not fire for this
driver, which sets ->raw_event; on the USB Magic Mouse 2 / Magic Trackpad
2 paths hidraw and hiddev are claimed as well. hid_hw_start() therefore
returns 0 and magicmouse_probe() continues with msc->input pointing at
freed memory. Being non-NULL, it passes the "input not registered" check
in probe and the NULL checks in ->raw_event and ->event, so the next
input report dereferences freed memory.
Clear msc->input when the HID core did not claim an input device, so the
existing NULL checks cover this case as well.
Fixes: f1a9a149abc8 ("HID: magicmouse: fix race between input_register() and probe()")
Link: https://lore.kernel.org/linux-input/20260728185542.65F091F000E9@smtp.kernel.org/
Cc: stable@vger.kernel.org
Signed-off-by: Jose Villaseñor Montfort <pepemontfort@gmail.com>
Reviewed-by: Alec Hall <signshop.alec@gmail.com>
Tested-by: Alec Hall <signshop.alec@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-magicmouse.c | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -872,6 +872,16 @@ static int magicmouse_probe(struct hid_d
return ret;
}
+ /*
+ * When hidinput_connect() fails it frees every input device it
+ * created, but that does not fail hid_hw_start(): the core simply
+ * does not claim an input. msc->input, cached in ->input_mapping
+ * while the report descriptor was parsed, would then be a dangling
+ * pointer that passes every NULL check. Trust the core's claim.
+ */
+ if (!(hdev->claimed & HID_CLAIMED_INPUT))
+ msc->input = NULL;
+
if (is_usb_magicmouse2(id->vendor, id->product) ||
is_usb_magictrackpad2(id->vendor, id->product)) {
timer_setup(&msc->battery_timer, magicmouse_battery_timer_tick, 0);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 60/77] HID: magicmouse: Prevent out-of-bounds (OOB) read during DOUBLE_REPORT_ID
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (58 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 59/77] HID: magicmouse: do not keep a stale msc->input if no input is claimed Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 61/77] HID: core: fix OOB read of field->usage in hid_set_field() Greg Kroah-Hartman
` (24 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Lee Jones, Günther Noack,
Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lee Jones <lee@kernel.org>
commit d93ba918a185aca2594da63e92fdc5495b559c0f upstream.
It is currently possible for a malicious or misconfigured USB device to
cause an out-of-bounds (OOB) read when submitting reports using
DOUBLE_REPORT_ID by specifying a large report length and providing a
smaller one.
Let's prevent that by comparing the specified report length with the
actual size of the data read in from userspace. If the actual data
length ends up being smaller than specified, we'll politely warn the
user and prevent any further processing.
Signed-off-by: Lee Jones <lee@kernel.org>
Reviewed-by: Günther Noack <gnoack@google.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-magicmouse.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -387,6 +387,10 @@ static int magicmouse_raw_event(struct h
struct input_dev *input = msc->input;
int x = 0, y = 0, ii, clicks = 0, npoints;
+ /* Protect against zero sized recursive calls from DOUBLE_REPORT_ID */
+ if (size < 1)
+ return 0;
+
switch (data[0]) {
case TRACKPAD_REPORT_ID:
case TRACKPAD2_BT_REPORT_ID:
@@ -487,6 +491,18 @@ static int magicmouse_raw_event(struct h
/* Sometimes the trackpad sends two touch reports in one
* packet.
*/
+
+ /* Ensure that we have at least 2 elements (report type and size) */
+ if (size < 2)
+ return 0;
+
+ if (size < data[1] + 2) {
+ hid_warn(hdev,
+ "received report length (%d) was smaller than specified (%d)",
+ size, data[1] + 2);
+ return 0;
+ }
+
magicmouse_raw_event(hdev, report, data + 2, data[1]);
magicmouse_raw_event(hdev, report, data + 2 + data[1],
size - 2 - data[1]);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 61/77] HID: core: fix OOB read of field->usage in hid_set_field()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (59 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 60/77] HID: magicmouse: Prevent out-of-bounds (OOB) read during DOUBLE_REPORT_ID Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 62/77] net/ionic: avoid OOB TX partner lookup for hwstamp RXQ Greg Kroah-Hartman
` (23 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Federico Kirschbaum, Baul Lee,
Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <baul.lee@xbow.com>
commit a13cdb19fcb223ed41bdab3bab42b98dba87e90b upstream.
hid_set_field() hands field->usage + offset to hid_dump_input() before
the guard that bounds offset:
hid_dump_input(field->report->device, field->usage + offset, value);
if (offset >= field->report_count) {
hid_err(...);
return -1;
}
Under CONFIG_DEBUG_FS hid_dump_input() dereferences that pointer, with
buf = hid_resolv_usage(usage->hid, NULL). The usage[] array is
allocated inline with the hid_field in hid_register_field() and holds
field->maxusage entries, so an offset past it reads off the end of the
kvzalloc()ed allocation and into a neighbouring object. Had the guard
run first, offset < report_count <= maxusage would already have confined
the pointer to the array.
A caller supplies such an offset today. picolcd_fb_send_tile()
validates only report->maxfield before issuing
hid_set_field(report->field[0], 11 + i, ...) for i = 0..31, so its
offsets are fixed at 11..42 and are never checked against the bound
field. When the device registers that field with fewer usages, the
framebuffer deferred-io work drives the read on every tile. KASAN
reports a 4-byte slab-out-of-bounds read in hid_dump_input() below
hid_set_field(), and the same boot logs "offset (1) exceeds
report_count (1)" from the guard that runs only afterwards.
Move the hid_dump_input() call below the guard. Because
field->maxusage >= field->report_count, the guard then establishes that
field->usage + offset lies inside the array before it is dereferenced,
for every caller and without changing behaviour on the valid path.
Discovered by XBOW, triaged by Baul Lee <baul.lee@xbow.com>
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: Federico Kirschbaum <federico.kirschbaum@xbow.com>
Reported-by: Baul Lee <baul.lee@xbow.com>
Cc: stable@vger.kernel.org
Signed-off-by: Baul Lee <baul.lee@xbow.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-core.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1894,13 +1894,14 @@ int hid_set_field(struct hid_field *fiel
size = field->report_size;
- hid_dump_input(field->report->device, field->usage + offset, value);
-
if (offset >= field->report_count) {
hid_err(field->report->device, "offset (%d) exceeds report_count (%d)\n",
offset, field->report_count);
return -1;
}
+
+ hid_dump_input(field->report->device, field->usage + offset, value);
+
if (field->logical_minimum < 0) {
if (value != snto32(s32ton(value, size), size)) {
hid_err(field->report->device, "value %d is out of range\n", value);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 62/77] net/ionic: avoid OOB TX partner lookup for hwstamp RXQ
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (60 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 61/77] HID: core: fix OOB read of field->usage in hid_set_field() Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 63/77] xfrm: fix sk_dst_cache double-free in xfrm_user_policy() Greg Kroah-Hartman
` (22 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Si-Wei Liu, Shannon Nelson,
Anand Khoje, Simon Horman, Brett Creeley, Paolo Abeni
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anand Khoje <anand.a.khoje@oracle.com>
commit d92255b405fb6f5acca408239ccd742e0a42c9cb upstream.
The dedicated hardware timestamp RX queue is allocated with q->index
equal to lif->ionic->nrxqs_per_lif. The normal txqcqs array only
contains the regular queue pairs, so using that index to set rxq->partner
can read one entry past txqcqs[] and then write through the derived
pointer.
Only link RX/TX partners for normal queue-pair indexes. Leave the hwstamp
RX queue unpaired, and make the XDP_TX path abort cleanly if an RX queue
has no TX partner.
Fixes: 8eeed8373e1c ("ionic: Add XDP_TX support")
Reviewed-by: Si-Wei Liu <si-wei.liu@oracle.com>
Reviewed-by: Shannon Nelson <sln@onemain.com>
Cc: stable@vger.kernel.org
Signed-off-by: Anand Khoje <anand.a.khoje@oracle.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Brett Creeley <brett.creeley@amd.com>
Link: https://patch.msgid.link/20260813083705.454897-1-anand.a.khoje@oracle.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/net/ethernet/pensando/ionic/ionic_lif.c | 17 +++++++++++++++--
drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 7 ++++++-
2 files changed, 21 insertions(+), 3 deletions(-)
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -917,8 +917,21 @@ static int ionic_lif_rxq_init(struct ion
};
int err;
- q->partner = &lif->txqcqs[q->index]->q;
- q->partner->partner = q;
+ q->partner = NULL;
+
+ /* Only normal RX queues have matching TX queue partners. */
+ if (q->index < lif->nxqs) {
+ if (!lif->txqcqs ||
+ q->index >= lif->ionic->ntxqs_per_lif ||
+ !lif->txqcqs[q->index]) {
+ dev_err(dev, "missing TX queue partner for RX queue %u\n",
+ q->index);
+ return -ENXIO;
+ }
+
+ q->partner = &lif->txqcqs[q->index]->q;
+ q->partner->partner = q;
+ }
if (!lif->xdp_prog ||
(lif->xdp_prog->aux && lif->xdp_prog->aux->xdp_has_frags))
--- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
@@ -545,13 +545,18 @@ static bool ionic_run_xdp(struct ionic_r
break;
case XDP_TX:
+ txq = rxq->partner;
+ if (unlikely(!txq)) {
+ err = -EIO;
+ break;
+ }
+
xdpf = xdp_convert_buff_to_frame(&xdp_buf);
if (!xdpf) {
err = -ENOSPC;
break;
}
- txq = rxq->partner;
nq = netdev_get_tx_queue(netdev, txq->index);
__netif_tx_lock(nq, smp_processor_id());
txq_trans_cond_update(nq);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 63/77] xfrm: fix sk_dst_cache double-free in xfrm_user_policy()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (61 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 62/77] net/ionic: avoid OOB TX partner lookup for hwstamp RXQ Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 64/77] ipv4: start using dst_dev_rcu() Greg Kroah-Hartman
` (21 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, AutonomousCodeSecurity,
Xiang Mei (Microsoft), Steffen Klassert, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei (Microsoft) <xmei5@asu.edu>
[ Upstream commit c283e9ada7fcb7dd4b10592623086b2e6d2f9925 ]
xfrm_user_policy() clears the socket dst cache with __sk_dst_reset(),
i.e. the non-atomic __sk_dst_set(sk, NULL): it reads sk_dst_cache with
rcu_dereference_protected(), stores NULL and dst_release()s the old dst.
That is only safe if no other thread modifies sk_dst_cache concurrently.
For a connected UDP socket that does not hold: the transmit fast path
(udp_sendmsg -> sk_dst_check -> sk_dst_reset) resets the cache locklessly
with an atomic xchg(). A per-socket policy change racing a send can make
both sides observe the same old dst and each dst_release() it, dropping
the socket's single reference twice and freeing the xfrm_dst bundle while
it is still referenced:
BUG: KASAN: slab-use-after-free in dst_release
Write of size 4 at addr ffff88801897b6c0 by task exploit/155
Call Trace:
...
dst_release (... ./include/linux/rcuref.h:109)
xfrm_user_policy (./include/net/sock.h:2239 ./include/net/sock.h:2256 net/xfrm/xfrm_state.c:3053)
do_ip_setsockopt (net/ipv4/ip_sockglue.c:1347)
ip_setsockopt (net/ipv4/ip_sockglue.c:1417)
do_sock_setsockopt (net/socket.c:2368)
__sys_setsockopt (net/socket.c:2393)
__x64_sys_setsockopt (net/socket.c:2396)
do_syscall_64 (arch/x86/entry/syscall_64.c:94)
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
Reachable by an unprivileged user via a user+network namespace.
Use the atomic sk_dst_reset() so the cache is cleared and released with a
single xchg(): whichever side wins releases the dst once, the other sees
NULL and does nothing. Behaviour is otherwise unchanged.
Fixes: 2b06cdf3e688 ("xfrm: Clear sk_dst_cache when applying per-socket policy.")
Fixes: be8f8284cd89 ("net: xfrm: allow clearing socket xfrm policies.")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/xfrm/xfrm_state.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 792e5ef9361aa..e399cd5696cf9 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -2881,7 +2881,7 @@ int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
if (sockptr_is_null(optval) && !optlen) {
xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
- __sk_dst_reset(sk);
+ sk_dst_reset(sk);
return 0;
}
@@ -2921,7 +2921,7 @@ int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
if (err >= 0) {
xfrm_sk_policy_insert(sk, err, pol);
xfrm_pol_put(pol);
- __sk_dst_reset(sk);
+ sk_dst_reset(sk);
err = 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 86+ messages in thread* [PATCH 6.12 64/77] ipv4: start using dst_dev_rcu()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (62 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 63/77] xfrm: fix sk_dst_cache double-free in xfrm_user_policy() Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 65/77] mptcp: pm: fix memory leak from alloc-during-teardown race Greg Kroah-Hartman
` (20 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Eric Dumazet, David Ahern,
Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <edumazet@google.com>
[ Upstream commit 6ad8de3cefdb6ffa6708b21c567df0dbf82c43a8 ]
Change icmpv4_xrlim_allow(), ip_defrag() to prevent possible UAF.
Change ipmr_prepare_xmit(), ipmr_queue_fwd_xmit(), ip_mr_output(),
ipv4_neigh_lookup() to use lockdep enabled dst_dev_rcu().
Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20250828195823.3958522-9-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/ipv4/icmp.c | 6 +++---
net/ipv4/ip_fragment.c | 6 ++++--
net/ipv4/ipmr.c | 2 +-
net/ipv4/route.c | 4 ++--
4 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index c7af8b914e13c..1fc967a60bb9c 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -320,17 +320,17 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
return true;
/* No rate limit on loopback */
- dev = dst_dev(dst);
+ rcu_read_lock();
+ dev = dst_dev_rcu(dst);
if (dev && (dev->flags & IFF_LOOPBACK))
goto out;
- rcu_read_lock();
peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr,
l3mdev_master_ifindex_rcu(dev));
rc = inet_peer_xrlim_allow(peer,
READ_ONCE(net->ipv4.sysctl_icmp_ratelimit));
- rcu_read_unlock();
out:
+ rcu_read_unlock();
if (!rc)
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
else
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 5825aa8eac7fd..9cc55a0c64f7d 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -470,14 +470,16 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
/* Process an incoming IP datagram fragment. */
int ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
{
- struct net_device *dev = skb->dev ? : skb_dst_dev(skb);
- int vif = l3mdev_master_ifindex_rcu(dev);
+ struct net_device *dev;
struct ipq *qp;
+ int vif;
__IP_INC_STATS(net, IPSTATS_MIB_REASMREQDS);
/* Lookup (or create) queue header */
rcu_read_lock();
+ dev = skb->dev ? : skb_dst_dev_rcu(skb);
+ vif = l3mdev_master_ifindex_rcu(dev);
qp = ip_find(net, ip_hdr(skb), user, vif);
if (qp) {
int ret, refs = 0;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index de0d9cc7806a1..f0294b1148246 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1894,7 +1894,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
goto out_free;
}
- dev = rt->dst.dev;
+ dev = dst_dev_rcu(&rt->dst);
if (skb->len+encap > dst_mtu(&rt->dst) && (ntohs(iph->frag_off) & IP_DF)) {
/* Do not fragment multicasts. Alas, IPv4 does not
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 28d83b3baae3b..9135a9dc8f297 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -413,11 +413,11 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
const void *daddr)
{
const struct rtable *rt = container_of(dst, struct rtable, dst);
- struct net_device *dev = dst_dev(dst);
+ struct net_device *dev;
struct neighbour *n;
rcu_read_lock();
-
+ dev = dst_dev_rcu(dst);
if (likely(rt->rt_gw_family == AF_INET)) {
n = ip_neigh_gw4(dev, rt->rt_gw4);
} else if (rt->rt_gw_family == AF_INET6) {
--
2.53.0
^ permalink raw reply related [flat|nested] 86+ messages in thread* [PATCH 6.12 65/77] mptcp: pm: fix memory leak from alloc-during-teardown race
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (63 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 64/77] ipv4: start using dst_dev_rcu() Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 66/77] Input: atkbd - skip deactivate for HONOR FMB-Ps internal keyboard Greg Kroah-Hartman
` (19 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Shardul Bankar,
Matthieu Baerts (NGI0), Jakub Kicinski, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shardul Bankar <shardul.b@mpiricsoftware.com>
[ Upstream commit efc33b5102ff859bacd390a5f30112d8e0c084c0 ]
mptcp_pm_destroy() empties msk->pm.anno_list and
msk->pm.userspace_pm_local_addr_list under msk->pm.lock during socket
teardown, dropping the lock between the two.
A concurrent userspace PM genl ANNOUNCE on the same msk holds a sock
reference via mptcp_token_get_sock() and, in
mptcp_pm_nl_announce_doit(), calls
mptcp_userspace_pm_append_new_local_addr() and
mptcp_pm_announced_alloc(). Both take msk->pm.lock briefly to add to
their respective lists. Because the genl handler holds a sock reference,
mptcp_pm_destroy() may run on the same msk via mptcp_disconnect(), which
invokes mptcp_destroy_common() without dropping the sock refcount,
before the handler completes.
If the lock acquisitions interleave such that mptcp_pm_destroy() empties
a list first, the later alloc adds its entry to a list head that nothing
else iterates for this msk, and the entry leaks. kmemleak reports both
mptcp_pm_add_addr objects (from mptcp_pm_announced_alloc()) and
mptcp_pm_addr_entry objects (from
mptcp_userspace_pm_append_new_local_addr()) under sustained concurrent
ANNOUNCE + close load against the userspace PM.
Add an MPTCP_PM_DESTROYING bit in msk->pm.status, set by
mptcp_pm_destroy() under pm.lock before the lists are emptied and
checked under pm.lock by the alloc paths. Either the alloc takes pm.lock
first, in which case its entry is on the list when mptcp_pm_destroy()
frees it; or mptcp_pm_destroy() takes pm.lock first, in which case the
later alloc observes the bit and refuses.
Found by an MPTCP protocol-flow harness extending BRF (arXiv:2305.08782).
Fixes: 9ab4807c84a4 ("mptcp: netlink: Add MPTCP_PM_CMD_ANNOUNCE")
Cc: stable@vger.kernel.org
Signed-off-by: Shardul Bankar <shardul.b@mpiricsoftware.com>
Reviewed-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20260803-net-mptcp-misc-fixes-7-2-rc6-v2-6-b8f496d71664@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
[ Inlined `mptcp_pm_destroy()` at its call site in `mptcp_destroy_common()` and moved the fences into the pre-rename `mptcp_pm_alloc_anno_list()`/`mptcp_free_local_addr_list()` equivalents, deleting the `mptcp_pm_is_userspace()` guard from inside the callee instead of the call site. ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/mptcp/pm_netlink.c | 3 +++
net/mptcp/pm_userspace.c | 7 ++++---
net/mptcp/protocol.c | 9 +++++++++
net/mptcp/protocol.h | 7 ++++---
4 files changed, 20 insertions(+), 6 deletions(-)
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -397,6 +397,9 @@ bool mptcp_pm_alloc_anno_list(struct mpt
lockdep_assert_held(&msk->pm.lock);
+ if (msk->pm.status & BIT(MPTCP_PM_DESTROYING))
+ return false;
+
add_entry = mptcp_lookup_anno_list_by_saddr(msk, addr);
if (add_entry) {
--- a/net/mptcp/pm_userspace.c
+++ b/net/mptcp/pm_userspace.c
@@ -14,9 +14,6 @@ void mptcp_free_local_addr_list(struct m
struct sock *sk = (struct sock *)msk;
LIST_HEAD(free_list);
- if (!mptcp_pm_is_userspace(msk))
- return;
-
spin_lock_bh(&msk->pm.lock);
list_splice_init(&msk->pm.userspace_pm_local_addr_list, &free_list);
spin_unlock_bh(&msk->pm.lock);
@@ -54,6 +51,10 @@ static int mptcp_userspace_pm_append_new
bitmap_zero(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
spin_lock_bh(&msk->pm.lock);
+ if (msk->pm.status & BIT(MPTCP_PM_DESTROYING)) {
+ ret = -EINVAL;
+ goto append_err;
+ }
list_for_each_entry(e, &msk->pm.userspace_pm_local_addr_list, list) {
addr_match = mptcp_addresses_equal(&e->addr, &entry->addr, true);
if (addr_match && entry->addr.id == 0 && needs_id)
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -3578,7 +3578,16 @@ void mptcp_destroy_common(struct mptcp_s
sk_forward_alloc_add(sk, msk->rmem_fwd_alloc);
WRITE_ONCE(msk->rmem_fwd_alloc, 0);
mptcp_token_destroy(msk);
+
+ spin_lock_bh(&msk->pm.lock);
+ msk->pm.status |= BIT(MPTCP_PM_DESTROYING);
+ spin_unlock_bh(&msk->pm.lock);
+
mptcp_pm_free_anno_list(msk);
+
+ /* Free the userspace local address list unconditionally: the socket
+ * can be reused (mptcp_disconnect()) and re-selected to a different PM
+ */
mptcp_free_local_addr_list(msk);
}
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -190,9 +190,10 @@ enum mptcp_pm_status {
MPTCP_PM_ESTABLISHED,
MPTCP_PM_SUBFLOW_ESTABLISHED,
MPTCP_PM_ALREADY_ESTABLISHED, /* persistent status, set after ESTABLISHED event */
- MPTCP_PM_MPC_ENDPOINT_ACCOUNTED /* persistent status, set after MPC local address is
- * accounted int id_avail_bitmap
- */
+ MPTCP_PM_MPC_ENDPOINT_ACCOUNTED, /* persistent status, set after MPC local address is
+ * accounted int id_avail_bitmap
+ */
+ MPTCP_PM_DESTROYING, /* To fence out PM list allocs */
};
enum mptcp_pm_type {
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 66/77] Input: atkbd - skip deactivate for HONOR FMB-Ps internal keyboard
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (64 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 65/77] mptcp: pm: fix memory leak from alloc-during-teardown race Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 67/77] Input: atkbd - skip deactivate for HONOR ZQC-P Greg Kroah-Hartman
` (18 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Mikura Kyouka, foad.elkhattabi,
Cryolitia PukNgae, Hans de Goede, Dmitry Torokhov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cryolitia PukNgae <cryolitia.pukngae@linux.dev>
[ Upstream commit 2aaf33c6e1e82561d7dce2345298a985a2483266 ]
After commit 9cf6e24c9fbf17e52de9fff07f12be7565ea6d61 ("Input: atkbd -
do not skip atkbd_deactivate() when skipping ATKBD_CMD_GETID"), HONOR
FMB-P, aka HONOR MagicBook Pro 14 2025's internal keyboard stops
working. Adding the atkbd_deactivate_fixup quirk fixes it.
DMI: HONOR FMB-P/FMB-P-PCB, BIOS 1.13 05/08/2025
Fixes: 9cf6e24c9fbf17e52de9fff07f12be7565ea6d61 ("Input: atkbd - do not skip atkbd_deactivate() when skipping ATKBD_CMD_GETID")
Reported-by: Mikura Kyouka <mikurakyouka@aosc.io>
Reported-by: foad.elkhattabi <foad.elkhattabi@gmail.com>
Signed-off-by: Cryolitia PukNgae <cryolitia.pukngae@linux.dev>
Reviewed-by: Hans de Goede <hansg@kernel.org>
Link: https://patch.msgid.link/20251022-honor-v1-1-ff894ed271a9@linux.dev
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Stable-dep-of: 410c44b10967 ("Input: atkbd - skip deactivate for HONOR ZQC-P")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/input/keyboard/atkbd.c | 7 +++++++
1 file changed, 7 insertions(+)
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -1938,6 +1938,13 @@ static const struct dmi_system_id atkbd_
.callback = atkbd_deactivate_fixup,
},
{
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "FMB-P"),
+ },
+ .callback = atkbd_deactivate_fixup,
+ },
+ {
/* Lenovo Yoga Air 14 (83QK) */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 67/77] Input: atkbd - skip deactivate for HONOR ZQC-P
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (65 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 66/77] Input: atkbd - skip deactivate for HONOR FMB-Ps internal keyboard Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 68/77] HID: nintendo: fix out-of-bounds read in joycon_ctlr_read_handler() Greg Kroah-Hartman
` (17 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Donglin Lyu, Ruslan Shevchenko,
Dmitry Torokhov, Sasha Levin
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Donglin Lyu <DongLin_Lyu@outlook.com>
[ Upstream commit 410c44b1096789d0c40fbee706520e981dba7bc1 ]
The internal keyboard on the HONOR ZQC-P (HONOR MagicBook Pro 14 2026)
does not work after boot.
Using the kernel command line 'i8042.dumbkbd=1' makes the keyboard
functional, but the CapsLock LED does not work. Adding the
'atkbd_deactivate_fixup' quirk fixes the keyboard and CapsLock LED
natively without requiring boot parameters.
DMI: HONOR ZQC-P/ZQC-P-PCB, BIOS 1.09 03/19/2026
Fixes: 9cf6e24c9fbf ("Input: atkbd - do not skip atkbd_deactivate() when skipping ATKBD_CMD_GETID")
Signed-off-by: Donglin Lyu <donglin_lyu@outlook.com>
Tested-by: Ruslan Shevchenko <adefka@gmail.com>
Link: https://patch.msgid.link/20260801151115.52709-1-donglin_lyu@outlook.com
Cc: stable@vger.kernel.org
[dtor: keep all HONOR entries together]
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/input/keyboard/atkbd.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -1940,22 +1940,30 @@ static const struct dmi_system_id atkbd_
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
- DMI_MATCH(DMI_PRODUCT_NAME, "FMB-P"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "BCC-N"),
},
.callback = atkbd_deactivate_fixup,
},
{
- /* Lenovo Yoga Air 14 (83QK) */
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_NAME, "83QK"),
+ DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "FMB-P"),
},
.callback = atkbd_deactivate_fixup,
},
{
+ /* HONOR MagicBook Pro 14 2026 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
- DMI_MATCH(DMI_PRODUCT_NAME, "BCC-N"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ZQC-P"),
+ },
+ .callback = atkbd_deactivate_fixup,
+ },
+ {
+ /* Lenovo Yoga Air 14 (83QK) */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83QK"),
},
.callback = atkbd_deactivate_fixup,
},
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 68/77] HID: nintendo: fix out-of-bounds read in joycon_ctlr_read_handler()
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (66 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 67/77] Input: atkbd - skip deactivate for HONOR ZQC-P Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 69/77] HID: nintendo: register input device after capabilities are set Greg Kroah-Hartman
` (16 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Ibrahim Hashimov, Silvan Jegen,
Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <security@auditcode.ai>
commit 27b376b945c0aac46fcdfcc950b14a85b874b557 upstream.
joycon_ctlr_read_handler() casts an incoming HID input report to
struct joycon_input_report and parses it, guarding the cast only with a
12-byte length check:
if (size >= 12) /* make sure it contains the input report */
joycon_parse_report(ctlr, (struct joycon_input_report *)data);
struct joycon_input_report is 49 bytes: a 13-byte header followed by a
union whose IMU arm is 36 bytes. For an IMU report joycon_parse_report()
-> joycon_parse_imu_report() walks that union (struct offsets 13..48),
so a report of exactly 12 bytes with data[0] == JC_INPUT_IMU_DATA passes
the guard yet is read up to 37 bytes past its declared length. The
over-read bytes are decoded into accelerometer/gyroscope values and
forwarded to userspace through the "(IMU)" input device, leaking
driver-internal memory. data[0] and size are fully controlled by a
malicious or spoofed Joy-Con/Pro Controller.
Receive buffers are sized to the maximum report length, so this is an
over-read within the allocation rather than a slab OOB, but the decoded
bytes still reach userspace.
The sibling subcmd path in joycon_ctlr_handle_event() already bounds the
same cast correctly:
if (size < sizeof(struct joycon_input_report) ||
data[0] != JC_INPUT_SUBCMD_REPLY)
break;
Use the same sizeof(struct joycon_input_report) bound here.
Fixes: 2af16c1f846b ("HID: nintendo: add nintendo switch controller driver")
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
Reviewed-by: Silvan Jegen <s.jegen@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-nintendo.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
@@ -2563,7 +2563,12 @@ static int joycon_ctlr_read_handler(stru
{
if (data[0] == JC_INPUT_SUBCMD_REPLY || data[0] == JC_INPUT_IMU_DATA ||
data[0] == JC_INPUT_MCU_DATA) {
- if (size >= 12) /* make sure it contains the input report */
+ /*
+ * The whole struct is cast and parsed below, including the
+ * IMU/subcmd union, not just the 12-byte partial header this
+ * used to check for.
+ */
+ if (size >= sizeof(struct joycon_input_report))
joycon_parse_report(ctlr,
(struct joycon_input_report *)data);
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 69/77] HID: nintendo: register input device after capabilities are set
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (67 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 68/77] HID: nintendo: fix out-of-bounds read in joycon_ctlr_read_handler() Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 70/77] HID: nintendo: stop device IO before hid_hw_stop on probe failure Greg Kroah-Hartman
` (15 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, sashiko-bot, Jiangshan Yi,
Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiangshan Yi <yijiangshan@kylinos.cn>
commit d723bc1fe2e72b9252234e94c11af644ec477bf7 upstream.
input_register_device() exposes the device to userspace immediately.
In joycon_input_create() it was called before joycon_config_rumble()
configures the FF_RUMBLE capability and the memless force-feedback
device, so a concurrent EVIOCSFF could dereference a NULL dev->ff.
Registering early also means the initial udev event lacks button and
axis information, which can make input managers ignore the device.
Move input_register_device() to the end of joycon_input_create(), after
all capabilities, the IMU input device and the force-feedback callbacks
have been configured.
Fixes: 2af16c1f846b ("HID: nintendo: add nintendo switch controller driver")
Reported-by: sashiko-bot@kernel.org
Closes: https://sashiko.dev/#/patchset/20260730031927.25444-1-yijiangshan@kylinos.cn?part=1
Cc: stable@vger.kernel.org
Signed-off-by: Jiangshan Yi <yijiangshan@kylinos.cn>
Link: https://sashiko.dev/#/patchset/20260730031927.25444-1-yijiangshan@kylinos.cn?part=1
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-nintendo.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
@@ -2142,10 +2142,6 @@ static int joycon_input_create(struct jo
ctlr->input->phys = hdev->phys;
input_set_drvdata(ctlr->input, ctlr);
- ret = input_register_device(ctlr->input);
- if (ret)
- return ret;
-
if (joycon_type_is_right_joycon(ctlr)) {
joycon_config_right_stick(ctlr->input);
joycon_config_buttons(ctlr->input, right_joycon_button_mappings);
@@ -2185,6 +2181,10 @@ static int joycon_input_create(struct jo
if (joycon_has_rumble(ctlr))
joycon_config_rumble(ctlr);
+ ret = input_register_device(ctlr->input);
+ if (ret)
+ return ret;
+
return 0;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 70/77] HID: nintendo: stop device IO before hid_hw_stop on probe failure
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (68 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 69/77] HID: nintendo: register input device after capabilities are set Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 71/77] HID: core: fix number/pointer type confusion on long items Greg Kroah-Hartman
` (14 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jiangshan Yi, Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiangshan Yi <yijiangshan@kylinos.cn>
commit 1f74d3bff6fe04a64e02ab3661d2e0d554565aa6 upstream.
nintendo_hid_probe() calls hid_device_io_start() before joycon_init()
and joycon_leds_create(). If either fails, the error path jumps to
err_close which calls hid_hw_close()/hid_hw_stop() without first calling
hid_device_io_stop().
hid_hw_stop() does not stop device IO, so hid_input_report() may still
run and access driver data that is being torn down, resulting in a
use-after-free.
Add an err_io_stop label that calls hid_device_io_stop() before
hid_hw_close(), and point the two post-io_start error paths at it.
Fixes: 2af16c1f846b ("HID: nintendo: add nintendo switch controller driver")
Cc: stable@vger.kernel.org
Signed-off-by: Jiangshan Yi <yijiangshan@kylinos.cn>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-nintendo.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
@@ -2696,14 +2696,14 @@ static int nintendo_hid_probe(struct hid
ret = joycon_init(hdev);
if (ret) {
hid_err(hdev, "Failed to initialize controller; ret=%d\n", ret);
- goto err_close;
+ goto err_io_stop;
}
/* Initialize the leds */
ret = joycon_leds_create(ctlr);
if (ret) {
hid_err(hdev, "Failed to create leds; ret=%d\n", ret);
- goto err_close;
+ goto err_io_stop;
}
/* Initialize the battery power supply */
@@ -2726,7 +2726,8 @@ static int nintendo_hid_probe(struct hid
err_ida:
ida_free(&nintendo_player_id_allocator, ctlr->player_id);
-err_close:
+err_io_stop:
+ hid_device_io_stop(hdev);
hid_hw_close(hdev);
err_stop:
hid_hw_stop(hdev);
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 71/77] HID: core: fix number/pointer type confusion on long items
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (69 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 70/77] HID: nintendo: stop device IO before hid_hw_stop on probe failure Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 72/77] HID: sensor: custom: Fix use-after-free in enable_sensor Greg Kroah-Hartman
` (13 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Jann Horn, Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <jannh@google.com>
commit 28abce951343fcec26e397610868efa4e1395c3f upstream.
When fetch_item() is called by hid_scan_report() on an item with
HID_ITEM_TAG_LONG, it stores a pointer to the item data in
item->data.longdata instead of storing a value directly in
item->data.{u8/u16/u32}.
When item_udata() or item_sdata() encounters such an item, it incorrectly
assumes that the item is in short format, and therefore returns the lower
part of a kernel pointer reinterpreted as a number.
When a HID device is connected whose descriptor contains a
HID_GLOBAL_ITEM_TAG_REPORT_SIZE encoded in long format with size=4, this
causes the lower half of a kernel pointer to be printed into dmesg as a
number, like this:
hid (null): invalid report_size 107953555
To fix it, let item_udata() and item_sdata() verify that the item is in
short format.
Note that this bug only affects hid_scan_report(), while the main parsing
pass hid_parse_collections() will always bail out when encountering a long
item.
Sidenote: There are currently no users of data.longdata; maybe we should
just remove any parsing of long-format descriptors as a follow-up.
Fixes: 3dc8fc083dbf ("HID: Use hid_parser for pre-scanning the report descriptors")
Cc: stable@vger.kernel.org
Signed-off-by: Jann Horn <jannh@google.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-core.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -379,6 +379,9 @@ static int hid_add_field(struct hid_pars
static u32 item_udata(struct hid_item *item)
{
+ if (item->format != HID_ITEM_FORMAT_SHORT)
+ return 0;
+
switch (item->size) {
case 1: return item->data.u8;
case 2: return item->data.u16;
@@ -389,6 +392,9 @@ static u32 item_udata(struct hid_item *i
static s32 item_sdata(struct hid_item *item)
{
+ if (item->format != HID_ITEM_FORMAT_SHORT)
+ return 0;
+
switch (item->size) {
case 1: return item->data.s8;
case 2: return item->data.s16;
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 72/77] HID: sensor: custom: Fix use-after-free in enable_sensor
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (70 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 71/77] HID: core: fix number/pointer type confusion on long items Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 73/77] HID: hyperv: validate initial device info bounds Greg Kroah-Hartman
` (12 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Sashiko AI Review, Haoxiang Li,
Srinivas Pandruvada, Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <haoxiang_li2024@163.com>
commit ad8fb82b04422f49530d2aa2753cc81d1c60102c upstream.
enable_sensor_store() can call set_power_report_state(), which
dereferences sensor_inst->power_state and sensor_inst->report_state.
These pointers refer to entries in sensor_inst->fields.
Create the field attributes before exposing the enable_sensor sysfs
attribute, so enable_sensor cannot be accessed before the state it
depends on has been initialized.
On remove, delete enable_sensor before freeing the field attributes,
so a concurrent sysfs write cannot dereference freed memory through
power_state or report_state.
Reported-by: Sashiko AI Review <sashiko-bot@kernel.org>
Link: https://sashiko.dev/#/patchset/20260623021950.1736413-1-haoxiang_li2024@163.com?part=1
Fixes: 4a7de0519df5 ("HID: sensor: Custom and Generic sensor support")
Cc: stable@vger.kernel.org
Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-sensor-custom.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
--- a/drivers/hid/hid-sensor-custom.c
+++ b/drivers/hid/hid-sensor-custom.c
@@ -1005,26 +1005,26 @@ static int hid_sensor_custom_probe(struc
return ret;
}
- ret = sysfs_create_group(&sensor_inst->pdev->dev.kobj,
- &enable_sensor_attr_group);
+ ret = hid_sensor_custom_add_attributes(sensor_inst);
if (ret)
goto err_remove_callback;
- ret = hid_sensor_custom_add_attributes(sensor_inst);
+ ret = sysfs_create_group(&sensor_inst->pdev->dev.kobj,
+ &enable_sensor_attr_group);
if (ret)
- goto err_remove_group;
+ goto err_remove_attributes;
ret = hid_sensor_custom_dev_if_add(sensor_inst);
if (ret)
- goto err_remove_attributes;
+ goto err_remove_group;
return 0;
-err_remove_attributes:
- hid_sensor_custom_remove_attributes(sensor_inst);
err_remove_group:
sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
&enable_sensor_attr_group);
+err_remove_attributes:
+ hid_sensor_custom_remove_attributes(sensor_inst);
err_remove_callback:
sensor_hub_remove_callback(hsdev, hsdev->usage);
@@ -1042,9 +1042,10 @@ static void hid_sensor_custom_remove(str
}
hid_sensor_custom_dev_if_remove(sensor_inst);
- hid_sensor_custom_remove_attributes(sensor_inst);
+ /* Remove enable_sensor first as it uses fields via power_state/report_state. */
sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
&enable_sensor_attr_group);
+ hid_sensor_custom_remove_attributes(sensor_inst);
sensor_hub_remove_callback(hsdev, hsdev->usage);
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 73/77] HID: hyperv: validate initial device info bounds
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (71 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 72/77] HID: sensor: custom: Fix use-after-free in enable_sensor Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 74/77] Bluetooth: hci_event: fix LE list UAF on reset Greg Kroah-Hartman
` (11 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Michael Bommarito, Jiri Kosina
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <michael.bommarito@gmail.com>
commit 934b7778aa7b7c8f6bb073d2a73ba3674885bae0 upstream.
The Hyper-V synthetic HID host supplies SYNTH_HID_INITIAL_DEVICE_INFO
messages that contain a HID descriptor followed by the report descriptor
bytes. mousevsc_on_receive_device_info() trusts bLength and
wDescriptorLength without checking that the received packet contains both
byte ranges.
A malformed host or backend message can therefore make the guest read
past the received VMBus packet while copying the report descriptor. Pass
the received initial-device-info size into the parser and reject
descriptor lengths that exceed the packet.
Impact: A malicious Hyper-V host or backend can crash a guest by sending
a short initial device-info message with an oversized HID report
descriptor length.
Fixes: b95f5bcb811e ("HID: Move the hid-hyperv driver out of staging")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5-5-xhigh
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/hid/hid-hyperv.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -171,18 +171,32 @@ static void mousevsc_free_device(struct
}
static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
- struct synthhid_device_info *device_info)
+ struct synthhid_device_info *device_info,
+ u32 device_info_size)
{
int ret = 0;
struct hid_descriptor *desc;
struct mousevsc_prt_msg ack;
+ size_t desc_offset;
+ size_t desc_size;
input_device->dev_info_status = -ENOMEM;
+ if (device_info_size < sizeof(*device_info)) {
+ input_device->dev_info_status = -EINVAL;
+ goto cleanup;
+ }
+
input_device->hid_dev_info = device_info->hid_dev_info;
desc = &device_info->hid_descriptor;
+ desc_offset = offsetof(struct synthhid_device_info, hid_descriptor);
+ desc_size = device_info_size - desc_offset;
if (desc->bLength == 0)
goto cleanup;
+ if (desc->bLength < sizeof(*desc) || desc->bLength > desc_size) {
+ input_device->dev_info_status = -EINVAL;
+ goto cleanup;
+ }
/* The pointer is not NULL when we resume from hibernation */
kfree(input_device->hid_desc);
@@ -197,6 +211,10 @@ static void mousevsc_on_receive_device_i
input_device->dev_info_status = -EINVAL;
goto cleanup;
}
+ if (input_device->report_desc_size > desc_size - desc->bLength) {
+ input_device->dev_info_status = -EINVAL;
+ goto cleanup;
+ }
/* The pointer is not NULL when we resume from hibernation */
kfree(input_device->report_desc);
@@ -273,14 +291,17 @@ static void mousevsc_on_receive(struct h
break;
case SYNTH_HID_INITIAL_DEVICE_INFO:
- WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
+ if (WARN_ON_ONCE(pipe_msg->size <
+ sizeof(struct synthhid_device_info)))
+ break;
/*
* Parse out the device info into device attr,
* hid desc and report desc
*/
mousevsc_on_receive_device_info(input_dev,
- (struct synthhid_device_info *)pipe_msg->data);
+ (struct synthhid_device_info *)pipe_msg->data,
+ pipe_msg->size);
break;
case SYNTH_HID_INPUT_REPORT:
input_report =
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 74/77] Bluetooth: hci_event: fix LE list UAF on reset
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (72 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 73/77] HID: hyperv: validate initial device info bounds Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 75/77] Bluetooth: hci_event: validate LE Set CIG Parameters response Greg Kroah-Hartman
` (10 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Chengfeng Ye, Luiz Augusto von Dentz
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <nicoyip.dev@gmail.com>
commit 33af47e847fe4a28b109673affb5874015d54f5a upstream.
hci_cc_reset() clears the LE accept and resolving lists without taking
hdev->lock. Other command-complete handlers serialize updates to these
lists with that lock, and the debugfs readers hold it while walking them.
This permits the reset completion and a debugfs read to interleave as
follows:
hci_rx_work debugfs reader
----------- --------------
lock hdev->lock
fetch current entry
list_del(entry)
kfree(entry)
read entry fields
The reader then dereferences a freed list entry and may follow its stale
next pointer.
KASAN reported:
BUG: KASAN: slab-use-after-free in white_list_show+0x15f/0x180
Read of size 1 at addr ffff8881015dab16 by task poc/95
Call Trace:
white_list_show+0x15f/0x180
seq_read_iter+0x3ff/0x1190
seq_read+0x267/0x3d0
vfs_read+0x177/0xa20
ksys_read+0xf7/0x1c0
Allocated by task 91:
hci_bdaddr_list_add+0x1a6/0x3a0
hci_cc_le_add_to_accept_list+0xab/0x140
hci_cmd_complete_evt+0x26c/0x9a0
hci_event_packet+0x454/0xb20
hci_rx_work+0x293/0x730
Freed by task 90:
kfree+0x131/0x3c0
hci_bdaddr_list_clear+0xd8/0x160
hci_cc_reset+0x28a/0x370
hci_cmd_complete_evt+0x26c/0x9a0
hci_event_packet+0x454/0xb20
hci_rx_work+0x293/0x730
Take hdev->lock around both list clears. This matches the existing
mutation and traversal locking convention.
Fixes: a4d5504d5c39 ("Bluetooth: Clear LE white list when resetting controller")
Fixes: cfdb0c2d095a ("Bluetooth: Store Resolv list size")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/bluetooth/hci_event.c | 2 ++
1 file changed, 2 insertions(+)
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -293,8 +293,10 @@ static u8 hci_cc_reset(struct hci_dev *h
hdev->ssp_debug_mode = 0;
+ hci_dev_lock(hdev);
hci_bdaddr_list_clear(&hdev->le_accept_list);
hci_bdaddr_list_clear(&hdev->le_resolv_list);
+ hci_dev_unlock(hdev);
return rp->status;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 75/77] Bluetooth: hci_event: validate LE Set CIG Parameters response
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (73 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 74/77] Bluetooth: hci_event: fix LE list UAF on reset Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 76/77] Bluetooth: ISO: do not force BT_LISTEN after a failed BIG sync Greg Kroah-Hartman
` (9 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Laxman Acharya Padhya,
Luiz Augusto von Dentz
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
commit 0acd4eeb4b225b9bebbf9ef96cc10cdd79b94899 upstream.
The Command Complete dispatch validates only the fixed part of the LE Set
CIG Parameters response. After that part is pulled from the skb,
hci_cc_le_set_cig_params() trusts num_handles and reads each entry in the
trailing handle array.
Matching num_handles against the command's num_cis does not guarantee
that the response contains the advertised handles. A truncated response
from a malfunctioning controller can therefore make the handler read
beyond the skb data.
Validate that the remaining skb data contains all advertised handles.
Include this in the existing response validation so malformed responses
also follow the established CIG failure handling.
Fixes: 26afbd826ee3 ("Bluetooth: Add initial implementation of CIS connections")
Cc: stable@vger.kernel.org
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/bluetooth/hci_event.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3800,8 +3800,10 @@ static u8 hci_cc_le_set_cig_params(struc
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_CIG_PARAMS);
- if (!rp->status && (!cp || rp->num_handles != cp->num_cis ||
- rp->cig_id != cp->cig_id)) {
+ if (!rp->status &&
+ (!cp || rp->num_handles != cp->num_cis ||
+ rp->cig_id != cp->cig_id ||
+ skb->len < array_size(rp->num_handles, sizeof(*rp->handle)))) {
bt_dev_err(hdev, "unexpected Set CIG Parameters response data");
status = HCI_ERROR_UNSPECIFIED;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 76/77] Bluetooth: ISO: do not force BT_LISTEN after a failed BIG sync
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (74 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 75/77] Bluetooth: hci_event: validate LE Set CIG Parameters response Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 13:26 ` [PATCH 6.12 77/77] Bluetooth: hci_aml: validate firmware segment lengths Greg Kroah-Hartman
` (8 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable; +Cc: Greg Kroah-Hartman, patches, Ali Ahmet Memis,
Luiz Augusto von Dentz
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <ali@iusegentoo.com>
commit 9838a80096ba472d5e03057136a112631aabae6e upstream.
iso_sock_recvmsg() handles the deferred setup of a broadcast sink by
dropping the socket lock, calling iso_conn_big_sync() and taking the
lock again:
release_sock(sk);
iso_conn_big_sync(sk);
lock_sock(sk);
sk->sk_state = BT_LISTEN;
The state is written unconditionally, but iso_conn_big_sync() returns
void and has paths that do nothing at all: hci_get_route() may fail, and
after re-acquiring the socket lock the connection may already be gone,
in which case it bails out without ever issuing an LE BIG Create Sync.
While the lock is dropped the connection can be torn down, for example
when the controller reports HCI_EV_LE_PA_SYNC_LOST:
hci_le_pa_sync_lost_evt()
hci_disconn_cfm() -> iso_disconn_cfm() -> iso_conn_del()
iso_chan_del()
iso_pi(sk)->conn = NULL
sk->sk_state = BT_CLOSED
sock_set_flag(sk, SOCK_ZAPPED)
iso_conn_big_sync() then finds conn == NULL and returns, but the caller
still overwrites the BT_CLOSED that iso_chan_del() has just set. The
socket ends up marked BT_LISTEN with no connection, so recvmsg() reports
success for a setup that never happened and a later accept() waits for
BIS connections that can never arrive instead of failing.
A concurrent shutdown() reaches the same write by another route:
__iso_sock_close() takes the BT_CONNECT2 PA sync path to
iso_sock_disconn(), which sets BT_DISCONN but leaves conn and
conn->hcon in place, so iso_conn_big_sync() succeeds and BT_LISTEN is
written over BT_DISCONN. Both the BT_CONNECT2 and the BT_CONNECTED case
write the state the same way.
Let iso_conn_big_sync() report whether the BIG sync was started, and
only move the socket to BT_LISTEN when it was and when the state has not
changed while the lock was dropped, mirroring what the BT_CONNECT case
of the same switch already does with iso_connect_cis(). Both conditions
are needed, the error alone does not cover the shutdown() race.
This corrupts the socket state machine only, it is not a memory safety
issue. KASAN and lockdep stayed quiet in all of the runs below.
Reproduced with an emulated controller over /dev/vhci on a KASAN +
PROVE_LOCKING kernel. A PA sync broadcast sink socket is driven to
BT_CONNECT2 and recvmsg() on it is raced against teardown, with a debug
delay inside the lock-dropped section to widen the window:
- HCI_EV_LE_PA_SYNC_LOST injected: 64 of 64 rounds left the socket in
BT_LISTEN with the connection gone, recvmsg() returned 0 and accept()
on that fd returned EAGAIN, which iso_sock_accept() can only do while
the socket is BT_LISTEN. With this patch, 0 of 64, recvmsg() returns
an error and accept() returns EBADFD.
- shutdown() instead of a controller event: 24 of 32 rounds wedged in
BT_LISTEN, 0 of 32 with this patch. With only the error check in
place and a short window, one round still wedged while recvmsg()
returned 0, which is the case the state re-check covers.
An unraced control round behaves the same before and after: recvmsg()
returns 0, the socket reaches BT_LISTEN and an LE BIG Create Sync is
issued.
Fixes: 7a17308c1788 ("Bluetooth: iso: Fix circular lock in iso_conn_big_sync")
Cc: stable@vger.kernel.org
Signed-off-by: Ali Ahmet Memis <ali@iusegentoo.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
net/bluetooth/iso.c | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -1451,9 +1451,9 @@ static void iso_conn_defer_accept(struct
hci_send_cmd(hdev, HCI_OP_LE_ACCEPT_CIS, sizeof(cp), &cp);
}
-static void iso_conn_big_sync(struct sock *sk)
+static int iso_conn_big_sync(struct sock *sk)
{
- int err;
+ int err = 0;
struct hci_dev *hdev;
struct iso_conn *conn;
bdaddr_t src, dst;
@@ -1468,7 +1468,7 @@ static void iso_conn_big_sync(struct soc
hdev = hci_get_route(&dst, &src, src_type);
if (!hdev)
- return;
+ return -EHOSTUNREACH;
/* hci_le_big_create_sync requires hdev lock to be held, since
* it enqueues the HCI LE BIG Create Sync command via
@@ -1484,8 +1484,10 @@ static void iso_conn_big_sync(struct soc
* both before dereferencing conn->hcon.
*/
conn = iso_pi(sk)->conn;
- if (!conn || !conn->hcon)
+ if (!conn || !conn->hcon) {
+ err = -ENOTCONN;
goto unlock;
+ }
if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
err = hci_conn_big_create_sync(hdev, conn->hcon,
@@ -1501,6 +1503,8 @@ unlock:
release_sock(sk);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
+
+ return err;
}
static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -1521,10 +1525,19 @@ static int iso_sock_recvmsg(struct socke
case BT_CONNECT2:
if (test_bit(BT_SK_PA_SYNC, &pi->flags)) {
release_sock(sk);
- iso_conn_big_sync(sk);
+ err = iso_conn_big_sync(sk);
lock_sock(sk);
- sk->sk_state = BT_LISTEN;
+ /* The socket lock was dropped, so the
+ * connection may have been torn down
+ * meanwhile and iso_chan_del() may have
+ * already moved the socket to BT_CLOSED.
+ * Only move on to BT_LISTEN if the BIG sync
+ * was actually started and nothing else has
+ * changed the state.
+ */
+ if (!err && sk->sk_state == BT_CONNECT2)
+ sk->sk_state = BT_LISTEN;
} else {
iso_conn_defer_accept(pi->conn->hcon);
sk->sk_state = BT_CONFIG;
@@ -1535,10 +1548,11 @@ static int iso_sock_recvmsg(struct socke
case BT_CONNECTED:
if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
release_sock(sk);
- iso_conn_big_sync(sk);
+ err = iso_conn_big_sync(sk);
lock_sock(sk);
- sk->sk_state = BT_LISTEN;
+ if (!err && sk->sk_state == BT_CONNECTED)
+ sk->sk_state = BT_LISTEN;
early_ret = true;
}
^ permalink raw reply [flat|nested] 86+ messages in thread* [PATCH 6.12 77/77] Bluetooth: hci_aml: validate firmware segment lengths
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (75 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 76/77] Bluetooth: ISO: do not force BT_LISTEN after a failed BIG sync Greg Kroah-Hartman
@ 2026-08-25 13:26 ` Greg Kroah-Hartman
2026-08-25 22:32 ` [PATCH 6.12 00/77] 6.12.106-rc1 review Florian Fainelli
` (7 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-25 13:26 UTC (permalink / raw)
To: stable
Cc: Greg Kroah-Hartman, patches, Laxman Acharya Padhya,
Luiz Augusto von Dentz
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
commit 2bf6b9baca9372ea51b6d0f2820dc9bf29a83ef4 upstream.
aml_download_firmware() reads two lengths from the firmware header and
uses them to build pointers before checking that the header and segment
data are present. A truncated or inconsistent firmware image can make
the driver read past firmware->data while constructing TCI commands.
Reject images shorter than the header and ensure that the ICCM and DCCM
ranges fit within the loaded firmware before downloading either segment.
Fixes: 37bac77e4649 ("Bluetooth: hci_uart: Add support for Amlogic HCI UART")
Cc: stable@vger.kernel.org
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/bluetooth/hci_aml.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/bluetooth/hci_aml.c b/drivers/bluetooth/hci_aml.c
index 959d9e67b669..067fbf278b44 100644
--- a/drivers/bluetooth/hci_aml.c
+++ b/drivers/bluetooth/hci_aml.c
@@ -247,7 +247,7 @@ static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name)
struct hci_uart *hu = hci_get_drvdata(hdev);
struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);
const struct firmware *firmware = NULL;
- struct aml_fw_len *fw_len = NULL;
+ const struct aml_fw_len *fw_len = NULL;
u8 *iccm_start = NULL, *dccm_start = NULL;
u32 iccm_len, dccm_len;
u32 value = 0;
@@ -281,7 +281,21 @@ static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name)
goto exit;
}
- fw_len = (struct aml_fw_len *)firmware->data;
+ if (firmware->size < sizeof(*fw_len)) {
+ bt_dev_err(hdev, "Firmware is too small for its header");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ fw_len = (const struct aml_fw_len *)firmware->data;
+ if (fw_len->iccm_len < amldev->aml_dev_data->iccm_offset ||
+ fw_len->iccm_len > firmware->size - sizeof(*fw_len) ||
+ fw_len->dccm_len > firmware->size - sizeof(*fw_len) -
+ fw_len->iccm_len) {
+ bt_dev_err(hdev, "Invalid firmware segment lengths");
+ ret = -EINVAL;
+ goto exit;
+ }
/* Download ICCM */
iccm_start = (u8 *)(firmware->data) + sizeof(struct aml_fw_len)
--
2.55.0
^ permalink raw reply related [flat|nested] 86+ messages in thread* Re: [PATCH 6.12 00/77] 6.12.106-rc1 review
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (76 preceding siblings ...)
2026-08-25 13:26 ` [PATCH 6.12 77/77] Bluetooth: hci_aml: validate firmware segment lengths Greg Kroah-Hartman
@ 2026-08-25 22:32 ` Florian Fainelli
2026-08-26 0:09 ` Shuah Khan
` (6 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Florian Fainelli @ 2026-08-25 22:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, stable
Cc: patches, linux-kernel, torvalds, akpm, linux, shuah, patches,
lkft-triage, pavel, jonathanh, sudipm.mukherjee, rwarsow, conor,
hargar, broonie, achill, sr
On 8/25/26 06:25, Greg Kroah-Hartman wrote:
> This is the start of the stable review cycle for the 6.12.106 release.
> There are 77 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Thu, 27 Aug 2026 13:25:02 +0000.
> Anything received after that time might be too late.
>
> The whole patch series can be found in one patch at:
> https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.12.106-rc1.gz
> or in the git tree and branch at:
> git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.12.y
> and the diffstat can be found below.
>
> thanks,
>
> greg k-h
On ARCH_BRCMSTB using 32-bit and 64-bit ARM kernels, build tested on
BMIPS_GENERIC:
Tested-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply [flat|nested] 86+ messages in thread* Re: [PATCH 6.12 00/77] 6.12.106-rc1 review
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (77 preceding siblings ...)
2026-08-25 22:32 ` [PATCH 6.12 00/77] 6.12.106-rc1 review Florian Fainelli
@ 2026-08-26 0:09 ` Shuah Khan
2026-08-26 6:14 ` Ron Economos
` (5 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Shuah Khan @ 2026-08-26 0:09 UTC (permalink / raw)
To: Greg Kroah-Hartman, stable
Cc: patches, linux-kernel, torvalds, akpm, linux, shuah, patches,
lkft-triage, pavel, jonathanh, f.fainelli, sudipm.mukherjee,
rwarsow, conor, hargar, broonie, achill, sr, Shuah Khan
On 8/25/26 07:25, Greg Kroah-Hartman wrote:
> This is the start of the stable review cycle for the 6.12.106 release.
> There are 77 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Thu, 27 Aug 2026 13:25:02 +0000.
> Anything received after that time might be too late.
>
> The whole patch series can be found in one patch at:
> https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.12.106-rc1.gz
> or in the git tree and branch at:
> git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.12.y
> and the diffstat can be found below.
>
> thanks,
>
> greg k-h
>
Compiled and booted on my test system. No dmesg regressions.
Tested-by: Shuah Khan <skhan@linuxfoundation.org>
thanks,
-- Shuah
^ permalink raw reply [flat|nested] 86+ messages in thread* Re: [PATCH 6.12 00/77] 6.12.106-rc1 review
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (78 preceding siblings ...)
2026-08-26 0:09 ` Shuah Khan
@ 2026-08-26 6:14 ` Ron Economos
2026-08-26 6:38 ` Pavel Machek
` (4 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Ron Economos @ 2026-08-26 6:14 UTC (permalink / raw)
To: Greg Kroah-Hartman, stable
Cc: patches, linux-kernel, torvalds, akpm, linux, shuah, patches,
lkft-triage, pavel, jonathanh, f.fainelli, sudipm.mukherjee,
rwarsow, conor, hargar, broonie, achill, sr
On 8/25/26 06:25, Greg Kroah-Hartman wrote:
> This is the start of the stable review cycle for the 6.12.106 release.
> There are 77 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Thu, 27 Aug 2026 13:25:02 +0000.
> Anything received after that time might be too late.
>
> The whole patch series can be found in one patch at:
> https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.12.106-rc1.gz
> or in the git tree and branch at:
> git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.12.y
> and the diffstat can be found below.
>
> thanks,
>
> greg k-h
Built and booted successfully on RISC-V RV64 (HiFive Unmatched).
Tested-by: Ron Economos <re@w6rz.net>
^ permalink raw reply [flat|nested] 86+ messages in thread* Re: [PATCH 6.12 00/77] 6.12.106-rc1 review
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (79 preceding siblings ...)
2026-08-26 6:14 ` Ron Economos
@ 2026-08-26 6:38 ` Pavel Machek
2026-08-26 7:33 ` Dominique Martinet
` (3 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Pavel Machek @ 2026-08-26 6:38 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: stable, patches, linux-kernel, torvalds, akpm, linux, shuah,
patches, lkft-triage, pavel, jonathanh, f.fainelli,
sudipm.mukherjee, rwarsow, conor, hargar, broonie, achill, sr
[-- Attachment #1: Type: text/plain, Size: 504 bytes --]
Hi!
> This is the start of the stable review cycle for the 6.12.106 release.
> There are 77 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
CIP testing did not find any problems here:
https://gitlab.com/cip-project/cip-testing/linux-stable-rc-ci/-/tree/linux-6.12.y
Tested-by: Pavel Machek (CIP) <pavel@nabladev.com>
Best regards,
Pavel
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
^ permalink raw reply [flat|nested] 86+ messages in thread* Re: [PATCH 6.12 00/77] 6.12.106-rc1 review
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (80 preceding siblings ...)
2026-08-26 6:38 ` Pavel Machek
@ 2026-08-26 7:33 ` Dominique Martinet
2026-08-26 10:32 ` Brett A C Sheffield
` (2 subsequent siblings)
84 siblings, 0 replies; 86+ messages in thread
From: Dominique Martinet @ 2026-08-26 7:33 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: stable, patches, linux-kernel, torvalds, akpm, linux, shuah,
patches, lkft-triage, pavel, jonathanh, f.fainelli,
sudipm.mukherjee, rwarsow, conor, hargar, broonie, achill, sr
Greg Kroah-Hartman wrote on Tue, Aug 25, 2026 at 03:25:22PM +0200:
> This is the start of the stable review cycle for the 6.12.106 release.
> There are 77 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Thu, 27 Aug 2026 13:25:02 +0000.
> Anything received after that time might be too late.
>
> The whole patch series can be found in one patch at:
> https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.12.106-rc1.gz
> or in the git tree and branch at:
> git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.git linux-6.12.y
> and the diffstat can be found below.
Tested 8a0cfbd3eea7 ("Linux 6.12.106-rc1") on:
- arm i.MX6ULL (Armadillo 640)
- arm64 i.MX8ULP (Armadillo IoT A9E)
No obvious regression in dmesg or basic tests:
Tested-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
--
Dominique Martinet
^ permalink raw reply [flat|nested] 86+ messages in thread* Re: [PATCH 6.12 00/77] 6.12.106-rc1 review
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (81 preceding siblings ...)
2026-08-26 7:33 ` Dominique Martinet
@ 2026-08-26 10:32 ` Brett A C Sheffield
2026-08-26 11:56 ` Miguel Ojeda
2026-08-26 13:09 ` Peter Schneider
84 siblings, 0 replies; 86+ messages in thread
From: Brett A C Sheffield @ 2026-08-26 10:32 UTC (permalink / raw)
To: gregkh
Cc: stable, patches, linux-kernel, torvalds, akpm, linux, shuah,
patches, lkft-triage, pavel, jonathanh, f.fainelli,
sudipm.mukherjee, rwarsow, conor, hargar, broonie, achill, sr,
Brett A C Sheffield
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 6.12.106-rc1-g8a0cfbd3eea7 #1 SMP PREEMPT_DYNAMIC Wed Aug 26 10:07:20 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Tested-by: Brett A C Sheffield <bacs@librecast.net>
^ permalink raw reply [flat|nested] 86+ messages in thread* Re: [PATCH 6.12 00/77] 6.12.106-rc1 review
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (82 preceding siblings ...)
2026-08-26 10:32 ` Brett A C Sheffield
@ 2026-08-26 11:56 ` Miguel Ojeda
2026-08-26 13:09 ` Peter Schneider
84 siblings, 0 replies; 86+ messages in thread
From: Miguel Ojeda @ 2026-08-26 11:56 UTC (permalink / raw)
To: gregkh
Cc: achill, akpm, broonie, conor, f.fainelli, hargar, jonathanh,
linux-kernel, linux, lkft-triage, patches, patches, pavel,
rwarsow, shuah, sr, stable, sudipm.mukherjee, torvalds,
Miguel Ojeda
On Tue, 25 Aug 2026 15:25:22 +0200 Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
>
> This is the start of the stable review cycle for the 6.12.106 release.
> There are 77 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
>
> Responses should be made by Thu, 27 Aug 2026 13:25:02 +0000.
> Anything received after that time might be too late.
Boot-tested under QEMU for Rust x86_64, arm64 and riscv64; built-tested
for loongarch64:
Tested-by: Miguel Ojeda <ojeda@kernel.org>
Thanks!
Cheers,
Miguel
^ permalink raw reply [flat|nested] 86+ messages in thread* Re: [PATCH 6.12 00/77] 6.12.106-rc1 review
2026-08-25 13:25 [PATCH 6.12 00/77] 6.12.106-rc1 review Greg Kroah-Hartman
` (83 preceding siblings ...)
2026-08-26 11:56 ` Miguel Ojeda
@ 2026-08-26 13:09 ` Peter Schneider
84 siblings, 0 replies; 86+ messages in thread
From: Peter Schneider @ 2026-08-26 13:09 UTC (permalink / raw)
To: Greg Kroah-Hartman, stable
Cc: patches, linux-kernel, torvalds, akpm, linux, shuah, patches,
lkft-triage, pavel, jonathanh, f.fainelli, sudipm.mukherjee,
rwarsow, conor, hargar, broonie, achill, sr
Am 25.08.2026 um 15:25 schrieb Greg Kroah-Hartman:
> This is the start of the stable review cycle for the 6.12.106 release.
> There are 77 patches in this series, all will be posted as a response
> to this one. If anyone has any issues with these being applied, please
> let me know.
Builds, boots and works on my 2-socket Ivy Bridge Xeon E5-2697 v2 server. No dmesg oddities or regressions found.
Tested-by: Peter Schneider <pschneider1968@googlemail.com>
Beste Grüße,
Peter Schneider
--
Climb the mountain not to plant your flag, but to embrace the challenge,
enjoy the air and behold the view. Climb it so you can see the world,
not so the world can see you. -- David McCullough Jr.
OpenPGP: 0xA3828BD796CCE11A8CADE8866E3A92C92C3FF244
Download: https://www.peters-netzplatz.de/download/pschneider1968_pub.asc
https://keys.mailvelope.com/pks/lookup?op=get&search=pschneider1968@googlemail.com
https://keys.mailvelope.com/pks/lookup?op=get&search=pschneider1968@gmail.com
^ permalink raw reply [flat|nested] 86+ messages in thread