KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (10)

Status: moderation: reported on 2026/11/09 20:57
Subsystems: serial
Labels: prio:low
[Documentation on labels]
Reported-by: syzbot+2430ce6b487fe0119d03@syzkaller.appspotmail.com
First crash: 1h02m, last: 1h02m
✨ AI-generated root cause summary:

In drivers/tty/n_tty.c, ldata->lookahead_count tracks the number of characters inspected ahead for software flow control (XON/XOFF). While reset_buffer_flags() (called by n_tty_flush_buffer()) clears lookahead_count under exclusive termios_rwsem and __receive_buf() decrements it under shared termios_rwsem, n_tty_lookahead_flow_ctrl() performs an unsynchronized read-modify-write (ldata->lookahead_count += count) without holding termios_rwsem. When a concurrent hangup, close, or flush operation executes n_tty_flush_buffer() while the flush_to_ldisc worker runs lookahead_bufs(), a data race occurs on ldata->lookahead_count.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit 7475ea8b5861:

Technical Analysis of the Root Cause

1. Overview and Files Involved

  • File: drivers/tty/n_tty.c
  • Functions: n_tty_lookahead_flow_ctrl(), reset_buffer_flags() (inlined in n_tty_flush_buffer()), __receive_buf()
  • Structs and Fields: struct n_tty_data::lookahead_count, struct tty_struct::termios_rwsem

2. Synchronization Invariant and Mechanism

In the N_TTY line discipline (drivers/tty/n_tty.c), struct n_tty_data contains buffer pointers and counters that coordinate input processing between producers, consumers, and buffer flush operations. ldata->lookahead_count tracks how many incoming bytes have already been scanned ahead in tty_buffer to identify software flow control characters (START_CHAR / STOP_CHAR when IXON is enabled).

The synchronization rules for struct n_tty_data fields rely on tty->termios_rwsem:

  • Read/Consumer path & Normal receive path: n_tty_receive_buf_common() acquires down_read(&tty->termios_rwsem) before calling __receive_buf(). Inside __receive_buf(), ldata->lookahead_count is read (size_t la_count = min(ldata->lookahead_count, count);) and decremented (ldata->lookahead_count -= la_count;).
  • Buffer reset & flush path: n_tty_flush_buffer() acquires down_write(&tty->termios_rwsem) and calls reset_buffer_flags(), which resets ldata->lookahead_count = 0; alongside resetting head and tail indices.

3. Root Cause of the Data Race

When flush_to_ldisc() in drivers/tty/tty_buffer.c cannot push all characters to the line discipline (e.g. rcvd < count), it invokes lookahead_bufs() -> tty_port_default_lookahead_buf() -> n_tty_lookahead_flow_ctrl().

Unlike n_tty_receive_buf_common(), n_tty_lookahead_flow_ctrl() does not acquire tty->termios_rwsem (either for read or write):

