summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@fedoraproject.org>2016-02-24 08:31:05 -0500
committerJosh Boyer <jwboyer@fedoraproject.org>2016-02-24 08:31:05 -0500
commit6ccb085e3442584705e103044921dbcea257ac4b (patch)
treec18c32a5c0ac011116e3a0c3bcad602794509959
parent1c2eca9c65a694916f978519fe3a7ca0dcf4f77f (diff)
downloadkernel-6ccb085e3442584705e103044921dbcea257ac4b.tar.gz
kernel-6ccb085e3442584705e103044921dbcea257ac4b.tar.xz
kernel-6ccb085e3442584705e103044921dbcea257ac4b.zip
CVE-2016-2550 af_unix: incorrect accounting on in-flight fds (rhbz 1311517 1311518)
-rw-r--r--kernel.spec9
-rw-r--r--unix-correctly-track-in-flight-fds-in-sending-proces.patch159
2 files changed, 168 insertions, 0 deletions
diff --git a/kernel.spec b/kernel.spec
index 6bd2243f1..3e5c70ad1 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -697,6 +697,9 @@ Patch653: iw_cxgb3-Fix-incorrectly-returning-error-on-success.patch
Patch654: Revert-usb-hub-do-not-clear-BOS-field-during-reset-d.patch
+#CVE-2016-2550 rhbz 1311517 1311518
+Patch655: unix-correctly-track-in-flight-fds-in-sending-proces.patch
+
# END OF PATCH DEFINITIONS
%endif
@@ -1458,6 +1461,9 @@ ApplyPatch iw_cxgb3-Fix-incorrectly-returning-error-on-success.patch
ApplyPatch Revert-usb-hub-do-not-clear-BOS-field-during-reset-d.patch
+#CVE-2016-2550 rhbz 1311517 1311518
+ApplyPatch unix-correctly-track-in-flight-fds-in-sending-proces.patch
+
# END OF PATCH APPLICATIONS
%endif
@@ -2307,6 +2313,9 @@ fi
#
#
%changelog
+* Wed Feb 24 2016 Josh Boyer <jwboyer@fedoraproject.org>
+- CVE-2016-2550 af_unix: incorrect accounting on in-flight fds (rhbz 1311517 1311518)
+
* Mon Feb 22 2016 Josh Boyer <jwboyer@fedoraproject.org> - 4.3.6-201
- Revert broken usb patch
diff --git a/unix-correctly-track-in-flight-fds-in-sending-proces.patch b/unix-correctly-track-in-flight-fds-in-sending-proces.patch
new file mode 100644
index 000000000..eb513ef6b
--- /dev/null
+++ b/unix-correctly-track-in-flight-fds-in-sending-proces.patch
@@ -0,0 +1,159 @@
+From 415e3d3e90ce9e18727e8843ae343eda5a58fad6 Mon Sep 17 00:00:00 2001
+From: Hannes Frederic Sowa <hannes@stressinduktion.org>
+Date: Wed, 3 Feb 2016 02:11:03 +0100
+Subject: [PATCH] unix: correctly track in-flight fds in sending process
+ user_struct
+
+The commit referenced in the Fixes tag incorrectly accounted the number
+of in-flight fds over a unix domain socket to the original opener
+of the file-descriptor. This allows another process to arbitrary
+deplete the original file-openers resource limit for the maximum of
+open files. Instead the sending processes and its struct cred should
+be credited.
+
+To do so, we add a reference counted struct user_struct pointer to the
+scm_fp_list and use it to account for the number of inflight unix fds.
+
+Fixes: 712f4aad406bb1 ("unix: properly account for FDs passed over unix sockets")
+Reported-by: David Herrmann <dh.herrmann@gmail.com>
+Cc: David Herrmann <dh.herrmann@gmail.com>
+Cc: Willy Tarreau <w@1wt.eu>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/net/af_unix.h | 4 ++--
+ include/net/scm.h | 1 +
+ net/core/scm.c | 7 +++++++
+ net/unix/af_unix.c | 4 ++--
+ net/unix/garbage.c | 8 ++++----
+ 5 files changed, 16 insertions(+), 8 deletions(-)
+
+diff --git a/include/net/af_unix.h b/include/net/af_unix.h
+index 2a91a0561a47..9b4c418bebd8 100644
+--- a/include/net/af_unix.h
++++ b/include/net/af_unix.h
+@@ -6,8 +6,8 @@
+ #include <linux/mutex.h>
+ #include <net/sock.h>
+
+-void unix_inflight(struct file *fp);
+-void unix_notinflight(struct file *fp);
++void unix_inflight(struct user_struct *user, struct file *fp);
++void unix_notinflight(struct user_struct *user, struct file *fp);
+ void unix_gc(void);
+ void wait_for_unix_gc(void);
+ struct sock *unix_get_socket(struct file *filp);
+diff --git a/include/net/scm.h b/include/net/scm.h
+index 262532d111f5..59fa93c01d2a 100644
+--- a/include/net/scm.h
++++ b/include/net/scm.h
+@@ -21,6 +21,7 @@ struct scm_creds {
+ struct scm_fp_list {
+ short count;
+ short max;
++ struct user_struct *user;
+ struct file *fp[SCM_MAX_FD];
+ };
+
+diff --git a/net/core/scm.c b/net/core/scm.c
+index 14596fb37172..2696aefdc148 100644
+--- a/net/core/scm.c
++++ b/net/core/scm.c
+@@ -87,6 +87,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
+ *fplp = fpl;
+ fpl->count = 0;
+ fpl->max = SCM_MAX_FD;
++ fpl->user = NULL;
+ }
+ fpp = &fpl->fp[fpl->count];
+
+@@ -107,6 +108,10 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
+ *fpp++ = file;
+ fpl->count++;
+ }
++
++ if (!fpl->user)
++ fpl->user = get_uid(current_user());
++
+ return num;
+ }
+
+@@ -119,6 +124,7 @@ void __scm_destroy(struct scm_cookie *scm)
+ scm->fp = NULL;
+ for (i=fpl->count-1; i>=0; i--)
+ fput(fpl->fp[i]);
++ free_uid(fpl->user);
+ kfree(fpl);
+ }
+ }
+@@ -336,6 +342,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
+ for (i = 0; i < fpl->count; i++)
+ get_file(fpl->fp[i]);
+ new_fpl->max = new_fpl->count;
++ new_fpl->user = get_uid(fpl->user);
+ }
+ return new_fpl;
+ }
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index 49d5093eb055..29be035f9c65 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -1496,7 +1496,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
+ UNIXCB(skb).fp = NULL;
+
+ for (i = scm->fp->count-1; i >= 0; i--)
+- unix_notinflight(scm->fp->fp[i]);
++ unix_notinflight(scm->fp->user, scm->fp->fp[i]);
+ }
+
+ static void unix_destruct_scm(struct sk_buff *skb)
+@@ -1561,7 +1561,7 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
+ return -ENOMEM;
+
+ for (i = scm->fp->count - 1; i >= 0; i--)
+- unix_inflight(scm->fp->fp[i]);
++ unix_inflight(scm->fp->user, scm->fp->fp[i]);
+ return max_level;
+ }
+
+diff --git a/net/unix/garbage.c b/net/unix/garbage.c
+index 8fcdc2283af5..6a0d48525fcf 100644
+--- a/net/unix/garbage.c
++++ b/net/unix/garbage.c
+@@ -116,7 +116,7 @@ struct sock *unix_get_socket(struct file *filp)
+ * descriptor if it is for an AF_UNIX socket.
+ */
+
+-void unix_inflight(struct file *fp)
++void unix_inflight(struct user_struct *user, struct file *fp)
+ {
+ struct sock *s = unix_get_socket(fp);
+
+@@ -133,11 +133,11 @@ void unix_inflight(struct file *fp)
+ }
+ unix_tot_inflight++;
+ }
+- fp->f_cred->user->unix_inflight++;
++ user->unix_inflight++;
+ spin_unlock(&unix_gc_lock);
+ }
+
+-void unix_notinflight(struct file *fp)
++void unix_notinflight(struct user_struct *user, struct file *fp)
+ {
+ struct sock *s = unix_get_socket(fp);
+
+@@ -152,7 +152,7 @@ void unix_notinflight(struct file *fp)
+ list_del_init(&u->link);
+ unix_tot_inflight--;
+ }
+- fp->f_cred->user->unix_inflight--;
++ user->unix_inflight--;
+ spin_unlock(&unix_gc_lock);
+ }
+
+--
+2.5.0
+