ACK: [PATCH 1/1] ipv4: Don't do expensive useless work during inetdev destroy.
Chris J Arges
chris.j.arges at canonical.com
Mon Apr 18 15:15:35 UTC 2016
Backport looks correct, fixes a local DOS.
--chris
On Mon, Apr 18, 2016 at 03:05:00PM +0100, Luis Henriques wrote:
> From: "David S. Miller" <davem at davemloft.net>
>
> When an inetdev is destroyed, every address assigned to the interface
> is removed. And in this scenerio we do two pointless things which can
> be very expensive if the number of assigned interfaces is large:
>
> 1) Address promotion. We are deleting all addresses, so there is no
> point in doing this.
>
> 2) A full nf conntrack table purge for every address. We only need to
> do this once, as is already caught by the existing
> masq_dev_notifier so masq_inet_event() can skip this.
>
> Reported-by: Solar Designer <solar at openwall.com>
> Signed-off-by: David S. Miller <davem at davemloft.net>
> Tested-by: Cyrill Gorcunov <gorcunov at openvz.org>
> (backported from commit fbd40ea0180a2d328c5adc61414dc8bab9335ce2)
> [ luis: file rename: nf_nat_masquerade_ipv4.c -> ipt_MASQUERADE.c ]
> CVE-2016-3156
> BugLink: https://bugs.launchpad.net/bugs/1558847
> Signed-off-by: Luis Henriques <luis.henriques at canonical.com>
> ---
> net/ipv4/devinet.c | 4 ++++
> net/ipv4/fib_frontend.c | 4 ++++
> net/ipv4/netfilter/ipt_MASQUERADE.c | 12 ++++++++++--
> 3 files changed, 18 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
> index 68447109000f..6678bebb82c8 100644
> --- a/net/ipv4/devinet.c
> +++ b/net/ipv4/devinet.c
> @@ -328,6 +328,9 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
>
> ASSERT_RTNL();
>
> + if (in_dev->dead)
> + goto no_promotions;
> +
> /* 1. Deleting primary ifaddr forces deletion all secondaries
> * unless alias promotion is set
> **/
> @@ -374,6 +377,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
> fib_del_ifaddr(ifa, ifa1);
> }
>
> +no_promotions:
> /* 2. Unlink it */
>
> *ifap = ifa1->ifa_next;
> diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
> index c7539e22868b..4d4952129bc1 100644
> --- a/net/ipv4/fib_frontend.c
> +++ b/net/ipv4/fib_frontend.c
> @@ -812,6 +812,9 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
> subnet = 1;
> }
>
> + if (in_dev->dead)
> + goto no_promotions;
> +
> /* Deletion is more complicated than add.
> * We should take care of not to delete too much :-)
> *
> @@ -887,6 +890,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
> }
> }
>
> +no_promotions:
> if (!(ok & BRD_OK))
> fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
> if (subnet && ifa->ifa_prefixlen < 31) {
> diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
> index 00352ce0f0de..3bc1c98aa2f0 100644
> --- a/net/ipv4/netfilter/ipt_MASQUERADE.c
> +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
> @@ -128,10 +128,18 @@ static int masq_inet_event(struct notifier_block *this,
> unsigned long event,
> void *ptr)
> {
> - struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
> + struct in_device *idev = ((struct in_ifaddr *)ptr)->ifa_dev;
> struct netdev_notifier_info info;
>
> - netdev_notifier_info_init(&info, dev);
> + /* The masq_dev_notifier will catch the case of the device going
> + * down. So if the inetdev is dead and being destroyed we have
> + * no work to do. Otherwise this is an individual address removal
> + * and we have to perform the flush.
> + */
> + if (idev->dead)
> + return NOTIFY_DONE;
> +
> + netdev_notifier_info_init(&info, idev->dev);
> return masq_device_event(this, event, &info);
> }
>
>
> --
> kernel-team mailing list
> kernel-team at lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
>
More information about the kernel-team
mailing list