linux-stable/net/ipv6
Kuniyuki Iwashima d2c9e2ebaf tcp/udp: Fix memory leak in ipv6_renew_options().
commit 3c52c6bb83 upstream.

syzbot reported a memory leak [0] related to IPV6_ADDRFORM.

The scenario is that while one thread is converting an IPv6 socket into
IPv4 with IPV6_ADDRFORM, another thread calls do_ipv6_setsockopt() and
allocates memory to inet6_sk(sk)->XXX after conversion.

Then, the converted sk with (tcp|udp)_prot never frees the IPv6 resources,
which inet6_destroy_sock() should have cleaned up.

setsockopt(IPV6_ADDRFORM)                 setsockopt(IPV6_DSTOPTS)
+-----------------------+                 +----------------------+
- do_ipv6_setsockopt(sk, ...)
  - sockopt_lock_sock(sk)                 - do_ipv6_setsockopt(sk, ...)
    - lock_sock(sk)                         ^._ called via tcpv6_prot
  - WRITE_ONCE(sk->sk_prot, &tcp_prot)          before WRITE_ONCE()
  - xchg(&np->opt, NULL)
  - txopt_put(opt)
  - sockopt_release_sock(sk)
    - release_sock(sk)                      - sockopt_lock_sock(sk)
                                              - lock_sock(sk)
                                            - ipv6_set_opt_hdr(sk, ...)
                                              - ipv6_update_options(sk, opt)
                                                - xchg(&inet6_sk(sk)->opt, opt)
                                                  ^._ opt is never freed.

                                            - sockopt_release_sock(sk)
                                              - release_sock(sk)

Since IPV6_DSTOPTS allocates options under lock_sock(), we can avoid this
memory leak by testing whether sk_family is changed by IPV6_ADDRFORM after
acquiring the lock.

This issue exists from the initial commit between IPV6_ADDRFORM and
IPV6_PKTOPTIONS.

