On Fri, Jan 4, 2019 at 11:36 AM Casey Schaufler <ca...@schaufler-ca.com> wrote: > > On 1/4/2019 11:00 AM, Eric Dumazet wrote: > > syzbot was able to crash one host with the following stack trace : > > > > kasan: GPF could be caused by NULL-ptr deref or user memory access > > general protection fault: 0000 [#1] PREEMPT SMP KASAN > > CPU: 0 PID: 8625 Comm: syz-executor4 Not tainted 4.20.0+ #8 > > RIP: 0010:dev_net include/linux/netdevice.h:2169 [inline] > > RIP: 0010:icmp6_send+0x116/0x2d30 net/ipv6/icmp.c:426 > > icmpv6_send > > smack_socket_sock_rcv_skb > > security_sock_rcv_skb > > sk_filter_trim_cap > > __sk_receive_skb > > dccp_v6_do_rcv > > release_sock > > > > This is because a RX packet found socket owned by user and > > was stored into socket backlog. Before leaving RCU protected section, > > skb->dev was cleared in __sk_receive_skb(). When socket backlog > > was finally handled at release_sock() time, skb was fed to > > smack_socket_sock_rcv_skb() then icmp6_send() > > > > We could fix the bug in smack_socket_sock_rcv_skb(), or simply > > make icmp6_send() more robust against such possibility. > > The Smack patch would be a trivial check for skb->dev == NULL, > in which case it wouldn't call icmp6_send(). Unless there's a > timing issue, of course. If there are no known timing issues I > would be happy to create a Smack patch to address this problem. > > Or, I'm happy with the patch below if you like it. >
Well, doing the check in icmp6_send() is more generic, this is the path I took, thanks ;) > > > > In the future we might provide to icmp6_send() the net pointer > > instead of infering it. > > > > Fixes: d66a8acbda92 ("Smack: Inform peer that IPv6 traffic has been > > blocked") > > Signed-off-by: Eric Dumazet <eduma...@google.com> > > Cc: Piotr Sawicki <p.sawic...@partner.samsung.com> > > Cc: Casey Schaufler <ca...@schaufler-ca.com> > > Reported-by: syzbot <syzkal...@googlegroups.com> > > --- > > net/ipv6/icmp.c | 8 ++++++-- > > 1 file changed, 6 insertions(+), 2 deletions(-) > > > > diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c > > index > > 5d7aa2c2770ca2b4981d2dd211c3cf0a79a6f9e2..bbcdfd2996926a78c3ea0b274adfa9b5f297efbc > > 100644 > > --- a/net/ipv6/icmp.c > > +++ b/net/ipv6/icmp.c > > @@ -423,10 +423,10 @@ static int icmp6_iif(const struct sk_buff *skb) > > static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, > > const struct in6_addr *force_saddr) > > { > > - struct net *net = dev_net(skb->dev); > > struct inet6_dev *idev = NULL; > > struct ipv6hdr *hdr = ipv6_hdr(skb); > > struct sock *sk; > > + struct net *net; > > struct ipv6_pinfo *np; > > const struct in6_addr *saddr = NULL; > > struct dst_entry *dst; > > @@ -437,12 +437,16 @@ static void icmp6_send(struct sk_buff *skb, u8 type, > > u8 code, __u32 info, > > int iif = 0; > > int addr_type = 0; > > int len; > > - u32 mark = IP6_REPLY_MARK(net, skb->mark); > > + u32 mark; > > > > if ((u8 *)hdr < skb->head || > > (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) > > return; > > > > + if (!skb->dev) > > + return; > > + net = dev_net(skb->dev); > > + mark = IP6_REPLY_MARK(net, skb->mark); > > /* > > * Make sure we respect the rules > > * i.e. RFC 1885 2.4(e) >