Received: by 2002:a05:6a10:22f:0:0:0:0 with SMTP id 15csp3443490pxk; Mon, 28 Sep 2020 18:39:40 -0700 (PDT) X-Google-Smtp-Source: ABdhPJy/LODZ2qIQBt8fQ2+51Pb6zYOLQKxwwvdiEES0hv2evUdHumIXQwCNzUpiHwdByn6FFr/h X-Received: by 2002:aa7:d78f:: with SMTP id s15mr788807edq.322.1601343580164; Mon, 28 Sep 2020 18:39:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1601343580; cv=none; d=google.com; s=arc-20160816; b=ruEVXU+gk1j8xDjwY8Qznu/UrBu3UnaiGOZB3LOqsaTDmYy6jLz/TbegheywoqsFZH WLruCsth3w9NgDInvqGPnJJi2kGxBPqxklvc46f9mB0mB6S5bv4XBGWNPTKPnIHRqrfl oMeTbfY3BjVvYVy5VPzTzwT3dYFyLr7bqZx7rMBcwi2LHNOD+3D4MCZh30D8QgZ+yj+J 8GUaOtiMXUQKMoAWehrrwza9cZrNwbhM10+Ab9PWMV5XFbxfvizD0uRXaPAWoRTWw3hq TCyyGJxkGcsOFV6wu5gLjuCiM8yUVN6WRz/kh0y8pNcKmVSQTHd4YXf/ypvC25Cpyrrx HBvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=B2pP4/Nfcjbmpjdl6dcRpczvQtoVL920HQOIwWU8yZk=; b=cjkAOcEy1V6XjOzSOe/wQMMwrYvkMP0w3XGnd2EHVQfjeZsE4kyeBrkwAyjHZxZA+v dt+JBKn1jWMC//uS4D9CIdeOKllInwNc/BXx1L+XTMfCUn78pT6SQQBJ6J7qjLvNUNXR iQNIuz+zaPcuFYCNsxvOXkCurLDMRORZxZltzbFxEw9rgmSWwiEax+lw8vKNYPgkLR1S Ur6tPXCDZojHtHFWtvJDcZ2vXG8xeQzD/yy0IcrEPIuqEeojTfwVEl69NKVkP89A2Ia+ 54m3lPbt7phsKR/IlA73r5ZesKyQ7FCo2eX4YznoqVPSyT3f0CAgbNszmT9rXwlfy5cE 7ukQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=yGHRCLxd; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id u11si1812300edo.342.2020.09.28.18.39.09; Mon, 28 Sep 2020 18:39:40 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=yGHRCLxd; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727416AbgI2Baw (ORCPT + 99 others); Mon, 28 Sep 2020 21:30:52 -0400 Received: from mail.kernel.org ([198.145.29.99]:39832 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727177AbgI2Bar (ORCPT ); Mon, 28 Sep 2020 21:30:47 -0400 Received: from sasha-vm.mshome.net (c-73-47-72-35.hsd1.nh.comcast.net [73.47.72.35]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id DB780216C4; Tue, 29 Sep 2020 01:30:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1601343046; bh=FZJueCbKXlP1X/mzZDiM57QNy8OO3ThV2A/v+6+S+io=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=yGHRCLxdJ8HvqcphZj0F/YDyRasGOLeO5BsRm0uNejias8LqCXQZCOX9e3vWhB1XI fczfbxzrCvR0d2y5IyQHMamkSKWmWNPv0/D7TclD/cHmc/ZSk+gCcYGLzKFsXQ2Wem TqXlWBzx0JmmvCXgpCjMv66hjlkg9n56fWttqKG4= From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Charles Keepax , Mark Brown , Sasha Levin Subject: [PATCH AUTOSEL 5.8 14/29] regmap: debugfs: Fix handling of name string for debugfs init delays Date: Mon, 28 Sep 2020 21:30:11 -0400 Message-Id: <20200929013027.2406344-14-sashal@kernel.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200929013027.2406344-1-sashal@kernel.org> References: <20200929013027.2406344-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Charles Keepax [ Upstream commit 94cc89eb8fa5039fcb6e3e3d50f929ddcccee095 ] In regmap_debugfs_init the initialisation of the debugfs is delayed if the root node isn't ready yet. Most callers of regmap_debugfs_init pass the name from the regmap_config, which is considered temporary ie. may be unallocated after the regmap_init call returns. This leads to a potential use after free, where config->name has been freed by the time it is used in regmap_debugfs_initcall. This situation can be seen on Zynq, where the architecture init_irq callback registers a syscon device, using a local variable for the regmap_config. As init_irq is very early in the platform bring up the regmap debugfs root isn't ready yet. Although this doesn't crash it does result in the debugfs entry not having the correct name. Regmap already sets map->name from config->name on the regmap_init path and the fact that a separate field is used to pass the name to regmap_debugfs_init appears to be an artifact of the debugfs name being added before the map name. As such this patch updates regmap_debugfs_init to use map->name, which is already duplicated from the config avoiding the issue. This does however leave two lose ends, both regmap_attach_dev and regmap_reinit_cache can be called after a regmap is registered and would have had the effect of applying a new name to the debugfs entries. In both of these cases it was chosen to update the map name. In the case of regmap_attach_dev there are 3 users that currently use this function to update the name, thus doing so avoids changes for those users and it seems reasonable that attaching a device would want to set the name of the map. In the case of regmap_reinit_cache the primary use-case appears to be devices that need some register access to identify the device (for example devices in the same family) and then update the cache to match the exact hardware. Whilst no users do currently update the name here, given the use-case it seemed reasonable the name might want to be updated once the device is better identified. Signed-off-by: Charles Keepax Link: https://lore.kernel.org/r/20200917120828.12987-1-ckeepax@opensource.cirrus.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/base/regmap/internal.h | 4 +-- drivers/base/regmap/regmap-debugfs.c | 7 ++--- drivers/base/regmap/regmap.c | 44 +++++++++++++++++++++------- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 3d80c4b43f720..e0ff8e90ebdcf 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -217,7 +217,7 @@ struct regmap_field { #ifdef CONFIG_DEBUG_FS extern void regmap_debugfs_initcall(void); -extern void regmap_debugfs_init(struct regmap *map, const char *name); +extern void regmap_debugfs_init(struct regmap *map); extern void regmap_debugfs_exit(struct regmap *map); static inline void regmap_debugfs_disable(struct regmap *map) @@ -227,7 +227,7 @@ static inline void regmap_debugfs_disable(struct regmap *map) #else static inline void regmap_debugfs_initcall(void) { } -static inline void regmap_debugfs_init(struct regmap *map, const char *name) { } +static inline void regmap_debugfs_init(struct regmap *map) { } static inline void regmap_debugfs_exit(struct regmap *map) { } static inline void regmap_debugfs_disable(struct regmap *map) { } #endif diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index f58baff2be0af..b6d63ef16b442 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -17,7 +17,6 @@ struct regmap_debugfs_node { struct regmap *map; - const char *name; struct list_head link; }; @@ -544,11 +543,12 @@ static const struct file_operations regmap_cache_bypass_fops = { .write = regmap_cache_bypass_write_file, }; -void regmap_debugfs_init(struct regmap *map, const char *name) +void regmap_debugfs_init(struct regmap *map) { struct rb_node *next; struct regmap_range_node *range_node; const char *devname = "dummy"; + const char *name = map->name; /* * Userspace can initiate reads from the hardware over debugfs. @@ -569,7 +569,6 @@ void regmap_debugfs_init(struct regmap *map, const char *name) if (!node) return; node->map = map; - node->name = name; mutex_lock(®map_debugfs_early_lock); list_add(&node->link, ®map_debugfs_early_list); mutex_unlock(®map_debugfs_early_lock); @@ -679,7 +678,7 @@ void regmap_debugfs_initcall(void) mutex_lock(®map_debugfs_early_lock); list_for_each_entry_safe(node, tmp, ®map_debugfs_early_list, link) { - regmap_debugfs_init(node->map, node->name); + regmap_debugfs_init(node->map); list_del(&node->link); kfree(node); } diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 795a62a040220..a7ab49ce5de00 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -581,14 +581,34 @@ static void regmap_range_exit(struct regmap *map) kfree(map->selector_work_buf); } +static int regmap_set_name(struct regmap *map, const struct regmap_config *config) +{ + if (config->name) { + const char *name = kstrdup_const(config->name, GFP_KERNEL); + + if (!name) + return -ENOMEM; + + kfree_const(map->name); + map->name = name; + } + + return 0; +} + int regmap_attach_dev(struct device *dev, struct regmap *map, const struct regmap_config *config) { struct regmap **m; + int ret; map->dev = dev; - regmap_debugfs_init(map, config->name); + ret = regmap_set_name(map, config); + if (ret) + return ret; + + regmap_debugfs_init(map); /* Add a devres resource for dev_get_regmap() */ m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL); @@ -679,9 +699,9 @@ struct regmap *__regmap_init(struct device *dev, const char *lock_name) { struct regmap *map; - int ret = -EINVAL; enum regmap_endian reg_endian, val_endian; int i, j; + int ret; if (!config) goto err; @@ -692,13 +712,9 @@ struct regmap *__regmap_init(struct device *dev, goto err; } - if (config->name) { - map->name = kstrdup_const(config->name, GFP_KERNEL); - if (!map->name) { - ret = -ENOMEM; - goto err_map; - } - } + ret = regmap_set_name(map, config); + if (ret) + goto err_map; if (config->disable_locking) { map->lock = map->unlock = regmap_lock_unlock_none; @@ -1142,7 +1158,7 @@ struct regmap *__regmap_init(struct device *dev, if (ret != 0) goto err_regcache; } else { - regmap_debugfs_init(map, config->name); + regmap_debugfs_init(map); } return map; @@ -1302,6 +1318,8 @@ EXPORT_SYMBOL_GPL(regmap_field_free); */ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) { + int ret; + regcache_exit(map); regmap_debugfs_exit(map); @@ -1314,7 +1332,11 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) map->readable_noinc_reg = config->readable_noinc_reg; map->cache_type = config->cache_type; - regmap_debugfs_init(map, config->name); + ret = regmap_set_name(map, config); + if (ret) + return ret; + + regmap_debugfs_init(map); map->cache_bypass = false; map->cache_only = false; -- 2.25.1