Avoid recursion in put_user_ns, potential overflow

This commit is contained in:
Justin M. Forbes 2013-02-26 17:02:44 -06:00
parent f23e92fc88
commit c546daa7be
2 changed files with 116 additions and 1 deletions

View File

@ -62,7 +62,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 206
%global baserelease 207
%global fedora_build %{baserelease}
# base_sublevel is the kernel version we're starting with and patching
@ -825,6 +825,8 @@ Patch24000: alps-v2-3.7.patch
#rhbz 892060
Patch24001: ipv6-dst-from-ptr-race.patch
Patch24100: userns-avoid-recursion-in-put_user_ns.patch
# END OF PATCH DEFINITIONS
%endif
@ -1583,6 +1585,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
@ -2446,6 +2450,9 @@ fi
# ||----w |
# || ||
%changelog
* Tue Feb 26 2013 Justin M. Forbes <jforbes@redhat.com>
- Avoid recursion in put_user_ns, potential overflow
* Tue Feb 26 2013 Josh Boyer <jwboyer@redhat.com>
- CVE-2013-1767 tmpfs: fix use-after-free of mempolicy obj (rhbz 915592,915716)
- Fix vmalloc_fault oops during lazy MMU (rhbz 914737)

View File

@ -0,0 +1,108 @@
commit c61a2810a2161986353705b44d9503e6bb079f4f
Author: Eric W. Biederman <ebiederm@xmission.com>
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 <serge.hallyn@canonical.com>
Pointed-out-by: Vasily Kulikov <segoon@openwall.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
--- 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);