Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1279124 > unrolled thread

use-after-free in ip6_setup_cork

Started byDmitry Vyukov <dvyukov@google.com>
First post2015-11-28 12:10 +0100
Last post2015-12-03 06:40 +0100
Articles 10 — 4 participants

Back to article view | Back to linux.kernel


Contents

  use-after-free in ip6_setup_cork Dmitry Vyukov <dvyukov@google.com> - 2015-11-28 12:10 +0100
    Re: use-after-free in ip6_setup_cork Eric Dumazet <eric.dumazet@gmail.com> - 2015-11-28 18:20 +0100
      Re: use-after-free in ip6_setup_cork Eric Dumazet <eric.dumazet@gmail.com> - 2015-11-28 18:30 +0100
        Re: use-after-free in ip6_setup_cork Eric Dumazet <eric.dumazet@gmail.com> - 2015-11-30 04:30 +0100
        [PATCH net] ipv6: add complete rcu protection around np->opt Eric Dumazet <eric.dumazet@gmail.com> - 2015-11-30 04:40 +0100
          Re: [PATCH net] ipv6: add complete rcu protection around np->opt Hannes Frederic Sowa <hannes@stressinduktion.org> - 2015-12-01 12:20 +0100
            Re: [PATCH net] ipv6: add complete rcu protection around np->opt Eric Dumazet <eric.dumazet@gmail.com> - 2015-12-01 14:10 +0100
              Re: [PATCH net] ipv6: add complete rcu protection around np->opt Hannes Frederic Sowa <hannes@stressinduktion.org> - 2015-12-01 14:20 +0100
          Re: [PATCH net] ipv6: add complete rcu protection around np->opt David Miller <davem@davemloft.net> - 2015-12-03 05:40 +0100
            Re: [PATCH net] ipv6: add complete rcu protection around np->opt Eric Dumazet <eric.dumazet@gmail.com> - 2015-12-03 06:40 +0100

#1279124 — use-after-free in ip6_setup_cork

FromDmitry Vyukov <dvyukov@google.com>
Date2015-11-28 12:10 +0100
Subjectuse-after-free in ip6_setup_cork
Message-ID<qzLya-82k-1@gated-at.bofh.it>
Hello,

The following program triggers use-after-free in ip6_setup_cork:

// autogenerated by syzkaller (http://github.com/google/syzkaller)
#include <syscall.h>
#include <string.h>
#include <stdint.h>
#include <pthread.h>

int r1, r3, r4;

void *thr0(void *arg)
{
        *(uint64_t*)0x20000d90 = 0x20000fd3;
        *(uint64_t*)0x20000d98 = 0x2d;
        *(uint64_t*)0x20000da0 = 0x20000fa4;
        *(uint64_t*)0x20000da8 = 0x5c;
        *(uint64_t*)0x20000db0 = 0x20000fac;
        *(uint64_t*)0x20000db8 = 0x71;
        *(uint64_t*)0x20000dc0 = 0x20000fb6;
        *(uint64_t*)0x20000dc8 = 0xec;
        *(uint64_t*)0x20000dd0 = 0x20000fae;
        *(uint64_t*)0x20000dd8 = 0x70;
        syscall(SYS_vmsplice, r4, 0x20000d90ul, 0x5ul, 0x2ul, 0, 0);
        return 0;
}

void *thr1(void *arg)
{
        memcpy((void*)0x200025e5, "\xbb\xef\x44\xd6\x33\x93", 6);
        syscall(SYS_setsockopt, r1, 0x29ul, 0x6ul, 0x200025e5ul, 0x6ul, 0);
        return 0;
}

void *thr2(void *arg)
{
        syscall(SYS_splice, r3, 0x0ul, r1, 0x0ul, 0xaful, 0x3ul);
        return 0;
}

int main()
{
        syscall(SYS_mmap, 0x20000000ul, 0x10000ul, 0x3ul, 0x32ul,
0xfffffffffffffffful, 0x0ul);
        r1 = syscall(SYS_socket, 0xaul, 0x80002ul, 0x0ul, 0, 0, 0);
        syscall(SYS_pipe2, 0x20001000ul, 0x800ul, 0, 0, 0, 0);
        r3 = *(uint32_t*)0x20001000;
        r4 = *(uint32_t*)0x20001004;
        memcpy((void*)0x20003000,
"\x0a\x00\x33\xe2\x61\x44\xfe\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x5b\x11\x6d\x22",
28);
        long r6 = syscall(SYS_connect, r1, 0x20003000ul, 0x1cul, 0, 0, 0);
        pthread_t th[4];
        pthread_create(&th[0], 0, thr0, 0);
        pthread_create(&th[1], 0, thr1, 0);
        pthread_create(&th[2], 0, thr2, 0);
        pthread_create(&th[3], 0, thr1, 0);
        pthread_join(th[0], 0);
        pthread_join(th[1], 0);
        pthread_join(th[2], 0);
        pthread_join(th[3], 0);
        return 0;
}


==================================================================
BUG: KASAN: use-after-free in ip6_setup_cork+0xeb8/0x11a0 at addr
ffff88006d36da08
Read of size 4 by task executor/23958
=============================================================================
BUG kmalloc-64 (Not tainted): kasan: bad access detected
-----------------------------------------------------------------------------

