lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CADvbK_fnOyTVOQ0wopnVZSmbB5ZBkCft1mXWLy=SqKkLYv_q3Q@mail.gmail.com>
Date:   Sat, 17 Jul 2021 14:41:30 -0400
From:   Xin Long <lucien.xin@...il.com>
To:     Vadim Fedorenko <vfedorenko@...ek.ru>
Cc:     David Ahern <dsahern@...nel.org>,
        Willem de Bruijn <willemb@...gle.com>,
        Paolo Abeni <pabeni@...hat.com>,
        Jakub Kicinski <kuba@...nel.org>,
        "David S. Miller" <davem@...emloft.net>,
        network dev <netdev@...r.kernel.org>,
        Hideaki YOSHIFUJI <yoshfuji@...ux-ipv6.org>,
        Marcelo Ricardo Leitner <marcelo.leitner@...il.com>
Subject: Re: [PATCH net v2 1/2] udp: check encap socket in __udp_lib_err_encap

On Fri, Jul 16, 2021 at 6:32 PM Vadim Fedorenko <vfedorenko@...ek.ru> wrote:
>
> On 16.07.2021 19:46, Xin Long wrote:
> > On Fri, Jul 16, 2021 at 6:54 AM Vadim Fedorenko <vfedorenko@...ek.ru> wrote:
> >>
> >> 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@...ek.ru>
> >> ---
> >>   net/ipv4/udp.c | 23 +++++++++++++++++------
> >>   net/ipv6/udp.c | 23 +++++++++++++++++------
> >>   2 files changed, 34 insertions(+), 12 deletions(-)
> >>
> >> diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
> >> index 62cd4cd52e84..963275b94f00 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,12 +661,19 @@ 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))
> >> +                       goto out;
> >> +       }
> >> +
> > Currently SCTP reuses lookup() to handle some of ICMP error packets by itself
> > in lookup(), for these packets it will return 1, in which case we should
> > set sk = NULL, and not let udp4_lib_err() handle these packets again.
> >
> > Can you change this part to this below?
> >
> > +       if (sk) {
> > +               up = udp_sk(sk);
> > +
> > +               lookup = READ_ONCE(up->encap_err_lookup);
> > +               if (lookup && lookup(sk, skb))
> > +                       sk = NULL;
> > +
> > +               goto out;
> > +       }
> > +
> >
> > thanks.
> >
>
> But we have vxlan and geneve with encap_err_lookup handler enabled and which do
> not handle ICMP itself, just checks whether socket is correctly selected. Such
> code could break their implementation
Sorry, I don't see how this will break vxlan and geneve implementation.

It checking 'sk' and calling lookup() here means we believe this sk
should be the correct one (for the case of src == dst port only). So
even if lookup() returns !0, we should NOT go to another
__udp4_lib_lookup() in __udp4_lib_err_encap().

If we don't believe this sk should be the correct one, as the sk was
found with reverse ports, then we should NOT call lookup() with this sk
but call __udp4_lib_lookup() directly in __udp4_lib_err_encap(), as it
currently does, and fix this by checking READ_ONCE(up->encap_err_lookup)
in __udp4_lib_lookup(), as Paolo suggested.

Either way is fine to me, but not this one. what do you think?

Thanks.

>
> >>          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))
> >> @@ -674,6 +683,7 @@ static struct sock *__udp4_lib_err_encap(struct net *net,
> >>          if (!sk)
> >>                  sk = ERR_PTR(__udp4_lib_err_encap_no_sk(skb, info));
> >>
> >> +out:
> >>          skb_set_transport_header(skb, transport_offset);
> >>          skb_set_network_header(skb, network_offset);
> >>
> >> @@ -707,15 +717,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 0cc7ba531b34..0210ec93d21d 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,12 +520,19 @@ 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))
> >> +                       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))
> >> @@ -535,6 +544,7 @@ static struct sock *__udp6_lib_err_encap(struct net *net,
> >>                                                          offset, info));
> >>          }
> >>
> >> +out:
> >>          skb_set_transport_header(skb, transport_offset);
> >>          skb_set_network_header(skb, network_offset);
> >>
> >> @@ -558,16 +568,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.18.4
> >>
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