From patchwork Tue Jan 7 02:35:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13927990 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 33B9B6F30C; Tue, 7 Jan 2025 02:36:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217408; cv=none; b=ZxR/uQ7zoZ309LA7CRbA2GuUrbVhHq6c+OpSfZTNO4yqBZW3362UBhn2qNv0sxRXojA/LnYHwpRv7d7fE/XCFvotmNPCsptSwtX/6tKloQocA4/5vDcKapmehZGXmYG/WO8tgG2TxcEX2r12NZWw7sUOyjrEWr9hil5Hv98vXss= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217408; c=relaxed/simple; bh=LXUMqhGpXyCk+mN3SeUyOyODLVWgqRr9V9axoWpO9Oc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=E7/N4kAe/a04l1WoE0F13MBFQ+B4c/MfDvB3GOYbb1B7mpuCt50k3V02WK0DXCVC3Z2v7K5PQ2ipO5gWkFgS9u0HFoAY4lWNd8mD8Osk71cNYIXRC4SiOHpc78kYLjTeu2KZ9ntYCzz4ssVIG0bnEoWHKJ38+3VyXnimdSeaBPY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=YVEsvNuX; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="YVEsvNuX" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1736217404; bh=LXUMqhGpXyCk+mN3SeUyOyODLVWgqRr9V9axoWpO9Oc=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=YVEsvNuXwSA1aYM+jF8tW4csKmqzWNZHU82HavWJT4GA7fNfiFDkrqPm/IYUkrW4n GerpU0s04e/+VvLQ3zX5XvruX7Uc1ka8jfYrsZ7+t2pcs/2g/bheOcpzd1XdhiecIv 8EwNGep1Z7n+GzkhB6CegkdbnuUfRA5f7YmKGIeg= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 90D6012860B7; Mon, 06 Jan 2025 21:36:44 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id uXQFHwVykRdA; Mon, 6 Jan 2025 21:36:44 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 331F21281F72; Mon, 06 Jan 2025 21:36:44 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v2 1/6] efivarfs: remove unused efi_varaible.Attributes and .kobj Date: Mon, 6 Jan 2025 18:35:20 -0800 Message-Id: <20250107023525.11466-2-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> References: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 These fields look to be remnants of older code: Attributes was likely meant to stash the variable attributes, but doesn't because we always read them from the variable store and kobj was likely left over from an older iteration of code where we manually created the objects instead of using a filesystem. Signed-off-by: James Bottomley --- fs/efivarfs/internal.h | 2 -- fs/efivarfs/super.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index 74f0602a9e01..64d15d1bb6bf 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -24,13 +24,11 @@ struct efivarfs_fs_info { struct efi_variable { efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)]; efi_guid_t VendorGuid; - __u32 Attributes; }; struct efivar_entry { struct efi_variable var; struct list_head list; - struct kobject kobj; }; int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index beba15673be8..d3c8528274aa 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -245,7 +245,7 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, inode_lock(inode); inode->i_private = entry; - i_size_write(inode, size + sizeof(entry->var.Attributes)); + i_size_write(inode, size + sizeof(__u32)); /* attributes + data */ inode_unlock(inode); d_add(dentry, inode); From patchwork Tue Jan 7 02:35:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13927991 Received: from bedivere.hansenpartnership.com (unknown [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F1F241C69D; Tue, 7 Jan 2025 02:37:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217433; cv=none; b=AUNDSuyb5FX+g5FDJdYyjsasDm74RM/LuPuFyB0DbG5zlbWhQo9wX6FYoeI/adlIpsgoSwWO3ll1OkhoSDAqrPkUoIAPr3FehnrlKHqYc+yLH6hqvK1cDR5e04qGOdWkk8ZGSG4/O3utZhluEaV56kCxPnHb/XbmGC2/DNDD9+E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217433; c=relaxed/simple; bh=1zOgWcapBQJgcm45Fqy3RGNsrJnsNIwbYD2rxUWAOr0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=iJbBM9z0QPSwqW6641N2Xgy5iHWydRsrdBfph+Iq3PfAyPqi5CnO2fZd+rwbAjFRUGvRPiAEKnWFybFEjSWemhGcrgHnRvJNQf4+O8dtZuCJeydH1+nxac935mAIQySezFdpxVaoopIo2VG7KL/QscdLq/wMnJ4JfEO53mIKVUQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=U+Qj2e+f; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="U+Qj2e+f" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1736217430; bh=1zOgWcapBQJgcm45Fqy3RGNsrJnsNIwbYD2rxUWAOr0=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=U+Qj2e+ftlrSIQ42rccYh73yz+a0vtzdvegL6yw/N1LvrR1HINKFG+z1Xo7N5dde3 dB+UofvoZmGt1g+fihR1y9nA1KlfvhR2KIyX0hxLASEePox35/7Bu60NeqS8yQB5gy h7zzQcxyGt6TANNx9nGGUNi8IEBPaLSoUiFbcZ0c= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 4FB1B1280E9E; Mon, 06 Jan 2025 21:37:10 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id grlkZWDYgCAK; Mon, 6 Jan 2025 21:37:10 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id C3DBB128017F; Mon, 06 Jan 2025 21:37:09 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v2 2/6] efivarfs: add helper to convert from UC16 name and GUID to utf8 name Date: Mon, 6 Jan 2025 18:35:21 -0800 Message-Id: <20250107023525.11466-3-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> References: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 These will be used by a later patch to check for uniqueness on initial EFI variable iteration. Signed-off-by: James Bottomley --- fs/efivarfs/internal.h | 1 + fs/efivarfs/super.c | 17 +++-------------- fs/efivarfs/vars.c | 25 +++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index 64d15d1bb6bf..c10efc1ad0a7 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -55,6 +55,7 @@ bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, unsigned long data_size); bool efivar_variable_is_removable(efi_guid_t vendor, const char *name, size_t len); +char *efivar_get_utf8name(const efi_char16_t *name16, efi_guid_t *vendor); extern const struct file_operations efivarfs_file_operations; extern const struct inode_operations efivarfs_dir_inode_operations; diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index d3c8528274aa..b22441f7f7c6 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -205,27 +205,16 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, memcpy(entry->var.VariableName, name16, name_size); memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); - len = ucs2_utf8size(entry->var.VariableName); - - /* name, plus '-', plus GUID, plus NUL*/ - name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); + name = efivar_get_utf8name(name16, &vendor); if (!name) goto fail; - ucs2_as_utf8(name, entry->var.VariableName, len); + /* length of the variable name itself: remove GUID and separator */ + len = strlen(name) - EFI_VARIABLE_GUID_LEN - 1; if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) is_removable = true; - name[len] = '-'; - - efi_guid_to_str(&entry->var.VendorGuid, name + len + 1); - - name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; - - /* replace invalid slashes like kobject_set_name_vargs does for /sys/firmware/efi/vars. */ - strreplace(name, '/', '!'); - inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0, is_removable); if (!inode) diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c index f7d43c847ee9..13594087d9ee 100644 --- a/fs/efivarfs/vars.c +++ b/fs/efivarfs/vars.c @@ -225,6 +225,31 @@ variable_matches(const char *var_name, size_t len, const char *match_name, } } +char * +efivar_get_utf8name(const efi_char16_t *name16, efi_guid_t *vendor) +{ + int len = ucs2_utf8size(name16); + char *name; + + /* name, plus '-', plus GUID, plus NUL*/ + name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); + if (!name) + return NULL; + + ucs2_as_utf8(name, name16, len); + + name[len] = '-'; + + efi_guid_to_str(vendor, name + len + 1); + + name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; + + /* replace invalid slashes like kobject_set_name_vargs does for /sys/firmware/efi/vars. */ + strreplace(name, '/', '!'); + + return name; +} + bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, unsigned long data_size) From patchwork Tue Jan 7 02:35:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13927992 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B5B8218EAB; Tue, 7 Jan 2025 02:37:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217451; cv=none; b=RdU0bssmaqIcFsLDR0jc9eP/fJuhd7sIeFmTI/k+bbVTBhjdhdJZkRu4xLKXjdn3q7gmGX83eAv2drCEHelArIG7jr7ABSCqg6VOaXWwIPqlZMWRG165C1L/+5QD+j+4FcuzRfKD1Zk8hqh7KYtRAWjECqPZh3ps0lQVG2HKsn8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217451; c=relaxed/simple; bh=OJkRkHwCEqTFagotBRzVUHjnmsnMz0CSgaXEDuj3qV0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=aeWa4rfch4D9i/QEIwDHvj3DWR8UPyApHargOww4mgG6vHb0V3YGDv9pOVzodHQKmLhZ6CTV4n6YM9oEbLvV62vIoPKh1wB8LjS/PY5azkqSqQB7KPx8bTua6WxdniklPe5gw55wg/76dPo/yOlS2112syzGRkzHiAIhiRvpnv8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=UW62aC8E; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="UW62aC8E" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1736217447; bh=OJkRkHwCEqTFagotBRzVUHjnmsnMz0CSgaXEDuj3qV0=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=UW62aC8EtN16GUk8Ow6qQVXuRDIHfKNHvKNi5X7Wa/BZSimtQdJV7as7N5gAlwn/G GN/4zUy6+x/JH+lrHMIfj1MfBzpLQSPqRVRVRg/kVs59+Fs3t4YPjHNdFj0x1KjydD FW6liLlu9AvGzQzCILvo4Y/xfnNYoa9Fl0VUW6O8= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id DB1F412868D5; Mon, 06 Jan 2025 21:37:27 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id 6PEtlBuqTdeL; Mon, 6 Jan 2025 21:37:27 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id E05D1128017F; Mon, 06 Jan 2025 21:37:26 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v2 3/6] efivarfs: make variable_is_present use dcache lookup Date: Mon, 6 Jan 2025 18:35:22 -0800 Message-Id: <20250107023525.11466-4-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> References: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Instead of searching the variable entry list for a variable, use the dcache lookup functions to find it instead. Also add an efivarfs_ prefix to the function now it is no longer static. Signed-off-by: James Bottomley --- v2: add IS_ERR_OR_NULL check before doing dput --- fs/efivarfs/internal.h | 2 ++ fs/efivarfs/super.c | 29 +++++++++++++++++++++++++++++ fs/efivarfs/vars.c | 26 ++------------------------ 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index c10efc1ad0a7..597ccaa60d37 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -56,6 +56,8 @@ bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, bool efivar_variable_is_removable(efi_guid_t vendor, const char *name, size_t len); char *efivar_get_utf8name(const efi_char16_t *name16, efi_guid_t *vendor); +bool efivarfs_variable_is_present(efi_char16_t *variable_name, + efi_guid_t *vendor, void *data); extern const struct file_operations efivarfs_file_operations; extern const struct inode_operations efivarfs_dir_inode_operations; diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index b22441f7f7c6..9e90823f8009 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -181,6 +181,35 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) return ERR_PTR(-ENOMEM); } +bool efivarfs_variable_is_present(efi_char16_t *variable_name, + efi_guid_t *vendor, void *data) +{ + char *name = efivar_get_utf8name(variable_name, vendor); + struct super_block *sb = data; + struct dentry *dentry; + struct qstr qstr; + + if (!name) + /* + * If the allocation failed there'll already be an + * error in the log (and likely a huge and growing + * number of them since they system will be under + * extreme memory pressure), so simply assume + * collision for safety but don't add to the log + * flood. + */ + return true; + + qstr.name = name; + qstr.len = strlen(name); + dentry = d_hash_and_lookup(sb->s_root, &qstr); + kfree(name); + if (!IS_ERR_OR_NULL(dentry)) + dput(dentry); + + return dentry != NULL; +} + static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, unsigned long name_size, void *data, struct list_head *list) diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c index 13594087d9ee..b2fc5bdc759a 100644 --- a/fs/efivarfs/vars.c +++ b/fs/efivarfs/vars.c @@ -313,28 +313,6 @@ efivar_variable_is_removable(efi_guid_t vendor, const char *var_name, return found; } -static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor, - struct list_head *head) -{ - struct efivar_entry *entry, *n; - unsigned long strsize1, strsize2; - bool found = false; - - strsize1 = ucs2_strsize(variable_name, EFI_VAR_NAME_LEN); - list_for_each_entry_safe(entry, n, head, list) { - strsize2 = ucs2_strsize(entry->var.VariableName, EFI_VAR_NAME_LEN); - if (strsize1 == strsize2 && - !memcmp(variable_name, &(entry->var.VariableName), - strsize2) && - !efi_guidcmp(entry->var.VendorGuid, - *vendor)) { - found = true; - break; - } - } - return found; -} - /* * Returns the size of variable_name, in bytes, including the * terminating NULL character, or variable_name_size if no NULL @@ -439,8 +417,8 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, * we'll ever see a different variable name, * and may end up looping here forever. */ - if (variable_is_present(variable_name, &vendor_guid, - head)) { + if (efivarfs_variable_is_present(variable_name, + &vendor_guid, data)) { dup_variable_bug(variable_name, &vendor_guid, variable_name_size); status = EFI_NOT_FOUND; From patchwork Tue Jan 7 02:35:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13927993 Received: from bedivere.hansenpartnership.com (unknown [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 96FD228691; Tue, 7 Jan 2025 02:37:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217472; cv=none; b=O+S/m5DhCTblk3RPDzqGBo5L7qr/zf3BwLC8wM8hz6/MnIpsJYsbWJn9Rm/lCbs7dCI50Z6LvpWHMTrCD78gLAJjH+MlskxPOJ2Gm8vdgBBu6brnVF9R5Ti3EdW6kGNX2lcBJ5VK/39CdyTnPlmKbH7S4BnsEMzG9rW7swuy9yU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217472; c=relaxed/simple; bh=tmisDjAtGHl5r+ZSk8zOBzy8Eo+Drg9L4QPsIMl1ZY0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=prTcQiACJ1Q/M5ahyZC6DcuD82fw4pfrYGUlZXfoV/U3SRopumHmIPuxb32Xe9o74C0A7+GjjolvQ1Jex77HtOV9fvFXCQY1iNexc7wjBfjlzZ+h/DCnErXgAnMqfY2rHtp8lNDHS7noa0jMVNtIzRN5xuW8scDBecS8KOD9Xd0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=FFIeBk3t; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="FFIeBk3t" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1736217467; bh=tmisDjAtGHl5r+ZSk8zOBzy8Eo+Drg9L4QPsIMl1ZY0=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=FFIeBk3t7yq8Pu5J8N8AJYXIlLbfaTIlsN3jLGsHFP5qphWmPMpLo/6wP+D8EGHlE uTgnAYA5yoYRL4Qc2l+2AUfhB7JFjALbV07Iq9OgYRzrwxIr05iWOdkQmdbEgFsVQm yz1EI/13NfB9c9FlQhAJo2KqHEUrmb7th+dggZyY= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 0CE621280B6C; Mon, 06 Jan 2025 21:37:47 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id s-Pr2xzWKXJg; Mon, 6 Jan 2025 21:37:46 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id A6371128017F; Mon, 06 Jan 2025 21:37:46 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v2 4/6] efivarfs: move freeing of variable entry into evict_inode Date: Mon, 6 Jan 2025 18:35:23 -0800 Message-Id: <20250107023525.11466-5-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> References: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Make the inodes the default management vehicle for struct efivar_entry, so they are now all freed automatically if the file is removed and on unmount in kill_litter_super(). Remove the now superfluous iterator to free the entries after kill_litter_super(). Also fixes a bug where some entry freeing was missing causing efivarfs to leak memory. Signed-off-by: James Bottomley --- fs/efivarfs/internal.h | 1 - fs/efivarfs/super.c | 15 +++++++-------- fs/efivarfs/vars.c | 39 +++------------------------------------ 3 files changed, 10 insertions(+), 45 deletions(-) diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index 597ccaa60d37..8d82fc8bca31 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -37,7 +37,6 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, int efivar_entry_add(struct efivar_entry *entry, struct list_head *head); void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head); -void efivar_entry_remove(struct efivar_entry *entry); int efivar_entry_delete(struct efivar_entry *entry); int efivar_entry_size(struct efivar_entry *entry, unsigned long *size); diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 9e90823f8009..d7facc99b745 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -41,6 +41,12 @@ static int efivarfs_ops_notifier(struct notifier_block *nb, unsigned long event, static void efivarfs_evict_inode(struct inode *inode) { + struct efivar_entry *entry = inode->i_private; + + if (entry) { + list_del(&entry->list); + kfree(entry); + } clear_inode(inode); } @@ -278,13 +284,6 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, return err; } -static int efivarfs_destroy(struct efivar_entry *entry, void *data) -{ - efivar_entry_remove(entry); - kfree(entry); - return 0; -} - enum { Opt_uid, Opt_gid, }; @@ -407,7 +406,7 @@ static void efivarfs_kill_sb(struct super_block *sb) kill_litter_super(sb); /* Remove all entries and destroy */ - efivar_entry_iter(efivarfs_destroy, &sfi->efivarfs_list, NULL); + WARN_ON(!list_empty(&sfi->efivarfs_list)); kfree(sfi); } diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c index b2fc5bdc759a..bb9406e03a10 100644 --- a/fs/efivarfs/vars.c +++ b/fs/efivarfs/vars.c @@ -485,34 +485,6 @@ void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head) list_add(&entry->list, head); } -/** - * efivar_entry_remove - remove entry from variable list - * @entry: entry to remove from list - * - * Returns 0 on success, or a kernel error code on failure. - */ -void efivar_entry_remove(struct efivar_entry *entry) -{ - list_del(&entry->list); -} - -/* - * efivar_entry_list_del_unlock - remove entry from variable list - * @entry: entry to remove - * - * Remove @entry from the variable list and release the list lock. - * - * NOTE: slightly weird locking semantics here - we expect to be - * called with the efivars lock already held, and we release it before - * returning. This is because this function is usually called after - * set_variable() while the lock is still held. - */ -static void efivar_entry_list_del_unlock(struct efivar_entry *entry) -{ - list_del(&entry->list); - efivar_unlock(); -} - /** * efivar_entry_delete - delete variable and remove entry from list * @entry: entry containing variable to delete @@ -536,12 +508,10 @@ int efivar_entry_delete(struct efivar_entry *entry) status = efivar_set_variable_locked(entry->var.VariableName, &entry->var.VendorGuid, 0, 0, NULL, false); - if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) { - efivar_unlock(); + efivar_unlock(); + if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) return efi_status_to_err(status); - } - efivar_entry_list_del_unlock(entry); return 0; } @@ -679,10 +649,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, &entry->var.VendorGuid, NULL, size, NULL); - if (status == EFI_NOT_FOUND) - efivar_entry_list_del_unlock(entry); - else - efivar_unlock(); + efivar_unlock(); if (status && status != EFI_BUFFER_TOO_SMALL) return efi_status_to_err(status); From patchwork Tue Jan 7 02:35:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13927994 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EEDA2770FE; Tue, 7 Jan 2025 02:38:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217500; cv=none; b=t54UO4uAECukk5sKibaoMhxCiWYAeIeBoqutksWHpnPwMKthET1e4wQ/9RgsGxp/WhIdqSZqn7eM97nkqNpB8coFXFqaeUeliUY3E3Lm9MCIwFg7a8iMAwFUpmUx/DVWkXB5hoOcr1BKT+asl72AcF7Gmewr0vcIRpxOP/T7t4s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217500; c=relaxed/simple; bh=ZIao2ipGlchj3zDdHedAyQ0iemLWbX3K5aK04u6S9yY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=eRvdIK/IzvUpbPUGeKeyKmXeMFqrp8RYlhVFnUkcA1Cmh9ZZeBMv+G8okAbGWhrLjbj+qgOzRAuqNYY+wFKGUeNIdbIcpCOcgQl5HkYeom0gbA8ey5Nr1cWLhX9UQtQ/ZPZ/nCbEJJ9GwFpjYh0oH1Hn/CjnzjGzBwfN4sama1M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=Q2XlHOsc; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="Q2XlHOsc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1736217497; bh=ZIao2ipGlchj3zDdHedAyQ0iemLWbX3K5aK04u6S9yY=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=Q2XlHOscXb15RAPhYWS0TS/lf991Wl6bnaAzqpaVZixUaq6D1/s/CyJk1AOTH2uja uoH26K6MZHzpnO+bNUeyDI9c8We1XjYkZpA7CSCsLg9+XlHhCPDrmPenG/vKZ0pCIM OlCh+jTEgVdx37e02cY/Ngwi7uJEV0ZlQMpiI+p0= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 543481280B6C; Mon, 06 Jan 2025 21:38:17 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id ey0vm5j_mvJ9; Mon, 6 Jan 2025 21:38:17 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id E3C70128017F; Mon, 06 Jan 2025 21:38:16 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v2 5/6] efivarfs: remove unused efivarfs_list Date: Mon, 6 Jan 2025 18:35:24 -0800 Message-Id: <20250107023525.11466-6-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> References: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Remove all function helpers and mentions of the efivarfs_list now that all consumers of the list have been removed and entry management goes exclusively through the inode. Signed-off-by: James Bottomley --- fs/efivarfs/inode.c | 5 --- fs/efivarfs/internal.h | 12 +----- fs/efivarfs/super.c | 15 ++----- fs/efivarfs/vars.c | 89 ++++++------------------------------------ 4 files changed, 16 insertions(+), 105 deletions(-) diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c index ec23da8405ff..7fe1b5b60902 100644 --- a/fs/efivarfs/inode.c +++ b/fs/efivarfs/inode.c @@ -77,7 +77,6 @@ static bool efivarfs_valid_name(const char *str, int len) static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { - struct efivarfs_fs_info *info = dir->i_sb->s_fs_info; struct inode *inode = NULL; struct efivar_entry *var; int namelen, i = 0, err = 0; @@ -119,10 +118,6 @@ static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir, inode->i_private = var; kmemleak_ignore(var); - err = efivar_entry_add(var, &info->efivarfs_list); - if (err) - goto out; - d_instantiate(dentry, inode); dget(dentry); out: diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index 8d82fc8bca31..18a600f80992 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -6,7 +6,6 @@ #ifndef EFIVAR_FS_INTERNAL_H #define EFIVAR_FS_INTERNAL_H -#include #include struct efivarfs_mount_opts { @@ -16,7 +15,6 @@ struct efivarfs_mount_opts { struct efivarfs_fs_info { struct efivarfs_mount_opts mount_opts; - struct list_head efivarfs_list; struct super_block *sb; struct notifier_block nb; }; @@ -28,15 +26,11 @@ struct efi_variable { struct efivar_entry { struct efi_variable var; - struct list_head list; }; -int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, - struct list_head *), - void *data, struct list_head *head); +int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), + void *data); -int efivar_entry_add(struct efivar_entry *entry, struct list_head *head); -void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head); int efivar_entry_delete(struct efivar_entry *entry); int efivar_entry_size(struct efivar_entry *entry, unsigned long *size); @@ -47,8 +41,6 @@ int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, unsigned long *size, void *data, bool *set); -int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), - struct list_head *head, void *data); bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, unsigned long data_size); diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index d7facc99b745..2523e74dbcfd 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -43,10 +43,7 @@ static void efivarfs_evict_inode(struct inode *inode) { struct efivar_entry *entry = inode->i_private; - if (entry) { - list_del(&entry->list); - kfree(entry); - } + kfree(entry); clear_inode(inode); } @@ -217,8 +214,7 @@ bool efivarfs_variable_is_present(efi_char16_t *variable_name, } static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, - unsigned long name_size, void *data, - struct list_head *list) + unsigned long name_size, void *data) { struct super_block *sb = (struct super_block *)data; struct efivar_entry *entry; @@ -262,7 +258,6 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, } __efivar_entry_get(entry, NULL, &size, NULL); - __efivar_entry_add(entry, list); /* copied by the above to local storage in the dentry. */ kfree(name); @@ -353,7 +348,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc) if (err) return err; - return efivar_init(efivarfs_callback, sb, &sfi->efivarfs_list); + return efivar_init(efivarfs_callback, sb); } static int efivarfs_get_tree(struct fs_context *fc) @@ -388,8 +383,6 @@ static int efivarfs_init_fs_context(struct fs_context *fc) if (!sfi) return -ENOMEM; - INIT_LIST_HEAD(&sfi->efivarfs_list); - sfi->mount_opts.uid = GLOBAL_ROOT_UID; sfi->mount_opts.gid = GLOBAL_ROOT_GID; @@ -405,8 +398,6 @@ static void efivarfs_kill_sb(struct super_block *sb) blocking_notifier_chain_unregister(&efivar_ops_nh, &sfi->nb); kill_litter_super(sb); - /* Remove all entries and destroy */ - WARN_ON(!list_empty(&sfi->efivarfs_list)); kfree(sfi); } diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c index bb9406e03a10..d0beecbf9441 100644 --- a/fs/efivarfs/vars.c +++ b/fs/efivarfs/vars.c @@ -364,16 +364,14 @@ static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid, * efivar_init - build the initial list of EFI variables * @func: callback function to invoke for every variable * @data: function-specific data to pass to @func - * @head: initialised head of variable list * * Get every EFI variable from the firmware and invoke @func. @func - * should call efivar_entry_add() to build the list of variables. + * should populate the initial dentry and inode tree. * * Returns 0 on success, or a kernel error code on failure. */ -int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, - struct list_head *), - void *data, struct list_head *head) +int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), + void *data) { unsigned long variable_name_size = 512; efi_char16_t *variable_name; @@ -424,7 +422,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, status = EFI_NOT_FOUND; } else { err = func(variable_name, vendor_guid, - variable_name_size, data, head); + variable_name_size, data); if (err) status = EFI_NOT_FOUND; } @@ -456,42 +454,12 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, } /** - * efivar_entry_add - add entry to variable list - * @entry: entry to add to list - * @head: list head - * - * Returns 0 on success, or a kernel error code on failure. - */ -int efivar_entry_add(struct efivar_entry *entry, struct list_head *head) -{ - int err; - - err = efivar_lock(); - if (err) - return err; - list_add(&entry->list, head); - efivar_unlock(); - - return 0; -} - -/** - * __efivar_entry_add - add entry to variable list - * @entry: entry to add to list - * @head: list head - */ -void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head) -{ - list_add(&entry->list, head); -} - -/** - * efivar_entry_delete - delete variable and remove entry from list + * efivar_entry_delete - delete variable * @entry: entry containing variable to delete * - * Delete the variable from the firmware and remove @entry from the - * variable list. It is the caller's responsibility to free @entry - * once we return. + * Delete the variable from the firmware. It is the caller's + * responsibility to free @entry (by deleting the dentry/inode) once + * we return. * * Returns 0 on success, -EINTR if we can't grab the semaphore, * converted EFI status code if set_variable() fails. @@ -605,7 +573,7 @@ int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, * get_variable() fail. * * If the EFI variable does not exist when calling set_variable() - * (EFI_NOT_FOUND), @entry is removed from the variable list. + * (EFI_NOT_FOUND). */ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, unsigned long *size, void *data, bool *set) @@ -621,9 +589,8 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, return -EINVAL; /* - * The lock here protects the get_variable call, the conditional - * set_variable call, and removal of the variable from the efivars - * list (in the case of an authenticated delete). + * The lock here protects the get_variable call and the + * conditional set_variable call */ err = efivar_lock(); if (err) @@ -661,37 +628,3 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, return err; } - -/** - * efivar_entry_iter - iterate over variable list - * @func: callback function - * @head: head of variable list - * @data: function-specific data to pass to callback - * - * Iterate over the list of EFI variables and call @func with every - * entry on the list. It is safe for @func to remove entries in the - * list via efivar_entry_delete() while iterating. - * - * Some notes for the callback function: - * - a non-zero return value indicates an error and terminates the loop - * - @func is called from atomic context - */ -int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), - struct list_head *head, void *data) -{ - struct efivar_entry *entry, *n; - int err = 0; - - err = efivar_lock(); - if (err) - return err; - - list_for_each_entry_safe(entry, n, head, list) { - err = func(entry, data); - if (err) - break; - } - efivar_unlock(); - - return err; -} From patchwork Tue Jan 7 02:35:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13927995 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DD5D628691; Tue, 7 Jan 2025 02:38:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217531; cv=none; b=CB2Egqwh9gSI/webdKyN7JFCUX1NRBCA8Ku9+ILRjV4DjnsuPBg0T534KNMi4losDF/E0To8Ex8k/rirhVHea5ta49ilaF0W63wkjZl9Q6CevKFZnpflmv6SqbhExNHWQ7KDPMkkvLUhQmrGi1HGR4KW9BjTV5LM4DfGlMT7Cd8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1736217531; c=relaxed/simple; bh=l2trXjx4HpiseBIIESlN2FkB35bZXyr+ptQmuXg+Ukg=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=helk1yNS8oYxLWnSY+PM6A242NURItojiTfzQFu022mDtEYKc4xs0OPYLHhNZ+DwFk/qDqm3Ys8p+kOUzb+geETKcc4gm4azpSMiae/MIWGo81rNi93/69+2Kt3dJD+EEr7USQj6TjgNCDX4ySJQMycBq++ri5zZaxMZ2XiweeY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=FSA601H3; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="FSA601H3" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1736217528; bh=l2trXjx4HpiseBIIESlN2FkB35bZXyr+ptQmuXg+Ukg=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=FSA601H3HjC/yluXyzMRLIr7Z+zJww4wa1ZpPA2MjpAWytHrK6i9K4sNWZvNSR17V gm6PvG7HzAPczEnXxd9/DF4vQaBTDkzDg3AiNiwBvbuac94XBKQthCSWZ9UuSrFNJl AJwj9bL1fMx6qhEbEKtGExy4F0U0/S2B3mWtnkRs= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 5A39F1280B6C; Mon, 06 Jan 2025 21:38:48 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id uh0ioeHGCvMd; Mon, 6 Jan 2025 21:38:48 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id E5CDA128017F; Mon, 06 Jan 2025 21:38:47 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v2 6/6] efivarfs: fix error on write to new variable leaving remnants Date: Mon, 6 Jan 2025 18:35:25 -0800 Message-Id: <20250107023525.11466-7-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> References: <20250107023525.11466-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Make variable cleanup go through the fops release mechanism and use zero inode size as the indicator to delete the file. Since all EFI variables must have an initial u32 attribute, zero size occurs either because the update deleted the variable or because an unsuccessful write after create caused the size never to be set in the first place. In the case of multiple racing opens and closes, the open is counted to ensure that the zero size check is done on the last close. Even though this fixes the bug that a create either not followed by a write or followed by a write that errored would leave a remnant file for the variable, the file will appear momentarily globally visible until the last close of the fd deletes it. This is safe because the normal filesystem operations will mediate any races; however, it is still possible for a directory listing at that instant between create and close contain a zero size variable that doesn't exist in the EFI table. Signed-off-by: James Bottomley --- v2: implement counter for last close --- fs/efivarfs/file.c | 60 +++++++++++++++++++++++++++++++++++------- fs/efivarfs/internal.h | 1 + 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c index 23c51d62f902..cf0179d84bc5 100644 --- a/fs/efivarfs/file.c +++ b/fs/efivarfs/file.c @@ -36,28 +36,41 @@ static ssize_t efivarfs_file_write(struct file *file, if (IS_ERR(data)) return PTR_ERR(data); + inode_lock(inode); + if (d_unhashed(file->f_path.dentry)) { + /* + * file got removed; don't allow a set. Caused by an + * unsuccessful create or successful delete write + * racing with us. + */ + bytes = -EIO; + goto out; + } + bytes = efivar_entry_set_get_size(var, attributes, &datasize, data, &set); - if (!set && bytes) { + if (!set) { if (bytes == -ENOENT) bytes = -EIO; goto out; } if (bytes == -ENOENT) { - drop_nlink(inode); - d_delete(file->f_path.dentry); - dput(file->f_path.dentry); + /* + * zero size signals to release that the write deleted + * the variable + */ + i_size_write(inode, 0); } else { - inode_lock(inode); i_size_write(inode, datasize + sizeof(attributes)); inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); - inode_unlock(inode); } bytes = count; out: + inode_unlock(inode); + kfree(data); return bytes; @@ -106,8 +119,37 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, return size; } +static int efivarfs_file_release(struct inode *inode, struct file *file) +{ + bool release; + struct efivar_entry *var = inode->i_private; + + inode_lock(inode); + release = (--var->open_count == 0 && i_size_read(inode) == 0); + inode_unlock(inode); + + if (release) + simple_recursive_removal(file->f_path.dentry, NULL); + + return 0; +} + +static int efivarfs_file_open(struct inode *inode, struct file *file) +{ + struct efivar_entry *entry = inode->i_private; + + file->private_data = entry; + + inode_lock(inode); + entry->open_count++; + inode_unlock(inode); + + return 0; +} + const struct file_operations efivarfs_file_operations = { - .open = simple_open, - .read = efivarfs_file_read, - .write = efivarfs_file_write, + .open = efivarfs_file_open, + .read = efivarfs_file_read, + .write = efivarfs_file_write, + .release = efivarfs_file_release, }; diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index 18a600f80992..32b83f644798 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -26,6 +26,7 @@ struct efi_variable { struct efivar_entry { struct efi_variable var; + unsigned long open_count; }; int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),