[kernel] r16948 - in dists/squeeze/linux-2.6/debian: . patches/bugfix/all patches/debian patches/series
Ben Hutchings
benh at alioth.debian.org
Mon Feb 28 04:05:29 UTC 2011
Author: benh
Date: Mon Feb 28 04:05:25 2011
New Revision: 16948
Log:
af_unix: Limit recursion level of passing sockets through sockets
This fixes a variant of CVE-2010-4249, which does not seem to have
been assigned its own CVE yet.
Added:
dists/squeeze/linux-2.6/debian/patches/bugfix/all/af_unix-limit-recursion-level.patch
dists/squeeze/linux-2.6/debian/patches/debian/af_unix-Avoid-ABI-change-from-introduction-of-recursion-limit.patch
Modified:
dists/squeeze/linux-2.6/debian/changelog
dists/squeeze/linux-2.6/debian/patches/series/31
Modified: dists/squeeze/linux-2.6/debian/changelog
==============================================================================
--- dists/squeeze/linux-2.6/debian/changelog Mon Feb 28 03:37:49 2011 (r16947)
+++ dists/squeeze/linux-2.6/debian/changelog Mon Feb 28 04:05:25 2011 (r16948)
@@ -31,6 +31,8 @@
* virtio_net: Further fixes for out-of-memory conditions (Closes: #603835)
- Fix OOM handling on TX
- Add schedule check to napi_enable call
+ * af_unix: Limit recursion level of passing sockets through sockets
+ (variant of CVE-2010-4249)
[ dann frazier ]
* xfs: fix information leak using stale NFS handle (CVE-2010-2943)
Added: dists/squeeze/linux-2.6/debian/patches/bugfix/all/af_unix-limit-recursion-level.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/bugfix/all/af_unix-limit-recursion-level.patch Mon Feb 28 04:05:25 2011 (r16948)
@@ -0,0 +1,182 @@
+From: Eric Dumazet <eric.dumazet at gmail.com>
+Date: Thu, 25 Nov 2010 04:11:39 +0000
+Subject: [PATCH] af_unix: limit recursion level
+
+commit 25888e30319f8896fc656fc68643e6a078263060 upstream.
+
+Its easy to eat all kernel memory and trigger NMI watchdog, using an
+exploit program that queues unix sockets on top of others.
+
+lkml ref : http://lkml.org/lkml/2010/11/25/8
+
+This mechanism is used in applications, one choice we have is to have a
+recursion limit.
+
+Other limits might be needed as well (if we queue other types of files),
+since the passfd mechanism is currently limited by socket receive queue
+sizes only.
+
+Add a recursion_level to unix socket, allowing up to 4 levels.
+
+Each time we send an unix socket through sendfd mechanism, we copy its
+recursion level (plus one) to receiver. This recursion level is cleared
+when socket receive queue is emptied.
+
+Reported-by: Марк Коренберг <socketpair at gmail.com>
+Signed-off-by: Eric Dumazet <eric.dumazet at gmail.com>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+[bwh: Adjust for 2.6.32]
+---
+ include/net/af_unix.h | 2 ++
+ net/unix/af_unix.c | 37 ++++++++++++++++++++++++++++++++-----
+ net/unix/garbage.c | 2 +-
+ 3 files changed, 35 insertions(+), 6 deletions(-)
+
+diff --git a/include/net/af_unix.h b/include/net/af_unix.h
+index 1614d78..861045f 100644
+--- a/include/net/af_unix.h
++++ b/include/net/af_unix.h
+@@ -10,6 +10,7 @@ extern void unix_inflight(struct file *fp);
+ extern void unix_notinflight(struct file *fp);
+ extern void unix_gc(void);
+ extern void wait_for_unix_gc(void);
++extern struct sock *unix_get_socket(struct file *filp);
+
+ #define UNIX_HASH_SIZE 256
+
+@@ -56,6 +57,7 @@ struct unix_sock {
+ spinlock_t lock;
+ unsigned int gc_candidate : 1;
+ unsigned int gc_maybe_cycle : 1;
++ unsigned char recursion_level;
+ wait_queue_head_t peer_wait;
+ };
+ #define unix_sk(__sk) ((struct unix_sock *)__sk)
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index 065dc66..e707e26 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -1323,9 +1323,25 @@ static void unix_destruct_fds(struct sk_buff *skb)
+ sock_wfree(skb);
+ }
+
++#define MAX_RECURSION_LEVEL 4
++
+ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
+ {
+ int i;
++ unsigned char max_level = 0;
++ int unix_sock_count = 0;
++
++ for (i = scm->fp->count - 1; i >= 0; i--) {
++ struct sock *sk = unix_get_socket(scm->fp->fp[i]);
++
++ if (sk) {
++ unix_sock_count++;
++ max_level = max(max_level,
++ unix_sk(sk)->recursion_level);
++ }
++ }
++ if (unlikely(max_level > MAX_RECURSION_LEVEL))
++ return -ETOOMANYREFS;
+
+ /*
+ * Need to duplicate file references for the sake of garbage
+@@ -1336,10 +1352,12 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
+ if (!UNIXCB(skb).fp)
+ return -ENOMEM;
+
+- for (i = scm->fp->count-1; i >= 0; i--)
+- unix_inflight(scm->fp->fp[i]);
++ if (unix_sock_count) {
++ for (i = scm->fp->count - 1; i >= 0; i--)
++ unix_inflight(scm->fp->fp[i]);
++ }
+ skb->destructor = unix_destruct_fds;
+- return 0;
++ return max_level;
+ }
+
+ /*
+@@ -1361,6 +1379,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
+ struct sk_buff *skb;
+ long timeo;
+ struct scm_cookie tmp_scm;
++ int max_level = 0;
+
+ if (NULL == siocb->scm)
+ siocb->scm = &tmp_scm;
+@@ -1401,8 +1420,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
+ memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
+ if (siocb->scm->fp) {
+ err = unix_attach_fds(siocb->scm, skb);
+- if (err)
++ if (err < 0)
+ goto out_free;
++ max_level = err + 1;
+ }
+ unix_get_secdata(siocb->scm, skb);
+
+@@ -1483,6 +1503,8 @@ restart:
+ }
+
+ skb_queue_tail(&other->sk_receive_queue, skb);
++ if (max_level > unix_sk(other)->recursion_level)
++ unix_sk(other)->recursion_level = max_level;
+ unix_state_unlock(other);
+ other->sk_data_ready(other, len);
+ sock_put(other);
+@@ -1513,6 +1535,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
+ int sent = 0;
+ struct scm_cookie tmp_scm;
+ bool fds_sent = false;
++ int max_level = 0;
+
+ if (NULL == siocb->scm)
+ siocb->scm = &tmp_scm;
+@@ -1577,10 +1600,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
+ /* Only send the fds in the first buffer */
+ if (siocb->scm->fp && !fds_sent) {
+ err = unix_attach_fds(siocb->scm, skb);
+- if (err) {
++ if (err < 0) {
+ kfree_skb(skb);
+ goto out_err;
+ }
++ max_level = err + 1;
+ fds_sent = true;
+ }
+
+@@ -1597,6 +1621,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
+ goto pipe_err_free;
+
+ skb_queue_tail(&other->sk_receive_queue, skb);
++ if (max_level > unix_sk(other)->recursion_level)
++ unix_sk(other)->recursion_level = max_level;
+ unix_state_unlock(other);
+ other->sk_data_ready(other, size);
+ sent += size;
+@@ -1813,6 +1839,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
+ unix_state_lock(sk);
+ skb = skb_dequeue(&sk->sk_receive_queue);
+ if (skb == NULL) {
++ unix_sk(sk)->recursion_level = 0;
+ if (copied >= target)
+ goto unlock;
+
+diff --git a/net/unix/garbage.c b/net/unix/garbage.c
+index 736e6f9..cb72e91 100644
+--- a/net/unix/garbage.c
++++ b/net/unix/garbage.c
+@@ -97,7 +97,7 @@ static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait);
+ unsigned int unix_tot_inflight;
+
+
+-static struct sock *unix_get_socket(struct file *filp)
++struct sock *unix_get_socket(struct file *filp)
+ {
+ struct sock *u_sock = NULL;
+ struct inode *inode = filp->f_path.dentry->d_inode;
+--
+1.7.4.1
+
Added: dists/squeeze/linux-2.6/debian/patches/debian/af_unix-Avoid-ABI-change-from-introduction-of-recursion-limit.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/squeeze/linux-2.6/debian/patches/debian/af_unix-Avoid-ABI-change-from-introduction-of-recursion-limit.patch Mon Feb 28 04:05:25 2011 (r16948)
@@ -0,0 +1,44 @@
+From: Ben Hutchings <ben at decadent.org.uk>
+Date: Mon, 28 Feb 2011 03:31:55 +0000
+Subject: [PATCH] af_unix: Avoid ABI change from introduction of recursion limit
+
+---
+ include/net/af_unix.h | 5 ++++-
+ net/unix/af_unix.c | 5 +++--
+ 2 files changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/include/net/af_unix.h b/include/net/af_unix.h
+index 861045f..12e5f05 100644
+--- a/include/net/af_unix.h
++++ b/include/net/af_unix.h
+@@ -57,7 +57,10 @@ struct unix_sock {
+ spinlock_t lock;
+ unsigned int gc_candidate : 1;
+ unsigned int gc_maybe_cycle : 1;
+- unsigned char recursion_level;
++#ifndef __GENKSYSMS__
++ unsigned int : 6;
++ unsigned int recursion_level : 8;
++#endif
+ wait_queue_head_t peer_wait;
+ };
+ #define unix_sk(__sk) ((struct unix_sock *)__sk)
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index e707e26..e64ee65 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -1336,8 +1336,9 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
+
+ if (sk) {
+ unix_sock_count++;
+- max_level = max(max_level,
+- unix_sk(sk)->recursion_level);
++ max_level = max_t(unsigned char,
++ max_level,
++ unix_sk(sk)->recursion_level);
+ }
+ }
+ if (unlikely(max_level > MAX_RECURSION_LEVEL))
+--
+1.7.4.1
+
Modified: dists/squeeze/linux-2.6/debian/patches/series/31
==============================================================================
--- dists/squeeze/linux-2.6/debian/patches/series/31 Mon Feb 28 03:37:49 2011 (r16947)
+++ dists/squeeze/linux-2.6/debian/patches/series/31 Mon Feb 28 04:05:25 2011 (r16948)
@@ -36,3 +36,5 @@
+ bugfix/s390/remove-task_show_regs.patch
+ bugfix/all/can-use-inode-instead-of-kernel-address-for-proc-file.patch
+ bugfix/all/revert-USB-prevent-buggy-hubs-from-crashing-the-USB.patch
++ bugfix/all/af_unix-limit-recursion-level.patch
++ debian/af_unix-Avoid-ABI-change-from-introduction-of-recursion-limit.patch
More information about the Kernel-svn-changes
mailing list