Disabling lock debugging due to kernel taint
INFO: Allocated in sock_kmalloc+0x7f/0xc0 age=9 cpu=3 pid=23946
[<      none      >] ___slab_alloc+0x41c/0x460 mm/slub.c:2438
[<      none      >] __slab_alloc+0x1b/0x30 mm/slub.c:2467
[<     inline     >] slab_alloc_node mm/slub.c:2530
[<     inline     >] slab_alloc mm/slub.c:2572
[<      none      >] __kmalloc+0x156/0x1b0 mm/slub.c:3532
[<     inline     >] kmalloc include/linux/slab.h:463
[<      none      >] sock_kmalloc+0x7f/0xc0 net/core/sock.c:1774
[<      none      >] do_ipv6_setsockopt.isra.8+0x779/0x2a60
net/ipv6/ipv6_sockglue.c:483
[<      none      >] ipv6_setsockopt+0x9b/0x140 net/ipv6/ipv6_sockglue.c:885
[<      none      >] udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1425
[<      none      >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2645
[<     inline     >] SYSC_setsockopt net/socket.c:1757
[<      none      >] SyS_setsockopt+0x158/0x240 net/socket.c:1736
[<      none      >] entry_SYSCALL_64_fastpath+0x12/0x71
arch/x86/entry/entry_64.S:185

INFO: Freed in sock_kfree_s+0x29/0x70 age=11 cpu=2 pid=23957
[<      none      >] __slab_free+0x1fb/0x300 mm/slub.c:2648
[<     inline     >] slab_free mm/slub.c:2803
[<      none      >] kfree+0x13b/0x160 mm/slub.c:3632
[<     inline     >] __sock_kfree_s net/core/sock.c:1795
[<      none      >] sock_kfree_s+0x29/0x70 net/core/sock.c:1801
[<      none      >] do_ipv6_setsockopt.isra.8+0x815/0x2a60
net/ipv6/ipv6_sockglue.c:506
[<      none      >] ipv6_setsockopt+0x9b/0x140 net/ipv6/ipv6_sockglue.c:885
[<      none      >] udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1425
[<      none      >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2645
[<     inline     >] SYSC_setsockopt net/socket.c:1757
[<      none      >] SyS_setsockopt+0x158/0x240 net/socket.c:1736
[<      none      >] entry_SYSCALL_64_fastpath+0x12/0x71
arch/x86/entry/entry_64.S:185

INFO: Slab 0xffffea0001b4db00 objects=20 used=8 fp=0xffff88006d36da08
flags=0x500000000004080
INFO: Object 0xffff88006d36da08 @offset=6664 fp=0xffff88006d36d3e8
CPU: 3 PID: 23958 Comm: executor Tainted: G    B           4.4.0-rc2+ #1
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
 00000000ffffffff ffff88003c32f348 ffffffff81a2bdb0 ffff88003e807840
 ffff88006d36da08 ffff88006d36c000 ffff88003c32f378 ffffffff814541d4
 ffff88003e807840 ffffea0001b4db00 ffff88006d36da08 ffff88006d126000

Call Trace:
 [<ffffffff8145b9ae>] __asan_report_load4_noabort+0x3e/0x40
mm/kasan/report.c:279
 [<ffffffff829de1e8>] ip6_setup_cork+0xeb8/0x11a0 net/ipv6/ip6_output.c:1200
 [<ffffffff829e9e2a>] ip6_make_skb+0x19a/0x3b0 net/ipv6/ip6_output.c:1769
 [<ffffffff82a3c3e6>] udpv6_sendmsg+0x11c6/0x2120 net/ipv6/udp.c:1314
 [<ffffffff829038cc>] inet_sendmsg+0x23c/0x340 net/ipv4/af_inet.c:733
 [<     inline     >] sock_sendmsg_nosec net/socket.c:610
 [<ffffffff826adc2a>] sock_sendmsg+0xca/0x110 net/socket.c:620
 [<ffffffff826ae057>] kernel_sendmsg+0x47/0x60 net/socket.c:628
 [<ffffffff826b564a>] sock_no_sendpage+0xfa/0x130 net/core/sock.c:2270
 [<ffffffff826ac6d0>] kernel_sendpage+0x90/0xe0 net/socket.c:3278
 [<ffffffff826ac7c5>] sock_sendpage+0xa5/0xd0 net/socket.c:765
 [<ffffffff814feca4>] pipe_to_sendpage+0x264/0x320 fs/splice.c:720
 [<     inline     >] splice_from_pipe_feed fs/splice.c:772
 [<ffffffff81501435>] __splice_from_pipe+0x235/0x6d0 fs/splice.c:897
 [<ffffffff81504677>] splice_from_pipe+0xf7/0x140 fs/splice.c:932
 [<ffffffff81504700>] generic_splice_sendpage+0x40/0x50 fs/splice.c:1105
 [<     inline     >] do_splice_from fs/splice.c:1124
 [<     inline     >] do_splice fs/splice.c:1400
 [<     inline     >] SYSC_splice fs/splice.c:1703
 [<ffffffff815052f8>] SyS_splice+0x7c8/0x15c0 fs/splice.c:1686
 [<ffffffff82ddc0ae>] entry_SYSCALL_64_fastpath+0x12/0x71
arch/x86/entry/entry_64.S:185
==================================================================


On commit 78c4a49a69e910a162b05e4e8727b9bdbf948f13 (Nov 25).
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1279183

FromEric Dumazet <eric.dumazet@gmail.com>
Date2015-11-28 18:20 +0100
Message-ID<qzRkd-3eL-1@gated-at.bofh.it>
In reply to#1279124
On Sat, 2015-11-28 at 12:00 +0100, Dmitry Vyukov wrote:
> Hello,
> 
> The following program triggers use-after-free in ip6_setup_cork:
> 
> // autogenerated by syzkaller (http://github.com/google/syzkaller)
> #include <syscall.h>
> #include <string.h>
> #include <stdint.h>
> #include <pthread.h>
> 
> int r1, r3, r4;
> 
> void *thr0(void *arg)
> {
>         *(uint64_t*)0x20000d90 = 0x20000fd3;
>         *(uint64_t*)0x20000d98 = 0x2d;
>         *(uint64_t*)0x20000da0 = 0x20000fa4;
>         *(uint64_t*)0x20000da8 = 0x5c;
>         *(uint64_t*)0x20000db0 = 0x20000fac;
>         *(uint64_t*)0x20000db8 = 0x71;
>         *(uint64_t*)0x20000dc0 = 0x20000fb6;
>         *(uint64_t*)0x20000dc8 = 0xec;
>         *(uint64_t*)0x20000dd0 = 0x20000fae;
>         *(uint64_t*)0x20000dd8 = 0x70;
>         syscall(SYS_vmsplice, r4, 0x20000d90ul, 0x5ul, 0x2ul, 0, 0);
>         return 0;
> }
> 
> void *thr1(void *arg)
> {
>         memcpy((void*)0x200025e5, "\xbb\xef\x44\xd6\x33\x93", 6);
>         syscall(SYS_setsockopt, r1, 0x29ul, 0x6ul, 0x200025e5ul, 0x6ul, 0);
>         return 0;
> }
> 
> void *thr2(void *arg)
> {
>         syscall(SYS_splice, r3, 0x0ul, r1, 0x0ul, 0xaful, 0x3ul);
>         return 0;
> }
> 
> int main()
> {
>         syscall(SYS_mmap, 0x20000000ul, 0x10000ul, 0x3ul, 0x32ul,
> 0xfffffffffffffffful, 0x0ul);
>         r1 = syscall(SYS_socket, 0xaul, 0x80002ul, 0x0ul, 0, 0, 0);
>         syscall(SYS_pipe2, 0x20001000ul, 0x800ul, 0, 0, 0, 0);
>         r3 = *(uint32_t*)0x20001000;
>         r4 = *(uint32_t*)0x20001004;
>         memcpy((void*)0x20003000,
> "\x0a\x00\x33\xe2\x61\x44\xfe\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x5b\x11\x6d\x22",
> 28);
>         long r6 = syscall(SYS_connect, r1, 0x20003000ul, 0x1cul, 0, 0, 0);
>         pthread_t th[4];
>         pthread_create(&th[0], 0, thr0, 0);
>         pthread_create(&th[1], 0, thr1, 0);
>         pthread_create(&th[2], 0, thr2, 0);
>         pthread_create(&th[3], 0, thr1, 0);
>         pthread_join(th[0], 0);
>         pthread_join(th[1], 0);
>         pthread_join(th[2], 0);
>         pthread_join(th[3], 0);
>         return 0;
> }
> 
> 
> ==================================================================
> BUG: KASAN: use-after-free in ip6_setup_cork+0xeb8/0x11a0 at addr
> ffff88006d36da08
> Read of size 4 by task executor/23958
> =============================================================================
> BUG kmalloc-64 (Not tainted): kasan: bad access detected
> -----------------------------------------------------------------------------
> 
> Disabling lock debugging due to kernel taint
> INFO: Allocated in sock_kmalloc+0x7f/0xc0 age=9 cpu=3 pid=23946
> [<      none      >] ___slab_alloc+0x41c/0x460 mm/slub.c:2438
> [<      none      >] __slab_alloc+0x1b/0x30 mm/slub.c:2467
> [<     inline     >] slab_alloc_node mm/slub.c:2530
> [<     inline     >] slab_alloc mm/slub.c:2572
> [<      none      >] __kmalloc+0x156/0x1b0 mm/slub.c:3532
> [<     inline     >] kmalloc include/linux/slab.h:463
> [<      none      >] sock_kmalloc+0x7f/0xc0 net/core/sock.c:1774
> [<      none      >] do_ipv6_setsockopt.isra.8+0x779/0x2a60
> net/ipv6/ipv6_sockglue.c:483
> [<      none      >] ipv6_setsockopt+0x9b/0x140 net/ipv6/ipv6_sockglue.c:885
> [<      none      >] udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1425
> [<      none      >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2645
> [<     inline     >] SYSC_setsockopt net/socket.c:1757
> [<      none      >] SyS_setsockopt+0x158/0x240 net/socket.c:1736
> [<      none      >] entry_SYSCALL_64_fastpath+0x12/0x71
> arch/x86/entry/entry_64.S:185
> 
> INFO: Freed in sock_kfree_s+0x29/0x70 age=11 cpu=2 pid=23957
> [<      none      >] __slab_free+0x1fb/0x300 mm/slub.c:2648
> [<     inline     >] slab_free mm/slub.c:2803
> [<      none      >] kfree+0x13b/0x160 mm/slub.c:3632
> [<     inline     >] __sock_kfree_s net/core/sock.c:1795
> [<      none      >] sock_kfree_s+0x29/0x70 net/core/sock.c:1801
> [<      none      >] do_ipv6_setsockopt.isra.8+0x815/0x2a60
> net/ipv6/ipv6_sockglue.c:506
> [<      none      >] ipv6_setsockopt+0x9b/0x140 net/ipv6/ipv6_sockglue.c:885
> [<      none      >] udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1425
> [<      none      >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2645
> [<     inline     >] SYSC_setsockopt net/socket.c:1757
> [<      none      >] SyS_setsockopt+0x158/0x240 net/socket.c:1736
> [<      none      >] entry_SYSCALL_64_fastpath+0x12/0x71
> arch/x86/entry/entry_64.S:185
> 
> INFO: Slab 0xffffea0001b4db00 objects=20 used=8 fp=0xffff88006d36da08
> flags=0x500000000004080
> INFO: Object 0xffff88006d36da08 @offset=6664 fp=0xffff88006d36d3e8
> CPU: 3 PID: 23958 Comm: executor Tainted: G    B           4.4.0-rc2+ #1
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
>  00000000ffffffff ffff88003c32f348 ffffffff81a2bdb0 ffff88003e807840
>  ffff88006d36da08 ffff88006d36c000 ffff88003c32f378 ffffffff814541d4
>  ffff88003e807840 ffffea0001b4db00 ffff88006d36da08 ffff88006d126000
> 
> Call Trace:
>  [<ffffffff8145b9ae>] __asan_report_load4_noabort+0x3e/0x40
> mm/kasan/report.c:279
>  [<ffffffff829de1e8>] ip6_setup_cork+0xeb8/0x11a0 net/ipv6/ip6_output.c:1200
>  [<ffffffff829e9e2a>] ip6_make_skb+0x19a/0x3b0 net/ipv6/ip6_output.c:1769
>  [<ffffffff82a3c3e6>] udpv6_sendmsg+0x11c6/0x2120 net/ipv6/udp.c:1314
>  [<ffffffff829038cc>] inet_sendmsg+0x23c/0x340 net/ipv4/af_inet.c:733
>  [<     inline     >] sock_sendmsg_nosec net/socket.c:610
>  [<ffffffff826adc2a>] sock_sendmsg+0xca/0x110 net/socket.c:620
>  [<ffffffff826ae057>] kernel_sendmsg+0x47/0x60 net/socket.c:628
>  [<ffffffff826b564a>] sock_no_sendpage+0xfa/0x130 net/core/sock.c:2270
>  [<ffffffff826ac6d0>] kernel_sendpage+0x90/0xe0 net/socket.c:3278
>  [<ffffffff826ac7c5>] sock_sendpage+0xa5/0xd0 net/socket.c:765
>  [<ffffffff814feca4>] pipe_to_sendpage+0x264/0x320 fs/splice.c:720
>  [<     inline     >] splice_from_pipe_feed fs/splice.c:772
>  [<ffffffff81501435>] __splice_from_pipe+0x235/0x6d0 fs/splice.c:897
>  [<ffffffff81504677>] splice_from_pipe+0xf7/0x140 fs/splice.c:932
>  [<ffffffff81504700>] generic_splice_sendpage+0x40/0x50 fs/splice.c:1105
>  [<     inline     >] do_splice_from fs/splice.c:1124
>  [<     inline     >] do_splice fs/splice.c:1400
>  [<     inline     >] SYSC_splice fs/splice.c:1703
>  [<ffffffff815052f8>] SyS_splice+0x7c8/0x15c0 fs/splice.c:1686
>  [<ffffffff82ddc0ae>] entry_SYSCALL_64_fastpath+0x12/0x71
> arch/x86/entry/entry_64.S:185
> ==================================================================
> 
> 
> On commit 78c4a49a69e910a162b05e4e8727b9bdbf948f13 (Nov 25).
> --

Thanks for the report.

Bug probably added in :

commit 03485f2adcde0c2d4e9228b659be78e872486bbb
Author: Vlad Yasevich <vyasevich@gmail.com>
Date:   Sat Jan 31 10:40:17 2015 -0500

    udpv6: Add lockless sendmsg() support
    
    This commit adds the same functionaliy to IPv6 that
    commit 903ab86d195cca295379699299c5fc10beba31c7
    Author: Herbert Xu <herbert@gondor.apana.org.au>
    Date:   Tue Mar 1 02:36:48 2011 +0000
    
        udp: Add lockless transmit path
    
    added to IPv4.
    
    UDP transmit path can now run without a socket lock,
    thus allowing multiple threads to send to a single socket
    more efficiently.
    This is only used when corking/MSG_MORE is not used.
    
    Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1279185

FromEric Dumazet <eric.dumazet@gmail.com>
Date2015-11-28 18:30 +0100
Message-ID<qzRtU-3ig-21@gated-at.bofh.it>
In reply to#1279183
On Sat, 2015-11-28 at 09:11 -0800, Eric Dumazet wrote:
> On Sat, 2015-11-28 at 12:00 +0100, Dmitry Vyukov wrote:
> > Hello,
> > 
> > The following program triggers use-after-free in ip6_setup_cork:
> > 
> > // autogenerated by syzkaller (http://github.com/google/syzkaller)
> > #include <syscall.h>
> > #include <string.h>
> > #include <stdint.h>
> > #include <pthread.h>
> > 
> > int r1, r3, r4;
> > 
> > void *thr0(void *arg)
> > {
> >         *(uint64_t*)0x20000d90 = 0x20000fd3;
> >         *(uint64_t*)0x20000d98 = 0x2d;
> >         *(uint64_t*)0x20000da0 = 0x20000fa4;
> >         *(uint64_t*)0x20000da8 = 0x5c;
> >         *(uint64_t*)0x20000db0 = 0x20000fac;
> >         *(uint64_t*)0x20000db8 = 0x71;
> >         *(uint64_t*)0x20000dc0 = 0x20000fb6;
> >         *(uint64_t*)0x20000dc8 = 0xec;
> >         *(uint64_t*)0x20000dd0 = 0x20000fae;
> >         *(uint64_t*)0x20000dd8 = 0x70;
> >         syscall(SYS_vmsplice, r4, 0x20000d90ul, 0x5ul, 0x2ul, 0, 0);
> >         return 0;
> > }
> > 
> > void *thr1(void *arg)
> > {
> >         memcpy((void*)0x200025e5, "\xbb\xef\x44\xd6\x33\x93", 6);
> >         syscall(SYS_setsockopt, r1, 0x29ul, 0x6ul, 0x200025e5ul, 0x6ul, 0);
> >         return 0;
> > }
> > 
> > void *thr2(void *arg)
> > {
> >         syscall(SYS_splice, r3, 0x0ul, r1, 0x0ul, 0xaful, 0x3ul);
> >         return 0;
> > }
> > 
> > int main()
> > {
> >         syscall(SYS_mmap, 0x20000000ul, 0x10000ul, 0x3ul, 0x32ul,
> > 0xfffffffffffffffful, 0x0ul);
> >         r1 = syscall(SYS_socket, 0xaul, 0x80002ul, 0x0ul, 0, 0, 0);
> >         syscall(SYS_pipe2, 0x20001000ul, 0x800ul, 0, 0, 0, 0);
> >         r3 = *(uint32_t*)0x20001000;
> >         r4 = *(uint32_t*)0x20001004;
> >         memcpy((void*)0x20003000,
> > "\x0a\x00\x33\xe2\x61\x44\xfe\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x5b\x11\x6d\x22",
> > 28);
> >         long r6 = syscall(SYS_connect, r1, 0x20003000ul, 0x1cul, 0, 0, 0);
> >         pthread_t th[4];
> >         pthread_create(&th[0], 0, thr0, 0);
> >         pthread_create(&th[1], 0, thr1, 0);
> >         pthread_create(&th[2], 0, thr2, 0);
> >         pthread_create(&th[3], 0, thr1, 0);
> >         pthread_join(th[0], 0);
> >         pthread_join(th[1], 0);
> >         pthread_join(th[2], 0);
> >         pthread_join(th[3], 0);
> >         return 0;
> > }
> > 
> > 
> > ==================================================================
> > BUG: KASAN: use-after-free in ip6_setup_cork+0xeb8/0x11a0 at addr
> > ffff88006d36da08
> > Read of size 4 by task executor/23958
> > =============================================================================
> > BUG kmalloc-64 (Not tainted): kasan: bad access detected
> > -----------------------------------------------------------------------------
> > 
> > Disabling lock debugging due to kernel taint
> > INFO: Allocated in sock_kmalloc+0x7f/0xc0 age=9 cpu=3 pid=23946
> > [<      none      >] ___slab_alloc+0x41c/0x460 mm/slub.c:2438
> > [<      none      >] __slab_alloc+0x1b/0x30 mm/slub.c:2467
> > [<     inline     >] slab_alloc_node mm/slub.c:2530
> > [<     inline     >] slab_alloc mm/slub.c:2572
> > [<      none      >] __kmalloc+0x156/0x1b0 mm/slub.c:3532
> > [<     inline     >] kmalloc include/linux/slab.h:463
> > [<      none      >] sock_kmalloc+0x7f/0xc0 net/core/sock.c:1774
> > [<      none      >] do_ipv6_setsockopt.isra.8+0x779/0x2a60
> > net/ipv6/ipv6_sockglue.c:483
> > [<      none      >] ipv6_setsockopt+0x9b/0x140 net/ipv6/ipv6_sockglue.c:885
> > [<      none      >] udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1425
> > [<      none      >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2645
> > [<     inline     >] SYSC_setsockopt net/socket.c:1757
> > [<      none      >] SyS_setsockopt+0x158/0x240 net/socket.c:1736
> > [<      none      >] entry_SYSCALL_64_fastpath+0x12/0x71
> > arch/x86/entry/entry_64.S:185
> > 
> > INFO: Freed in sock_kfree_s+0x29/0x70 age=11 cpu=2 pid=23957
> > [<      none      >] __slab_free+0x1fb/0x300 mm/slub.c:2648
> > [<     inline     >] slab_free mm/slub.c:2803
> > [<      none      >] kfree+0x13b/0x160 mm/slub.c:3632
> > [<     inline     >] __sock_kfree_s net/core/sock.c:1795
> > [<      none      >] sock_kfree_s+0x29/0x70 net/core/sock.c:1801
> > [<      none      >] do_ipv6_setsockopt.isra.8+0x815/0x2a60
> > net/ipv6/ipv6_sockglue.c:506
> > [<      none      >] ipv6_setsockopt+0x9b/0x140 net/ipv6/ipv6_sockglue.c:885
> > [<      none      >] udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1425
> > [<      none      >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2645
> > [<     inline     >] SYSC_setsockopt net/socket.c:1757
> > [<      none      >] SyS_setsockopt+0x158/0x240 net/socket.c:1736
> > [<      none      >] entry_SYSCALL_64_fastpath+0x12/0x71
> > arch/x86/entry/entry_64.S:185
> > 
> > INFO: Slab 0xffffea0001b4db00 objects=20 used=8 fp=0xffff88006d36da08
> > flags=0x500000000004080
> > INFO: Object 0xffff88006d36da08 @offset=6664 fp=0xffff88006d36d3e8
> > CPU: 3 PID: 23958 Comm: executor Tainted: G    B           4.4.0-rc2+ #1
> > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
> >  00000000ffffffff ffff88003c32f348 ffffffff81a2bdb0 ffff88003e807840
> >  ffff88006d36da08 ffff88006d36c000 ffff88003c32f378 ffffffff814541d4
> >  ffff88003e807840 ffffea0001b4db00 ffff88006d36da08 ffff88006d126000
> > 
> > Call Trace:
> >  [<ffffffff8145b9ae>] __asan_report_load4_noabort+0x3e/0x40
> > mm/kasan/report.c:279
> >  [<ffffffff829de1e8>] ip6_setup_cork+0xeb8/0x11a0 net/ipv6/ip6_output.c:1200
> >  [<ffffffff829e9e2a>] ip6_make_skb+0x19a/0x3b0 net/ipv6/ip6_output.c:1769
> >  [<ffffffff82a3c3e6>] udpv6_sendmsg+0x11c6/0x2120 net/ipv6/udp.c:1314
> >  [<ffffffff829038cc>] inet_sendmsg+0x23c/0x340 net/ipv4/af_inet.c:733
> >  [<     inline     >] sock_sendmsg_nosec net/socket.c:610
> >  [<ffffffff826adc2a>] sock_sendmsg+0xca/0x110 net/socket.c:620
> >  [<ffffffff826ae057>] kernel_sendmsg+0x47/0x60 net/socket.c:628
> >  [<ffffffff826b564a>] sock_no_sendpage+0xfa/0x130 net/core/sock.c:2270
> >  [<ffffffff826ac6d0>] kernel_sendpage+0x90/0xe0 net/socket.c:3278
> >  [<ffffffff826ac7c5>] sock_sendpage+0xa5/0xd0 net/socket.c:765
> >  [<ffffffff814feca4>] pipe_to_sendpage+0x264/0x320 fs/splice.c:720
> >  [<     inline     >] splice_from_pipe_feed fs/splice.c:772
> >  [<ffffffff81501435>] __splice_from_pipe+0x235/0x6d0 fs/splice.c:897
> >  [<ffffffff81504677>] splice_from_pipe+0xf7/0x140 fs/splice.c:932
> >  [<ffffffff81504700>] generic_splice_sendpage+0x40/0x50 fs/splice.c:1105
> >  [<     inline     >] do_splice_from fs/splice.c:1124
> >  [<     inline     >] do_splice fs/splice.c:1400
> >  [<     inline     >] SYSC_splice fs/splice.c:1703
> >  [<ffffffff815052f8>] SyS_splice+0x7c8/0x15c0 fs/splice.c:1686
> >  [<ffffffff82ddc0ae>] entry_SYSCALL_64_fastpath+0x12/0x71
> > arch/x86/entry/entry_64.S:185
> > ==================================================================
> > 
> > 
> > On commit 78c4a49a69e910a162b05e4e8727b9bdbf948f13 (Nov 25).
> > --
> 
> Thanks for the report.
> 
> Bug probably added in :
> 
> commit 03485f2adcde0c2d4e9228b659be78e872486bbb
> Author: Vlad Yasevich <vyasevich@gmail.com>
> Date:   Sat Jan 31 10:40:17 2015 -0500
> 
>     udpv6: Add lockless sendmsg() support
>     
>     This commit adds the same functionaliy to IPv6 that
>     commit 903ab86d195cca295379699299c5fc10beba31c7
>     Author: Herbert Xu <herbert@gondor.apana.org.au>
>     Date:   Tue Mar 1 02:36:48 2011 +0000
>     
>         udp: Add lockless transmit path
>     
>     added to IPv4.
>     
>     UDP transmit path can now run without a socket lock,
>     thus allowing multiple threads to send to a single socket
>     more efficiently.
>     This is only used when corking/MSG_MORE is not used.
>     
>     Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
>     Signed-off-by: David S. Miller <davem@davemloft.net>
> 
> 

Oh well, bug is older than that.

inet6_sk(sk)->opt handling is completely racy, and has some xchg() calls
to hide how ugly it is.




--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1279548

FromEric Dumazet <eric.dumazet@gmail.com>
Date2015-11-30 04:30 +0100
Message-ID<qAnk6-6wh-3@gated-at.bofh.it>
In reply to#1279185
On Sat, 2015-11-28 at 09:23 -0800, Eric Dumazet wrote:
> On Sat, 2015-11-28 at 09:11 -0800, Eric Dumazet wrote:
> > On Sat, 2015-11-28 at 12:00 +0100, Dmitry Vyukov wrote:
> > > Hello,
> > > 
> > > The following program triggers use-after-free in ip6_setup_cork:
> > > 
> > > // autogenerated by syzkaller (http://github.com/google/syzkaller)
> > > #include <syscall.h>
> > > #include <string.h>
> > > #include <stdint.h>
> > > #include <pthread.h>
> > > 
> > > int r1, r3, r4;
> > > 
> > > void *thr0(void *arg)
> > > {
> > >         *(uint64_t*)0x20000d90 = 0x20000fd3;
> > >         *(uint64_t*)0x20000d98 = 0x2d;
> > >         *(uint64_t*)0x20000da0 = 0x20000fa4;
> > >         *(uint64_t*)0x20000da8 = 0x5c;
> > >         *(uint64_t*)0x20000db0 = 0x20000fac;
> > >         *(uint64_t*)0x20000db8 = 0x71;
> > >         *(uint64_t*)0x20000dc0 = 0x20000fb6;
> > >         *(uint64_t*)0x20000dc8 = 0xec;
> > >         *(uint64_t*)0x20000dd0 = 0x20000fae;
> > >         *(uint64_t*)0x20000dd8 = 0x70;
> > >         syscall(SYS_vmsplice, r4, 0x20000d90ul, 0x5ul, 0x2ul, 0, 0);
> > >         return 0;
> > > }
> > > 
> > > void *thr1(void *arg)
> > > {
> > >         memcpy((void*)0x200025e5, "\xbb\xef\x44\xd6\x33\x93", 6);
> > >         syscall(SYS_setsockopt, r1, 0x29ul, 0x6ul, 0x200025e5ul, 0x6ul, 0);
> > >         return 0;
> > > }
> > > 
> > > void *thr2(void *arg)
> > > {
> > >         syscall(SYS_splice, r3, 0x0ul, r1, 0x0ul, 0xaful, 0x3ul);
> > >         return 0;
> > > }
> > > 
> > > int main()
> > > {
> > >         syscall(SYS_mmap, 0x20000000ul, 0x10000ul, 0x3ul, 0x32ul,
> > > 0xfffffffffffffffful, 0x0ul);
> > >         r1 = syscall(SYS_socket, 0xaul, 0x80002ul, 0x0ul, 0, 0, 0);
> > >         syscall(SYS_pipe2, 0x20001000ul, 0x800ul, 0, 0, 0, 0);
> > >         r3 = *(uint32_t*)0x20001000;
> > >         r4 = *(uint32_t*)0x20001004;
> > >         memcpy((void*)0x20003000,
> > > "\x0a\x00\x33\xe2\x61\x44\xfe\x90\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x5b\x11\x6d\x22",
> > > 28);
> > >         long r6 = syscall(SYS_connect, r1, 0x20003000ul, 0x1cul, 0, 0, 0);
> > >         pthread_t th[4];
> > >         pthread_create(&th[0], 0, thr0, 0);
> > >         pthread_create(&th[1], 0, thr1, 0);
> > >         pthread_create(&th[2], 0, thr2, 0);
> > >         pthread_create(&th[3], 0, thr1, 0);
> > >         pthread_join(th[0], 0);
> > >         pthread_join(th[1], 0);
> > >         pthread_join(th[2], 0);
> > >         pthread_join(th[3], 0);
> > >         return 0;
> > > }
> > > 
> > > 
> > > ==================================================================
> > > BUG: KASAN: use-after-free in ip6_setup_cork+0xeb8/0x11a0 at addr
> > > ffff88006d36da08
> > > Read of size 4 by task executor/23958
> > > =============================================================================
> > > BUG kmalloc-64 (Not tainted): kasan: bad access detected
> > > -----------------------------------------------------------------------------
> > > 
> > > Disabling lock debugging due to kernel taint
> > > INFO: Allocated in sock_kmalloc+0x7f/0xc0 age=9 cpu=3 pid=23946
> > > [<      none      >] ___slab_alloc+0x41c/0x460 mm/slub.c:2438
> > > [<      none      >] __slab_alloc+0x1b/0x30 mm/slub.c:2467
> > > [<     inline     >] slab_alloc_node mm/slub.c:2530
> > > [<     inline     >] slab_alloc mm/slub.c:2572
> > > [<      none      >] __kmalloc+0x156/0x1b0 mm/slub.c:3532
> > > [<     inline     >] kmalloc include/linux/slab.h:463
> > > [<      none      >] sock_kmalloc+0x7f/0xc0 net/core/sock.c:1774
> > > [<      none      >] do_ipv6_setsockopt.isra.8+0x779/0x2a60
> > > net/ipv6/ipv6_sockglue.c:483
> > > [<      none      >] ipv6_setsockopt+0x9b/0x140 net/ipv6/ipv6_sockglue.c:885
> > > [<      none      >] udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1425
> > > [<      none      >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2645
> > > [<     inline     >] SYSC_setsockopt net/socket.c:1757
> > > [<      none      >] SyS_setsockopt+0x158/0x240 net/socket.c:1736
> > > [<      none      >] entry_SYSCALL_64_fastpath+0x12/0x71
> > > arch/x86/entry/entry_64.S:185
> > > 
> > > INFO: Freed in sock_kfree_s+0x29/0x70 age=11 cpu=2 pid=23957
> > > [<      none      >] __slab_free+0x1fb/0x300 mm/slub.c:2648
> > > [<     inline     >] slab_free mm/slub.c:2803
> > > [<      none      >] kfree+0x13b/0x160 mm/slub.c:3632
> > > [<     inline     >] __sock_kfree_s net/core/sock.c:1795
> > > [<      none      >] sock_kfree_s+0x29/0x70 net/core/sock.c:1801
> > > [<      none      >] do_ipv6_setsockopt.isra.8+0x815/0x2a60
> > > net/ipv6/ipv6_sockglue.c:506
> > > [<      none      >] ipv6_setsockopt+0x9b/0x140 net/ipv6/ipv6_sockglue.c:885
> > > [<      none      >] udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1425
> > > [<      none      >] sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2645
> > > [<     inline     >] SYSC_setsockopt net/socket.c:1757
> > > [<      none      >] SyS_setsockopt+0x158/0x240 net/socket.c:1736
> > > [<      none      >] entry_SYSCALL_64_fastpath+0x12/0x71
> > > arch/x86/entry/entry_64.S:185
> > > 
> > > INFO: Slab 0xffffea0001b4db00 objects=20 used=8 fp=0xffff88006d36da08
> > > flags=0x500000000004080
> > > INFO: Object 0xffff88006d36da08 @offset=6664 fp=0xffff88006d36d3e8
> > > CPU: 3 PID: 23958 Comm: executor Tainted: G    B           4.4.0-rc2+ #1
> > > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
> > >  00000000ffffffff ffff88003c32f348 ffffffff81a2bdb0 ffff88003e807840
> > >  ffff88006d36da08 ffff88006d36c000 ffff88003c32f378 ffffffff814541d4
> > >  ffff88003e807840 ffffea0001b4db00 ffff88006d36da08 ffff88006d126000
> > > 
> > > Call Trace:
> > >  [<ffffffff8145b9ae>] __asan_report_load4_noabort+0x3e/0x40
> > > mm/kasan/report.c:279
> > >  [<ffffffff829de1e8>] ip6_setup_cork+0xeb8/0x11a0 net/ipv6/ip6_output.c:1200
> > >  [<ffffffff829e9e2a>] ip6_make_skb+0x19a/0x3b0 net/ipv6/ip6_output.c:1769
> > >  [<ffffffff82a3c3e6>] udpv6_sendmsg+0x11c6/0x2120 net/ipv6/udp.c:1314
> > >  [<ffffffff829038cc>] inet_sendmsg+0x23c/0x340 net/ipv4/af_inet.c:733
> > >  [<     inline     >] sock_sendmsg_nosec net/socket.c:610
> > >  [<ffffffff826adc2a>] sock_sendmsg+0xca/0x110 net/socket.c:620
> > >  [<ffffffff826ae057>] kernel_sendmsg+0x47/0x60 net/socket.c:628
> > >  [<ffffffff826b564a>] sock_no_sendpage+0xfa/0x130 net/core/sock.c:2270
> > >  [<ffffffff826ac6d0>] kernel_sendpage+0x90/0xe0 net/socket.c:3278
> > >  [<ffffffff826ac7c5>] sock_sendpage+0xa5/0xd0 net/socket.c:765
> > >  [<ffffffff814feca4>] pipe_to_sendpage+0x264/0x320 fs/splice.c:720
> > >  [<     inline     >] splice_from_pipe_feed fs/splice.c:772
> > >  [<ffffffff81501435>] __splice_from_pipe+0x235/0x6d0 fs/splice.c:897
> > >  [<ffffffff81504677>] splice_from_pipe+0xf7/0x140 fs/splice.c:932
> > >  [<ffffffff81504700>] generic_splice_sendpage+0x40/0x50 fs/splice.c:1105
> > >  [<     inline     >] do_splice_from fs/splice.c:1124
> > >  [<     inline     >] do_splice fs/splice.c:1400
> > >  [<     inline     >] SYSC_splice fs/splice.c:1703
> > >  [<ffffffff815052f8>] SyS_splice+0x7c8/0x15c0 fs/splice.c:1686
> > >  [<ffffffff82ddc0ae>] entry_SYSCALL_64_fastpath+0x12/0x71
> > > arch/x86/entry/entry_64.S:185
> > > ==================================================================
> > > 
> > > 
> > > On commit 78c4a49a69e910a162b05e4e8727b9bdbf948f13 (Nov 25).
> > > --
> > 
> > Thanks for the report.
> > 
> > Bug probably added in :
> > 
> > commit 03485f2adcde0c2d4e9228b659be78e872486bbb
> > Author: Vlad Yasevich <vyasevich@gmail.com>
> > Date:   Sat Jan 31 10:40:17 2015 -0500
> > 
> >     udpv6: Add lockless sendmsg() support
> >     
> >     This commit adds the same functionaliy to IPv6 that
> >     commit 903ab86d195cca295379699299c5fc10beba31c7
> >     Author: Herbert Xu <herbert@gondor.apana.org.au>
> >     Date:   Tue Mar 1 02:36:48 2011 +0000
> >     
> >         udp: Add lockless transmit path
> >     
> >     added to IPv4.
> >     
> >     UDP transmit path can now run without a socket lock,
> >     thus allowing multiple threads to send to a single socket
> >     more efficiently.
> >     This is only used when corking/MSG_MORE is not used.
> >     
> >     Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
> >     Signed-off-by: David S. Miller <davem@davemloft.net>
> > 
> > 
> 
> Oh well, bug is older than that.
> 
> inet6_sk(sk)->opt handling is completely racy, and has some xchg() calls
> to hide how ugly it is.

I have a patch that looks ready for submission.

While testing it, I also saw a problem in ipv6_update_options(),
calling sk_dst_reset() which directly conflicts with ip6_dst_store()

(ip6_dst_store() uses spin_lock(&sk->sk_dst_lock), which basically
protects councurrent ip6_dst_store() ... :( )



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1279549 — [PATCH net] ipv6: add complete rcu protection around np->opt

FromEric Dumazet <eric.dumazet@gmail.com>
Date2015-11-30 04:40 +0100
Subject[PATCH net] ipv6: add complete rcu protection around np->opt
Message-ID<qAntM-6zI-5@gated-at.bofh.it>
In reply to#1279185
From: Eric Dumazet <edumazet@google.com>

This patch addresses multiple problems :

UDP/RAW sendmsg() need to get a stable struct ipv6_txoptions
while socket is not locked : Other threads can change np->opt
concurrently. Dmitry posted a syzkaller
(http://github.com/google/syzkaller) program desmonstrating
use-after-free.

Starting with TCP/DCCP lockless listeners, tcp_v6_syn_recv_sock()
and dccp_v6_request_recv_sock() also need to use RCU protection
to dereference np->opt once (before calling ipv6_dup_options())

This patch adds full RCU protection to np->opt

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 include/linux/ipv6.h             |    2 -
 include/net/ipv6.h               |   21 +++++++++++++++++-
 net/dccp/ipv6.c                  |   33 ++++++++++++++++++-----------
 net/ipv6/af_inet6.c              |   13 +++++++----
 net/ipv6/datagram.c              |    4 ++-
 net/ipv6/exthdrs.c               |    3 +-
 net/ipv6/inet6_connection_sock.c |   11 +++++++--
 net/ipv6/ipv6_sockglue.c         |   33 +++++++++++++++++++----------
 net/ipv6/raw.c                   |    8 +++++--
 net/ipv6/syncookies.c            |    2 -
 net/ipv6/tcp_ipv6.c              |   28 ++++++++++++++----------
 net/ipv6/udp.c                   |    8 +++++--
 net/l2tp/l2tp_ip6.c              |    8 +++++--
 13 files changed, 122 insertions(+), 52 deletions(-)

diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 0ef2a97ccdb5..402753bccafa 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -227,7 +227,7 @@ struct ipv6_pinfo {
 	struct ipv6_ac_socklist	*ipv6_ac_list;
 	struct ipv6_fl_socklist __rcu *ipv6_fl_list;
 
-	struct ipv6_txoptions	*opt;
+	struct ipv6_txoptions __rcu	*opt;
 	struct sk_buff		*pktoptions;
 	struct sk_buff		*rxpmtu;
 	struct inet6_cork	cork;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index e1a10b0ac0b0..d1da7d7ecb93 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -205,6 +205,7 @@ extern rwlock_t ip6_ra_lock;
  */
 
 struct ipv6_txoptions {
+	atomic_t		refcnt;
 	/* Length of this structure */
 	int			tot_len;
 
@@ -217,7 +218,7 @@ struct ipv6_txoptions {
 	struct ipv6_opt_hdr	*dst0opt;
 	struct ipv6_rt_hdr	*srcrt;	/* Routing Header */
 	struct ipv6_opt_hdr	*dst1opt;
-
+	struct rcu_head		rcu;
 	/* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
 };
 
@@ -252,6 +253,24 @@ struct ipv6_fl_socklist {
 	struct rcu_head			rcu;
 };
 
+static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)
+{
+	struct ipv6_txoptions *opt;
+
+	rcu_read_lock();
+	opt = rcu_dereference(np->opt);
+	if (opt && !atomic_inc_not_zero(&opt->refcnt))
+		opt = NULL;
+	rcu_read_unlock();
+	return opt;
+}
+
+static inline void txopt_put(struct ipv6_txoptions *opt)
+{
+	if (opt && atomic_dec_and_test(&opt->refcnt))
+		kfree_rcu(opt, rcu);
+}
+
 struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label);
 struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
 					 struct ip6_flowlabel *fl,
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index db5fc2440a23..e7e0b9bc2a43 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -202,7 +202,9 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
 	security_req_classify_flow(req, flowi6_to_flowi(&fl6));
 
 
-	final_p = fl6_update_dst(&fl6, np->opt, &final);
+	rcu_read_lock();
+	final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
+	rcu_read_unlock();
 
 	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
 	if (IS_ERR(dst)) {
@@ -219,7 +221,10 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
 							 &ireq->ir_v6_loc_addr,
 							 &ireq->ir_v6_rmt_addr);
 		fl6.daddr = ireq->ir_v6_rmt_addr;
-		err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
+		rcu_read_lock();
+		err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
+			       np->tclass);
+		rcu_read_unlock();
 		err = net_xmit_eval(err);
 	}
 
@@ -387,6 +392,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
 	struct inet_request_sock *ireq = inet_rsk(req);
 	struct ipv6_pinfo *newnp;
 	const struct ipv6_pinfo *np = inet6_sk(sk);
+	struct ipv6_txoptions *opt;
 	struct inet_sock *newinet;
 	struct dccp6_sock *newdp6;
 	struct sock *newsk;
@@ -488,13 +494,15 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
 	 * Yes, keeping reference count would be much more clever, but we make
 	 * one more one thing there: reattach optmem to newsk.
 	 */
-	if (np->opt != NULL)
-		newnp->opt = ipv6_dup_options(newsk, np->opt);
-
+	opt = rcu_dereference(np->opt);
+	if (opt) {
+		opt = ipv6_dup_options(newsk, opt);
+		RCU_INIT_POINTER(newnp->opt, opt);
+	}
 	inet_csk(newsk)->icsk_ext_hdr_len = 0;
-	if (newnp->opt != NULL)
-		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
-						     newnp->opt->opt_flen);
+	if (opt)
+		inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
+						    opt->opt_flen;
 
 	dccp_sync_mss(newsk, dst_mtu(dst));
 
@@ -757,6 +765,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct in6_addr *saddr = NULL, *final_p, final;
+	struct ipv6_txoptions *opt;
 	struct flowi6 fl6;
 	struct dst_entry *dst;
 	int addr_type;
@@ -856,7 +865,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	fl6.fl6_sport = inet->inet_sport;
 	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-	final_p = fl6_update_dst(&fl6, np->opt, &final);
+	opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+	final_p = fl6_update_dst(&fl6, opt, &final);
 
 	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
 	if (IS_ERR(dst)) {
@@ -876,9 +886,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	__ip6_dst_store(sk, dst, NULL, NULL);
 
 	icsk->icsk_ext_hdr_len = 0;
-	if (np->opt != NULL)
-		icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
-					  np->opt->opt_nflen);
+	if (opt)
+		icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
 
 	inet->inet_dport = usin->sin6_port;
 
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 44bb66bde0e2..38d66ddfb937 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -428,9 +428,11 @@ void inet6_destroy_sock(struct sock *sk)
 
 	/* Free tx options */
 
-	opt = xchg(&np->opt, NULL);
-	if (opt)
-		sock_kfree_s(sk, opt, opt->tot_len);
+	opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL);
+	if (opt) {
+		atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+		txopt_put(opt);
+	}
 }
 EXPORT_SYMBOL_GPL(inet6_destroy_sock);
 
@@ -659,7 +661,10 @@ int inet6_sk_rebuild_header(struct sock *sk)
 		fl6.fl6_sport = inet->inet_sport;
 		security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-		final_p = fl6_update_dst(&fl6, np->opt, &final);
+		rcu_read_lock();
+		final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt),
+					 &final);
+		rcu_read_unlock();
 
 		dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
 		if (IS_ERR(dst)) {
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index d70b0238f468..517c55b01ba8 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -167,8 +167,10 @@ ipv4_connected:
 
 	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-	opt = flowlabel ? flowlabel->opt : np->opt;
+	rcu_read_lock();
+	opt = flowlabel ? flowlabel->opt : rcu_dereference(np->opt);
 	final_p = fl6_update_dst(&fl6, opt, &final);
+	rcu_read_unlock();
 
 	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
 	err = 0;
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index ce203b0402be..ea7c4d64a00a 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -727,6 +727,7 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
 			*((char **)&opt2->dst1opt) += dif;
 		if (opt2->srcrt)
 			*((char **)&opt2->srcrt) += dif;
+		atomic_set(&opt2->refcnt, 1);
 	}
 	return opt2;
 }
@@ -790,7 +791,7 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
 		return ERR_PTR(-ENOBUFS);
 
 	memset(opt2, 0, tot_len);
-
+	atomic_set(&opt2->refcnt, 1);
 	opt2->tot_len = tot_len;
 	p = (char *)(opt2 + 1);
 
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 5d1c7cee2cb2..3ff5208772bb 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -78,7 +78,9 @@ struct dst_entry *inet6_csk_route_req(const struct sock *sk,
 	memset(fl6, 0, sizeof(*fl6));
 	fl6->flowi6_proto = proto;
 	fl6->daddr = ireq->ir_v6_rmt_addr;
-	final_p = fl6_update_dst(fl6, np->opt, &final);
+	rcu_read_lock();
+	final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+	rcu_read_unlock();
 	fl6->saddr = ireq->ir_v6_loc_addr;
 	fl6->flowi6_oif = ireq->ir_iif;
 	fl6->flowi6_mark = ireq->ir_mark;
@@ -142,7 +144,9 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
 	fl6->fl6_dport = inet->inet_dport;
 	security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
 
-	final_p = fl6_update_dst(fl6, np->opt, &final);
+	rcu_read_lock();
+	final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+	rcu_read_unlock();
 
 	dst = __inet6_csk_dst_check(sk, np->dst_cookie);
 	if (!dst) {
@@ -175,7 +179,8 @@ int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl_unused
 	/* Restore final destination back after routing done */
 	fl6.daddr = sk->sk_v6_daddr;
 
-	res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
+	res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
+		       np->tclass);
 	rcu_read_unlock();
 	return res;
 }
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 63e6956917c9..4449ad1f8114 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -111,7 +111,8 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
 			icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
 		}
 	}
-	opt = xchg(&inet6_sk(sk)->opt, opt);
+	opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt,
+		   opt);
 	sk_dst_reset(sk);
 
 	return opt;
@@ -231,9 +232,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 				sk->sk_socket->ops = &inet_dgram_ops;
 				sk->sk_family = PF_INET;
 			}
-			opt = xchg(&np->opt, NULL);
-			if (opt)
-				sock_kfree_s(sk, opt, opt->tot_len);
+			opt = xchg((__force struct ipv6_txoptions **)&np->opt,
+				   NULL);
+			if (opt) {
+				atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+				txopt_put(opt);
+			}
 			pktopt = xchg(&np->pktoptions, NULL);
 			kfree_skb(pktopt);
 
@@ -403,7 +407,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 		if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
 			break;
 
-		opt = ipv6_renew_options(sk, np->opt, optname,
+		opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+		opt = ipv6_renew_options(sk, opt, optname,
 					 (struct ipv6_opt_hdr __user *)optval,
 					 optlen);
 		if (IS_ERR(opt)) {
@@ -432,8 +437,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 		retv = 0;
 		opt = ipv6_update_options(sk, opt);
 sticky_done:
-		if (opt)
-			sock_kfree_s(sk, opt, opt->tot_len);
+		if (opt) {
+			atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+			txopt_put(opt);
+		}
 		break;
 	}
 
@@ -486,6 +493,7 @@ sticky_done:
 			break;
 
 		memset(opt, 0, sizeof(*opt));
+		atomic_set(&opt->refcnt, 1);
 		opt->tot_len = sizeof(*opt) + optlen;
 		retv = -EFAULT;
 		if (copy_from_user(opt+1, optval, optlen))
@@ -502,8 +510,10 @@ update:
 		retv = 0;
 		opt = ipv6_update_options(sk, opt);
 done:
-		if (opt)
-			sock_kfree_s(sk, opt, opt->tot_len);
+		if (opt) {
+			atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+			txopt_put(opt);
+		}
 		break;
 	}
 	case IPV6_UNICAST_HOPS:
@@ -1110,10 +1120,11 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
 	case IPV6_RTHDR:
 	case IPV6_DSTOPTS:
 	{
+		struct ipv6_txoptions *opt;
 
 		lock_sock(sk);
-		len = ipv6_getsockopt_sticky(sk, np->opt,
-					     optname, optval, len);
+		opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+		len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len);
 		release_sock(sk);
 		/* check if ipv6_getsockopt_sticky() returns err code */
 		if (len < 0)
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index dc65ec198f7c..99140986e887 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -733,6 +733,7 @@ static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
 
 static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 {
+	struct ipv6_txoptions *opt_to_free = NULL;
 	struct ipv6_txoptions opt_space;
 	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
 	struct in6_addr *daddr, *final_p, final;
@@ -839,8 +840,10 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 		if (!(opt->opt_nflen|opt->opt_flen))
 			opt = NULL;
 	}
-	if (!opt)
-		opt = np->opt;
+	if (!opt) {
+		opt = txopt_get(np);
+		opt_to_free = opt;
+		}
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 	opt = ipv6_fixup_options(&opt_space, opt);
@@ -906,6 +909,7 @@ done:
 	dst_release(dst);
 out:
 	fl6_sock_release(flowlabel);
+	txopt_put(opt_to_free);
 	return err < 0 ? err : len;
 do_confirm:
 	dst_confirm(dst);
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index bb8f2fa1c7fb..eaf7ac496d50 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -222,7 +222,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 		memset(&fl6, 0, sizeof(fl6));
 		fl6.flowi6_proto = IPPROTO_TCP;
 		fl6.daddr = ireq->ir_v6_rmt_addr;
-		final_p = fl6_update_dst(&fl6, np->opt, &final);
+		final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
 		fl6.saddr = ireq->ir_v6_loc_addr;
 		fl6.flowi6_oif = sk->sk_bound_dev_if;
 		fl6.flowi6_mark = ireq->ir_mark;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index c5429a636f1a..6a50bb4a0dae 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -120,6 +120,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct in6_addr *saddr = NULL, *final_p, final;
+	struct ipv6_txoptions *opt;
 	struct flowi6 fl6;
 	struct dst_entry *dst;
 	int addr_type;
@@ -235,7 +236,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 	fl6.fl6_dport = usin->sin6_port;
 	fl6.fl6_sport = inet->inet_sport;
 
-	final_p = fl6_update_dst(&fl6, np->opt, &final);
+	opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+	final_p = fl6_update_dst(&fl6, opt, &final);
 
 	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
@@ -263,9 +265,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 		tcp_fetch_timewait_stamp(sk, dst);
 
 	icsk->icsk_ext_hdr_len = 0;
-	if (np->opt)
-		icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
-					  np->opt->opt_nflen);
+	if (opt)
+		icsk->icsk_ext_hdr_len = opt->opt_flen +
+					 opt->opt_nflen;
 
 	tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
@@ -461,7 +463,8 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
 		if (np->repflow && ireq->pktopts)
 			fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
 
-		err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
+		err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt),
+			       np->tclass);
 		err = net_xmit_eval(err);
 	}
 
