diff --git a/kernel.spec b/kernel.spec index 97bf815..0666d21 100644 --- a/kernel.spec +++ b/kernel.spec @@ -54,7 +54,7 @@ Summary: The Linux kernel # For non-released -rc kernels, this will be appended after the rcX and # gitX tags, so a 3 here would become part of release "0.rcX.gitX.3" # -%global baserelease 105 +%global baserelease 106 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -790,6 +790,8 @@ Patch23000: silence-brcmsmac-warning.patch #rhbz 812111 Patch24000: alps-v2-3.7.patch +Patch24100: userns-avoid-recursion-in-put_user_ns.patch + # END OF PATCH DEFINITIONS %endif @@ -1525,6 +1527,8 @@ ApplyPatch x86-mm-Fix-vmalloc_fault-oops-during-lazy-MMU-updates.patch #CVE-2013-1767 rhbz 915592,915716 ApplyPatch tmpfs-fix-use-after-free-of-mempolicy-object.patch +ApplyPatch userns-avoid-recursion-in-put_user_ns.patch + # END OF PATCH APPLICATIONS %endif @@ -2380,6 +2384,9 @@ fi # '-' | | # '-' %changelog +* Tue Feb 26 2013 Justin M. Forbes +- Avoid recursion in put_user_ns, potential overflow + * Tue Feb 26 2013 Josh Boyer - CVE-2013-1767 tmpfs: fix use-after-free of mempolicy obj (rhbz 915592,915716) - Fix vmalloc_fault oops during lazy MMU (rhbz 914737) diff --git a/userns-avoid-recursion-in-put_user_ns.patch b/userns-avoid-recursion-in-put_user_ns.patch new file mode 100644 index 0000000..d364e79 --- /dev/null +++ b/userns-avoid-recursion-in-put_user_ns.patch @@ -0,0 +1,108 @@ +commit c61a2810a2161986353705b44d9503e6bb079f4f +Author: Eric W. Biederman +Date: Fri Dec 28 18:58:39 2012 -0800 + + userns: Avoid recursion in put_user_ns + + When freeing a deeply nested user namespace free_user_ns calls + put_user_ns on it's parent which may in turn call free_user_ns again. + When -fno-optimize-sibling-calls is passed to gcc one stack frame per + user namespace is left on the stack, potentially overflowing the + kernel stack. CONFIG_FRAME_POINTER forces -fno-optimize-sibling-calls + so we can't count on gcc to optimize this code. + + Remove struct kref and use a plain atomic_t. Making the code more + flexible and easier to comprehend. Make the loop in free_user_ns + explict to guarantee that the stack does not overflow with + CONFIG_FRAME_POINTER enabled. + + I have tested this fix with a simple program that uses unshare to + create a deeply nested user namespace structure and then calls exit. + With 1000 nesteuser namespaces before this change running my test + program causes the kernel to die a horrible death. With 10,000,000 + nested user namespaces after this change my test program runs to + completion and causes no harm. + + Acked-by: Serge Hallyn + Pointed-out-by: Vasily Kulikov + Signed-off-by: "Eric W. Biederman" + +--- linux-3.7.9-105.fc17.noarch/include/linux/user_namespace.h 2013-02-14 11:29:49.757652513 -0600 ++++ linux-3.7.9-105.fc17.user_ns/include/linux/user_namespace.h 2013-02-26 15:19:40.696782035 -0600 +@@ -21,7 +21,7 @@ struct user_namespace { + struct uid_gid_map uid_map; + struct uid_gid_map gid_map; + struct uid_gid_map projid_map; +- struct kref kref; ++ atomic_t count; + struct user_namespace *parent; + kuid_t owner; + kgid_t group; +@@ -34,17 +34,17 @@ extern struct user_namespace init_user_n + static inline struct user_namespace *get_user_ns(struct user_namespace *ns) + { + if (ns) +- kref_get(&ns->kref); ++ atomic_inc(&ns->count); + return ns; + } + + extern int create_user_ns(struct cred *new); +-extern void free_user_ns(struct kref *kref); ++extern void free_user_ns(struct user_namespace *ns); + + static inline void put_user_ns(struct user_namespace *ns) + { +- if (ns) +- kref_put(&ns->kref, free_user_ns); ++ if (ns && atomic_dec_and_test(&ns->count)) ++ free_user_ns(ns); + } + + struct seq_operations; +--- linux-3.7.9-105.fc17.noarch/kernel/user.c 2013-02-14 11:29:46.675652732 -0600 ++++ linux-3.7.9-105.fc17.user_ns/kernel/user.c 2013-02-26 15:16:12.347796824 -0600 +@@ -46,9 +46,7 @@ struct user_namespace init_user_ns = { + .count = 4294967295U, + }, + }, +- .kref = { +- .refcount = ATOMIC_INIT(3), +- }, ++ .count = ATOMIC_INIT(3), + .owner = GLOBAL_ROOT_UID, + .group = GLOBAL_ROOT_GID, + }; +--- linux-3.7.9-105.fc17.noarch/kernel/user_namespace.c 2013-02-14 11:29:46.690652731 -0600 ++++ linux-3.7.9-105.fc17.user_ns/kernel/user_namespace.c 2013-02-26 15:24:47.984760224 -0600 +@@ -52,7 +52,7 @@ int create_user_ns(struct cred *new) + if (!ns) + return -ENOMEM; + +- kref_init(&ns->kref); ++ atomic_set(&ns->count, 1); + ns->parent = parent_ns; + ns->owner = owner; + ns->group = group; +@@ -78,14 +78,15 @@ int create_user_ns(struct cred *new) + return 0; + } + +-void free_user_ns(struct kref *kref) ++void free_user_ns(struct user_namespace *ns) + { +- struct user_namespace *parent, *ns = +- container_of(kref, struct user_namespace, kref); ++ struct user_namespace *parent; + +- parent = ns->parent; +- kmem_cache_free(user_ns_cachep, ns); +- put_user_ns(parent); ++ do { ++ parent = ns->parent; ++ kmem_cache_free(user_ns_cachep, ns); ++ ns = parent; ++ } while (atomic_dec_and_test(&parent->count)); + } + EXPORT_SYMBOL(free_user_ns); +