Update to 3.13.10

svn path=/dists/sid/linux/; revision=21234
This commit is contained in:
Ben Hutchings 2014-04-14 21:12:50 +00:00
parent ca418520c6
commit 3785b88bc1
13 changed files with 40 additions and 729 deletions

43
debian/changelog vendored
View File

@ -1,4 +1,4 @@
linux (3.13.9-1) UNRELEASED; urgency=medium
linux (3.13.10-1) UNRELEASED; urgency=medium
* New upstream stable update:
http://www.kernel.org/pub/linux/kernel/v3.x/ChangeLog-3.13.8
@ -40,10 +40,43 @@ linux (3.13.9-1) UNRELEASED; urgency=medium
- cgroup: protect modifications to cgroup_idr with cgroup_mutex
- netfilter: nf_conntrack_dccp: fix skb_header_pointer API usages
(CVE-2014-2523)
[ Ben Hutchings ]
* vhost: fix total length when packets are too short (CVE-2014-0077)
* vhost: validate vhost_get_vq_desc return value (CVE-2014-0055)
http://www.kernel.org/pub/linux/kernel/v3.x/ChangeLog-3.13.10
- selinux: correctly label /proc inodes in use before the policy is loaded
- net: sctp: fix skb leakage in COOKIE ECHO path of chunk->auth_chunk
- bridge: multicast: add sanity check for query source addresses
- tipc: allow connection shutdown callback to be invoked in advance
- tipc: fix connection refcount leak
- tipc: drop subscriber connection id invalidation
- inet: frag: make sure forced eviction removes all frags
- vlan: Set correct source MAC address with TX VLAN offload enabled
(regression in 3.13)
- tcp: tcp_release_cb() should release socket ownership
- bridge: multicast: add sanity check for general query destination
- bridge: multicast: enable snooping on general queries only
- net: socket: error on a negative msg_namelen (regression in 3.11.10)
- bonding: set correct vlan id for alb xmit path (regression in 3.12)
- ipv6: Avoid unnecessary temporary addresses being generated
- net: cdc_ncm: fix control message ordering (regression in 3.13)
- tcp: syncookies: do not use getnstimeofday() (regression in 3.13)
- tipc: fix spinlock recursion bug for failed subscriptions
- ip_tunnel: Fix dst ref-count. (regression in 3.13.7)
- tg3: Do not include vlan acceleration features in vlan_features
- virtio-net: correct error handling of virtqueue_kick()
(regression in 3.13)
- usbnet: include wait queue head in device structure
- vhost: fix total length when packets are too short (CVE-2014-0077)
- vhost: validate vhost_get_vq_desc return value (CVE-2014-0055)
- tcp: fix get_timewait4_sock() delay computation on 64bit
(regression in 3.13)
- xen-netback: remove pointless clause from if statement
- netlink: don't compare the nul-termination in nla_strcmp
- xen-netback: disable rogue vif in kthread context
- net: vxlan: fix crash when interface is created with no group
- rds: prevent dereference of a NULL device in rds_iw_laddr_check
(CVE-2014-2678)
- powernow-k6: disable cache when changing frequency
- [m68k] Skip futex_atomic_cmpxchg_inatomic() test
- crypto: ghash-clmulni-intel - use C implementation for setkey()
-- Ben Hutchings <ben@decadent.org.uk> Mon, 31 Mar 2014 21:12:56 +0100

View File