[0]:
BUG: memory leak
unreferenced object 0xffff888009ab9f80 (size 96):
  comm "syz-executor583", pid 328, jiffies 4294916198 (age 13.034s)
  hex dump (first 32 bytes):
    01 00 00 00 48 00 00 00 08 00 00 00 00 00 00 00  ....H...........
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  backtrace:
    [<000000002ee98ae1>] kmalloc include/linux/slab.h:605 [inline]
    [<000000002ee98ae1>] sock_kmalloc+0xb3/0x100 net/core/sock.c:2566
    [<0000000065d7b698>] ipv6_renew_options+0x21e/0x10b0 net/ipv6/exthdrs.c:1318
    [<00000000a8c756d7>] ipv6_set_opt_hdr net/ipv6/ipv6_sockglue.c:354 [inline]
    [<00000000a8c756d7>] do_ipv6_setsockopt.constprop.0+0x28b7/0x4350 net/ipv6/ipv6_sockglue.c:668
    [<000000002854d204>] ipv6_setsockopt+0xdf/0x190 net/ipv6/ipv6_sockglue.c:1021
    [<00000000e69fdcf8>] tcp_setsockopt+0x13b/0x2620 net/ipv4/tcp.c:3789
    [<0000000090da4b9b>] __sys_setsockopt+0x239/0x620 net/socket.c:2252
    [<00000000b10d192f>] __do_sys_setsockopt net/socket.c:2263 [inline]
    [<00000000b10d192f>] __se_sys_setsockopt net/socket.c:2260 [inline]
    [<00000000b10d192f>] __x64_sys_setsockopt+0xbe/0x160 net/socket.c:2260
    [<000000000a80d7aa>] do_syscall_x64 arch/x86/entry/common.c:50 [inline]
    [<000000000a80d7aa>] do_syscall_64+0x38/0x90 arch/x86/entry/common.c:80
    [<000000004562b5c6>] entry_SYSCALL_64_after_hwframe+0x63/0xcd

Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2022-12-08 11:15:42 +01:00
..
ila
netfilter netfilter: ip6_tables: zero-initialize fragment offset 2021-10-17 10:05:40 +02:00
Kconfig
Makefile
addrconf.c ipv6: Don't send rs packets to the interface of ARPHRD_TUNNEL 2022-06-14 16:52:29 +02:00
addrconf_core.c net: ipv6_stub: use ip6_dst_lookup_flow instead of ip6_dst_lookup 2020-05-20 08:15:30 +02:00
addrlabel.c ipv6: addrlabel: fix infoleak when sending struct ifaddrlblmsg to network 2022-11-25 17:35:35 +01:00
af_inet6.c net: ipv6_stub: use ip6_dst_lookup_flow instead of ip6_dst_lookup 2020-05-20 08:15:30 +02:00
ah6.c ah6: fix error return code in ah6_input() 2020-11-24 13:02:52 +01:00
anycast.c ipv6: fix memory leaks on IPV6_ADDRFORM path 2020-08-21 11:01:55 +02:00
calipso.c cipso,calipso: resolve a number of problems with the DOI refcounts 2022-01-27 08:47:42 +01:00
datagram.c net: ipv6: keep sk status consistent after datagram connect failure 2021-01-09 13:35:49 +01:00
esp6.c esp6: fix memleak on error path in esp6_input 2020-06-11 09:22:18 +02:00
exthdrs.c
exthdrs_core.c
exthdrs_offload.c
fib6_rules.c
fou6.c
icmp.c net: icmp: pass zeroed opts from icmp{,v6}_ndo_send before sending 2021-03-03 17:44:46 +01:00
inet6_connection_sock.c net: ipv6: add net argument to ip6_dst_lookup_flow 2020-05-20 08:15:30 +02:00
inet6_hashtables.c secure_seq: use the 64 bits of the siphash for port offset calculation 2022-06-25 11:45:19 +02:00
ip6_checksum.c net: udp: fix handling of CHECKSUM_COMPLETE packets 2018-11-10 07:42:58 -08:00
ip6_fib.c ipv6: Fix route replacement with dev-only route 2020-03-11 07:53:05 +01:00
ip6_flowlabel.c ipv6: flowlabel: fl6_sock_lookup() must use atomic_inc_not_zero 2019-06-22 08:17:21 +02:00
ip6_gre.c ipv6: remove extra dev_hold() for fallback tunnels 2021-05-22 10:40:34 +02:00
ip6_icmp.c net: icmp: pass zeroed opts from icmp{,v6}_ndo_send before sending 2021-03-03 17:44:46 +01:00
ip6_input.c ipv6: weaken the v4mapped source check 2021-04-07 12:05:38 +02:00
ip6_offload.c gso: do not skip outer ip header in case of ipip and net_failover 2022-03-02 11:32:02 +01:00
ip6_offload.h
ip6_output.c net: ipv6: fix skb_over_panic in __ip6_append_data 2022-03-28 08:06:05 +02:00
ip6_tunnel.c ipv6_tunnel: Rate limit warning messages 2022-02-08 18:15:27 +01:00
ip6_udp_tunnel.c ipv6: explicitly initialize udp6_addr in udp_sock_create6() 2019-01-09 16:16:40 +01:00
ip6_vti.c ip6_vti: initialize __ip6_tnl_parm struct in vti6_siocdevprivate 2022-01-11 13:38:13 +01:00
ip6mr.c ipmr,ip6mr: acquire RTNL before calling ip[6]mr_free_table() on failure path 2022-02-16 12:43:53 +01:00
ipcomp6.c
ipv6_sockglue.c tcp/udp: Fix memory leak in ipv6_renew_options(). 2022-12-08 11:15:42 +01:00
mcast.c mld: fix panic in mld_newpack() 2021-06-03 08:23:32 +02:00
mcast_snoop.c
mip6.c
ndisc.c ipv6/ndisc: Preserve IPv6 control buffer if protocol error handlers are called 2018-11-10 07:42:57 -08:00
netfilter.c
output_core.c ipv6: use prandom_u32() for ID generation 2021-07-20 16:21:07 +02:00
ping.c net: ping6: Fix memleak in ipv6_renew_options(). 2022-08-25 11:09:20 +02:00
proc.c inet: frags: break the 2GB limit for frags storage 2018-10-18 09:13:24 +02:00
protocol.c
raw.c net: ipv6: add net argument to ip6_dst_lookup_flow 2020-05-20 08:15:30 +02:00
reassembly.c inet: frags: call inet_frags_fini() after unregister_pernet_subsys() 2020-01-29 10:24:25 +01:00
route.c net: ipv6: check for validity before dereferencing cfg->fc_nlinfo.nlh 2021-04-16 11:59:06 +02:00
sit.c ipv6/sit: fix ipip6_tunnel_get_prl return value 2022-07-07 17:30:11 +02:00
syncookies.c net: Update window_clamp if SOCK_RCVBUF is set 2020-11-18 18:26:29 +01:00
sysctl_net_ipv6.c
tcp_ipv6.c inet: fully convert sk->sk_rx_dst to RCU rules 2022-10-26 13:15:48 +02:00
tcpv6_offload.c
tunnel6.c
udp.c net: udp: annotate data race around udp_sk(sk)->corkflag 2021-10-06 10:23:42 +02:00
udp_impl.h
udp_offload.c
udplite.c
xfrm6_input.c
xfrm6_mode_beet.c
xfrm6_mode_ro.c
xfrm6_mode_transport.c
xfrm6_mode_tunnel.c
xfrm6_output.c net: ipv6: fix return value of ip6_skb_dst_mtu 2021-07-28 09:14:25 +02:00
xfrm6_policy.c xfrm: Fix ignored return value in xfrm6_init() 2022-12-08 11:15:39 +01:00
xfrm6_protocol.c
xfrm6_state.c
xfrm6_tunnel.c xfrm6_tunnel: Fix potential panic when unloading xfrm6_tunnel module 2019-05-25 18:26:54 +02:00