Avoid recursion in put_user_ns, potential overflow
This commit is contained in:
parent
f23e92fc88
commit
c546daa7be
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
Loading…
Reference in New Issue