From patchwork Fri Oct 4 13:46:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Catalin Marinas X-Patchwork-Id: 175230 Delivered-To: patch@linaro.org Received: by 2002:a92:7e96:0:0:0:0:0 with SMTP id q22csp724785ill; Fri, 4 Oct 2019 06:46:31 -0700 (PDT) X-Google-Smtp-Source: APXvYqyZR+6b4cM7MWlXAPjqCgfF1S/RK6Zz0PNsxSL7tiIWv7CqJeFojxwWwGK4/d2ffr9ZpfPM X-Received: by 2002:a17:906:34d0:: with SMTP id h16mr12685113ejb.190.1570196791366; Fri, 04 Oct 2019 06:46:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1570196791; cv=none; d=google.com; s=arc-20160816; b=SX7c8nG75aOcYx9QHa1jHbuBeNrKsXI+O9/y0M+8KdntMawspFOHuuFFQ9skrRjhMO uVSOuLT2WKh5O1cffAkQ7h903bilIBPumDwXFtogtlezVAv6XHX7ggbYyBFCj24JKXq3 rLVzeI53PcfLm09oAzlulU/XYbWtN4U3devO68bc52H6ItIMgnyigsKd9Z5lxFSouHJq K8AGPzYg7ALodAK45bl4IQzMwi7rg5LTAQVcnCe0/iz53O0KPsWQbR3CkzAE4Ok8ngU6 7NZTXOml75m2g6Cwjo9y37u/wXjv2mzPJEhvOVyYMuiQOb0lyHwCYwtZ/jAIdVIgdAgu 9iVA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=nAjaUoBo1rGjm+2eTRSZw2g8eBANZcj+4GdOdddGxDM=; b=IoXwpofctyJcVZ80f/CmgOT0tJ7hdZkH+sEoXYBAZF0baYAJq7IyhnaBj8KZj9bSUj Ywb4Y73W4uJ3ECE/U4oXIISgie6XPKg2dkRThrAGseXkwnAlrA/4YJS6mxY1Gwq1eEfN AhgHCbGS2zhB5LV8iCfutChDDd1RKL6LvGpgdQrEaT5vvzPi0xLSMoQo5bhHh6gUa6cm 8CeY4yqE+aXgomaJ0QzK2w1qbmFIgkoeui+/b75B/+8fkXgTGGlJ7Bj4vZsbnXNMgMJa 6aKEfy11y7A728O8rykzWOY7S9/y5Nmb25yq+1t+6izbpciDWTrtW7A3jHt7gb2+OXY5 hHfA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id v4si3588062edm.183.2019.10.04.06.46.31; Fri, 04 Oct 2019 06:46:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388780AbfJDNqa (ORCPT + 27 others); Fri, 4 Oct 2019 09:46:30 -0400 Received: from foss.arm.com ([217.140.110.172]:45510 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388333AbfJDNqa (ORCPT ); Fri, 4 Oct 2019 09:46:30 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 6845B15A1; Fri, 4 Oct 2019 06:46:29 -0700 (PDT) Received: from arrakis.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com [10.121.207.14]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 7E22F3F739; Fri, 4 Oct 2019 06:46:28 -0700 (PDT) From: Catalin Marinas To: linux-mm@kvack.org Cc: linux-kernel@vger.kernel.org, Alexey Kardashevskiy , Marc Dionne , Andrew Morton Subject: [PATCH] kmemleak: Do not corrupt the object_list during clean-up Date: Fri, 4 Oct 2019 14:46:24 +0100 Message-Id: <20191004134624.46216-1-catalin.marinas@arm.com> X-Mailer: git-send-email 2.23.0 MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In case of an error (e.g. memory pool too small), kmemleak disables itself and cleans up the already allocated metadata objects. However, if this happens early before the RCU callback mechanism is available, put_object() skips call_rcu() and frees the object directly. This is not safe with the RCU list traversal in __kmemleak_do_cleanup(). Change the list traversal in __kmemleak_do_cleanup() to list_for_each_entry_safe() and remove the rcu_read_{lock,unlock} since the kmemleak is already disabled at this point. In addition, avoid an unnecessary metadata object rb-tree look-up since it already has the struct kmemleak_object pointer. Fixes: c5665868183f ("mm: kmemleak: use the memory pool for early allocations") Reported-by: Alexey Kardashevskiy Reported-by: Marc Dionne Cc: Andrew Morton Signed-off-by: Catalin Marinas --- mm/kmemleak.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) Tested-by: Alexey Kardashevskiy Tested-by: Song Liu diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 03a8d84badad..244607663363 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -526,6 +526,16 @@ static struct kmemleak_object *find_and_get_object(unsigned long ptr, int alias) return object; } +/* + * Remove an object from the object_tree_root and object_list. Must be called + * with the kmemleak_lock held _if_ kmemleak is still enabled. + */ +static void __remove_object(struct kmemleak_object *object) +{ + rb_erase(&object->rb_node, &object_tree_root); + list_del_rcu(&object->object_list); +} + /* * Look up an object in the object search tree and remove it from both * object_tree_root and object_list. The returned object's use_count should be @@ -538,10 +548,8 @@ static struct kmemleak_object *find_and_remove_object(unsigned long ptr, int ali write_lock_irqsave(&kmemleak_lock, flags); object = lookup_object(ptr, alias); - if (object) { - rb_erase(&object->rb_node, &object_tree_root); - list_del_rcu(&object->object_list); - } + if (object) + __remove_object(object); write_unlock_irqrestore(&kmemleak_lock, flags); return object; @@ -1834,12 +1842,16 @@ static const struct file_operations kmemleak_fops = { static void __kmemleak_do_cleanup(void) { - struct kmemleak_object *object; + struct kmemleak_object *object, *tmp; - rcu_read_lock(); - list_for_each_entry_rcu(object, &object_list, object_list) - delete_object_full(object->pointer); - rcu_read_unlock(); + /* + * Kmemleak has already been disabled, no need for RCU list traversal + * or kmemleak_lock held. + */ + list_for_each_entry_safe(object, tmp, &object_list, object_list) { + __remove_object(object); + __delete_object(object); + } } /*