out-of-bounds write in the function ata_pio_sector

reveliofuzzing
2025-01-02T02:17:14Z

Hi there,

We found an out-of-bounds write in the function ata_pio_sector, which can cause
the kernel to crash. We would like to report it for your reference.

## Problem in ata_pio_sector
ata_pio_sector uses the following code to decide which page to use for the I/O:
page = sg_page(qc->cursg);
offset = qc->cursg->offset + qc->cursg_ofs;

/* get the current page and offset */
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;
but we found that `offset` could be as high as 0x5000---qc->cursg_ofs==0x5000,
qc->cursg->offset == 0x0, making `page` point to a higher-position page that
belongs to other threads.

## Example crash
This out-of-bound write can cause the kernel to crash at arbitrary places,
depending on when the corrupted page is accessed by the other thread.

We found this problem can happen in Linux kernel 6.1~6.12. Here is one crash in
Linux kernel 6.1:
executing program
[ 15.461899] program syz-executor is using a deprecated SCSI ioctl,
please convert it to SG_IO
[ 79.990338] ata1: lost interrupt (Status 0x58)
[ 80.510447] ata1: found unknown device (class 0)
[ 80.519176] BUG: kernel NULL pointer dereference, address: 0000000000000030
[ 80.527336] #PF: supervisor read access in kernel mode
[ 80.533045] #PF: error_code(0x0000) - not-present page
[ 80.538614] PGD 0 P4D 0
[ 80.543339] Oops: 0000 [#1] PREEMPT SMP PTI
[ 80.547027] CPU: 0 PID: 195 Comm: syz-executor Not tainted
6.1.0-rc7-g29106f2b0871 #774
[ 80.551328] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014
[ 80.555779] RIP: 0010:do_exit+0x34a/0xa40
[ 80.557528] Code: 08 4c 89 64 24 10 e8 15 ec 7e 00 48 8b 93 78 05
00 00 48 8d 83 78 05 00 00 48 39 c2 0f 85 7e 05 00 00 48 89 df e8 26
7e 01 00 <48> 8b 68 30 49 89 c5 48 39 e0
[ 80.562666] RSP: 0018:ffffc900004cbd80 EFLAGS: 00010046
[ 80.564524] RAX: 0000000000000000 RBX: ffff888003b30f80 RCX: 0000000000000000
[ 80.566399] RDX: 0000000000000000 RSI: ffff888003ec84a8 RDI: ffff888003b30f80
[ 80.568231] RBP: ffff888003d003c0 R08: ffff888003b31870 R09: ffffc900004cbcb0
[ 80.570042] R10: ffff888003b08090 R11: fffffffffffcc2c7 R12: ffffc900004cbd88
[ 80.571629] R13: ffff888003d00420 R14: ffff888003b30f01 R15: ffff888003b31768
[ 80.573237] FS: 0000000000000000(0000) GS:ffff88807dc00000(0000)
knlGS:0000000000000000
[ 80.574916] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 80.576221] CR2: 0000000000000030 CR3: 000000000220a000 CR4: 0000000000350eb0
[ 80.577652] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 80.579075] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 80.580435] Call Trace:
[ 80.581092] <TASK>
[ 80.581704] do_group_exit+0x28/0x80
[ 80.582514] get_signal+0x8de/0x910
[ 80.583309] ? sg_ioctl+0x331/0xb20
[ 80.584112] arch_do_signal_or_restart+0x1b/0x660
[ 80.585093] ? __x64_sys_ioctl+0x178/0x9b0
[ 80.585973] ? handle_mm_fault+0x6a/0x1b0
[ 80.586817] exit_to_user_mode_prepare+0x89/0x150
[ 80.587766] syscall_exit_to_user_mode+0x1d/0x40
[ 80.588739] do_syscall_64+0x50/0x90
[ 80.589572] entry_SYSCALL_64_after_hwframe+0x63/0xcd
[ 80.590552] RIP: 0033:0x7f5e0333aaad
[ 80.591358] Code: Unable to access opcode bytes at 0x7f5e0333aa83.
[ 80.592529] RSP: 002b:00007ffc19613458 EFLAGS: 00000246 ORIG_RAX:
0000000000000010
[ 80.593999] RAX: 0000000000000002 RBX: 00007ffc19613480 RCX: 00007f5e0333aaad
[ 80.595319] RDX: 0000000020000040 RSI: 0000000000000001 RDI: 0000000000000003
[ 80.596569] RBP: 0000000000000000 R08: 0000000000000012 R09: 0000000000000000
[ 80.597824] R10: 00007f5e0338803c R11: 0000000000000246 R12: 00007ffc19613490
[ 80.599134] R13: 00007f5e033b2df0 R14: 0000000000000000 R15: 0000000000000000
[ 80.600467] </TASK>
[ 80.601090] Modules linked in:
[ 80.602009] CR2: 0000000000000030
[ 80.602904] ---[ end trace 0000000000000000 ]---
[ 80.603834] RIP: 0010:do_exit+0x34a/0xa40
[ 80.604703] Code: 08 4c 89 64 24 10 e8 15 ec 7e 00 48 8b 93 78 05
00 00 48 8d 83 78 05 00 00 48 39 c2 0f 85 7e 05 00 00 48 89 df e8 26
7e 01 00 <48> 8b 68 30 49 89 c5 48 39 e0
[ 80.607601] RSP: 0018:ffffc900004cbd80 EFLAGS: 00010046
[ 80.608740] RAX: 0000000000000000 RBX: ffff888003b30f80 RCX: 0000000000000000
[ 80.610073] RDX: 0000000000000000 RSI: ffff888003ec84a8 RDI: ffff888003b30f80
[ 80.611394] RBP: ffff888003d003c0 R08: ffff888003b31870 R09: ffffc900004cbcb0
[ 80.612717] R10: ffff888003b08090 R11: fffffffffffcc2c7 R12: ffffc900004cbd88
[ 80.614027] R13: ffff888003d00420 R14: ffff888003b30f01 R15: ffff888003b31768
[ 80.615335] FS: 0000000000000000(0000) GS:ffff88807dc00000(0000)
knlGS:0000000000000000
[ 80.616721] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 80.617845] CR2: 0000000000000030 CR3: 000000000220a000 CR4: 0000000000350eb0
[ 80.619171] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 80.620385] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 80.621706] note: syz-executor[195] exited with preempt_count 1
[ 80.622850] Fixing recursive fault but reboot is needed!
[ 80.623910] BUG: scheduling while atomic: syz-executor/195/0x00000000
[ 80.625128] Modules linked in:
[ 80.626096] Preemption disabled at:
[ 80.626202] [<0000000000000000>] 0x0
[ 80.627687] CPU: 0 PID: 195 Comm: syz-executor Tainted: G D
6.1.0-rc7-g29106f2b0871 #774
[ 80.629278] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014
[ 80.631147] Call Trace:
[ 80.631834] <TASK>
[ 80.632459] dump_stack_lvl+0x33/0x46
[ 80.633285] __schedule_bug.cold+0x7d/0x8e
[ 80.634181] __schedule+0x63b/0x700
[ 80.634986] ? _printk+0x43/0x49
[ 80.635775] do_task_dead+0x3f/0x50
[ 80.636575] make_task_dead.cold+0x51/0xab
[ 80.637446] rewind_stack_and_make_dead+0x17/0x20
[ 80.638434] RIP: 0033:0x7f5e0333aaad
[ 80.639306] Code: Unable to access opcode bytes at 0x7f5e0333aa83.
[ 80.640466] RSP: 002b:00007ffc19613458 EFLAGS: 00000246 ORIG_RAX:
0000000000000010
[ 80.641901] RAX: 0000000000000002 RBX: 00007ffc19613480 RCX: 00007f5e0333aaad
[ 80.643213] RDX: 0000000020000040 RSI: 0000000000000001 RDI: 0000000000000003
[ 80.644474] RBP: 0000000000000000 R08: 0000000000000012 R09: 0000000000000000
[ 80.645789] R10: 00007f5e0338803c R11: 0000000000000246 R12: 00007ffc19613490
[ 80.647105] R13: 00007f5e033b2df0 R14: 0000000000000000 R15: 0000000000000000
[ 80.648441] </TASK>