From patchwork Thu Jul 7 11:17:07 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Whitcroft X-Patchwork-Id: 103639 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id 7E676B6F77 for ; Thu, 7 Jul 2011 21:17:59 +1000 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1Qemab-000520-E9; Thu, 07 Jul 2011 11:17:49 +0000 Received: from adelie.canonical.com ([91.189.90.139]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1QemaY-00051W-M5 for kernel-team@lists.ubuntu.com; Thu, 07 Jul 2011 11:17:46 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by adelie.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1QemaY-0005xp-J5; Thu, 07 Jul 2011 11:17:46 +0000 Received: from 79-71-114-181.dynamic.dsl.as9105.com ([79.71.114.181] helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1QemaW-0000lx-Mc; Thu, 07 Jul 2011 11:17:46 +0000 From: Andy Whitcroft To: kernel-team@lists.ubuntu.com Subject: [hardy CVE 1/1] taskstats: don't allow duplicate entries in listener mode Date: Thu, 7 Jul 2011 12:17:07 +0100 Message-Id: <1310037428-20088-2-git-send-email-apw@canonical.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1310037428-20088-1-git-send-email-apw@canonical.com> References: <1310037428-20088-1-git-send-email-apw@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.13 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com From: Vasiliy Kulikov Currently a single process may register exit handlers unlimited times. It may lead to a bloated listeners chain and very slow process terminations. Eg after 10KK sent TASKSTATS_CMD_ATTR_REGISTER_CPUMASKs ~300 Mb of kernel memory is stolen for the handlers chain and "time id" shows 2-7 seconds instead of normal 0.003. It makes it possible to exhaust all kernel memory and to eat much of CPU time by triggerring numerous exits on a single CPU. The patch limits the number of times a single process may register itself on a single CPU to one. One little issue is kept unfixed - as taskstats_exit() is called before exit_files() in do_exit(), the orphaned listener entry (if it was not explicitly deregistered) is kept until the next someone's exit() and implicit deregistration in send_cpu_listeners(). So, if a process registered itself as a listener exits and the next spawned process gets the same pid, it would inherit taskstats attributes. Signed-off-by: Vasiliy Kulikov Cc: Balbir Singh Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (backported from commit 26c4caea9d697043cc5a458b96411b86d7f6babd) CVE-2011-2484 BugLink: http://bugs.launchpad.net/bugs/806390 Signed-off-by: Andy Whitcroft --- kernel/taskstats.c | 15 ++++++++++++--- 1 files changed, 12 insertions(+), 3 deletions(-) diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 07e86a8..99e20d1 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -293,17 +293,19 @@ ret: static int add_del_listener(pid_t pid, cpumask_t *maskp, int isadd) { struct listener_list *listeners; - struct listener *s, *tmp; + struct listener *s, *tmp, *s2; unsigned int cpu; cpumask_t mask = *maskp; if (!cpus_subset(mask, cpu_possible_map)) return -EINVAL; + s = NULL; if (isadd == REGISTER) { for_each_cpu_mask(cpu, mask) { - s = kmalloc_node(sizeof(struct listener), GFP_KERNEL, - cpu_to_node(cpu)); + if (!s) + s = kmalloc_node(sizeof(struct listener), + GFP_KERNEL, cpu_to_node(cpu)); if (!s) goto cleanup; s->pid = pid; @@ -312,9 +314,16 @@ static int add_del_listener(pid_t pid, cpumask_t *maskp, int isadd) listeners = &per_cpu(listener_array, cpu); down_write(&listeners->sem); + list_for_each_entry_safe(s2, tmp, &listeners->list, list) { + if (s2->pid == pid) + goto next_cpu; + } list_add(&s->list, &listeners->list); + s = NULL; +next_cpu: up_write(&listeners->sem); } + kfree(s); return 0; }