diff --git a/debian/changelog b/debian/changelog index ee2c5c441..094c951ed 100644 --- a/debian/changelog +++ b/debian/changelog @@ -237,6 +237,7 @@ linux (4.5.1-1) UNRELEASED; urgency=medium * netfilter: x_tables: Fix parsing of IPT_SO_SET_REPLACE blobs (CVE-2016-3134) - validate e->target_offset early - make sure e->next_offset covers remaining blob size + * ipv4: Don't do expensive useless work during inetdev destroy (CVE-2016-3156) [ Aurelien Jarno ] * [mipsel/mips/config.loongson-2f] Disable VIDEO_CX23885, VIDEO_IVTV, diff --git a/debian/patches/bugfix/all/ipv4-don-t-do-expensive-useless-work-during-inetdev-.patch b/debian/patches/bugfix/all/ipv4-don-t-do-expensive-useless-work-during-inetdev-.patch new file mode 100644 index 000000000..581301c59 --- /dev/null +++ b/debian/patches/bugfix/all/ipv4-don-t-do-expensive-useless-work-during-inetdev-.patch @@ -0,0 +1,94 @@ +From: "David S. Miller" +Date: Sun, 13 Mar 2016 23:28:00 -0400 +Subject: ipv4: Don't do expensive useless work during inetdev destroy. +Origin: https://git.kernel.org/linus/fbd40ea0180a2d328c5adc61414dc8bab9335ce2 + +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 +Signed-off-by: David S. Miller +Tested-by: Cyrill Gorcunov +--- + net/ipv4/devinet.c | 4 ++++ + net/ipv4/fib_frontend.c | 4 ++++ + net/ipv4/netfilter/nf_nat_masquerade_ipv4.c | 12 ++++++++++-- + 3 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c +index 65e76a48382c..e333bc86bd39 100644 +--- a/net/ipv4/devinet.c ++++ b/net/ipv4/devinet.c +@@ -334,6 +334,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 + **/ +@@ -380,6 +383,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 473447593060..21add552e56a 100644 +--- a/net/ipv4/fib_frontend.c ++++ b/net/ipv4/fib_frontend.c +@@ -922,6 +922,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 :-) + * +@@ -997,6 +1000,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/nf_nat_masquerade_ipv4.c b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c +index c6eb42100e9a..ea91058b5f6f 100644 +--- a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c ++++ b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c +@@ -108,10 +108,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); + } + diff --git a/debian/patches/series b/debian/patches/series index 2d1301184..7a725df65 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -140,3 +140,4 @@ bugfix/all/tools-lib-traceevent-fix-use-of-uninitialized-variables.patch bugfix/all/scripts-fix-x.509-pem-support-in-sign-file.patch bugfix/all/netfilter-x_tables-validate-e-target_offset-early.patch bugfix/all/netfilter-x_tables-make-sure-e-next_offset-covers-re.patch +bugfix/all/ipv4-don-t-do-expensive-useless-work-during-inetdev-.patch