netfilter: nf_socket: Fix out of bounds access in nf_sk_lookup_slow_v{4,6}
authorSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Fri, 23 Mar 2018 03:12:39 +0000 (21:12 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 22 May 2018 16:53:58 +0000 (18:53 +0200)
commit 32c1733f0dd4bd11d6e65512bf4dc337c0452c8e upstream.

skb_header_pointer will copy data into a buffer if data is non linear,
otherwise it will return a pointer in the linear section of the data.
nf_sk_lookup_slow_v{4,6} always copies data of size udphdr but later
accesses memory within the size of tcphdr (th->doff) in case of TCP
packets. This causes a crash when running with KASAN with the following
call stack -

BUG: KASAN: stack-out-of-bounds in xt_socket_lookup_slow_v4+0x524/0x718
net/netfilter/xt_socket.c:178
Read of size 2 at addr ffffffe3d417a87c by task syz-executor/28971
CPU: 2 PID: 28971 Comm: syz-executor Tainted: G    B   W  O    4.9.65+ #1
Call trace:
[<ffffff9467e8d390>] dump_backtrace+0x0/0x428 arch/arm64/kernel/traps.c:76
[<ffffff9467e8d7e0>] show_stack+0x28/0x38 arch/arm64/kernel/traps.c:226
[<ffffff946842d9b8>] __dump_stack lib/dump_stack.c:15 [inline]
[<ffffff946842d9b8>] dump_stack+0xd4/0x124 lib/dump_stack.c:51
[<ffffff946811d4b0>] print_address_description+0x68/0x258 mm/kasan/report.c:248
[<ffffff946811d8c8>] kasan_report_error mm/kasan/report.c:347 [inline]
[<ffffff946811d8c8>] kasan_report.part.2+0x228/0x2f0 mm/kasan/report.c:371
[<ffffff946811df44>] kasan_report+0x5c/0x70 mm/kasan/report.c:372
[<ffffff946811bebc>] check_memory_region_inline mm/kasan/kasan.c:308 [inline]
[<ffffff946811bebc>] __asan_load2+0x84/0x98 mm/kasan/kasan.c:739
[<ffffff94694d6f04>] __tcp_hdrlen include/linux/tcp.h:35 [inline]
[<ffffff94694d6f04>] xt_socket_lookup_slow_v4+0x524/0x718 net/netfilter/xt_socket.c:178

Fix this by copying data into appropriate size headers based on protocol.

Fixes: a583636a83ea ("inet: refactor inet[6]_lookup functions to take skb")
Signed-off-by: Tejaswi Tanikella <tejaswit@codeaurora.org>
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/ipv4/netfilter/nf_socket_ipv4.c
net/ipv6/netfilter/nf_socket_ipv6.c

index e9293bdebba04f5b329cd4fd4a6b5b676ade5988..4824b1e183a1dc61f5438bb1b56d6a465ca8bf00 100644 (file)
@@ -108,10 +108,12 @@ struct sock *nf_sk_lookup_slow_v4(struct net *net, const struct sk_buff *skb,
        int doff = 0;
 
        if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
-               struct udphdr _hdr, *hp;
+               struct tcphdr _hdr;
+               struct udphdr *hp;
 
                hp = skb_header_pointer(skb, ip_hdrlen(skb),
-                                       sizeof(_hdr), &_hdr);
+                                       iph->protocol == IPPROTO_UDP ?
+                                       sizeof(*hp) : sizeof(_hdr), &_hdr);
                if (hp == NULL)
                        return NULL;
 
index ebb2bf84232acd1fac088dbc4d3151701cc52a40..f14de4b6d639df72f6bbc34630581b1b6fdddfae 100644 (file)
@@ -116,9 +116,11 @@ struct sock *nf_sk_lookup_slow_v6(struct net *net, const struct sk_buff *skb,
        }
 
        if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
-               struct udphdr _hdr, *hp;
+               struct tcphdr _hdr;
+               struct udphdr *hp;
 
-               hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
+               hp = skb_header_pointer(skb, thoff, tproto == IPPROTO_UDP ?
+                                       sizeof(*hp) : sizeof(_hdr), &_hdr);
                if (hp == NULL)
                        return NULL;