lkml.org 
[lkml]   [2021]   [Jul]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.13 131/223] udp: check encap socket in __udp_lib_err
    Date
    From: Vadim Fedorenko <vfedorenko@novek.ru>

    [ Upstream commit 9bfce73c8921c92a9565562e6e7d458d37b7ce80 ]

    Commit d26796ae5894 ("udp: check udp sock encap_type in __udp_lib_err")
    added checks for encapsulated sockets but it broke cases when there is
    no implementation of encap_err_lookup for encapsulation, i.e. ESP in
    UDP encapsulation. Fix it by calling encap_err_lookup only if socket
    implements this method otherwise treat it as legal socket.

    Fixes: d26796ae5894 ("udp: check udp sock encap_type in __udp_lib_err")
    Signed-off-by: Vadim Fedorenko <vfedorenko@novek.ru>
    Reviewed-by: Xin Long <lucien.xin@gmail.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    net/ipv4/udp.c | 25 +++++++++++++++++++------
    net/ipv6/udp.c | 25 +++++++++++++++++++------
    2 files changed, 38 insertions(+), 12 deletions(-)

    diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
    index ca9cf1051b1e..568dc31a0467 100644
    --- a/net/ipv4/udp.c
    +++ b/net/ipv4/udp.c
    @@ -645,10 +645,12 @@ static struct sock *__udp4_lib_err_encap(struct net *net,
    const struct iphdr *iph,
    struct udphdr *uh,
    struct udp_table *udptable,
    + struct sock *sk,
    struct sk_buff *skb, u32 info)
    {
    + int (*lookup)(struct sock *sk, struct sk_buff *skb);
    int network_offset, transport_offset;
    - struct sock *sk;
    + struct udp_sock *up;

    network_offset = skb_network_offset(skb);
    transport_offset = skb_transport_offset(skb);
    @@ -659,18 +661,28 @@ static struct sock *__udp4_lib_err_encap(struct net *net,
    /* Transport header needs to point to the UDP header */
    skb_set_transport_header(skb, iph->ihl << 2);

    + if (sk) {
    + up = udp_sk(sk);
    +
    + lookup = READ_ONCE(up->encap_err_lookup);
    + if (lookup && lookup(sk, skb))
    + sk = NULL;
    +
    + goto out;
    + }
    +
    sk = __udp4_lib_lookup(net, iph->daddr, uh->source,
    iph->saddr, uh->dest, skb->dev->ifindex, 0,
    udptable, NULL);
    if (sk) {
    - int (*lookup)(struct sock *sk, struct sk_buff *skb);
    - struct udp_sock *up = udp_sk(sk);
    + up = udp_sk(sk);

    lookup = READ_ONCE(up->encap_err_lookup);
    if (!lookup || lookup(sk, skb))
    sk = NULL;
    }

    +out:
    if (!sk)
    sk = ERR_PTR(__udp4_lib_err_encap_no_sk(skb, info));

    @@ -707,15 +719,16 @@ int __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
    sk = __udp4_lib_lookup(net, iph->daddr, uh->dest,
    iph->saddr, uh->source, skb->dev->ifindex,
    inet_sdif(skb), udptable, NULL);
    +
    if (!sk || udp_sk(sk)->encap_type) {
    /* No socket for error: try tunnels before discarding */
    - sk = ERR_PTR(-ENOENT);
    if (static_branch_unlikely(&udp_encap_needed_key)) {
    - sk = __udp4_lib_err_encap(net, iph, uh, udptable, skb,
    + sk = __udp4_lib_err_encap(net, iph, uh, udptable, sk, skb,
    info);
    if (!sk)
    return 0;
    - }
    + } else
    + sk = ERR_PTR(-ENOENT);

    if (IS_ERR(sk)) {
    __ICMP_INC_STATS(net, ICMP_MIB_INERRORS);
    diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
    index 6774e776228c..2d3bd4a9b0d0 100644
    --- a/net/ipv6/udp.c
    +++ b/net/ipv6/udp.c
    @@ -502,12 +502,14 @@ static struct sock *__udp6_lib_err_encap(struct net *net,
    const struct ipv6hdr *hdr, int offset,
    struct udphdr *uh,
    struct udp_table *udptable,
    + struct sock *sk,
    struct sk_buff *skb,
    struct inet6_skb_parm *opt,
    u8 type, u8 code, __be32 info)
    {
    + int (*lookup)(struct sock *sk, struct sk_buff *skb);
    int network_offset, transport_offset;
    - struct sock *sk;
    + struct udp_sock *up;

    network_offset = skb_network_offset(skb);
    transport_offset = skb_transport_offset(skb);
    @@ -518,18 +520,28 @@ static struct sock *__udp6_lib_err_encap(struct net *net,
    /* Transport header needs to point to the UDP header */
    skb_set_transport_header(skb, offset);

    + if (sk) {
    + up = udp_sk(sk);
    +
    + lookup = READ_ONCE(up->encap_err_lookup);
    + if (lookup && lookup(sk, skb))
    + sk = NULL;
    +
    + goto out;
    + }
    +
    sk = __udp6_lib_lookup(net, &hdr->daddr, uh->source,
    &hdr->saddr, uh->dest,
    inet6_iif(skb), 0, udptable, skb);
    if (sk) {
    - int (*lookup)(struct sock *sk, struct sk_buff *skb);
    - struct udp_sock *up = udp_sk(sk);
    + up = udp_sk(sk);

    lookup = READ_ONCE(up->encap_err_lookup);
    if (!lookup || lookup(sk, skb))
    sk = NULL;
    }

    +out:
    if (!sk) {
    sk = ERR_PTR(__udp6_lib_err_encap_no_sk(skb, opt, type, code,
    offset, info));
    @@ -558,16 +570,17 @@ int __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,

    sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source,
    inet6_iif(skb), inet6_sdif(skb), udptable, NULL);
    +
    if (!sk || udp_sk(sk)->encap_type) {
    /* No socket for error: try tunnels before discarding */
    - sk = ERR_PTR(-ENOENT);
    if (static_branch_unlikely(&udpv6_encap_needed_key)) {
    sk = __udp6_lib_err_encap(net, hdr, offset, uh,
    - udptable, skb,
    + udptable, sk, skb,
    opt, type, code, info);
    if (!sk)
    return 0;
    - }
    + } else
    + sk = ERR_PTR(-ENOENT);

    if (IS_ERR(sk)) {
    __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev),
    --
    2.30.2


    \
     
     \ /
      Last update: 2021-07-26 18:43    [W:2.582 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site