* [PATCH net 0/2] Fix slab out-of-bounds on insufficient headroom for IPv6 packets
@ 2018-12-05 0:13 Stefano Brivio
2018-12-05 0:13 ` [PATCH net 1/2] ipv6: Check available headroom in ip6_xmit() even without options Stefano Brivio
2018-12-05 0:13 ` [PATCH net 2/2] neighbour: BUG_ON() writing before skb->head in neigh_hh_output() Stefano Brivio
0 siblings, 2 replies; 4+ messages in thread
From: Stefano Brivio @ 2018-12-05 0:13 UTC (permalink / raw)
To: David S. Miller
Cc: Jianlin Shi, Hangbin Liu, Eric Dumazet, Stephen Hemminger, netdev
Patch 1/2 fixes a slab out-of-bounds occurring with short SCTP packets over
IPv4 over L2TP over IPv6 on a configuration with relatively low HEADER_MAX.
Patch 2/2 makes sure we panic in neigh_hh_output() instead of silently
writing before the allocated buffer in case the headroom is enough for the
unaligned hardware header size, but not enough for the aligned one.
Stefano Brivio (2):
ipv6: Check available headroom in ip6_xmit() even without options
neighbour: BUG_ON() writing before skb->head in neigh_hh_output()
include/net/neighbour.h | 8 ++++++--
net/ipv6/ip6_output.c | 42 ++++++++++++++++++++---------------------
2 files changed, 27 insertions(+), 23 deletions(-)
--
2.19.2
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH net 1/2] ipv6: Check available headroom in ip6_xmit() even without options
2018-12-05 0:13 [PATCH net 0/2] Fix slab out-of-bounds on insufficient headroom for IPv6 packets Stefano Brivio
@ 2018-12-05 0:13 ` Stefano Brivio
2018-12-05 0:13 ` [PATCH net 2/2] neighbour: BUG_ON() writing before skb->head in neigh_hh_output() Stefano Brivio
1 sibling, 0 replies; 4+ messages in thread
From: Stefano Brivio @ 2018-12-05 0:13 UTC (permalink / raw)
To: David S. Miller
Cc: Jianlin Shi, Hangbin Liu, Eric Dumazet, Stephen Hemminger, netdev
Even if we send an IPv6 packet without options, MAX_HEADER might not be
enough to account for the additional headroom required by alignment of
hardware headers.
On a configuration without HYPERV_NET, WLAN, AX25, and with IPV6_TUNNEL,
sending short SCTP packets over IPv4 over L2TP over IPv6, we start with
100 bytes of allocated headroom in sctp_packet_transmit(), end up with 54
bytes after l2tp_xmit_skb(), and 14 bytes in ip6_finish_output2().
Those would be enough to append our 14 bytes header, but we're going to
align that to 16 bytes, and write 2 bytes out of the allocated slab in
neigh_hh_output().
KASan says:
[ 264.967848] ==================================================================
[ 264.967861] BUG: KASAN: slab-out-of-bounds in ip6_finish_output2+0x1aec/0x1c70
[ 264.967866] Write of size 16 at addr 000000006af1c7fe by task netperf/6201
[ 264.967870]
[ 264.967876] CPU: 0 PID: 6201 Comm: netperf Not tainted 4.20.0-rc4+ #1
[ 264.967881] Hardware name: IBM 2827 H43 400 (z/VM 6.4.0)
[ 264.967887] Call Trace:
[ 264.967896] ([<00000000001347d6>] show_stack+0x56/0xa0)
[ 264.967903] [<00000000017e379c>] dump_stack+0x23c/0x290
[ 264.967912] [<00000000007bc594>] print_address_description+0xf4/0x290
[ 264.967919] [<00000000007bc8fc>] kasan_report+0x13c/0x240
[ 264.967927] [<000000000162f5e4>] ip6_finish_output2+0x1aec/0x1c70
[ 264.967935] [<000000000163f890>] ip6_finish_output+0x430/0x7f0
[ 264.967943] [<000000000163fe44>] ip6_output+0x1f4/0x580
[ 264.967953] [<000000000163882a>] ip6_xmit+0xfea/0x1ce8
[ 264.967963] [<00000000017396e2>] inet6_csk_xmit+0x282/0x3f8
[ 264.968033] [<000003ff805fb0ba>] l2tp_xmit_skb+0xe02/0x13e0 [l2tp_core]
[ 264.968037] [<000003ff80631192>] l2tp_eth_dev_xmit+0xda/0x150 [l2tp_eth]
[ 264.968041] [<0000000001220020>] dev_hard_start_xmit+0x268/0x928
[ 264.968069] [<0000000001330e8e>] sch_direct_xmit+0x7ae/0x1350
[ 264.968071] [<000000000122359c>] __dev_queue_xmit+0x2b7c/0x3478
[ 264.968075] [<00000000013d2862>] ip_finish_output2+0xce2/0x11a0
[ 264.968078] [<00000000013d9b14>] ip_finish_output+0x56c/0x8c8
[ 264.968081] [<00000000013ddd1e>] ip_output+0x226/0x4c0
[ 264.968083] [<00000000013dbd6c>] __ip_queue_xmit+0x894/0x1938
[ 264.968100] [<000003ff80bc3a5c>] sctp_packet_transmit+0x29d4/0x3648 [sctp]
[ 264.968116] [<000003ff80b7bf68>] sctp_outq_flush_ctrl.constprop.5+0x8d0/0xe50 [sctp]
[ 264.968131] [<000003ff80b7c716>] sctp_outq_flush+0x22e/0x7d8 [sctp]
[ 264.968146] [<000003ff80b35c68>] sctp_cmd_interpreter.isra.16+0x530/0x6800 [sctp]
[ 264.968161] [<000003ff80b3410a>] sctp_do_sm+0x222/0x648 [sctp]
[ 264.968177] [<000003ff80bbddac>] sctp_primitive_ASSOCIATE+0xbc/0xf8 [sctp]
[ 264.968192] [<000003ff80b93328>] __sctp_connect+0x830/0xc20 [sctp]
[ 264.968208] [<000003ff80bb11ce>] sctp_inet_connect+0x2e6/0x378 [sctp]
[ 264.968212] [<0000000001197942>] __sys_connect+0x21a/0x450
[ 264.968215] [<000000000119aff8>] sys_socketcall+0x3d0/0xb08
[ 264.968218] [<000000000184ea7a>] system_call+0x2a2/0x2c0
[...]
Just like ip_finish_output2() does for IPv4, check that we have enough
headroom in ip6_xmit(), and reallocate it if we don't.
This issue is older than git history.
Reported-by: Jianlin Shin <jishi@redhat.com>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
---
net/ipv6/ip6_output.c | 42 +++++++++++++++++++++---------------------
1 file changed, 21 insertions(+), 21 deletions(-)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 827a3f5ff3bb..fcd3c66ded16 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -195,37 +195,37 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
const struct ipv6_pinfo *np = inet6_sk(sk);
struct in6_addr *first_hop = &fl6->daddr;
struct dst_entry *dst = skb_dst(skb);
+ unsigned int head_room;
struct ipv6hdr *hdr;
u8 proto = fl6->flowi6_proto;
int seg_len = skb->len;
int hlimit = -1;
u32 mtu;
- if (opt) {
- unsigned int head_room;
+ head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev);
+ if (opt)
+ head_room += opt->opt_nflen + opt->opt_flen;
- /* First: exthdrs may take lots of space (~8K for now)
- MAX_HEADER is not enough.
- */
- head_room = opt->opt_nflen + opt->opt_flen;
- seg_len += head_room;
- head_room += sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev);
-
- if (skb_headroom(skb) < head_room) {
- struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
- if (!skb2) {
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
- IPSTATS_MIB_OUTDISCARDS);
- kfree_skb(skb);
- return -ENOBUFS;
- }
- if (skb->sk)
- skb_set_owner_w(skb2, skb->sk);
- consume_skb(skb);
- skb = skb2;
+ if (unlikely(skb_headroom(skb) < head_room)) {
+ struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
+ if (!skb2) {
+ IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
+ IPSTATS_MIB_OUTDISCARDS);
+ kfree_skb(skb);
+ return -ENOBUFS;
}
+ if (skb->sk)
+ skb_set_owner_w(skb2, skb->sk);
+ consume_skb(skb);
+ skb = skb2;
+ }
+
+ if (opt) {
+ seg_len += opt->opt_nflen + opt->opt_flen;
+
if (opt->opt_flen)
ipv6_push_frag_opts(skb, opt, &proto);
+
if (opt->opt_nflen)
ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop,
&fl6->saddr);
--
2.19.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH net 2/2] neighbour: BUG_ON() writing before skb->head in neigh_hh_output()
2018-12-05 0:13 [PATCH net 0/2] Fix slab out-of-bounds on insufficient headroom for IPv6 packets Stefano Brivio
2018-12-05 0:13 ` [PATCH net 1/2] ipv6: Check available headroom in ip6_xmit() even without options Stefano Brivio
@ 2018-12-05 0:13 ` Stefano Brivio
[not found] ` <CANn89i+VoX7LNq4uGztJvH3EVzbE=Rhab=erkCOzHo3xyWBExg@mail.gmail.com>
1 sibling, 1 reply; 4+ messages in thread
From: Stefano Brivio @ 2018-12-05 0:13 UTC (permalink / raw)
To: David S. Miller
Cc: Jianlin Shi, Hangbin Liu, Eric Dumazet, Stephen Hemminger, netdev
While skb_push() makes the kernel panic if the skb headroom is less than
the unaligned hardware header size in neigh_hh_output(), it will proceed
silently in case we copy more than that because of alignment.
In the case fixed by the previous patch,
"ipv6: Check available headroom in ip6_xmit() even without options", we
end up in neigh_hh_output() with 14 bytes headroom, 14 bytes hardware
header and write 16 bytes, starting 2 bytes before the allocated buffer.
Panic, instead of silently corrupting adjacent slabs.
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
---
include/net/neighbour.h | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index f58b384aa6c9..95dcba741fd5 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -454,6 +454,7 @@ static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb)
{
+ unsigned int hh_alen = 0;
unsigned int seq;
unsigned int hh_len;
@@ -461,15 +462,18 @@ static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb
seq = read_seqbegin(&hh->hh_lock);
hh_len = hh->hh_len;
if (likely(hh_len <= HH_DATA_MOD)) {
+ hh_alen = HH_DATA_MOD;
/* this is inlined by gcc */
memcpy(skb->data - HH_DATA_MOD, hh->hh_data, HH_DATA_MOD);
} else {
- unsigned int hh_alen = HH_DATA_ALIGN(hh_len);
-
+ hh_alen = HH_DATA_ALIGN(hh_len);
memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
}
} while (read_seqretry(&hh->hh_lock, seq));
+ /* skb_push() won't panic if we have room for the unaligned size only */
+ BUG_ON(skb_headroom(skb) < hh_alen);
+
skb_push(skb, hh_len);
return dev_queue_xmit(skb);
}
--
2.19.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH net 2/2] neighbour: BUG_ON() writing before skb->head in neigh_hh_output()
[not found] ` <CANn89i+VoX7LNq4uGztJvH3EVzbE=Rhab=erkCOzHo3xyWBExg@mail.gmail.com>
@ 2018-12-05 0:38 ` Stefano Brivio
0 siblings, 0 replies; 4+ messages in thread
From: Stefano Brivio @ 2018-12-05 0:38 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, Jianlin Shi, Hangbin Liu, Stephen Hemminger, netdev
On Tue, 4 Dec 2018 16:26:05 -0800
Eric Dumazet <edumazet@google.com> wrote:
> > + /* skb_push() won't panic if we have room for the unaligned size
> > only */
> > + BUG_ON(skb_headroom(skb) < hh_alen);
> >
>
> What about avoiding the panic and instead call kfree_skb() ?
>
> if (WARN_ON_ONCE(skb_headroom(skb) < hh_alen)) {
> kfree_skb(skb);
> return NET_XMIT_DROP;
> }
Okay, I guess it won't go unnoticed anyway, and it's probably better
than the alternative.
> > +
> > skb_push(skb, hh_len);
> >
>
> Maybe we can use __skb_push() here, since prior safety check should be
> enough ?
Indeed, I'll change that in v2. Thanks!
--
Stefano
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2018-12-05 0:38 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-05 0:13 [PATCH net 0/2] Fix slab out-of-bounds on insufficient headroom for IPv6 packets Stefano Brivio
2018-12-05 0:13 ` [PATCH net 1/2] ipv6: Check available headroom in ip6_xmit() even without options Stefano Brivio
2018-12-05 0:13 ` [PATCH net 2/2] neighbour: BUG_ON() writing before skb->head in neigh_hh_output() Stefano Brivio
[not found] ` <CANn89i+VoX7LNq4uGztJvH3EVzbE=Rhab=erkCOzHo3xyWBExg@mail.gmail.com>
2018-12-05 0:38 ` Stefano Brivio
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.