lkml.org 
[lkml]   [2015]   [Sep]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.14 57/84] ipv6: lock socket in ip6_datagram_connect()
    Date
    3.14-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Eric Dumazet <edumazet@google.com>

    [ Upstream commit 03645a11a570d52e70631838cb786eb4253eb463 ]

    ip6_datagram_connect() is doing a lot of socket changes without
    socket being locked.

    This looks wrong, at least for udp_lib_rehash() which could corrupt
    lists because of concurrent udp_sk(sk)->udp_portaddr_hash accesses.

    Signed-off-by: Eric Dumazet <edumazet@google.com>
    Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    include/net/ip.h | 1 +
    net/ipv4/datagram.c | 16 ++++++++++++----
    net/ipv6/datagram.c | 20 +++++++++++++++-----
    3 files changed, 28 insertions(+), 9 deletions(-)

    --- a/include/net/ip.h
    +++ b/include/net/ip.h
    @@ -154,6 +154,7 @@ static inline __u8 get_rtconn_flags(stru
    }

    /* datagram.c */
    +int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
    int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);

    void ip4_datagram_release_cb(struct sock *sk);
    --- a/net/ipv4/datagram.c
    +++ b/net/ipv4/datagram.c
    @@ -20,7 +20,7 @@
    #include <net/route.h>
    #include <net/tcp_states.h>

    -int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
    +int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
    {
    struct inet_sock *inet = inet_sk(sk);
    struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
    @@ -39,8 +39,6 @@ int ip4_datagram_connect(struct sock *sk

    sk_dst_reset(sk);

    - lock_sock(sk);
    -
    oif = sk->sk_bound_dev_if;
    saddr = inet->inet_saddr;
    if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
    @@ -81,9 +79,19 @@ int ip4_datagram_connect(struct sock *sk
    sk_dst_set(sk, &rt->dst);
    err = 0;
    out:
    - release_sock(sk);
    return err;
    }
    +EXPORT_SYMBOL(__ip4_datagram_connect);
    +
    +int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
    +{
    + int res;
    +
    + lock_sock(sk);
    + res = __ip4_datagram_connect(sk, uaddr, addr_len);
    + release_sock(sk);
    + return res;
    +}
    EXPORT_SYMBOL(ip4_datagram_connect);

    /* Because UDP xmit path can manipulate sk_dst_cache without holding
    --- a/net/ipv6/datagram.c
    +++ b/net/ipv6/datagram.c
    @@ -40,7 +40,7 @@ static bool ipv6_mapped_addr_any(const s
    return ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0);
    }

    -int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
    +static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
    {
    struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
    struct inet_sock *inet = inet_sk(sk);
    @@ -56,7 +56,7 @@ int ip6_datagram_connect(struct sock *sk
    if (usin->sin6_family == AF_INET) {
    if (__ipv6_only_sock(sk))
    return -EAFNOSUPPORT;
    - err = ip4_datagram_connect(sk, uaddr, addr_len);
    + err = __ip4_datagram_connect(sk, uaddr, addr_len);
    goto ipv4_connected;
    }

    @@ -98,9 +98,9 @@ int ip6_datagram_connect(struct sock *sk
    sin.sin_addr.s_addr = daddr->s6_addr32[3];
    sin.sin_port = usin->sin6_port;

    - err = ip4_datagram_connect(sk,
    - (struct sockaddr *) &sin,
    - sizeof(sin));
    + err = __ip4_datagram_connect(sk,
    + (struct sockaddr *) &sin,
    + sizeof(sin));

    ipv4_connected:
    if (err)
    @@ -203,6 +203,16 @@ out:
    fl6_sock_release(flowlabel);
    return err;
    }
    +
    +int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
    +{
    + int res;
    +
    + lock_sock(sk);
    + res = __ip6_datagram_connect(sk, uaddr, addr_len);
    + release_sock(sk);
    + return res;
    +}
    EXPORT_SYMBOL_GPL(ip6_datagram_connect);

    int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr,



    \
     
     \ /
      Last update: 2015-09-29 17:41    [W:4.858 / U:0.032 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site