Cherry-pick security fixes from upstream
svn path=/dists/sid/linux/; revision=21144
This commit is contained in:
parent
27be88dc25
commit
1e9361b9ed
|
@ -86,6 +86,13 @@ linux (3.13.6-1) UNRELEASED; urgency=medium
|
|||
- Revert "USBNET: ax88179_178a: enable tso if usb host supports sg dma"
|
||||
* aufs: Update to aufs3.13-20140303
|
||||
- bugfix, Fix unmount to properly free anonymous block devices
|
||||
* net: fix for a race condition in the inet frag code (CVE-2014-0100)
|
||||
* net: sctp: fix sctp_sf_do_5_1D_ce to verify if we/peer is AUTH capable
|
||||
(CVE-2014-0101)
|
||||
* KEYS: Make the keyring cycle detector ignore other keyrings of the
|
||||
same name (CVE-2014-0102)
|
||||
* skbuff: skb_segment: orphan frags before copying (CVE-2014-0131)
|
||||
* ipv6: don't set DST_NOCOUNT for remotely added routes (CVE-2014-2309)
|
||||
|
||||
-- Ben Hutchings <ben@decadent.org.uk> Sun, 09 Mar 2014 22:26:13 +0000
|
||||
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
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:
|
|
@ -0,0 +1,77 @@
|
|||
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));
|
|
@ -0,0 +1,144 @@
|
|||
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;
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
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 >=
|
59
debian/patches/bugfix/all/0005-skbuff-skb_segment-orphan-frags-before-copying.patch
vendored
Normal file
59
debian/patches/bugfix/all/0005-skbuff-skb_segment-orphan-frags-before-copying.patch
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
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);
|
71
debian/patches/bugfix/all/KEYS-Make-the-keyring-cycle-detector-ignore-other-ke.patch
vendored
Normal file
71
debian/patches/bugfix/all/KEYS-Make-the-keyring-cycle-detector-ignore-other-ke.patch
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
From: David Howells <dhowells@redhat.com>
|
||||
Date: Sun, 9 Mar 2014 08:21:58 +0000
|
||||
Subject: KEYS: Make the keyring cycle detector ignore other keyrings of the
|
||||
same name
|
||||
Origin: https://git.kernel.org/linus/979e0d74651ba5aa533277f2a6423d0f982fb6f6
|
||||
|
||||
This fixes CVE-2014-0102.
|
||||
|
||||
The following command sequence produces an oops:
|
||||
|
||||
keyctl new_session
|
||||
i=`keyctl newring _ses @s`
|
||||
keyctl link @s $i
|
||||
|
||||
The problem is that search_nested_keyrings() sees two keyrings that have
|
||||
matching type and description, so keyring_compare_object() returns true.
|
||||
s_n_k() then passes the key to the iterator function -
|
||||
keyring_detect_cycle_iterator() - which *should* check to see whether this is
|
||||
the keyring of interest, not just one with the same name.
|
||||
|
||||
Because assoc_array_find() will return one and only one match, I assumed that
|
||||
the iterator function would only see an exact match or never be called - but
|
||||
the iterator isn't only called from assoc_array_find()...
|
||||
|
||||
The oops looks something like this:
|
||||
|
||||
kernel BUG at /data/fs/linux-2.6-fscache/security/keys/keyring.c:1003!
|
||||
invalid opcode: 0000 [#1] SMP
|
||||
...
|
||||
RIP: keyring_detect_cycle_iterator+0xe/0x1f
|
||||
...
|
||||
Call Trace:
|
||||
search_nested_keyrings+0x76/0x2aa
|
||||
__key_link_check_live_key+0x50/0x5f
|
||||
key_link+0x4e/0x85
|
||||
keyctl_keyring_link+0x60/0x81
|
||||
SyS_keyctl+0x65/0xe4
|
||||
tracesys+0xdd/0xe2
|
||||
|
||||
The fix is to make keyring_detect_cycle_iterator() check that the key it
|
||||
has is the key it was actually looking for rather than calling BUG_ON().
|
||||
|
||||
A testcase has been included in the keyutils testsuite for this:
|
||||
|
||||
http://git.kernel.org/cgit/linux/kernel/git/dhowells/keyutils.git/commit/?id=891f3365d07f1996778ade0e3428f01878a1790b
|
||||
|
||||
Reported-by: Tommi Rantala <tt.rantala@gmail.com>
|
||||
Signed-off-by: David Howells <dhowells@redhat.com>
|
||||
Acked-by: James Morris <james.l.morris@oracle.com>
|
||||
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
---
|
||||
security/keys/keyring.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
|
||||
index d46cbc5..2fb2576 100644
|
||||
--- a/security/keys/keyring.c
|
||||
+++ b/security/keys/keyring.c
|
||||
@@ -1000,7 +1000,11 @@ static int keyring_detect_cycle_iterator(const void *object,
|
||||
|
||||
kenter("{%d}", key->serial);
|
||||
|
||||
- BUG_ON(key != ctx->match_data);
|
||||
+ /* We might get a keyring with matching index-key that is nonetheless a
|
||||
+ * different keyring. */
|
||||
+ if (key != ctx->match_data)
|
||||
+ return 0;
|
||||
+
|
||||
ctx->result = ERR_PTR(-EDEADLK);
|
||||
return 1;
|
||||
}
|
30
debian/patches/bugfix/all/ipv6-don-t-set-DST_NOCOUNT-for-remotely-added-routes.patch
vendored
Normal file
30
debian/patches/bugfix/all/ipv6-don-t-set-DST_NOCOUNT-for-remotely-added-routes.patch
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
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;
|
91
debian/patches/bugfix/all/net-fix-for-a-race-condition-in-the-inet-frag-code.patch
vendored
Normal file
91
debian/patches/bugfix/all/net-fix-for-a-race-condition-in-the-inet-frag-code.patch
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
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;
|
||||
}
|
||||
|
135
debian/patches/bugfix/all/net-sctp-fix-sctp_sf_do_5_1D_ce-to-verify-if-we-peer.patch
vendored
Normal file
135
debian/patches/bugfix/all/net-sctp-fix-sctp_sf_do_5_1D_ce-to-verify-if-we-peer.patch
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
From: Daniel Borkmann <dborkman@redhat.com>
|
||||
Date: Mon, 3 Mar 2014 17:23:04 +0100
|
||||
Subject: net: sctp: fix sctp_sf_do_5_1D_ce to verify if we/peer is AUTH
|
||||
capable
|
||||
Origin: https://git.kernel.org/linus/ec0223ec48a90cb605244b45f7c62de856403729
|
||||
|
||||
RFC4895 introduced AUTH chunks for SCTP; during the SCTP
|
||||
handshake RANDOM; CHUNKS; HMAC-ALGO are negotiated (CHUNKS
|
||||
being optional though):
|
||||
|
||||
---------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ---------->
|
||||
<------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] ---------
|
||||
-------------------- COOKIE-ECHO -------------------->
|
||||
<-------------------- COOKIE-ACK ---------------------
|
||||
|
||||
A special case is when an endpoint requires COOKIE-ECHO
|
||||
chunks to be authenticated:
|
||||
|
||||
---------- INIT[RANDOM; CHUNKS; HMAC-ALGO] ---------->
|
||||
<------- INIT-ACK[RANDOM; CHUNKS; HMAC-ALGO] ---------
|
||||
------------------ AUTH; COOKIE-ECHO ---------------->
|
||||
<-------------------- COOKIE-ACK ---------------------
|
||||
|
||||
RFC4895, section 6.3. Receiving Authenticated Chunks says:
|
||||
|
||||
The receiver MUST use the HMAC algorithm indicated in
|
||||
the HMAC Identifier field. If this algorithm was not
|
||||
specified by the receiver in the HMAC-ALGO parameter in
|
||||
the INIT or INIT-ACK chunk during association setup, the
|
||||
AUTH chunk and all the chunks after it MUST be discarded
|
||||
and an ERROR chunk SHOULD be sent with the error cause
|
||||
defined in Section 4.1. [...] If no endpoint pair shared
|
||||
key has been configured for that Shared Key Identifier,
|
||||
all authenticated chunks MUST be silently discarded. [...]
|
||||
|
||||
When an endpoint requires COOKIE-ECHO chunks to be
|
||||
authenticated, some special procedures have to be followed
|
||||
because the reception of a COOKIE-ECHO chunk might result
|
||||
in the creation of an SCTP association. If a packet arrives
|
||||
containing an AUTH chunk as a first chunk, a COOKIE-ECHO
|
||||
chunk as the second chunk, and possibly more chunks after
|
||||
them, and the receiver does not have an STCB for that
|
||||
packet, then authentication is based on the contents of
|
||||
the COOKIE-ECHO chunk. In this situation, the receiver MUST
|
||||
authenticate the chunks in the packet by using the RANDOM
|
||||
parameters, CHUNKS parameters and HMAC_ALGO parameters
|
||||
obtained from the COOKIE-ECHO chunk, and possibly a local
|
||||
shared secret as inputs to the authentication procedure
|
||||
specified in Section 6.3. If authentication fails, then
|
||||
the packet is discarded. If the authentication is successful,
|
||||
the COOKIE-ECHO and all the chunks after the COOKIE-ECHO
|
||||
MUST be processed. If the receiver has an STCB, it MUST
|
||||
process the AUTH chunk as described above using the STCB
|
||||
from the existing association to authenticate the
|
||||
COOKIE-ECHO chunk and all the chunks after it. [...]
|
||||
|
||||
Commit bbd0d59809f9 introduced the possibility to receive
|
||||
and verification of AUTH chunk, including the edge case for
|
||||
authenticated COOKIE-ECHO. On reception of COOKIE-ECHO,
|
||||
the function sctp_sf_do_5_1D_ce() handles processing,
|
||||
unpacks and creates a new association if it passed sanity
|
||||
checks and also tests for authentication chunks being
|
||||
present. After a new association has been processed, it
|
||||
invokes sctp_process_init() on the new association and
|
||||
walks through the parameter list it received from the INIT
|
||||
chunk. It checks SCTP_PARAM_RANDOM, SCTP_PARAM_HMAC_ALGO
|
||||
and SCTP_PARAM_CHUNKS, and copies them into asoc->peer
|
||||
meta data (peer_random, peer_hmacs, peer_chunks) in case
|
||||
sysctl -w net.sctp.auth_enable=1 is set. If in INIT's
|
||||
SCTP_PARAM_SUPPORTED_EXT parameter SCTP_CID_AUTH is set,
|
||||
peer_random != NULL and peer_hmacs != NULL the peer is to be
|
||||
assumed asoc->peer.auth_capable=1, in any other case
|
||||
asoc->peer.auth_capable=0.
|
||||
|
||||
Now, if in sctp_sf_do_5_1D_ce() chunk->auth_chunk is
|
||||
available, we set up a fake auth chunk and pass that on to
|
||||
sctp_sf_authenticate(), which at latest in
|
||||
sctp_auth_calculate_hmac() reliably dereferences a NULL pointer
|
||||
at position 0..0008 when setting up the crypto key in
|
||||
crypto_hash_setkey() by using asoc->asoc_shared_key that is
|
||||
NULL as condition key_id == asoc->active_key_id is true if
|
||||
the AUTH chunk was injected correctly from remote. This
|
||||
happens no matter what net.sctp.auth_enable sysctl says.
|
||||
|
||||
The fix is to check for net->sctp.auth_enable and for
|
||||
asoc->peer.auth_capable before doing any operations like
|
||||
sctp_sf_authenticate() as no key is activated in
|
||||
sctp_auth_asoc_init_active_key() for each case.
|
||||
|
||||
Now as RFC4895 section 6.3 states that if the used HMAC-ALGO
|
||||
passed from the INIT chunk was not used in the AUTH chunk, we
|
||||
SHOULD send an error; however in this case it would be better
|
||||
to just silently discard such a maliciously prepared handshake
|
||||
as we didn't even receive a parameter at all. Also, as our
|
||||
endpoint has no shared key configured, section 6.3 says that
|
||||
MUST silently discard, which we are doing from now onwards.
|
||||
|
||||
Before calling sctp_sf_pdiscard(), we need not only to free
|
||||
the association, but also the chunk->auth_chunk skb, as
|
||||
commit bbd0d59809f9 created a skb clone in that case.
|
||||
|
||||
I have tested this locally by using netfilter's nfqueue and
|
||||
re-injecting packets into the local stack after maliciously
|
||||
modifying the INIT chunk (removing RANDOM; HMAC-ALGO param)
|
||||
and the SCTP packet containing the COOKIE_ECHO (injecting
|
||||
AUTH chunk before COOKIE_ECHO). Fixed with this patch applied.
|
||||
|
||||
Fixes: bbd0d59809f9 ("[SCTP]: Implement the receive and verification of AUTH chunk")
|
||||
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
|
||||
Cc: Vlad Yasevich <yasevich@gmail.com>
|
||||
Cc: Neil Horman <nhorman@tuxdriver.com>
|
||||
Acked-by: Vlad Yasevich <vyasevich@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
net/sctp/sm_statefuns.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
|
||||
index 591b44d..ae65b6b 100644
|
||||
--- a/net/sctp/sm_statefuns.c
|
||||
+++ b/net/sctp/sm_statefuns.c
|
||||
@@ -758,6 +758,13 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
|
||||
struct sctp_chunk auth;
|
||||
sctp_ierror_t ret;
|
||||
|
||||
+ /* Make sure that we and the peer are AUTH capable */
|
||||
+ if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
|
||||
+ kfree_skb(chunk->auth_chunk);
|
||||
+ sctp_association_free(new_asoc);
|
||||
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
||||
+ }
|
||||
+
|
||||
/* set-up our fake chunk so that we can process it */
|
||||
auth.skb = chunk->auth_chunk;
|
||||
auth.asoc = chunk->asoc;
|
|
@ -81,3 +81,12 @@ debian/snd-pcsp-disable-autoload.patch
|
|||
bugfix/all/bluetooth-allocate-static-minor-for-vhci.patch
|
||||
bugfix/all/revert-xhci-1.0-limit-arbitrarilyaligned-scatter-gather.patch
|
||||
bugfix/all/revert-usbnet-ax88179_178a-enable-tso-if-usb-host.patch
|
||||
bugfix/all/net-fix-for-a-race-condition-in-the-inet-frag-code.patch
|
||||
bugfix/all/net-sctp-fix-sctp_sf_do_5_1D_ce-to-verify-if-we-peer.patch
|
||||
bugfix/all/KEYS-Make-the-keyring-cycle-detector-ignore-other-ke.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
|
||||
|
|
Loading…
Reference in New Issue