All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] efi: vars: allow passing fmode= and dmode= when mounting
@ 2022-11-10 15:45 Jason A. Donenfeld
  0 siblings, 0 replies; only message in thread
From: Jason A. Donenfeld @ 2022-11-10 15:45 UTC (permalink / raw)
  To: linux-efi, linux-kernel, ardb
  Cc: Jason A. Donenfeld, Jeremy Kerr, Matthew Garrett, Lennart Poettering

The default wide-open permissions of efivarfs make the prospect of
storing secrets there a bit sketchy. Currently systemd does this, and
then pid 1 takes care of chmodding particular nodes. But this is limited
and error-prone. Rather, allow passing an explicit dmode for directories
and fmode for files.

Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Jeremy Kerr <jk@ozlabs.org>
Cc: Matthew Garrett <matthew.garrett@nebula.com>
Suggested-by: Lennart Poettering <lennart@poettering.net>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
 fs/efivarfs/internal.h |  5 ++++
 fs/efivarfs/super.c    | 60 ++++++++++++++++++++++++++++++++++++++----
 2 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h
index 8ebf3a6a8aa2..ea1ca322d247 100644
--- a/fs/efivarfs/internal.h
+++ b/fs/efivarfs/internal.h
@@ -24,6 +24,11 @@ struct efivar_entry {
 	struct kobject kobj;
 };
 
+struct efivarfs_sb_info {
+	umode_t dmode;
+	umode_t fmode;
+};
+
 int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
 		void *data, bool duplicates, struct list_head *head);
 
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index 6780fc81cc11..45edbb1550e9 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -8,6 +8,7 @@
 #include <linux/efi.h>
 #include <linux/fs.h>
 #include <linux/fs_context.h>
+#include <linux/fs_parser.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
 #include <linux/ucs2_string.h>
@@ -107,6 +108,7 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
 			     unsigned long name_size, void *data)
 {
 	struct super_block *sb = (struct super_block *)data;
+	struct efivarfs_sb_info *sbi = sb->s_fs_info;
 	struct efivar_entry *entry;
 	struct inode *inode = NULL;
 	struct dentry *dentry, *root = sb->s_root;
@@ -144,7 +146,7 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
 	/* 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,
+	inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | sbi->fmode, 0,
 				   is_removable);
 	if (!inode)
 		goto fail_name;
@@ -187,6 +189,7 @@ static int efivarfs_destroy(struct efivar_entry *entry, void *data)
 
 static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
+	struct efivarfs_sb_info *sbi = sb->s_fs_info;
 	struct inode *inode = NULL;
 	struct dentry *root;
 	int err;
@@ -202,7 +205,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
 	if (!efivar_supports_writes())
 		sb->s_flags |= SB_RDONLY;
 
-	inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true);
+	inode = efivarfs_get_inode(sb, NULL, S_IFDIR | sbi->dmode, 0, true);
 	if (!inode)
 		return -ENOMEM;
 	inode->i_op = &efivarfs_dir_inode_operations;
@@ -226,12 +229,58 @@ static int efivarfs_get_tree(struct fs_context *fc)
 	return get_tree_single(fc, efivarfs_fill_super);
 }
 
+enum {
+	Opt_dmode,
+	Opt_fmode,
+};
+
+static const struct fs_parameter_spec efivarfs_parameters[] = {
+	fsparam_u32oct("dmode",			Opt_dmode),
+	fsparam_u32oct("fmode",			Opt_fmode),
+	{}
+};
+
+static int efivarfs_parse_param(struct fs_context *fc,
+				struct fs_parameter *param)
+{
+	struct efivarfs_sb_info *sbi = fc->s_fs_info;
+	struct fs_parse_result result;
+	int opt;
+
+	opt = fs_parse(fc, efivarfs_parameters, param, &result);
+	if (opt < 0)
+		return opt;
+
+	switch (opt) {
+	case Opt_dmode:
+		sbi->dmode = result.uint_32;
+		break;
+	case Opt_fmode:
+		sbi->fmode = result.uint_32;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static const struct fs_context_operations efivarfs_context_ops = {
 	.get_tree	= efivarfs_get_tree,
+	.parse_param	= efivarfs_parse_param,
 };
 
 static int efivarfs_init_fs_context(struct fs_context *fc)
 {
+	struct efivarfs_sb_info *sbi;
+
+	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+	if (!sbi)
+		return -ENOMEM;
+	sbi->dmode = 0755;
+	sbi->fmode = 0644;
+	fc->s_fs_info = sbi;
+
 	fc->ops = &efivarfs_context_ops;
 	return 0;
 }
@@ -245,10 +294,11 @@ static void efivarfs_kill_sb(struct super_block *sb)
 }
 
 static struct file_system_type efivarfs_type = {
-	.owner   = THIS_MODULE,
-	.name    = "efivarfs",
+	.owner   	 = THIS_MODULE,
+	.name    	 = "efivarfs",
 	.init_fs_context = efivarfs_init_fs_context,
-	.kill_sb = efivarfs_kill_sb,
+	.parameters	 = efivarfs_parameters,
+	.kill_sb 	 = efivarfs_kill_sb,
 };
 
 static __init int efivarfs_init(void)
-- 
2.38.1


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2022-11-10 15:46 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-10 15:45 [PATCH] efi: vars: allow passing fmode= and dmode= when mounting Jason A. Donenfeld

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.