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 for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 6 Feb 2020 18:50:40 -0800
From:   Eric Dumazet <edumazet@...gle.com>
To:     David Miller <davem@...emloft.net>
Cc:     netdev <netdev@...r.kernel.org>,
        Eric Dumazet <eric.dumazet@...il.com>,
        syzbot <syzkaller@...glegroups.com>, maximmi@...lanox.com
Subject: Re: [PATCH net] ipv6/addrconf: fix potential NULL deref in inet6_set_link_af()

On Thu, Feb 6, 2020 at 7:18 AM Eric Dumazet <edumazet@...gle.com> wrote:
>
> On Thu, Feb 6, 2020 at 5:13 AM David Miller <davem@...emloft.net> wrote:
> >
> > From: Eric Dumazet <edumazet@...gle.com>
> > Date: Wed,  5 Feb 2020 08:55:44 -0800
> >
> > > __in6_dev_get(dev) called from inet6_set_link_af() can return NULL.
> > >
> > > The needed check has been recently removed, let's add it back.
> >
> > I am having trouble understanding this one.
> >
> > When we have a do_setlink operation the flow is that we first validate
> > the AFs and then invoke setlink operations after that validation.
> >
> > do_setlink() {
> >  ..
> >         err = validate_linkmsg(dev, tb);
> >         if (err < 0)
> >                 return err;
> >  ..
> >         if (tb[IFLA_AF_SPEC]) {
> >  ...
> >                         err = af_ops->set_link_af(dev, af);
> >                         if (err < 0) {
> >                                 rcu_read_unlock();
> >                                 goto errout;
> >                         }
> >
> > By definition, we only get to ->set_link_af() if there is an
> > IFLA_AF_SPEC nested attribute and if we look at the validation
> > performed by validate_linkmsg() it goes:
> >
> >         if (tb[IFLA_AF_SPEC]) {
> >  ...
> >                         if (af_ops->validate_link_af) {
> >                                 err = af_ops->validate_link_af(dev, af);
> >  ...
> >
> > And validate_link_af in net/ipv6/addrconf.c clearly does the
> > following:
> >
> > static int inet6_validate_link_af(const struct net_device *dev,
> >                                   const struct nlattr *nla)
> >  ...
> >         if (dev) {
> >                 idev = __in6_dev_get(dev);
> >                 if (!idev)
> >                         return -EAFNOSUPPORT;
> >         }
> >  ...
> >
> > It checks the idev and makes sure it is not-NULL.
> >
> > I therefore cannot find a path by which we arrive at inet6_set_link_af
> > with a NULL idev.  The above validation code should trap it.
> >
> > Please explain.
> >
>
> I can give a repro if that helps.
>
> (I have to run, I might have more time later)
>


If I understood the repro well enough, it seems it sets the device MTU
to 1023, thus IPV6 is automatically disabled. (as mtu < 1280)

do_setlink()
...
err = validate_linkmsg(dev, tb); /* OK at this point */
...
if (tb[IFLA_MTU]) {
    err = dev_set_mtu_ext(dev, nla_get_u32(tb[IFLA_MTU]), extack);
    if (err < 0)
          goto errout;
    status |= DO_SETLINK_MODIFIED;
}
if (tb[IFLA_AF_SPEC]) {
   ...
   err = af_ops->set_link_af(dev, af);
   ->inet6_set_link_af() // CRASH because idev is NULL


Please note that IPv4 is immune to the bug since inet_set_link_af() does :

struct in_device *in_dev = __in_dev_get_rcu(dev);
if (!in_dev)
    return -EAFNOSUPPORT;

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