diff options
author | Stanislaw Gruszka <sgruszka@redhat.com> | 2013-02-15 05:08:11 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2013-02-15 05:41:56 -0500 |
commit | e6c42c295e071dd74a66b5a9fcf4f44049888ed8 (patch) | |
tree | 7d417f64b7fa04511b4006eb4907ef41b7e401ed /kernel | |
parent | 9f4646d28362bc424b8a4c7d09ea1c2f1759371a (diff) |
posix-cpu-timers: Fix nanosleep task_struct leak
The trinity fuzzer triggered a task_struct reference leak via
clock_nanosleep with CPU_TIMERs. do_cpu_nanosleep() calls
posic_cpu_timer_create(), but misses a corresponding
posix_cpu_timer_del() which leads to the task_struct reference leak.
Reported-and-tested-by: Tommi Rantala <tt.rantala@gmail.com>
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Cc: Dave Jones <davej@redhat.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/20130215100810.GF4392@redhat.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/posix-cpu-timers.c | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index a278cad1d5d6..942ca27a28b7 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c | |||
@@ -1401,8 +1401,10 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, | |||
1401 | while (!signal_pending(current)) { | 1401 | while (!signal_pending(current)) { |
1402 | if (timer.it.cpu.expires.sched == 0) { | 1402 | if (timer.it.cpu.expires.sched == 0) { |
1403 | /* | 1403 | /* |
1404 | * Our timer fired and was reset. | 1404 | * Our timer fired and was reset, below |
1405 | * deletion can not fail. | ||
1405 | */ | 1406 | */ |
1407 | posix_cpu_timer_del(&timer); | ||
1406 | spin_unlock_irq(&timer.it_lock); | 1408 | spin_unlock_irq(&timer.it_lock); |
1407 | return 0; | 1409 | return 0; |
1408 | } | 1410 | } |
@@ -1420,9 +1422,26 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags, | |||
1420 | * We were interrupted by a signal. | 1422 | * We were interrupted by a signal. |
1421 | */ | 1423 | */ |
1422 | sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp); | 1424 | sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp); |
1423 | posix_cpu_timer_set(&timer, 0, &zero_it, it); | 1425 | error = posix_cpu_timer_set(&timer, 0, &zero_it, it); |
1426 | if (!error) { | ||
1427 | /* | ||
1428 | * Timer is now unarmed, deletion can not fail. | ||
1429 | */ | ||
1430 | posix_cpu_timer_del(&timer); | ||
1431 | } | ||
1424 | spin_unlock_irq(&timer.it_lock); | 1432 | spin_unlock_irq(&timer.it_lock); |
1425 | 1433 | ||
1434 | while (error == TIMER_RETRY) { | ||
1435 | /* | ||
1436 | * We need to handle case when timer was or is in the | ||
1437 | * middle of firing. In other cases we already freed | ||
1438 | * resources. | ||
1439 | */ | ||
1440 | spin_lock_irq(&timer.it_lock); | ||
1441 | error = posix_cpu_timer_del(&timer); | ||
1442 | spin_unlock_irq(&timer.it_lock); | ||
1443 | } | ||
1444 | |||
1426 | if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) { | 1445 | if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) { |
1427 | /* | 1446 | /* |
1428 | * It actually did fire already. | 1447 | * It actually did fire already. |