@@ -972,6 +975,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
 	struct inet_request_sock *ireq;
 	struct ipv6_pinfo *newnp;
 	const struct ipv6_pinfo *np = inet6_sk(sk);
+	struct ipv6_txoptions *opt;
 	struct tcp6_sock *newtcp6sk;
 	struct inet_sock *newinet;
 	struct tcp_sock *newtp;
@@ -1098,13 +1102,15 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
 	   but we make one more one thing there: reattach optmem
 	   to newsk.
 	 */
-	if (np->opt)
-		newnp->opt = ipv6_dup_options(newsk, np->opt);
-
+	opt = rcu_dereference(np->opt);
+	if (opt) {
+		opt = ipv6_dup_options(newsk, opt);
+		RCU_INIT_POINTER(newnp->opt, opt);
+	}
 	inet_csk(newsk)->icsk_ext_hdr_len = 0;
-	if (newnp->opt)
-		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
-						     newnp->opt->opt_flen);
+	if (opt)
+		inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
+						    opt->opt_flen;
 
 	tcp_ca_openreq_child(newsk, dst);
 
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 01bcb49619ee..9da3287a3923 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1110,6 +1110,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
 	struct in6_addr *daddr, *final_p, final;
 	struct ipv6_txoptions *opt = NULL;
+	struct ipv6_txoptions *opt_to_free = NULL;
 	struct ip6_flowlabel *flowlabel = NULL;
 	struct flowi6 fl6;
 	struct dst_entry *dst;
