Hello,
syzbot found the following issue on:
HEAD commit: e7c5433c5aaa tools: ynl: Remove duplicated include in hand..
git tree: net-next
console+strace: https://syzkaller.appspot.com/x/log.txt?x=10d8188b280000
kernel config: https://syzkaller.appspot.com/x/.config?x=526f919910d4a671
dashboard link: https://syzkaller.appspot.com/bug?extid=f9e28a23426ac3b24f20
compiler: gcc (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=12715143280000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=17a936f1280000
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/13c08af1fd21/disk-e7c5433c.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/35820511752b/vmlinux-e7c5433c.xz
kernel image: https://storage.googleapis.com/syzbot-assets/6a8cbec0d40f/bzImage-e7c5433c.xz
The issue was bisected to:
commit 2dc334f1a63a8839b88483a3e73c0f27c9c1791c
Author: David Howells <[email protected]>
Date: Wed Jun 7 18:19:09 2023 +0000
splice, net: Use sendmsg(MSG_SPLICE_PAGES) rather than ->sendpage()
bisection log: https://syzkaller.appspot.com/x/bisect.txt?x=12c225b3280000
final oops: https://syzkaller.appspot.com/x/report.txt?x=11c225b3280000
console output: https://syzkaller.appspot.com/x/log.txt?x=16c225b3280000
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: [email protected]
Fixes: 2dc334f1a63a ("splice, net: Use sendmsg(MSG_SPLICE_PAGES) rather than ->sendpage()")
general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] PREEMPT SMP KASAN
KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
CPU: 1 PID: 5007 Comm: syz-executor330 Not tainted 6.4.0-rc5-syzkaller-00915-ge7c5433c5aaa #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/25/2023
RIP: 0010:pipe_buf_release include/linux/pipe_fs_i.h:203 [inline]
RIP: 0010:splice_to_socket+0xa91/0xe30 fs/splice.c:933
Code: 10 48 89 f8 48 c1 e8 03 42 80 3c 28 00 0f 85 19 03 00 00 49 8b 46 10 49 c7 46 10 00 00 00 00 48 8d 78 08 48 89 fa 48 c1 ea 03 <42> 80 3c 2a 00 0f 85 e3 02 00 00 4c 89 f6 4c 89 e7 ff 50 08 83 44
RSP: 0018:ffffc90003adfa28 EFLAGS: 00010202
RAX: 0000000000000000 RBX: 0000000000008001 RCX: 0000000000000000
RDX: 0000000000000001 RSI: ffffffff81f4e014 RDI: 0000000000000008
RBP: 0000000000000000 R08: 0000000000000005 R09: 0000000000000000
R10: 0000000000000000 R11: 1ffffffff2186c9b R12: ffff88802819f000
R13: dffffc0000000000 R14: ffff888077c05028 R15: 0000000000008001
FS: 00007f82b229b700(0000) GS:ffff8880b9900000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f82b227a718 CR3: 0000000075e14000 CR4: 00000000003506e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<TASK>
do_splice_from fs/splice.c:969 [inline]
do_splice+0xb8c/0x1e50 fs/splice.c:1309
__do_splice+0x14e/0x270 fs/splice.c:1387
__do_sys_splice fs/splice.c:1598 [inline]
__se_sys_splice fs/splice.c:1580 [inline]
__x64_sys_splice+0x19c/0x250 fs/splice.c:1580
do_syscall_x64 arch/x86/entry/common.c:50 [inline]
do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
entry_SYSCALL_64_after_hwframe+0x63/0xcd
RIP: 0033:0x7f82b22e8fc9
Code: 28 00 00 00 75 05 48 83 c4 28 c3 e8 81 14 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f82b229b2f8 EFLAGS: 00000246 ORIG_RAX: 0000000000000113
RAX: ffffffffffffffda RBX: 00007f82b2371428 RCX: 00007f82b22e8fc9
RDX: 0000000000000008 RSI: 0000000000000000 RDI: 0000000000000003
RBP: 00007f82b2371420 R08: 0000000002000007 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00007f82b237142c
R13: 00007f82b233f004 R14: 0100000000000000 R15: 0000000000022000
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:pipe_buf_release include/linux/pipe_fs_i.h:203 [inline]
RIP: 0010:splice_to_socket+0xa91/0xe30 fs/splice.c:933
Code: 10 48 89 f8 48 c1 e8 03 42 80 3c 28 00 0f 85 19 03 00 00 49 8b 46 10 49 c7 46 10 00 00 00 00 48 8d 78 08 48 89 fa 48 c1 ea 03 <42> 80 3c 2a 00 0f 85 e3 02 00 00 4c 89 f6 4c 89 e7 ff 50 08 83 44
RSP: 0018:ffffc90003adfa28 EFLAGS: 00010202
RAX: 0000000000000000 RBX: 0000000000008001 RCX: 0000000000000000
RDX: 0000000000000001 RSI: ffffffff81f4e014 RDI: 0000000000000008
RBP: 0000000000000000 R08: 0000000000000005 R09: 0000000000000000
R10: 0000000000000000 R11: 1ffffffff2186c9b R12: ffff88802819f000
R13: dffffc0000000000 R14: ffff888077c05028 R15: 0000000000008001
FS: 00007f82b229b700(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fa5f3ff2304 CR3: 0000000075e14000 CR4: 00000000003506f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
----------------
Code disassembly (best guess):
0: 10 48 89 adc %cl,-0x77(%rax)
3: f8 clc
4: 48 c1 e8 03 shr $0x3,%rax
8: 42 80 3c 28 00 cmpb $0x0,(%rax,%r13,1)
d: 0f 85 19 03 00 00 jne 0x32c
13: 49 8b 46 10 mov 0x10(%r14),%rax
17: 49 c7 46 10 00 00 00 movq $0x0,0x10(%r14)
1e: 00
1f: 48 8d 78 08 lea 0x8(%rax),%rdi
23: 48 89 fa mov %rdi,%rdx
26: 48 c1 ea 03 shr $0x3,%rdx
* 2a: 42 80 3c 2a 00 cmpb $0x0,(%rdx,%r13,1) <-- trapping instruction
2f: 0f 85 e3 02 00 00 jne 0x318
35: 4c 89 f6 mov %r14,%rsi
38: 4c 89 e7 mov %r12,%rdi
3b: ff 50 08 callq *0x8(%rax)
3e: 83 .byte 0x83
3f: 44 rex.R
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at [email protected].
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
For information about bisection process see: https://goo.gl/tpsmEJ#bisection
If the bug is already fixed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
If you want to change bug's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the bug is a duplicate of another bug, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
Here's a much reduced test program. The key is to splice more than a page
from the pipe into the second socket (AF_ALG in this case) and more than that
into the pipe.
David
---
// https://syzkaller.appspot.com/bug?id=613f5060400df25674e1b213295ef45a8422b077
// autogenerated by syzkaller (https://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <endian.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <linux/if_alg.h>
#define OSERROR(R, S) do { if ((long)(R) == -1L) { perror((S)); exit(1); } } while(0)
static const unsigned char data[1024 * 1024] = {
"\x44\xf9\xb1\x08\xb1\xcd\xc8\x85\xc9\xc5\x33\xd2\x1f\x47\x4b\xec\x8b"
"\xfe\xf1\xdf\x1e\x2d\xa7\x1e\x57\x8d\xc6\xb9\x1d\x09\xf7\xab\x15\x37"
"\x85\x71\xd8\xe2\x75\x46\x09\x00\x00\x00\x6e\x75\x43\x69\x14\xab\x71"
"\x75\x28\xee\x4b\x7a\x9b\xea\xf9\x08\xd1\x11\x37\xc1\x19\x03\x06\x4e"
"\x83\xb4\x95\x1f\x4d\x43\x3a\x54\x04\x97\x0c\x85\xd9\x2d\x70\x83\xfd"
"\x38\x84\x4c\xbb\x0c\x6c\x5e\xb5\x08\xdd\xc2\xdc\x7a\x59\x0a\xa7\x94"
"\x1b\x1e\x9e\xeb\x5a\x68\x81\x38\xde\xa0\x9b\x77\x6c\xbf\xa7\x84\xcb"
"\xf5\x50\xbf\x30\x74\xfb\x0d\x77\x5d\xa4\xdf\x5a\x3f\x48\xbb\xdf\x45"
"\x2e\xeb\x6b\x92\x3d\xa9\xd0\xe2\x5b\x80\xf7\x6a\x87\x36\x64\xb5\x75"
"\x34\x44\xfe\x05\xf3\x3e\x5f\x91\x04\x55\x40\x83\x6c\x3c\xd6\xaf\x10"
"\xf0\xcd\x01\x8f\x0c\x6f\x57\xf9\x26\xac\x95\x9a\x56\x28\xc4\x50\x88"
"\xfb\xe0\xc8\x7f\xbe\x6c\xbc\xda\x46\x62\xd2\xa1\x2f\x6d\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
};
int main(int argc, char *argv[])
{
struct sockaddr_in6 sin6;
struct sockaddr_alg salg;
int pipefd[2], ipv6fd, algfd, hashfd, res, wt;
res = pipe(pipefd);
OSERROR(res, "pipe");
ipv6fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
OSERROR(ipv6fd, "socket/inet6");
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(2);
res = bind(ipv6fd, (struct sockaddr *)&sin6, sizeof(sin6));
OSERROR(res, "bind/inet6");
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(2);
sin6.sin6_addr.s6_addr[15] = 1;
res = sendto(ipv6fd, NULL, 0, MSG_OOB|MSG_NOSIGNAL|MSG_FASTOPEN|0x2000000,
(struct sockaddr *)&sin6, sizeof(sin6));
OSERROR(res, "sendto_1");
res = send(ipv6fd, data, 0xd0d0c2ac /* massive overrun */, MSG_OOB);
OSERROR(res, "sendto_2");
algfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
OSERROR(algfd, "socket/alg");
memset(&salg, 0, sizeof(salg));
salg.salg_family = AF_ALG;
strcpy(salg.salg_type, "hash");
strcpy(salg.salg_name, "sha3-512");
res = bind(algfd, (struct sockaddr *)&salg, sizeof(salg));
OSERROR(res, "bind/alg");
hashfd = accept4(algfd, NULL, 0, 0);
OSERROR(hashfd, "accept/alg");
switch (fork()) {
case -1:
OSERROR(-1, "fork");
case 0:
res = splice(pipefd[0], 0, hashfd, 0, 65536, 0);
OSERROR(res, "splice/p->h");
return 0;
default:
sleep(1);
break;
}
res = splice(ipv6fd, 0, pipefd[1], 0, 32767, 0);
OSERROR(res, "splice/i->p");
wait(&wt);
return 0;
}
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git main
commit d302bc9baf84c549891bedee57ee917d9e0485d7
Author: David Howells <[email protected]>
Date: Wed Jun 14 09:14:50 2023 +0100
splice: Fix splice_to_socket() to handle pipe bufs larger than a page
splice_to_socket() assumes that a pipe_buffer won't hold more than a single
page of data - but it seems that this assumption can be violated when
splicing from a socket into a pipe.
The problem is that splice_to_socket() doesn't advance the pipe_buffer
length and offset when transcribing from the pipe buf into a bio_vec, so if
the buf is >PAGE_SIZE, it keeps repeating the same initial chunk and
doesn't advance the tail index. It then subtracts this from "remain" and
overcounts the amount of data to be sent.
The cleanup phase then tries to overclean the pipe, hits an unused pipe buf
and a NULL-pointer dereference occurs.
Fix this by not restricting the bio_vec size to PAGE_SIZE and instead
transcribing the entirety of each pipe_buffer into a single bio_vec and
advancing the tail index if remain hasn't hit zero yet.
Large bio_vecs will then be split up iterator functions such as
iov_iter_extract_pages().
This resulted in a KASAN report looking like:
general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] PREEMPT SMP KASAN
KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f]
...
RIP: 0010:pipe_buf_release include/linux/pipe_fs_i.h:203 [inline]
RIP: 0010:splice_to_socket+0xa91/0xe30 fs/splice.c:933
Reported-by: [email protected]
Fixes: 2dc334f1a63a ("splice, net: Use sendmsg(MSG_SPLICE_PAGES) rather than ->sendpage()")
Signed-off-by: David Howells <[email protected]>
cc: Willem de Bruijn <[email protected]>
cc: David Ahern <[email protected]>
cc: "David S. Miller" <[email protected]>
cc: Eric Dumazet <[email protected]>
cc: Jakub Kicinski <[email protected]>
cc: Paolo Abeni <[email protected]>
cc: Jens Axboe <[email protected]>
cc: Matthew Wilcox <[email protected]>
cc: Christian Brauner <[email protected]>
cc: Alexander Viro <[email protected]>
cc: [email protected]
cc: [email protected]
diff --git a/fs/splice.c b/fs/splice.c
index e337630aed64..567a1f03ea1e 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -886,7 +886,6 @@ ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out,
}
seg = min_t(size_t, remain, buf->len);
- seg = min_t(size_t, seg, PAGE_SIZE);
ret = pipe_buf_confirm(pipe, buf);
if (unlikely(ret)) {
@@ -897,10 +896,9 @@ ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out,
bvec_set_page(&bvec[bc++], buf->page, seg, buf->offset);
remain -= seg;
- if (seg >= buf->len)
- tail++;
- if (bc >= ARRAY_SIZE(bvec))
+ if (remain == 0 || bc >= ARRAY_SIZE(bvec))
break;
+ tail++;
}
if (!bc)
Hello,
syzbot has tested the proposed patch and the reproducer did not trigger any issue:
Reported-and-tested-by: [email protected]
Tested on:
commit: 2bddad9e ethtool: ioctl: account for sopass diff in se..
git tree: git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git main
console output: https://syzkaller.appspot.com/x/log.txt?x=12d9c93b280000
kernel config: https://syzkaller.appspot.com/x/.config?x=526f919910d4a671
dashboard link: https://syzkaller.appspot.com/bug?extid=f9e28a23426ac3b24f20
compiler: gcc (Debian 10.2.1-6) 10.2.1 20210110, GNU ld (GNU Binutils for Debian) 2.35.2
patch: https://syzkaller.appspot.com/x/patch.diff?x=12c4f0d9280000
Note: testing is done by a robot and is best-effort only.