dccp_v6_rcv() calls __sk_receive_skb() which calls sk_filter_trim_cap(). sk_filter_trim_cap() should return a value not equal to 0 and cause the skb to be dropped, since icmpv6_send() is called when smack_socket_sock_rcv_skb() returns -EACCES.
So, the packet shouldn't be put into the backlog queue. How did it get there? Regards, Piotr On 1/4/19 8:00 PM, 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. > > 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)