@@ -1263,8 +1264,10 @@ do_udp_sendmsg:
 			opt = NULL;
 		connected = 0;
 	}
-	if (!opt)
-		opt = np->opt;
+	if (!opt) {
+		opt = txopt_get(np);
+		opt_to_free = opt;
+	}
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 	opt = ipv6_fixup_options(&opt_space, opt);
@@ -1373,6 +1376,7 @@ release_dst:
 out:
 	dst_release(dst);
 	fl6_sock_release(flowlabel);
+	txopt_put(opt_to_free);
 	if (!err)
 		return len;
 	/*
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index aca38d8aed8e..a2c8747d2936 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -486,6 +486,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name);
 	struct in6_addr *daddr, *final_p, final;
 	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct ipv6_txoptions *opt_to_free = NULL;
 	struct ipv6_txoptions *opt = NULL;
 	struct ip6_flowlabel *flowlabel = NULL;
 	struct dst_entry *dst = NULL;
@@ -575,8 +576,10 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 			opt = NULL;
 	}
 
-	if (opt == NULL)
-		opt = np->opt;
+	if (!opt) {
+		opt = txopt_get(np);
+		opt_to_free = opt;
+	}
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 	opt = ipv6_fixup_options(&opt_space, opt);
@@ -631,6 +634,7 @@ done:
 	dst_release(dst);
 out:
 	fl6_sock_release(flowlabel);
+	txopt_put(opt_to_free);
 
 	return err < 0 ? err : len;
 


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1280790 — Re: [PATCH net] ipv6: add complete rcu protection around np->opt

FromHannes Frederic Sowa <hannes@stressinduktion.org>
Date2015-12-01 12:20 +0100
SubjectRe: [PATCH net] ipv6: add complete rcu protection around np->opt
Message-ID<qAR8v-sX-29@gated-at.bofh.it>
In reply to#1279549
Hi Eric,

On Mon, Nov 30, 2015, at 04:37, Eric Dumazet wrote:
> -                       opt = xchg(&np->opt, NULL);
> -                       if (opt)
> -                               sock_kfree_s(sk, opt, opt->tot_len);
> +                       opt = xchg((__force struct ipv6_txoptions
> **)&np->opt,
> +                                  NULL);
> +                       if (opt) {
> +                               atomic_sub(opt->tot_len,
> &sk->sk_omem_alloc);
> +                               txopt_put(opt);
> +                       }
>  			pktopt = xchg(&np->pktoptions, NULL);
>  			kfree_skb(pktopt);

Is here something special going on (because of the xchg). I don't see
why you cannot simply use a RCU_INIT_POINTER?

Thanks,
Hannes
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1280846 — Re: [PATCH net] ipv6: add complete rcu protection around np->opt

FromEric Dumazet <eric.dumazet@gmail.com>
Date2015-12-01 14:10 +0100
SubjectRe: [PATCH net] ipv6: add complete rcu protection around np->opt
Message-ID<qASQX-1Dr-45@gated-at.bofh.it>
In reply to#1280790
On Tue, 2015-12-01 at 12:11 +0100, Hannes Frederic Sowa wrote:
> Hi Eric,
> 
> On Mon, Nov 30, 2015, at 04:37, Eric Dumazet wrote:
> > -                       opt = xchg(&np->opt, NULL);
> > -                       if (opt)
> > -                               sock_kfree_s(sk, opt, opt->tot_len);
> > +                       opt = xchg((__force struct ipv6_txoptions
> > **)&np->opt,
> > +                                  NULL);
> > +                       if (opt) {
> > +                               atomic_sub(opt->tot_len,
> > &sk->sk_omem_alloc);
> > +                               txopt_put(opt);
> > +                       }
> >  			pktopt = xchg(&np->pktoptions, NULL);
> >  			kfree_skb(pktopt);
> 
> Is here something special going on (because of the xchg). I don't see
> why you cannot simply use a RCU_INIT_POINTER?
> 
> Thanks,
> Hannes

Yes, I mentioned this earlier, and will be addressed in net-next tree
later.

(Same for np->pktoptions)

The xchg() here does not bring additional protection as we are the last
user of np.

Thanks.




--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1280854 — Re: [PATCH net] ipv6: add complete rcu protection around np->opt

FromHannes Frederic Sowa <hannes@stressinduktion.org>
Date2015-12-01 14:20 +0100
SubjectRe: [PATCH net] ipv6: add complete rcu protection around np->opt
Message-ID<qAT0B-1GT-11@gated-at.bofh.it>
In reply to#1280846
On Tue, Dec 1, 2015, at 14:05, Eric Dumazet wrote:
> On Tue, 2015-12-01 at 12:11 +0100, Hannes Frederic Sowa wrote:
> > Hi Eric,
> > 
> > On Mon, Nov 30, 2015, at 04:37, Eric Dumazet wrote:
> > > -                       opt = xchg(&np->opt, NULL);
> > > -                       if (opt)
> > > -                               sock_kfree_s(sk, opt, opt->tot_len);
> > > +                       opt = xchg((__force struct ipv6_txoptions
> > > **)&np->opt,
> > > +                                  NULL);
> > > +                       if (opt) {
> > > +                               atomic_sub(opt->tot_len,
> > > &sk->sk_omem_alloc);
> > > +                               txopt_put(opt);
> > > +                       }
> > >  			pktopt = xchg(&np->pktoptions, NULL);
> > >  			kfree_skb(pktopt);
> > 
> > Is here something special going on (because of the xchg). I don't see
> > why you cannot simply use a RCU_INIT_POINTER?
> > 
> > Thanks,
> > Hannes
> 
> Yes, I mentioned this earlier, and will be addressed in net-next tree
> later.
> 
> (Same for np->pktoptions)
> 
> The xchg() here does not bring additional protection as we are the last
> user of np.
> 
> Thanks.

Ah, sorry, maybe I missed it. Just reviewed the patches after a longer
weekend here.

The rest looked fine to me:

Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>

Thanks!
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1282697 — Re: [PATCH net] ipv6: add complete rcu protection around np->opt

FromDavid Miller <davem@davemloft.net>
Date2015-12-03 05:40 +0100
SubjectRe: [PATCH net] ipv6: add complete rcu protection around np->opt
Message-ID<qBtQu-6V-7@gated-at.bofh.it>
In reply to#1279549
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Sun, 29 Nov 2015 19:37:57 -0800

> From: Eric Dumazet <edumazet@google.com>
> 
> This patch addresses multiple problems :
> 
> UDP/RAW sendmsg() need to get a stable struct ipv6_txoptions
> while socket is not locked : Other threads can change np->opt
> concurrently. Dmitry posted a syzkaller
> (http://github.com/google/syzkaller) program desmonstrating
> use-after-free.
> 
> Starting with TCP/DCCP lockless listeners, tcp_v6_syn_recv_sock()
> and dccp_v6_request_recv_sock() also need to use RCU protection
> to dereference np->opt once (before calling ipv6_dup_options())
> 
> This patch adds full RCU protection to np->opt
> 
> Reported-by: Dmitry Vyukov <dvyukov@google.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>

Applied and queued up for -stable.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1282716 — Re: [PATCH net] ipv6: add complete rcu protection around np->opt

FromEric Dumazet <eric.dumazet@gmail.com>
Date2015-12-03 06:40 +0100
SubjectRe: [PATCH net] ipv6: add complete rcu protection around np->opt
Message-ID<qBuMx-JD-1@gated-at.bofh.it>
In reply to#1282697
On Wed, 2015-12-02 at 23:38 -0500, David Miller wrote:
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Sun, 29 Nov 2015 19:37:57 -0800
> 
> > From: Eric Dumazet <edumazet@google.com>
> > 
> > This patch addresses multiple problems :
> > 
> > UDP/RAW sendmsg() need to get a stable struct ipv6_txoptions
> > while socket is not locked : Other threads can change np->opt
> > concurrently. Dmitry posted a syzkaller
> > (http://github.com/google/syzkaller) program desmonstrating
> > use-after-free.
> > 
> > Starting with TCP/DCCP lockless listeners, tcp_v6_syn_recv_sock()
> > and dccp_v6_request_recv_sock() also need to use RCU protection
> > to dereference np->opt once (before calling ipv6_dup_options())
> > 
> > This patch adds full RCU protection to np->opt
> > 
> > Reported-by: Dmitry Vyukov <dvyukov@google.com>
> > Signed-off-by: Eric Dumazet <edumazet@google.com>
> 
> Applied and queued up for -stable.

Thanks David.

I will send a followup patch, as I missed the sctp part, now triggering
following sparse warnings.

  CHECK   net/sctp/ipv6.c
net/sctp/ipv6.c:223:41: warning: incorrect type in argument 4 (different address spaces)
net/sctp/ipv6.c:223:41:    expected struct ipv6_txoptions *opt
net/sctp/ipv6.c:223:41:    got struct ipv6_txoptions [noderef] <asn:4>*opt
net/sctp/ipv6.c:265:41: warning: incorrect type in argument 2 (different address spaces)
net/sctp/ipv6.c:265:41:    expected struct ipv6_txoptions const *opt
net/sctp/ipv6.c:265:41:    got struct ipv6_txoptions [noderef] <asn:4>*opt
net/sctp/ipv6.c:324:49: warning: incorrect type in argument 2 (different address spaces)
net/sctp/ipv6.c:324:49:    expected struct ipv6_txoptions const *opt
net/sctp/ipv6.c:324:49:    got struct ipv6_txoptions [noderef] <asn:4>*opt



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web