| From 86cb2d2c01ee7b0032f9c7f2957947c13bbad975 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 15 Apr 2022 11:14:42 -0700 |
| Subject: netlink: reset network and mac headers in netlink_dump() |
| |
| From: Eric Dumazet <edumazet@google.com> |
| |
| [ Upstream commit 99c07327ae11e24886d552dddbe4537bfca2765d ] |
| |
| netlink_dump() is allocating an skb, reserves space in it |
| but forgets to reset network header. |
| |
| This allows a BPF program, invoked later from sk_filter() |
| to access uninitialized kernel memory from the reserved |
| space. |
| |
| Theorically mac header reset could be omitted, because |
| it is set to a special initial value. |
| bpf_internal_load_pointer_neg_helper calls skb_mac_header() |
| without checking skb_mac_header_was_set(). |
| Relying on skb->len not being too big seems fragile. |
| We also could add a sanity check in bpf_internal_load_pointer_neg_helper() |
| to avoid surprises in the future. |
| |
| syzbot report was: |
| |
| BUG: KMSAN: uninit-value in ___bpf_prog_run+0xa22b/0xb420 kernel/bpf/core.c:1637 |
| ___bpf_prog_run+0xa22b/0xb420 kernel/bpf/core.c:1637 |
| __bpf_prog_run32+0x121/0x180 kernel/bpf/core.c:1796 |
| bpf_dispatcher_nop_func include/linux/bpf.h:784 [inline] |
| __bpf_prog_run include/linux/filter.h:626 [inline] |
| bpf_prog_run include/linux/filter.h:633 [inline] |
| __bpf_prog_run_save_cb+0x168/0x580 include/linux/filter.h:756 |
| bpf_prog_run_save_cb include/linux/filter.h:770 [inline] |
| sk_filter_trim_cap+0x3bc/0x8c0 net/core/filter.c:150 |
| sk_filter include/linux/filter.h:905 [inline] |
| netlink_dump+0xe0c/0x16c0 net/netlink/af_netlink.c:2276 |
| netlink_recvmsg+0x1129/0x1c80 net/netlink/af_netlink.c:2002 |
| sock_recvmsg_nosec net/socket.c:948 [inline] |
| sock_recvmsg net/socket.c:966 [inline] |
| sock_read_iter+0x5a9/0x630 net/socket.c:1039 |
| do_iter_readv_writev+0xa7f/0xc70 |
| do_iter_read+0x52c/0x14c0 fs/read_write.c:786 |
| vfs_readv fs/read_write.c:906 [inline] |
| do_readv+0x432/0x800 fs/read_write.c:943 |
| __do_sys_readv fs/read_write.c:1034 [inline] |
| __se_sys_readv fs/read_write.c:1031 [inline] |
| __x64_sys_readv+0xe5/0x120 fs/read_write.c:1031 |
| do_syscall_x64 arch/x86/entry/common.c:51 [inline] |
| do_syscall_64+0x54/0xd0 arch/x86/entry/common.c:81 |
| entry_SYSCALL_64_after_hwframe+0x44/0xae |
| |
| Uninit was stored to memory at: |
| ___bpf_prog_run+0x96c/0xb420 kernel/bpf/core.c:1558 |
| __bpf_prog_run32+0x121/0x180 kernel/bpf/core.c:1796 |
| bpf_dispatcher_nop_func include/linux/bpf.h:784 [inline] |
| __bpf_prog_run include/linux/filter.h:626 [inline] |
| bpf_prog_run include/linux/filter.h:633 [inline] |
| __bpf_prog_run_save_cb+0x168/0x580 include/linux/filter.h:756 |
| bpf_prog_run_save_cb include/linux/filter.h:770 [inline] |
| sk_filter_trim_cap+0x3bc/0x8c0 net/core/filter.c:150 |
| sk_filter include/linux/filter.h:905 [inline] |
| netlink_dump+0xe0c/0x16c0 net/netlink/af_netlink.c:2276 |
| netlink_recvmsg+0x1129/0x1c80 net/netlink/af_netlink.c:2002 |
| sock_recvmsg_nosec net/socket.c:948 [inline] |
| sock_recvmsg net/socket.c:966 [inline] |
| sock_read_iter+0x5a9/0x630 net/socket.c:1039 |
| do_iter_readv_writev+0xa7f/0xc70 |
| do_iter_read+0x52c/0x14c0 fs/read_write.c:786 |
| vfs_readv fs/read_write.c:906 [inline] |
| do_readv+0x432/0x800 fs/read_write.c:943 |
| __do_sys_readv fs/read_write.c:1034 [inline] |
| __se_sys_readv fs/read_write.c:1031 [inline] |
| __x64_sys_readv+0xe5/0x120 fs/read_write.c:1031 |
| do_syscall_x64 arch/x86/entry/common.c:51 [inline] |
| do_syscall_64+0x54/0xd0 arch/x86/entry/common.c:81 |
| entry_SYSCALL_64_after_hwframe+0x44/0xae |
| |
| Uninit was created at: |
| slab_post_alloc_hook mm/slab.h:737 [inline] |
| slab_alloc_node mm/slub.c:3244 [inline] |
| __kmalloc_node_track_caller+0xde3/0x14f0 mm/slub.c:4972 |
| kmalloc_reserve net/core/skbuff.c:354 [inline] |
| __alloc_skb+0x545/0xf90 net/core/skbuff.c:426 |
| alloc_skb include/linux/skbuff.h:1158 [inline] |
| netlink_dump+0x30f/0x16c0 net/netlink/af_netlink.c:2242 |
| netlink_recvmsg+0x1129/0x1c80 net/netlink/af_netlink.c:2002 |
| sock_recvmsg_nosec net/socket.c:948 [inline] |
| sock_recvmsg net/socket.c:966 [inline] |
| sock_read_iter+0x5a9/0x630 net/socket.c:1039 |
| do_iter_readv_writev+0xa7f/0xc70 |
| do_iter_read+0x52c/0x14c0 fs/read_write.c:786 |
| vfs_readv fs/read_write.c:906 [inline] |
| do_readv+0x432/0x800 fs/read_write.c:943 |
| __do_sys_readv fs/read_write.c:1034 [inline] |
| __se_sys_readv fs/read_write.c:1031 [inline] |
| __x64_sys_readv+0xe5/0x120 fs/read_write.c:1031 |
| do_syscall_x64 arch/x86/entry/common.c:51 [inline] |
| do_syscall_64+0x54/0xd0 arch/x86/entry/common.c:81 |
| entry_SYSCALL_64_after_hwframe+0x44/0xae |
| |
| CPU: 0 PID: 3470 Comm: syz-executor751 Not tainted 5.17.0-syzkaller #0 |
| Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 |
| |
| Fixes: db65a3aaf29e ("netlink: Trim skb to alloc size to avoid MSG_TRUNC") |
| Fixes: 9063e21fb026 ("netlink: autosize skb lengthes") |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Reported-by: syzbot <syzkaller@googlegroups.com> |
| Link: https://lore.kernel.org/r/20220415181442.551228-1-eric.dumazet@gmail.com |
| Signed-off-by: Paolo Abeni <pabeni@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/netlink/af_netlink.c | 7 +++++++ |
| 1 file changed, 7 insertions(+) |
| |
| diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c |
| index fb28969899af..8aefc52542a0 100644 |
| --- a/net/netlink/af_netlink.c |
| +++ b/net/netlink/af_netlink.c |
| @@ -2253,6 +2253,13 @@ static int netlink_dump(struct sock *sk) |
| * single netdev. The outcome is MSG_TRUNC error. |
| */ |
| skb_reserve(skb, skb_tailroom(skb) - alloc_size); |
| + |
| + /* Make sure malicious BPF programs can not read unitialized memory |
| + * from skb->head -> skb->data |
| + */ |
| + skb_reset_network_header(skb); |
| + skb_reset_mac_header(skb); |
| + |
| netlink_skb_set_owner_r(skb, sk); |
| |
| if (nlk->dump_done_errno > 0) { |
| -- |
| 2.35.1 |
| |