static void n_tty_lookahead_flow_ctrl(struct tty_struct *tty, const u8 *cp,
				      const u8 *fp, size_t count)
{
	struct n_tty_data *ldata = tty->disc_data;
	u8 flag = TTY_NORMAL;

	ldata->lookahead_count += count;  /* Unsynchronized read-modify-write */
...

When a concurrent thread initiates hangup, close, or an ioctl flush (such as pty_close() -> tty_vhangup() -> __tty_hangup() -> tty_ldisc_hangup() -> n_tty_flush_buffer()), it executes:

static void reset_buffer_flags(struct n_tty_data *ldata)
{
...
	ldata->lookahead_count = 0;
}

Because n_tty_lookahead_flow_ctrl() executes without tty->termios_rwsem, the write ldata->lookahead_count = 0 in reset_buffer_flags() and the read-modify-write ldata->lookahead_count += count in n_tty_lookahead_flow_ctrl() execute concurrently on different CPUs without synchronization, triggering the reported KCSAN data race.

▶ ▼ ✨ AI Jobs (2)
ID Workflow Result Correct Bug Created Started Finished Revision
92971ffd assessment-kcsan 🏃 KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (10) 2026/11/09 20:23 2026/11/09 20:23 5cecaf1f
86c838dc assessment-security DenialOfService: ❌ Exploitable: ❌ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ❌ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ✅ UserNamespace: ✅ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (10) 2026/11/09 20:23 2026/11/09 20:23 2026/11/09 20:46 5cecaf1f
▶ ▼ Similar bugs (9)
Kernel Title Rank 🛈 Repro Cause bisect Fix bisect Count Last Reported Patched Status
upstream KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl serial 6 1 1512d 1512d 0/29 auto-obsoleted due to no activity on 2022/10/24 16:46
upstream KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (9) serial 6 1 276d 276d 0/29 auto-obsoleted due to no activity on 2026/04/03 13:20
upstream KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (8) serial 6 1 417d 417d 0/29 auto-obsoleted due to no activity on 2025/11/13 20:33
upstream KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (5) serial 6 11 815d 974d 0/29 auto-obsoleted due to no activity on 2024/09/20 19:47
upstream KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (4) serial 6 1 1053d 1053d 0/29 auto-obsoleted due to no activity on 2024/01/26 04:56
upstream KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (2) serial 6 14 1287d 1462d 0/29 auto-obsoleted due to no activity on 2023/06/06 13:18
upstream KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (7) serial 6 2 481d 486d 0/29 auto-obsoleted due to no activity on 2025/09/10 16:46
upstream KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (3) serial 6 6 1178d 1241d 0/29 auto-obsoleted due to no activity on 2023/09/23 08:11
upstream KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl (6) serial 6 13 556d 728d 0/29 auto-obsoleted due to no activity on 2025/06/27 12:49

Sample crash report:
==================================================================
BUG: KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl

read-write to 0xffffc90002eed270 of 8 bytes by task 368 on cpu 1:
 n_tty_lookahead_flow_ctrl+0x52/0x2d0 drivers/tty/n_tty.c:1483
 tty_port_default_lookahead_buf+0x91/0xc0 drivers/tty/tty_port.c:59
 lookahead_bufs drivers/tty/tty_buffer.c:435 [inline]
 flush_to_ldisc+0x279/0x320 drivers/tty/tty_buffer.c:505
 process_one_work kernel/workqueue.c:3495 [inline]
 process_scheduled_works+0x53f/0xa20 kernel/workqueue.c:3578
 worker_thread+0x56c/0x770 kernel/workqueue.c:3659
 kthread+0x223/0x270 kernel/kthread.c:436
 ret_from_fork+0x146/0x330 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245

write to 0xffffc90002eed270 of 8 bytes by task 19255 on cpu 0:
 reset_buffer_flags drivers/tty/n_tty.c:322 [inline]
 n_tty_flush_buffer+0xa8/0x180 drivers/tty/n_tty.c:350
 tty_ldisc_hangup+0x77/0x480 drivers/tty/tty_ldisc.c:699
 __tty_hangup+0x37e/0x520 drivers/tty/tty_io.c:621
 tty_vhangup+0x17/0x20 drivers/tty/tty_io.c:693
 pty_close+0x266/0x290 drivers/tty/pty.c:77
 tty_release+0x1e7/0xaf0 drivers/tty/tty_io.c:1720
 __fput+0x286/0x610 fs/file_table.c:512
 ____fput+0x1c/0x30 fs/file_table.c:541
 task_work_run+0x133/0x190 kernel/task_work.c:233
 resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
 __exit_to_user_mode_loop kernel/entry/common.c:70 [inline]
 exit_to_user_mode_loop+0x1e4/0x8c0 kernel/entry/common.c:101
 __exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
 syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:230 [inline]
 syscall_exit_to_user_mode include/linux/entry-common.h:343 [inline]
 do_syscall_64+0x216/0x380 arch/x86/entry/syscall_64.c:107
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

value changed: 0x0000000000000ab3 -> 0x00000000000018b3

Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 19255 Comm: syz.2.12303 Not tainted syzkaller #0 PREEMPT(lazy) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 11/06/2026
==================================================================

Crashes (1):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/11/09 20:22 upstream 7475ea8b5861 5cecaf1f .config console log report info [disk image] [vmlinux] [kernel image] ci2-upstream-kcsan-gce KCSAN: data-race in n_tty_flush_buffer / n_tty_lookahead_flow_ctrl
* Struck through repros no longer work on HEAD.