Received: by 2002:a05:7412:419a:b0:f3:1519:9f41 with SMTP id i26csp1270204rdh; Fri, 24 Nov 2023 08:35:33 -0800 (PST) X-Google-Smtp-Source: AGHT+IH703ID+WwARnSiCR8V2MKlGQ1gIRSgbEavTu8muAA5N+hCdV8kHIEVl6UitA2xHJjdbBbg X-Received: by 2002:a05:6a00:981:b0:6c3:720a:157a with SMTP id u1-20020a056a00098100b006c3720a157amr4159729pfg.12.1700843733259; Fri, 24 Nov 2023 08:35:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1700843733; cv=none; d=google.com; s=arc-20160816; b=NCRcZXDIladbiCekBHYLoIYfrwn2O7EgA2DlwaocCqVkLo4Y5SPH0uSztKQzlZFOSc x0vHZIaV8IiIAzcxeifFyYwEoEAzAwbbnjswiH2MiLyA3wq3Tmet8gt+bECPAgiKRHmY vEQ3Fp76rafYk3m+6d3wgGo0rL8kvfr6Z9qhH4zT41AcIV3B9VqWAXxDHbYASbD4PD4m Z5KPFPUvb0viediSGTpb4LuwCfHap5tekt+YpWjEHyR1lsVgSN7N2l28AXjRjr7mXJQX lxDMFt/k8+HN1jUJGc1e8gz9fB+oaVx8nIavV3Y4yVF9sRfuXNS+7+dJi1cZE3lS01ZE HBdA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=0UN9GHGXC0XIxHJJM2egpSDSxRBo8sXF/uDuCd6FNTk=; fh=A9B0uqHrLOhV8lpdKrDO+2kao9UNQ/xn2a9tcpNN72M=; b=cj4sF6O5UrczZK2BP7tJ3TPh9beUeAA799gHv7ie/L7GCO0xpCdtFK84ptJZuipZz3 Qsng3VKSebg0G5H2DaHLn9oXdPlIhyQs76P4NP70X9Xu11AUik1Rj3bxY8CN+7fBZ+Eu 4CIZRx2Kt+E5V5eTOHXIoNuXKSWXFmfCvU7E8wdNy2IoHGuZBvXdvos19xCkQCsJCBSR nHzb0vN46/O13YmcjoAUHXimQnxSpR+J9/WDJFAvxnYxHGO4P1aGnIp5wOtiEJLPMihI OSU7mTMuKJsdz/6N50lG4qlTHV1o1WVlQyLQNR1Naob1VAUBDxhvRMBeY3NlGX1mcGPQ K0kw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sipsolutions.net header.s=mail header.b=dEGBjhHq; spf=pass (google.com: domain of linux-wireless+bounces-54-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) smtp.mailfrom="linux-wireless+bounces-54-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=REJECT dis=NONE) header.from=sipsolutions.net Return-Path: Received: from sy.mirrors.kernel.org (sy.mirrors.kernel.org. [147.75.48.161]) by mx.google.com with ESMTPS id ka40-20020a056a0093a800b006c4f047a75asi3997146pfb.225.2023.11.24.08.35.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 24 Nov 2023 08:35:33 -0800 (PST) Received-SPF: pass (google.com: domain of linux-wireless+bounces-54-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) client-ip=147.75.48.161; Authentication-Results: mx.google.com; dkim=pass header.i=@sipsolutions.net header.s=mail header.b=dEGBjhHq; spf=pass (google.com: domain of linux-wireless+bounces-54-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) smtp.mailfrom="linux-wireless+bounces-54-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=REJECT dis=NONE) header.from=sipsolutions.net Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sy.mirrors.kernel.org (Postfix) with ESMTPS id 1F1A1B21122 for ; Fri, 24 Nov 2023 16:35:26 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3D71735F04; Fri, 24 Nov 2023 16:35:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=sipsolutions.net header.i=@sipsolutions.net header.b="dEGBjhHq" X-Original-To: linux-wireless@vger.kernel.org Received: from sipsolutions.net (s3.sipsolutions.net [IPv6:2a01:4f8:242:246e::2]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 632D919A9; Fri, 24 Nov 2023 08:35:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sipsolutions.net; s=mail; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Content-Type:Sender :Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-To: Resent-Cc:Resent-Message-ID; bh=0UN9GHGXC0XIxHJJM2egpSDSxRBo8sXF/uDuCd6FNTk=; t=1700843718; x=1702053318; b=dEGBjhHqJTsI3Lj/zIFvfVU7hpUSbW4Q9f/75tq8/BRq+gz d5a7ajw/fcQc+64/94LsyvdAiGny149/bB7Edf4HI3QcolFt8gwjbK+D/PQeF1xr/Uf6jb49bLaVb ErHwiI/9GmwQlGhDr2/QV9qDStvblr4682sGC3LEzQAoyUNsXj+l5FUPk48CaZO2APtXvFJKClZjF 98j1oCKAWshh7zmB5Iz9EotnmdZ/oHm28S2icUHnTD9JqjhIlpZEyR+Gi4R5jyfWQAd+menPV1qGb QqwD3qo3sLCw/7I5Aeix1ofhT6g98eSAQpAYy1CPu3Yh6hWEXuj3G0ImMewrRWIw==; Received: by sipsolutions.net with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.97) (envelope-from ) id 1r6Z99-00000002fA8-1aGJ; Fri, 24 Nov 2023 17:35:15 +0100 From: Johannes Berg To: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , "Rafael J. Wysocki" , Johannes Berg Subject: [PATCH v2 1/6] debugfs: fix automount d_fsdata usage Date: Fri, 24 Nov 2023 17:25:24 +0100 Message-ID: <20231124172522.01928f127e73.I64fe5615568e87f9ae2d7fb2ac4e5fa96924cb50@changeid> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231124162522.16344-7-johannes@sipsolutions.net> References: <20231124162522.16344-7-johannes@sipsolutions.net> Precedence: bulk X-Mailing-List: linux-wireless@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Johannes Berg debugfs_create_automount() stores a function pointer in d_fsdata, but since commit 7c8d469877b1 ("debugfs: add support for more elaborate ->d_fsdata") debugfs_release_dentry() will free it, now conditionally on DEBUGFS_FSDATA_IS_REAL_FOPS_BIT, but that's not set for the function pointer in automount. As a result, removing an automount dentry would attempt to free the function pointer. Luckily, the only user of this (tracing) never removes it. Nevertheless, it's safer if we just handle the fsdata in one way, namely either DEBUGFS_FSDATA_IS_REAL_FOPS_BIT or allocated. Thus, change the automount to allocate it, and use the real_fops in the data to indicate whether or not automount is filled, rather than adding a type tag. At least for now this isn't actually needed, but the next changes will require it. Also check in debugfs_file_get() that it gets only called on regular files, just to make things clearer. Signed-off-by: Johannes Berg --- v2: add missing kfree() pointed out by smatch --- fs/debugfs/file.c | 8 ++++++++ fs/debugfs/inode.c | 27 ++++++++++++++++++++------- fs/debugfs/internal.h | 10 ++++++++-- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 87b3753aa4b1..e00189aebbf4 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -84,6 +84,14 @@ int debugfs_file_get(struct dentry *dentry) struct debugfs_fsdata *fsd; void *d_fsd; + /* + * This could only happen if some debugfs user erroneously calls + * debugfs_file_get() on a dentry that isn't even a file, let + * them know about it. + */ + if (WARN_ON(!d_is_reg(dentry))) + return -EINVAL; + d_fsd = READ_ONCE(dentry->d_fsdata); if (!((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) { fsd = d_fsd; diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 83e57e9f9fa0..dcde4199a625 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -236,17 +236,19 @@ static const struct super_operations debugfs_super_operations = { static void debugfs_release_dentry(struct dentry *dentry) { - void *fsd = dentry->d_fsdata; + struct debugfs_fsdata *fsd = dentry->d_fsdata; - if (!((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) - kfree(dentry->d_fsdata); + if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) + return; + + kfree(fsd); } static struct vfsmount *debugfs_automount(struct path *path) { - debugfs_automount_t f; - f = (debugfs_automount_t)path->dentry->d_fsdata; - return f(path->dentry, d_inode(path->dentry)->i_private); + struct debugfs_fsdata *fsd = path->dentry->d_fsdata; + + return fsd->automount(path->dentry, d_inode(path->dentry)->i_private); } static const struct dentry_operations debugfs_dops = { @@ -634,13 +636,23 @@ struct dentry *debugfs_create_automount(const char *name, void *data) { struct dentry *dentry = start_creating(name, parent); + struct debugfs_fsdata *fsd; struct inode *inode; if (IS_ERR(dentry)) return dentry; + fsd = kzalloc(sizeof(*fsd), GFP_KERNEL); + if (!fsd) { + failed_creating(dentry); + return ERR_PTR(-ENOMEM); + } + + fsd->automount = f; + if (!(debugfs_allow & DEBUGFS_ALLOW_API)) { failed_creating(dentry); + kfree(fsd); return ERR_PTR(-EPERM); } @@ -648,13 +660,14 @@ struct dentry *debugfs_create_automount(const char *name, if (unlikely(!inode)) { pr_err("out of free dentries, can not create automount '%s'\n", name); + kfree(fsd); return failed_creating(dentry); } make_empty_dir_inode(inode); inode->i_flags |= S_AUTOMOUNT; inode->i_private = data; - dentry->d_fsdata = (void *)f; + dentry->d_fsdata = fsd; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); d_instantiate(dentry, inode); diff --git a/fs/debugfs/internal.h b/fs/debugfs/internal.h index 92af8ae31313..f7c489b5a368 100644 --- a/fs/debugfs/internal.h +++ b/fs/debugfs/internal.h @@ -17,8 +17,14 @@ extern const struct file_operations debugfs_full_proxy_file_operations; struct debugfs_fsdata { const struct file_operations *real_fops; - refcount_t active_users; - struct completion active_users_drained; + union { + /* automount_fn is used when real_fops is NULL */ + debugfs_automount_t automount; + struct { + refcount_t active_users; + struct completion active_users_drained; + }; + }; }; /* -- 2.42.0