diff options
author | Jiri Slaby <jslaby@suse.cz> | 2016-05-20 17:00:25 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-20 17:58:30 -0700 |
commit | 0740aa5f6375681c57488c4ea55d05a0341cfc9c (patch) | |
tree | b6c23b0037f9938467896b885b59234cbd47dd4b /kernel/fork.c | |
parent | e64646946ed32902fd597fa6e514b1da84642de3 (diff) | |
download | linux-0740aa5f6375681c57488c4ea55d05a0341cfc9c.tar.gz linux-0740aa5f6375681c57488c4ea55d05a0341cfc9c.tar.bz2 linux-0740aa5f6375681c57488c4ea55d05a0341cfc9c.zip |
fork: free thread in copy_process on failure
When using this program (as root):
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/io.h>
#include <sys/types.h>
#include <sys/wait.h>
#define ITER 1000
#define FORKERS 15
#define THREADS (6000/FORKERS) // 1850 is proc max
static void fork_100_wait()
{
unsigned a, to_wait = 0;
printf("\t%d forking %d\n", THREADS, getpid());
for (a = 0; a < THREADS; a++) {
switch (fork()) {
case 0:
usleep(1000);
exit(0);
break;
case -1:
break;
default:
to_wait++;
break;
}
}
printf("\t%d forked from %d, waiting for %d\n", THREADS, getpid(),
to_wait);
for (a = 0; a < to_wait; a++)
wait(NULL);
printf("\t%d waited from %d\n", THREADS, getpid());
}
static void run_forkers()
{
pid_t forkers[FORKERS];
unsigned a;
for (a = 0; a < FORKERS; a++) {
switch ((forkers[a] = fork())) {
case 0:
fork_100_wait();
exit(0);
break;
case -1:
err(1, "DIE fork of %d'th forker", a);
break;
default:
break;
}
}
for (a = 0; a < FORKERS; a++)
waitpid(forkers[a], NULL, 0);
}
int main()
{
unsigned a;
int ret;
ret = ioperm(10, 20, 0);
if (ret < 0)
err(1, "ioperm");
for (a = 0; a < ITER; a++)
run_forkers();
return 0;
}
kmemleak reports many occurences of this leak:
unreferenced object 0xffff8805917c8000 (size 8192):
comm "fork-leak", pid 2932, jiffies 4295354292 (age 1871.028s)
hex dump (first 32 bytes):
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................
backtrace:
[<ffffffff814cfbf5>] kmemdup+0x25/0x50
[<ffffffff8103ab43>] copy_thread_tls+0x6c3/0x9a0
[<ffffffff81150174>] copy_process+0x1a84/0x5790
[<ffffffff811dc375>] wake_up_new_task+0x2d5/0x6f0
[<ffffffff8115411d>] _do_fork+0x12d/0x820
...
Due to the leakage of the memory items which should have been freed in
arch/x86/kernel/process.c:exit_thread().
Make sure the memory is freed when fork fails later in copy_process.
This is done by calling exit_thread with the thread to kill.
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
Cc: Aurelien Jacquiot <a-jacquiot@ti.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chen Liqin <liqin.linux@gmail.com>
Cc: Chris Metcalf <cmetcalf@mellanox.com>
Cc: Chris Zankel <chris@zankel.net>
Cc: David Howells <dhowells@redhat.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Guan Xuetao <gxt@mprc.pku.edu.cn>
Cc: Haavard Skinnemoen <hskinnemoen@gmail.com>
Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Helge Deller <deller@gmx.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: James Hogan <james.hogan@imgtec.com>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Jesper Nilsson <jesper.nilsson@axis.com>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Jonas Bonn <jonas@southpole.se>
Cc: Koichi Yasutake <yasutake.koichi@jp.panasonic.com>
Cc: Lennox Wu <lennox.wu@gmail.com>
Cc: Ley Foon Tan <lftan@altera.com>
Cc: Mark Salter <msalter@redhat.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Matt Turner <mattst88@gmail.com>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Michal Simek <monstr@monstr.eu>
Cc: Mikael Starvik <starvik@axis.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Rich Felker <dalias@libc.org>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Richard Kuo <rkuo@codeaurora.org>
Cc: Richard Weinberger <richard@nod.at>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Steven Miao <realmz6@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Vineet Gupta <vgupta@synopsys.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 8fbed7194af1..103d78fd8f75 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1490,7 +1490,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, pid = alloc_pid(p->nsproxy->pid_ns_for_children); if (IS_ERR(pid)) { retval = PTR_ERR(pid); - goto bad_fork_cleanup_io; + goto bad_fork_cleanup_thread; } } @@ -1652,6 +1652,8 @@ bad_fork_cancel_cgroup: bad_fork_free_pid: if (pid != &init_struct_pid) free_pid(pid); +bad_fork_cleanup_thread: + exit_thread(p); bad_fork_cleanup_io: if (p->io_context) exit_io_context(p); |