* BUG: net/ipv6: kernel memory leak in ip6_datagram_recv_specific_ctl
@ 2016-10-12 11:09 Baozeng Ding
2016-10-12 15:05 ` Eric Dumazet
2016-10-12 17:01 ` [PATCH net] ipv6: tcp: restore IP6CB for pktoptions skbs Eric Dumazet
0 siblings, 2 replies; 3+ messages in thread
From: Baozeng Ding @ 2016-10-12 11:09 UTC (permalink / raw)
To: netdev
Hi all,
The following program triggers use-after-free in ip6_datagram_recv_specific_ctl, which may leak kernel memory. The
kernel version is 4.8.0+ (on Oct 7 commit d1f5323370fceaed43a7ee38f4c7bfc7e70f28d0).
==========================================================
BUG: KASAN: use-after-free in ip6_datagram_recv_specific_ctl+0x13f1/0x15c0 at addr ffff880029c84ec8
Read of size 1 by task poc/25548
Call Trace:
[<ffffffff82cf43c9>] dump_stack+0x12e/0x185 /lib/dump_stack.c:15
[< inline >] print_address_description /mm/kasan/report.c:204
[<ffffffff817ced3b>] kasan_report_error+0x48b/0x4b0 /mm/kasan/report.c:283
[< inline >] kasan_report /mm/kasan/report.c:303
[<ffffffff817ced9e>] __asan_report_load1_noabort+0x3e/0x40 /mm/kasan/report.c:321
[<ffffffff85c71da1>] ip6_datagram_recv_specific_ctl+0x13f1/0x15c0 /net/ipv6/datagram.c:687
[<ffffffff85c734c3>] ip6_datagram_recv_ctl+0x33/0x40
[<ffffffff85c0b07c>] do_ipv6_getsockopt.isra.4+0xaec/0x2150
[<ffffffff85c0c7f6>] ipv6_getsockopt+0x116/0x230
[<ffffffff859b5a12>] tcp_getsockopt+0x82/0xd0 /net/ipv4/tcp.c:3035
[<ffffffff855fb385>] sock_common_getsockopt+0x95/0xd0 /net/core/sock.c:2647
[< inline >] SYSC_getsockopt /net/socket.c:1776
[<ffffffff855f8ba2>] SyS_getsockopt+0x142/0x230 /net/socket.c:1758
[<ffffffff8685cdc5>] entry_SYSCALL_64_fastpath+0x23/0xc6
Memory state around the buggy address:
ffff880029c84d80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff880029c84e00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> ffff880029c84e80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
^
ffff880029c84f00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff880029c84f80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
==========================================================
#include <unistd.h>
#include <stdint.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <errno.h>
#define IPV6_2292DSTOPTS 4
#define IPV6_2292PKTOPTIONS 6
#define IPV6_FLOWINFO 11
int main()
{
int fd;
int i, r;
int opt = 1, len = 0;
struct msghdr msg;
struct sockaddr_in6 addr;
int sub_addr[4];
struct iovec iov;
memset(sub_addr, 0, sizeof(sub_addr));
sub_addr[3] = 0x1000000;
memcpy(&addr.sin6_addr, sub_addr, sizeof(sub_addr));
addr.sin6_family = AF_INET6;
addr.sin6_port = 0x10ab;
addr.sin6_flowinfo = 0x1;
addr.sin6_scope_id = 0;
mmap(0x20000000ul, 0x1c000ul, 0x3ul, 0x32ul, -1, 0x0ul, 0, 0, 0);
memset(0x20000000, 'a', 0x1c000);
fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
bind(fd, &addr, sizeof(addr));
setsockopt(fd, IPPROTO_IPV6, IPV6_2292DSTOPTS, &opt, 4);
setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO, &opt, 4);
addr.sin6_flowinfo = 0;
addr.sin6_scope_id = 0;
msg.msg_name = &addr;
msg.msg_namelen = sizeof(addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_iov->iov_base = 0x20000000;
msg.msg_iov->iov_len = 0x100;
msg.msg_control = 0x20000000;
msg.msg_controllen = 0x100;
msg.msg_flags = 0;
r = sendmsg(fd, &msg, MSG_FASTOPEN);
if (r < 0) {
printf("sendmsg errno=%d\n", r);
}
r = getsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, 0x20012000ul, &len);
if (r < 0) printf("getsockopt error\n");
return 0;
}
The following lines case out-of-bounds read, which may leak kernel memory by put_cmsg.
686 u8 *ptr = nh + opt->dst0; // Out-of-bouds when opt->dst0 is large.
687 put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
I debuged using printk and got some values of opt as the following, which may help locate the root cause of the bug. Thanks.
[85564.842733] degug: opt->iif is 0xe111121c
[85564.842737] degug: opt->ra is 0x121c
[85564.842741] degug: opt->dst0 is 0xe111
Best Regards,
Baozeng Ding
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: BUG: net/ipv6: kernel memory leak in ip6_datagram_recv_specific_ctl
2016-10-12 11:09 BUG: net/ipv6: kernel memory leak in ip6_datagram_recv_specific_ctl Baozeng Ding
@ 2016-10-12 15:05 ` Eric Dumazet
2016-10-12 17:01 ` [PATCH net] ipv6: tcp: restore IP6CB for pktoptions skbs Eric Dumazet
1 sibling, 0 replies; 3+ messages in thread
From: Eric Dumazet @ 2016-10-12 15:05 UTC (permalink / raw)
To: Baozeng Ding; +Cc: netdev
On Wed, 2016-10-12 at 19:09 +0800, Baozeng Ding wrote:
> Hi all,
> The following program triggers use-after-free in ip6_datagram_recv_specific_ctl, which may leak kernel memory. The
> kernel version is 4.8.0+ (on Oct 7 commit d1f5323370fceaed43a7ee38f4c7bfc7e70f28d0).
> ==========================================================
> BUG: KASAN: use-after-free in ip6_datagram_recv_specific_ctl+0x13f1/0x15c0 at addr ffff880029c84ec8
> Read of size 1 by task poc/25548
> Call Trace:
> [<ffffffff82cf43c9>] dump_stack+0x12e/0x185 /lib/dump_stack.c:15
> [< inline >] print_address_description /mm/kasan/report.c:204
> [<ffffffff817ced3b>] kasan_report_error+0x48b/0x4b0 /mm/kasan/report.c:283
> [< inline >] kasan_report /mm/kasan/report.c:303
> [<ffffffff817ced9e>] __asan_report_load1_noabort+0x3e/0x40 /mm/kasan/report.c:321
> [<ffffffff85c71da1>] ip6_datagram_recv_specific_ctl+0x13f1/0x15c0 /net/ipv6/datagram.c:687
> [<ffffffff85c734c3>] ip6_datagram_recv_ctl+0x33/0x40
> [<ffffffff85c0b07c>] do_ipv6_getsockopt.isra.4+0xaec/0x2150
> [<ffffffff85c0c7f6>] ipv6_getsockopt+0x116/0x230
> [<ffffffff859b5a12>] tcp_getsockopt+0x82/0xd0 /net/ipv4/tcp.c:3035
> [<ffffffff855fb385>] sock_common_getsockopt+0x95/0xd0 /net/core/sock.c:2647
> [< inline >] SYSC_getsockopt /net/socket.c:1776
> [<ffffffff855f8ba2>] SyS_getsockopt+0x142/0x230 /net/socket.c:1758
> [<ffffffff8685cdc5>] entry_SYSCALL_64_fastpath+0x23/0xc6
> Memory state around the buggy address:
> ffff880029c84d80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> ffff880029c84e00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> > ffff880029c84e80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> ^
> ffff880029c84f00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> ffff880029c84f80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>
>
> ==========================================================
> #include <unistd.h>
> #include <stdint.h>
> #include <sys/socket.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <sys/syscall.h>
> #include <linux/in.h>
> #include <linux/in6.h>
> #include <errno.h>
>
> #define IPV6_2292DSTOPTS 4
> #define IPV6_2292PKTOPTIONS 6
> #define IPV6_FLOWINFO 11
>
>
> int main()
> {
> int fd;
> int i, r;
> int opt = 1, len = 0;
> struct msghdr msg;
> struct sockaddr_in6 addr;
> int sub_addr[4];
> struct iovec iov;
> memset(sub_addr, 0, sizeof(sub_addr));
> sub_addr[3] = 0x1000000;
> memcpy(&addr.sin6_addr, sub_addr, sizeof(sub_addr));
> addr.sin6_family = AF_INET6;
> addr.sin6_port = 0x10ab;
> addr.sin6_flowinfo = 0x1;
> addr.sin6_scope_id = 0;
>
> mmap(0x20000000ul, 0x1c000ul, 0x3ul, 0x32ul, -1, 0x0ul, 0, 0, 0);
> memset(0x20000000, 'a', 0x1c000);
> fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
> bind(fd, &addr, sizeof(addr));
>
> setsockopt(fd, IPPROTO_IPV6, IPV6_2292DSTOPTS, &opt, 4);
> setsockopt(fd, IPPROTO_IPV6, IPV6_FLOWINFO, &opt, 4);
>
> addr.sin6_flowinfo = 0;
> addr.sin6_scope_id = 0;
> msg.msg_name = &addr;
> msg.msg_namelen = sizeof(addr);
> msg.msg_iov = &iov;
> msg.msg_iovlen = 1;
> msg.msg_iov->iov_base = 0x20000000;
> msg.msg_iov->iov_len = 0x100;
> msg.msg_control = 0x20000000;
> msg.msg_controllen = 0x100;
> msg.msg_flags = 0;
> r = sendmsg(fd, &msg, MSG_FASTOPEN);
> if (r < 0) {
> printf("sendmsg errno=%d\n", r);
> }
>
> r = getsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, 0x20012000ul, &len);
> if (r < 0) printf("getsockopt error\n");
> return 0;
> }
>
> The following lines case out-of-bounds read, which may leak kernel memory by put_cmsg.
> 686 u8 *ptr = nh + opt->dst0; // Out-of-bouds when opt->dst0 is large.
> 687 put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);
>
> I debuged using printk and got some values of opt as the following, which may help locate the root cause of the bug. Thanks.
>
> [85564.842733] degug: opt->iif is 0xe111121c
> [85564.842737] degug: opt->ra is 0x121c
> [85564.842741] degug: opt->dst0 is 0xe111
>
> Best Regards,
> Baozeng Ding
Thanks for the report.
I am testing a patch to fix this issue.
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH net] ipv6: tcp: restore IP6CB for pktoptions skbs
2016-10-12 11:09 BUG: net/ipv6: kernel memory leak in ip6_datagram_recv_specific_ctl Baozeng Ding
2016-10-12 15:05 ` Eric Dumazet
@ 2016-10-12 17:01 ` Eric Dumazet
1 sibling, 0 replies; 3+ messages in thread
From: Eric Dumazet @ 2016-10-12 17:01 UTC (permalink / raw)
To: Baozeng Ding, David Miller; +Cc: netdev
From: Eric Dumazet <edumazet@google.com>
Baozeng Ding reported following KASAN splat :
BUG: KASAN: use-after-free in ip6_datagram_recv_specific_ctl+0x13f1/0x15c0 at addr ffff880029c84ec8
Read of size 1 by task poc/25548
Call Trace:
[<ffffffff82cf43c9>] dump_stack+0x12e/0x185 /lib/dump_stack.c:15
[< inline >] print_address_description /mm/kasan/report.c:204
[<ffffffff817ced3b>] kasan_report_error+0x48b/0x4b0 /mm/kasan/report.c:283
[< inline >] kasan_report /mm/kasan/report.c:303
[<ffffffff817ced9e>] __asan_report_load1_noabort+0x3e/0x40 /mm/kasan/report.c:321
[<ffffffff85c71da1>] ip6_datagram_recv_specific_ctl+0x13f1/0x15c0 /net/ipv6/datagram.c:687
[<ffffffff85c734c3>] ip6_datagram_recv_ctl+0x33/0x40
[<ffffffff85c0b07c>] do_ipv6_getsockopt.isra.4+0xaec/0x2150
[<ffffffff85c0c7f6>] ipv6_getsockopt+0x116/0x230
[<ffffffff859b5a12>] tcp_getsockopt+0x82/0xd0 /net/ipv4/tcp.c:3035
[<ffffffff855fb385>] sock_common_getsockopt+0x95/0xd0 /net/core/sock.c:2647
[< inline >] SYSC_getsockopt /net/socket.c:1776
[<ffffffff855f8ba2>] SyS_getsockopt+0x142/0x230 /net/socket.c:1758
[<ffffffff8685cdc5>] entry_SYSCALL_64_fastpath+0x23/0xc6
Memory state around the buggy address:
ffff880029c84d80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff880029c84e00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
> ffff880029c84e80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
^
ffff880029c84f00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff880029c84f80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
He also provided a syzkaller reproducer.
Issue is that ip6_datagram_recv_specific_ctl() expects to find IP6CB
data that was moved at a different place in tcp_v6_rcv()
This patch moves tcp_v6_restore_cb() up and calls it from
tcp_v6_do_rcv() when np->pktoptions is set.
Fixes: 971f10eca186 ("tcp: better TCP_SKB_CB layout to reduce cache line misses")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Baozeng Ding <sploving1@gmail.com>
---
net/ipv6/tcp_ipv6.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 54cf7197c7ab..5a27ab4eab39 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1190,6 +1190,16 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
return NULL;
}
+static void tcp_v6_restore_cb(struct sk_buff *skb)
+{
+ /* We need to move header back to the beginning if xfrm6_policy_check()
+ * and tcp_v6_fill_cb() are going to be called again.
+ * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
+ */
+ memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
+ sizeof(struct inet6_skb_parm));
+}
+
/* The socket must have it's spinlock held when we get
* here, unless it is a TCP_LISTEN socket.
*
@@ -1319,6 +1329,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
if (ipv6_opt_accepted(sk, opt_skb, &TCP_SKB_CB(opt_skb)->header.h6)) {
skb_set_owner_r(opt_skb, sk);
+ tcp_v6_restore_cb(opt_skb);
opt_skb = xchg(&np->pktoptions, opt_skb);
} else {
__kfree_skb(opt_skb);
@@ -1352,15 +1363,6 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr,
TCP_SKB_CB(skb)->sacked = 0;
}
-static void tcp_v6_restore_cb(struct sk_buff *skb)
-{
- /* We need to move header back to the beginning if xfrm6_policy_check()
- * and tcp_v6_fill_cb() are going to be called again.
- */
- memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
- sizeof(struct inet6_skb_parm));
-}
-
static int tcp_v6_rcv(struct sk_buff *skb)
{
const struct tcphdr *th;
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2016-10-12 17:15 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-10-12 11:09 BUG: net/ipv6: kernel memory leak in ip6_datagram_recv_specific_ctl Baozeng Ding
2016-10-12 15:05 ` Eric Dumazet
2016-10-12 17:01 ` [PATCH net] ipv6: tcp: restore IP6CB for pktoptions skbs Eric Dumazet
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox