summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Boyer <jwboyer@fedoraproject.org>2016-06-13 07:40:54 -0400
committerJosh Boyer <jwboyer@fedoraproject.org>2016-06-13 07:41:18 -0400
commit742a0bf3f5055444eeb07c9bdd9a0fc28f0c6c41 (patch)
tree93e622b333b11f93313a6dca71b181f754fdf76c
parent46da3167608e8136c89c7654e3e7a6fed68ec0c7 (diff)
downloadkernel-742a0bf3f5055444eeb07c9bdd9a0fc28f0c6c41.tar.gz
kernel-742a0bf3f5055444eeb07c9bdd9a0fc28f0c6c41.tar.xz
kernel-742a0bf3f5055444eeb07c9bdd9a0fc28f0c6c41.zip
CVE-2016-1583 stack overflow via ecryptfs and /proc (rhbz 1344721 1344722)
-rw-r--r--ecryptfs-fix-handling-of-directory-opening.patch142
-rw-r--r--ecryptfs-forbid-opening-files-without-mmap-handler.patch59
-rw-r--r--kernel.spec9
-rw-r--r--proc-prevent-stacking-filesystems-on-top.patch41
-rw-r--r--sched-panic-on-corrupted-stack-end.patch36
5 files changed, 287 insertions, 0 deletions
diff --git a/ecryptfs-fix-handling-of-directory-opening.patch b/ecryptfs-fix-handling-of-directory-opening.patch
new file mode 100644
index 000000000..ce5f511d4
--- /dev/null
+++ b/ecryptfs-fix-handling-of-directory-opening.patch
@@ -0,0 +1,142 @@
+From 6a480a7842545ec520a91730209ec0bae41694c1 Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Wed, 4 May 2016 14:04:13 -0400
+Subject: [PATCH] ecryptfs: fix handling of directory opening
+
+First of all, trying to open them r/w is idiocy; it's guaranteed to fail.
+Moreover, assigning ->f_pos and assuming that everything will work is
+blatantly broken - try that with e.g. tmpfs as underlying layer and watch
+the fireworks. There may be a non-trivial amount of state associated with
+current IO position, well beyond the numeric offset. Using the single
+struct file associated with underlying inode is really not a good idea;
+we ought to open one for each ecryptfs directory struct file.
+
+Additionally, file_operations both for directories and non-directories are
+full of pointless methods; non-directories should *not* have ->iterate(),
+directories should not have ->flush(), ->fasync() and ->splice_read().
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+---
+ fs/ecryptfs/file.c | 71 ++++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 55 insertions(+), 16 deletions(-)
+
+diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
+index feef8a9c4de7..f02404052b7b 100644
+--- a/fs/ecryptfs/file.c
++++ b/fs/ecryptfs/file.c
+@@ -112,7 +112,6 @@ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx)
+ .sb = inode->i_sb,
+ };
+ lower_file = ecryptfs_file_to_lower(file);
+- lower_file->f_pos = ctx->pos;
+ rc = iterate_dir(lower_file, &buf.ctx);
+ ctx->pos = buf.ctx.pos;
+ if (rc < 0)
+@@ -223,14 +222,6 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
+ }
+ ecryptfs_set_file_lower(
+ file, ecryptfs_inode_to_private(inode)->lower_file);
+- if (d_is_dir(ecryptfs_dentry)) {
+- ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
+- mutex_lock(&crypt_stat->cs_mutex);
+- crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+- mutex_unlock(&crypt_stat->cs_mutex);
+- rc = 0;
+- goto out;
+- }
+ rc = read_or_initialize_metadata(ecryptfs_dentry);
+ if (rc)
+ goto out_put;
+@@ -247,6 +238,45 @@ out:
+ return rc;
+ }
+
++/**
++ * ecryptfs_dir_open
++ * @inode: inode speciying file to open
++ * @file: Structure to return filled in
++ *
++ * Opens the file specified by inode.
++ *
++ * Returns zero on success; non-zero otherwise
++ */
++static int ecryptfs_dir_open(struct inode *inode, struct file *file)
++{
++ struct dentry *ecryptfs_dentry = file->f_path.dentry;
++ /* Private value of ecryptfs_dentry allocated in
++ * ecryptfs_lookup() */
++ struct ecryptfs_file_info *file_info;
++ struct file *lower_file;
++
++ /* Released in ecryptfs_release or end of function if failure */
++ file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL);
++ ecryptfs_set_file_private(file, file_info);
++ if (unlikely(!file_info)) {
++ ecryptfs_printk(KERN_ERR,
++ "Error attempting to allocate memory\n");
++ return -ENOMEM;
++ }
++ lower_file = dentry_open(ecryptfs_dentry_to_lower_path(ecryptfs_dentry),
++ file->f_flags, current_cred());
++ if (IS_ERR(lower_file)) {
++ printk(KERN_ERR "%s: Error attempting to initialize "
++ "the lower file for the dentry with name "
++ "[%pd]; rc = [%ld]\n", __func__,
++ ecryptfs_dentry, PTR_ERR(lower_file));
++ kmem_cache_free(ecryptfs_file_info_cache, file_info);
++ return PTR_ERR(lower_file);
++ }
++ ecryptfs_set_file_lower(file, lower_file);
++ return 0;
++}
++
+ static int ecryptfs_flush(struct file *file, fl_owner_t td)
+ {
+ struct file *lower_file = ecryptfs_file_to_lower(file);
+@@ -267,6 +297,19 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
+ return 0;
+ }
+
++static int ecryptfs_dir_release(struct inode *inode, struct file *file)
++{
++ fput(ecryptfs_file_to_lower(file));
++ kmem_cache_free(ecryptfs_file_info_cache,
++ ecryptfs_file_to_private(file));
++ return 0;
++}
++
++static loff_t ecryptfs_dir_llseek(struct file *file, loff_t offset, int whence)
++{
++ return vfs_llseek(ecryptfs_file_to_lower(file), offset, whence);
++}
++
+ static int
+ ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+ {
+@@ -346,20 +389,16 @@ const struct file_operations ecryptfs_dir_fops = {
+ #ifdef CONFIG_COMPAT
+ .compat_ioctl = ecryptfs_compat_ioctl,
+ #endif
+- .open = ecryptfs_open,
+- .flush = ecryptfs_flush,
+- .release = ecryptfs_release,
++ .open = ecryptfs_dir_open,
++ .release = ecryptfs_dir_release,
+ .fsync = ecryptfs_fsync,
+- .fasync = ecryptfs_fasync,
+- .splice_read = generic_file_splice_read,
+- .llseek = default_llseek,
++ .llseek = ecryptfs_dir_llseek,
+ };
+
+ const struct file_operations ecryptfs_main_fops = {
+ .llseek = generic_file_llseek,
+ .read_iter = ecryptfs_read_update_atime,
+ .write_iter = generic_file_write_iter,
+- .iterate = ecryptfs_readdir,
+ .unlocked_ioctl = ecryptfs_unlocked_ioctl,
+ #ifdef CONFIG_COMPAT
+ .compat_ioctl = ecryptfs_compat_ioctl,
+--
+2.5.5
+
diff --git a/ecryptfs-forbid-opening-files-without-mmap-handler.patch b/ecryptfs-forbid-opening-files-without-mmap-handler.patch
new file mode 100644
index 000000000..2d40e68ed
--- /dev/null
+++ b/ecryptfs-forbid-opening-files-without-mmap-handler.patch
@@ -0,0 +1,59 @@
+From 2f36db71009304b3f0b95afacd8eba1f9f046b87 Mon Sep 17 00:00:00 2001
+From: Jann Horn <jannh@google.com>
+Date: Wed, 1 Jun 2016 11:55:06 +0200
+Subject: [PATCH] ecryptfs: forbid opening files without mmap handler
+
+This prevents users from triggering a stack overflow through a recursive
+invocation of pagefault handling that involves mapping procfs files into
+virtual memory.
+
+Signed-off-by: Jann Horn <jannh@google.com>
+Acked-by: Tyler Hicks <tyhicks@canonical.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ fs/ecryptfs/kthread.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c
+index 866bb18efefe..e818f5ac7a26 100644
+--- a/fs/ecryptfs/kthread.c
++++ b/fs/ecryptfs/kthread.c
+@@ -25,6 +25,7 @@
+ #include <linux/slab.h>
+ #include <linux/wait.h>
+ #include <linux/mount.h>
++#include <linux/file.h>
+ #include "ecryptfs_kernel.h"
+
+ struct ecryptfs_open_req {
+@@ -147,7 +148,7 @@ int ecryptfs_privileged_open(struct file **lower_file,
+ flags |= IS_RDONLY(d_inode(lower_dentry)) ? O_RDONLY : O_RDWR;
+ (*lower_file) = dentry_open(&req.path, flags, cred);
+ if (!IS_ERR(*lower_file))
+- goto out;
++ goto have_file;
+ if ((flags & O_ACCMODE) == O_RDONLY) {
+ rc = PTR_ERR((*lower_file));
+ goto out;
+@@ -165,8 +166,16 @@ int ecryptfs_privileged_open(struct file **lower_file,
+ mutex_unlock(&ecryptfs_kthread_ctl.mux);
+ wake_up(&ecryptfs_kthread_ctl.wait);
+ wait_for_completion(&req.done);
+- if (IS_ERR(*lower_file))
++ if (IS_ERR(*lower_file)) {
+ rc = PTR_ERR(*lower_file);
++ goto out;
++ }
++have_file:
++ if ((*lower_file)->f_op->mmap == NULL) {
++ fput(*lower_file);
++ *lower_file = NULL;
++ rc = -EMEDIUMTYPE;
++ }
+ out:
+ return rc;
+ }
+--
+2.5.5
+
diff --git a/kernel.spec b/kernel.spec
index ce1970d03..142e50700 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -658,6 +658,12 @@ Patch721: tipc-fix-an-infoleak-in-tipc_nl_compat_link_dump.patch
#CVE-2016-5244 rhbz 1343338 1343337
Patch722: rds-fix-an-infoleak-in-rds_inc_info_copy.txt
+#CVE-2016-1583 rhbz 1344721 1344722
+Patch723: proc-prevent-stacking-filesystems-on-top.patch
+Patch724: ecryptfs-fix-handling-of-directory-opening.patch
+Patch725: ecryptfs-forbid-opening-files-without-mmap-handler.patch
+Patch726: sched-panic-on-corrupted-stack-end.patch
+
# END OF PATCH DEFINITIONS
%endif
@@ -2175,6 +2181,9 @@ fi
#
#
%changelog
+* Mon Jun 13 2016 Josh Boyer <jwboyer@fedoraproject.org>
+- CVE-2016-1583 stack overflow via ecryptfs and /proc (rhbz 1344721 1344722)
+
* Wed Jun 08 2016 Josh Boyer <jwboyer@fedoraproject.org> - 4.5.7-200
- Linux v4.5.7
diff --git a/proc-prevent-stacking-filesystems-on-top.patch b/proc-prevent-stacking-filesystems-on-top.patch
new file mode 100644
index 000000000..178aa3ba6
--- /dev/null
+++ b/proc-prevent-stacking-filesystems-on-top.patch
@@ -0,0 +1,41 @@
+From e54ad7f1ee263ffa5a2de9c609d58dfa27b21cd9 Mon Sep 17 00:00:00 2001
+From: Jann Horn <jannh@google.com>
+Date: Wed, 1 Jun 2016 11:55:05 +0200
+Subject: [PATCH] proc: prevent stacking filesystems on top
+
+This prevents stacking filesystems (ecryptfs and overlayfs) from using
+procfs as lower filesystem. There is too much magic going on inside
+procfs, and there is no good reason to stack stuff on top of procfs.
+
+(For example, procfs does access checks in VFS open handlers, and
+ecryptfs by design calls open handlers from a kernel thread that doesn't
+drop privileges or so.)
+
+Signed-off-by: Jann Horn <jannh@google.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ fs/proc/root.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/fs/proc/root.c b/fs/proc/root.c
+index 361ab4ee42fc..ec649c92d270 100644
+--- a/fs/proc/root.c
++++ b/fs/proc/root.c
+@@ -121,6 +121,13 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
+ if (IS_ERR(sb))
+ return ERR_CAST(sb);
+
++ /*
++ * procfs isn't actually a stacking filesystem; however, there is
++ * too much magic going on inside it to permit stacking things on
++ * top of it
++ */
++ sb->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH;
++
+ if (!proc_parse_options(options, ns)) {
+ deactivate_locked_super(sb);
+ return ERR_PTR(-EINVAL);
+--
+2.5.5
+
diff --git a/sched-panic-on-corrupted-stack-end.patch b/sched-panic-on-corrupted-stack-end.patch
new file mode 100644
index 000000000..1d6bbaf3d
--- /dev/null
+++ b/sched-panic-on-corrupted-stack-end.patch
@@ -0,0 +1,36 @@
+From 29d6455178a09e1dc340380c582b13356227e8df Mon Sep 17 00:00:00 2001
+From: Jann Horn <jannh@google.com>
+Date: Wed, 1 Jun 2016 11:55:07 +0200
+Subject: [PATCH] sched: panic on corrupted stack end
+
+Until now, hitting this BUG_ON caused a recursive oops (because oops
+handling involves do_exit(), which calls into the scheduler, which in
+turn raises an oops), which caused stuff below the stack to be
+overwritten until a panic happened (e.g. via an oops in interrupt
+context, caused by the overwritten CPU index in the thread_info).
+
+Just panic directly.
+
+Signed-off-by: Jann Horn <jannh@google.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+---
+ kernel/sched/core.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/sched/core.c b/kernel/sched/core.c
+index d1f7149f8704..11546a6ed5df 100644
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -3047,7 +3047,8 @@ static noinline void __schedule_bug(struct task_struct *prev)
+ static inline void schedule_debug(struct task_struct *prev)
+ {
+ #ifdef CONFIG_SCHED_STACK_END_CHECK
+- BUG_ON(task_stack_end_corrupted(prev));
++ if (task_stack_end_corrupted(prev))
++ panic("corrupted stack end detected inside scheduler\n");
+ #endif
+
+ if (unlikely(in_atomic_preempt_off())) {
+--
+2.5.5
+