@ -5,6 +5,8 @@ ignore-changes:
module:drivers/target/iscsi/iscsi_target_mod
tcp_cong_avoid_ai
tcp_slow_start
# Not expected to be used by OOT drivers
module:drivers/net/usb/*
[base]
arches:

View File

@ -1,68 +0,0 @@
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Mon, 10 Mar 2014 18:29:04 +0200
Subject: [1/5] skbuff: skb_segment: s/frag/nskb_frag/
Origin: https://git.kernel.org/linus/8cb19905e9287a93ce7c2cbbdf742a060b00e219
frag points at nskb, so name it appropriately
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/skbuff.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 5d6236d..60e8cd7 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2876,7 +2876,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
do {
struct sk_buff *nskb;
- skb_frag_t *frag;
+ skb_frag_t *nskb_frag;
int hsize;
int size;
@@ -2969,7 +2969,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
continue;
}
- frag = skb_shinfo(nskb)->frags;
+ nskb_frag = skb_shinfo(nskb)->frags;
skb_copy_from_linear_data_offset(skb, offset,
skb_put(nskb, hsize), hsize);
@@ -2997,13 +2997,13 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
goto err;
}
- *frag = *skb_frag;
- __skb_frag_ref(frag);
- size = skb_frag_size(frag);
+ *nskb_frag = *skb_frag;
+ __skb_frag_ref(nskb_frag);
+ size = skb_frag_size(nskb_frag);
if (pos < offset) {
- frag->page_offset += offset - pos;
- skb_frag_size_sub(frag, offset - pos);
+ nskb_frag->page_offset += offset - pos;
+ skb_frag_size_sub(nskb_frag, offset - pos);
}
skb_shinfo(nskb)->nr_frags++;
@@ -3013,11 +3013,11 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
skb_frag++;
pos += size;
} else {
- skb_frag_size_sub(frag, pos + size - (offset + len));
+ skb_frag_size_sub(nskb_frag, pos + size - (offset + len));
goto skip_fraglist;
}
- frag++;
+ nskb_frag++;
}
skip_fraglist:

View File

@ -1,77 +0,0 @@
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Mon, 10 Mar 2014 18:29:14 +0200
Subject: [2/5] skbuff: skb_segment: s/skb_frag/frag/
Origin: https://git.kernel.org/linus/4e1beba12d094c6c761ba5c49032b9b9e46380e8
skb_frag can in fact point at either skb
or fskb so rename it generally "frag".
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/skbuff.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 60e8cd7..d788a98 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2850,7 +2850,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
struct sk_buff *segs = NULL;
struct sk_buff *tail = NULL;
struct sk_buff *fskb = skb_shinfo(skb)->frag_list;
- skb_frag_t *skb_frag = skb_shinfo(skb)->frags;
+ skb_frag_t *frag = skb_shinfo(skb)->frags;
unsigned int mss = skb_shinfo(skb)->gso_size;
unsigned int doffset = skb->data - skb_mac_header(skb);
unsigned int offset = doffset;
@@ -2896,19 +2896,19 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
i = 0;
nfrags = skb_shinfo(fskb)->nr_frags;
- skb_frag = skb_shinfo(fskb)->frags;
+ frag = skb_shinfo(fskb)->frags;
pos += skb_headlen(fskb);
while (pos < offset + len) {
BUG_ON(i >= nfrags);
- size = skb_frag_size(skb_frag);
+ size = skb_frag_size(frag);
if (pos + size > offset + len)
break;
i++;
pos += size;
- skb_frag++;
+ frag++;
}
nskb = skb_clone(fskb, GFP_ATOMIC);
@@ -2982,7 +2982,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
i = 0;
nfrags = skb_shinfo(fskb)->nr_frags;
- skb_frag = skb_shinfo(fskb)->frags;
+ frag = skb_shinfo(fskb)->frags;
BUG_ON(!nfrags);
@@ -2997,7 +2997,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
goto err;
}
- *nskb_frag = *skb_frag;
+ *nskb_frag = *frag;
__skb_frag_ref(nskb_frag);
size = skb_frag_size(nskb_frag);
@@ -3010,7 +3010,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
if (pos + size <= offset + len) {
i++;
- skb_frag++;
+ frag++;
pos += size;
} else {
skb_frag_size_sub(nskb_frag, pos + size - (offset + len));

View File

@ -1,144 +0,0 @@
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Mon, 10 Mar 2014 18:29:19 +0200
Subject: [3/5] skbuff: skb_segment: s/skb/head_skb/
Origin: https://git.kernel.org/linus/df5771ffefb13f8af5392bd54fd7e2b596a3a357
rename local variable to make it easier to tell at a glance that we are
dealing with a head skb.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/skbuff.c | 46 ++++++++++++++++++++++++----------------------
1 file changed, 24 insertions(+), 22 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d788a98..fdc065d 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2838,41 +2838,42 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum);
/**
* skb_segment - Perform protocol segmentation on skb.
- * @skb: buffer to segment
+ * @head_skb: buffer to segment
* @features: features for the output path (see dev->features)
*
* This function performs segmentation on the given skb. It returns
* a pointer to the first in a list of new skbs for the segments.
* In case of error it returns ERR_PTR(err).
*/
-struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
+struct sk_buff *skb_segment(struct sk_buff *head_skb,
+ netdev_features_t features)
{
struct sk_buff *segs = NULL;
struct sk_buff *tail = NULL;
- struct sk_buff *fskb = skb_shinfo(skb)->frag_list;
- skb_frag_t *frag = skb_shinfo(skb)->frags;
- unsigned int mss = skb_shinfo(skb)->gso_size;
- unsigned int doffset = skb->data - skb_mac_header(skb);
+ struct sk_buff *fskb = skb_shinfo(head_skb)->frag_list;
+ skb_frag_t *frag = skb_shinfo(head_skb)->frags;
+ unsigned int mss = skb_shinfo(head_skb)->gso_size;
+ unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
unsigned int offset = doffset;
- unsigned int tnl_hlen = skb_tnl_header_len(skb);
+ unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
unsigned int headroom;
unsigned int len;
__be16 proto;
bool csum;
int sg = !!(features & NETIF_F_SG);
- int nfrags = skb_shinfo(skb)->nr_frags;
+ int nfrags = skb_shinfo(head_skb)->nr_frags;
int err = -ENOMEM;
int i = 0;
int pos;
- proto = skb_network_protocol(skb);
+ proto = skb_network_protocol(head_skb);
if (unlikely(!proto))
return ERR_PTR(-EINVAL);
csum = !!can_checksum_protocol(features, proto);
- __skb_push(skb, doffset);
- headroom = skb_headroom(skb);
- pos = skb_headlen(skb);
+ __skb_push(head_skb, doffset);
+ headroom = skb_headroom(head_skb);
+ pos = skb_headlen(head_skb);
do {
struct sk_buff *nskb;
@@ -2880,11 +2881,11 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
int hsize;
int size;
- len = skb->len - offset;
+ len = head_skb->len - offset;
if (len > mss)
len = mss;
- hsize = skb_headlen(skb) - offset;
+ hsize = skb_headlen(head_skb) - offset;
if (hsize < 0)
hsize = 0;
if (hsize > len || !sg)
@@ -2933,7 +2934,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
__skb_push(nskb, doffset);
} else {
nskb = __alloc_skb(hsize + doffset + headroom,
- GFP_ATOMIC, skb_alloc_rx_flag(skb),
+ GFP_ATOMIC, skb_alloc_rx_flag(head_skb),
NUMA_NO_NODE);
if (unlikely(!nskb))
@@ -2949,12 +2950,12 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
segs = nskb;
tail = nskb;
- __copy_skb_header(nskb, skb);
- nskb->mac_len = skb->mac_len;
+ __copy_skb_header(nskb, head_skb);
+ nskb->mac_len = head_skb->mac_len;
skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom);
- skb_copy_from_linear_data_offset(skb, -tnl_hlen,
+ skb_copy_from_linear_data_offset(head_skb, -tnl_hlen,
nskb->data - tnl_hlen,
doffset + tnl_hlen);
@@ -2963,7 +2964,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
if (!sg) {
nskb->ip_summed = CHECKSUM_NONE;
- nskb->csum = skb_copy_and_csum_bits(skb, offset,
+ nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
skb_put(nskb, len),
len, 0);
continue;
@@ -2971,10 +2972,11 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
nskb_frag = skb_shinfo(nskb)->frags;
- skb_copy_from_linear_data_offset(skb, offset,
+ skb_copy_from_linear_data_offset(head_skb, offset,
skb_put(nskb, hsize), hsize);
- skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
+ skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags &
+ SKBTX_SHARED_FRAG;
while (pos < offset + len) {
if (i >= nfrags) {
@@ -3031,7 +3033,7 @@ perform_csum_check:
nskb->len - doffset, 0);
nskb->ip_summed = CHECKSUM_NONE;
}
- } while ((offset += len) < skb->len);
+ } while ((offset += len) < head_skb->len);
return segs;

View File

@ -1,79 +0,0 @@
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Mon, 10 Mar 2014 19:27:59 +0200
Subject: [4/5] skbuff: skb_segment: s/fskb/list_skb/
Origin: https://git.kernel.org/linus/1a4cedaf65491e66e1e55b8428c89209da729209
fskb is unrelated to frag: it's coming from
frag_list. Rename it list_skb to avoid confusion.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/skbuff.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index fdc065d..dc4f768 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2850,7 +2850,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
{
struct sk_buff *segs = NULL;
struct sk_buff *tail = NULL;
- struct sk_buff *fskb = skb_shinfo(head_skb)->frag_list;
+ struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list;
skb_frag_t *frag = skb_shinfo(head_skb)->frags;
unsigned int mss = skb_shinfo(head_skb)->gso_size;
unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
@@ -2891,14 +2891,14 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
if (hsize > len || !sg)
hsize = len;
- if (!hsize && i >= nfrags && skb_headlen(fskb) &&
- (skb_headlen(fskb) == len || sg)) {
- BUG_ON(skb_headlen(fskb) > len);
+ if (!hsize && i >= nfrags && skb_headlen(list_skb) &&
+ (skb_headlen(list_skb) == len || sg)) {
+ BUG_ON(skb_headlen(list_skb) > len);
i = 0;
- nfrags = skb_shinfo(fskb)->nr_frags;
- frag = skb_shinfo(fskb)->frags;
- pos += skb_headlen(fskb);
+ nfrags = skb_shinfo(list_skb)->nr_frags;
+ frag = skb_shinfo(list_skb)->frags;
+ pos += skb_headlen(list_skb);
while (pos < offset + len) {
BUG_ON(i >= nfrags);
@@ -2912,8 +2912,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
frag++;
}
- nskb = skb_clone(fskb, GFP_ATOMIC);
- fskb = fskb->next;
+ nskb = skb_clone(list_skb, GFP_ATOMIC);
+ list_skb = list_skb->next;
if (unlikely(!nskb))
goto err;
@@ -2980,15 +2980,15 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
while (pos < offset + len) {
if (i >= nfrags) {
- BUG_ON(skb_headlen(fskb));
+ BUG_ON(skb_headlen(list_skb));
i = 0;
- nfrags = skb_shinfo(fskb)->nr_frags;
- frag = skb_shinfo(fskb)->frags;
+ nfrags = skb_shinfo(list_skb)->nr_frags;
+ frag = skb_shinfo(list_skb)->frags;
BUG_ON(!nfrags);
- fskb = fskb->next;
+ list_skb = list_skb->next;
}
if (unlikely(skb_shinfo(nskb)->nr_frags >=

View File

@ -1,59 +0,0 @@
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Mon, 10 Mar 2014 19:28:08 +0200
Subject: [5/5] skbuff: skb_segment: orphan frags before copying
Origin: https://git.kernel.org/linus/1fd819ecb90cc9b822cd84d3056ddba315d3340f
skb_segment copies frags around, so we need
to copy them carefully to avoid accessing
user memory after reporting completion to userspace
through a callback.
skb_segment doesn't normally happen on datapath:
TSO needs to be disabled - so disabling zero copy
in this case does not look like a big deal.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/skbuff.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index dc4f768..869c7af 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2854,6 +2854,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
skb_frag_t *frag = skb_shinfo(head_skb)->frags;
unsigned int mss = skb_shinfo(head_skb)->gso_size;
unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
+ struct sk_buff *frag_skb = head_skb;
unsigned int offset = doffset;
unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
unsigned int headroom;
@@ -2898,6 +2899,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
i = 0;
nfrags = skb_shinfo(list_skb)->nr_frags;
frag = skb_shinfo(list_skb)->frags;
+ frag_skb = list_skb;
pos += skb_headlen(list_skb);
while (pos < offset + len) {
@@ -2985,6 +2987,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
i = 0;
nfrags = skb_shinfo(list_skb)->nr_frags;
frag = skb_shinfo(list_skb)->frags;
+ frag_skb = list_skb;
BUG_ON(!nfrags);
@@ -2999,6 +3002,9 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
goto err;
}
+ if (unlikely(skb_orphan_frags(frag_skb, GFP_ATOMIC)))
+ goto err;
+
*nskb_frag = *frag;
__skb_frag_ref(nskb_frag);
size = skb_frag_size(nskb_frag);

View File

@ -1,30 +0,0 @@
From: Sabrina Dubroca <sd@queasysnail.net>
Date: Thu, 6 Mar 2014 17:51:57 +0100
Subject: ipv6: don't set DST_NOCOUNT for remotely added routes
Origin: https://git.kernel.org/linus/c88507fbad8055297c1d1e21e599f46960cbee39
DST_NOCOUNT should only be used if an authorized user adds routes
locally. In case of routes which are added on behalf of router
advertisments this flag must not get used as it allows an unlimited
number of routes getting added remotely.
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/ipv6/route.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 11dac21..fba54a4 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1513,7 +1513,7 @@ int ip6_route_add(struct fib6_config *cfg)
if (!table)
goto out;
- rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table);
+ rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
if (!rt) {
err = -ENOMEM;

View File

@ -1,91 +0,0 @@
From: Nikolay Aleksandrov <nikolay@redhat.com>
Date: Mon, 3 Mar 2014 23:19:18 +0100
Subject: net: fix for a race condition in the inet frag code
Origin: https://git.kernel.org/linus/24b9bf43e93e0edd89072da51cf1fab95fc69dec
I stumbled upon this very serious bug while hunting for another one,
it's a very subtle race condition between inet_frag_evictor,
inet_frag_intern and the IPv4/6 frag_queue and expire functions
(basically the users of inet_frag_kill/inet_frag_put).
What happens is that after a fragment has been added to the hash chain
but before it's been added to the lru_list (inet_frag_lru_add) in
inet_frag_intern, it may get deleted (either by an expired timer if
the system load is high or the timer sufficiently low, or by the
fraq_queue function for different reasons) before it's added to the
lru_list, then after it gets added it's a matter of time for the
evictor to get to a piece of memory which has been freed leading to a
number of different bugs depending on what's left there.
I've been able to trigger this on both IPv4 and IPv6 (which is normal
as the frag code is the same), but it's been much more difficult to
trigger on IPv4 due to the protocol differences about how fragments
are treated.
The setup I used to reproduce this is: 2 machines with 4 x 10G bonded
in a RR bond, so the same flow can be seen on multiple cards at the
same time. Then I used multiple instances of ping/ping6 to generate
fragmented packets and flood the machines with them while running
other processes to load the attacked machine.
*It is very important to have the _same flow_ coming in on multiple CPUs
concurrently. Usually the attacked machine would die in less than 30
minutes, if configured properly to have many evictor calls and timeouts
it could happen in 10 minutes or so.
An important point to make is that any caller (frag_queue or timer) of
inet_frag_kill will remove both the timer refcount and the
original/guarding refcount thus removing everything that's keeping the
frag from being freed at the next inet_frag_put. All of this could
happen before the frag was ever added to the LRU list, then it gets
added and the evictor uses a freed fragment.
An example for IPv6 would be if a fragment is being added and is at
the stage of being inserted in the hash after the hash lock is
released, but before inet_frag_lru_add executes (or is able to obtain
the lru lock) another overlapping fragment for the same flow arrives
at a different CPU which finds it in the hash, but since it's
overlapping it drops it invoking inet_frag_kill and thus removing all
guarding refcounts, and afterwards freeing it by invoking
inet_frag_put which removes the last refcount added previously by
inet_frag_find, then inet_frag_lru_add gets executed by
inet_frag_intern and we have a freed fragment in the lru_list.
The fix is simple, just move the lru_add under the hash chain locked
region so when a removing function is called it'll have to wait for
the fragment to be added to the lru_list, and then it'll remove it (it
works because the hash chain removal is done before the lru_list one
and there's no window between the two list adds when the frag can get
dropped). With this fix applied I couldn't kill the same machine in 24
hours with the same setup.
Fixes: 3ef0eb0db4bf ("net: frag, move LRU list maintenance outside of
rwlock")
CC: Florian Westphal <fw@strlen.de>
CC: Jesper Dangaard Brouer <brouer@redhat.com>
CC: David S. Miller <davem@davemloft.net>
Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/ipv4/inet_fragment.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index bb075fc..322dceb 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -278,9 +278,10 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
atomic_inc(&qp->refcnt);
hlist_add_head(&qp->list, &hb->chain);
+ inet_frag_lru_add(nf, qp);
spin_unlock(&hb->chain_lock);
read_unlock(&f->lock);
- inet_frag_lru_add(nf, qp);
+
return qp;
}

View File

@ -1,69 +0,0 @@
From: Eric Dumazet <edumazet@google.com>
Date: Fri, 20 Dec 2013 14:29:08 -0800
Subject: net: use kfree_skb_list() helper
Origin: https://git.kernel.org/linus/289dccbe141e01efc5968fe39a0993c9f611375e
We can use kfree_skb_list() instead of open coding it.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/dev.c | 18 +++---------------
net/core/skbuff.c | 5 +----
2 files changed, 4 insertions(+), 19 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index c482fe8..973c236 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2454,13 +2454,8 @@ static void dev_gso_skb_destructor(struct sk_buff *skb)
{
struct dev_gso_cb *cb;
- do {
- struct sk_buff *nskb = skb->next;
-
- skb->next = nskb->next;
- nskb->next = NULL;
- kfree_skb(nskb);
- } while (skb->next);
+ kfree_skb_list(skb->next);
+ skb->next = NULL;
cb = DEV_GSO_CB(skb);
if (cb->destructor)
@@ -4240,17 +4235,10 @@ EXPORT_SYMBOL(netif_napi_add);
void netif_napi_del(struct napi_struct *napi)
{
- struct sk_buff *skb, *next;
-
list_del_init(&napi->dev_list);
napi_free_frags(napi);
- for (skb = napi->gro_list; skb; skb = next) {
- next = skb->next;
- skb->next = NULL;
- kfree_skb(skb);
- }
-
+ kfree_skb_list(napi->gro_list);
napi->gro_list = NULL;
napi->gro_count = 0;
}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 2b6b863..eb96c2c 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2981,10 +2981,7 @@ perform_csum_check:
return segs;
err:
- while ((skb = segs)) {
- segs = skb->next;
- kfree_skb(skb);
- }
+ kfree_skb_list(segs);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(skb_segment);

View File

@ -1,58 +0,0 @@
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Thu, 27 Mar 2014 12:00:26 +0200
Subject: [1/2] vhost: fix total length when packets are too short
Origin: https://git.kernel.org/linus/d8316f3991d207fe32881a9ac20241be8fa2bad0
When mergeable buffers are disabled, and the
incoming packet is too large for the rx buffer,
get_rx_bufs returns success.
This was intentional in order for make recvmsg
truncate the packet and then handle_rx would
detect err != sock_len and drop it.
Unfortunately we pass the original sock_len to
recvmsg - which means we use parts of iov not fully
validated.
Fix this up by detecting this overrun and doing packet drop
immediately.
CVE-2014-0077
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/vhost/net.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -528,6 +528,12 @@ static int get_rx_bufs(struct vhost_virt
*iovcount = seg;
if (unlikely(log))
*log_num = nlogs;
+
+ /* Detect overrun */
+ if (unlikely(datalen > 0)) {
+ r = UIO_MAXIOV + 1;
+ goto err;
+ }
return headcount;
err:
vhost_discard_vq_desc(vq, headcount);
@@ -583,6 +589,14 @@ static void handle_rx(struct vhost_net *
/* On error, stop handling until the next kick. */
if (unlikely(headcount < 0))
break;
+ /* On overrun, truncate and discard */
+ if (unlikely(headcount > UIO_MAXIOV)) {
+ msg.msg_iovlen = 1;
+ err = sock->ops->recvmsg(NULL, sock, &msg,
+ 1, MSG_DONTWAIT | MSG_TRUNC);
+ pr_debug("Discarded rx packet: len %zd\n", sock_len);
+ continue;
+ }
/* OK, now we need to know about added descriptors. */
if (!headcount) {
if (unlikely(vhost_enable_notify(&net->dev, vq))) {

View File

@ -1,39 +0,0 @@
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Thu, 27 Mar 2014 12:53:37 +0200
Subject: [2/2] vhost: validate vhost_get_vq_desc return value
Origin: https://git.kernel.org/linus/a39ee449f96a2cd44ce056d8a0a112211a9b1a1f
vhost fails to validate negative error code
from vhost_get_vq_desc causing
a crash: we are using -EFAULT which is 0xfffffff2
as vector size, which exceeds the allocated size.
The code in question was introduced in commit
8dd014adfea6f173c1ef6378f7e5e7924866c923
vhost-net: mergeable buffers support
CVE-2014-0055
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/vhost/net.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -501,9 +501,13 @@ static int get_rx_bufs(struct vhost_virt
r = -ENOBUFS;
goto err;
}
- d = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
+ r = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
ARRAY_SIZE(vq->iov) - seg, &out,
&in, log, log_num);
+ if (unlikely(r < 0))
+ goto err;
+
+ d = r;
if (d == vq->num) {
r = 0;
goto err;

10
debian/patches/series vendored
View File

@ -79,20 +79,10 @@ bugfix/all/staging-lustre-Make-LUSTRE_LLITE_LLOOP-tristate.patch
bugfix/all/i2c-designware-remove-HAVE_CLK-build-dependecy.patch
debian/snd-pcsp-disable-autoload.patch
bugfix/all/bluetooth-allocate-static-minor-for-vhci.patch
bugfix/all/net-fix-for-a-race-condition-in-the-inet-frag-code.patch
bugfix/all/KEYS-Make-the-keyring-cycle-detector-ignore-other-ke.patch
bugfix/all/net-use-kfree_skb_list-helper.patch
bugfix/all/0001-skbuff-skb_segment-s-frag-nskb_frag.patch
bugfix/all/0002-skbuff-skb_segment-s-skb_frag-frag.patch
bugfix/all/0003-skbuff-skb_segment-s-skb-head_skb.patch
bugfix/all/0004-skbuff-skb_segment-s-fskb-list_skb.patch
bugfix/all/0005-skbuff-skb_segment-orphan-frags-before-copying.patch
bugfix/all/ipv6-don-t-set-DST_NOCOUNT-for-remotely-added-routes.patch
debian/fs-avoid-abi-change-in-3.13.6.patch
debian/netdev-avoid-abi-change-in-3.13.6.patch
debian/can-avoid-abi-change-in-3.13.6.patch
debian/arm-mm-avoid-abi-change-in-3.13.6.patch
debian/fireware-avoid-abi-change-in-3.13.7.patch
bugfix/all/net-core-nfqueue-openvswitch-Orphan-frags-in-skb_zerocopy-and-handle-errors.patch
bugfix/all/vhost-fix-total-length-when-packets-are-too-short.patch
bugfix/all/vhost-validate-vhost_get_vq_desc-return-value.patch