d2912cb15bdda (Thomas Gleixner 2019-06-04 10:11:33 +0200 1) // SPDX-License-Identifier: GPL-2.0-only
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 2) /*
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 3) * Copyright (C) 2012 Red Hat, Inc.
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 4) * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 5) */
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 6)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 7) #include <linux/efi.h>
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 8) #include <linux/fs.h>
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 9) #include <linux/ctype.h>
ff04f3b6f2e27 (Ard Biesheuvel 2020-11-25 08:45:55 +0100 10) #include <linux/kmemleak.h>
20b4fb4852274 (Linus Torvalds 2013-05-01 17:51:54 -0700 11) #include <linux/slab.h>
8236431d8d09e (Andy Shevchenko 2016-05-20 17:01:21 -0700 12) #include <linux/uuid.h>
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 13) #include <linux/fileattr.h>
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 14)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 15) #include "internal.h"
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 16)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 17) static const struct inode_operations efivarfs_file_inode_operations;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 18)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 19) struct inode *efivarfs_get_inode(struct super_block *sb,
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 20) const struct inode *dir, int mode,
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 21) dev_t dev, bool is_removable)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 22) {
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 23) struct inode *inode = new_inode(sb);
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 24)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 25) if (inode) {
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 26) inode->i_ino = get_next_ino();
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 27) inode->i_mode = mode;
078cd8279e659 (Deepa Dinamani 2016-09-14 07:48:04 -0700 28) inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 29) inode->i_flags = is_removable ? 0 : S_IMMUTABLE;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 30) switch (mode & S_IFMT) {
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 31) case S_IFREG:
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 32) inode->i_op = &efivarfs_file_inode_operations;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 33) inode->i_fop = &efivarfs_file_operations;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 34) break;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 35) case S_IFDIR:
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 36) inode->i_op = &efivarfs_dir_inode_operations;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 37) inode->i_fop = &simple_dir_operations;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 38) inc_nlink(inode);
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 39) break;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 40) }
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 41) }
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 42) return inode;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 43) }
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 44)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 45) /*
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 46) * Return true if 'str' is a valid efivarfs filename of the form,
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 47) *
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 48) * VariableName-12345678-1234-1234-1234-1234567891bc
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 49) */
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 50) bool efivarfs_valid_name(const char *str, int len)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 51) {
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 52) const char *s = str + len - EFI_VARIABLE_GUID_LEN;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 53)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 54) /*
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 55) * We need a GUID, plus at least one letter for the variable name,
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 56) * plus the '-' separator
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 57) */
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 58) if (len < EFI_VARIABLE_GUID_LEN + 2)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 59) return false;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 60)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 61) /* GUID must be preceded by a '-' */
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 62) if (*(s - 1) != '-')
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 63) return false;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 64)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 65) /*
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 66) * Validate that 's' is of the correct format, e.g.
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 67) *
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 68) * 12345678-1234-1234-1234-123456789abc
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 69) */
8236431d8d09e (Andy Shevchenko 2016-05-20 17:01:21 -0700 70) return uuid_is_valid(s);
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 71) }
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 72)
549c7297717c3 (Christian Brauner 2021-01-21 14:19:43 +0100 73) static int efivarfs_create(struct user_namespace *mnt_userns, struct inode *dir,
549c7297717c3 (Christian Brauner 2021-01-21 14:19:43 +0100 74) struct dentry *dentry, umode_t mode, bool excl)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 75) {
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 76) struct inode *inode = NULL;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 77) struct efivar_entry *var;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 78) int namelen, i = 0, err = 0;
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 79) bool is_removable = false;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 80)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 81) if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 82) return -EINVAL;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 83)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 84) var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 85) if (!var)
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 86) return -ENOMEM;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 87)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 88) /* length of the variable name itself: remove GUID and separator */
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 89) namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 90)
c4326563d9abe (Andy Shevchenko 2018-07-20 10:47:26 +0900 91) err = guid_parse(dentry->d_name.name + namelen + 1, &var->var.VendorGuid);
c4326563d9abe (Andy Shevchenko 2018-07-20 10:47:26 +0900 92) if (err)
c4326563d9abe (Andy Shevchenko 2018-07-20 10:47:26 +0900 93) goto out;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 94)
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 95) if (efivar_variable_is_removable(var->var.VendorGuid,
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 96) dentry->d_name.name, namelen))
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 97) is_removable = true;
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 98)
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 99) inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable);
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 100) if (!inode) {
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 101) err = -ENOMEM;
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 102) goto out;
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 103) }
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 104)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 105) for (i = 0; i < namelen; i++)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 106) var->var.VariableName[i] = dentry->d_name.name[i];
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 107)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 108) var->var.VariableName[i] = '\0';
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 109)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 110) inode->i_private = var;
ff04f3b6f2e27 (Ard Biesheuvel 2020-11-25 08:45:55 +0100 111) kmemleak_ignore(var);
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 112)
21b3ddd39feec (Sylvain Chouleur 2016-07-15 21:36:30 +0200 113) err = efivar_entry_add(var, &efivarfs_list);
21b3ddd39feec (Sylvain Chouleur 2016-07-15 21:36:30 +0200 114) if (err)
21b3ddd39feec (Sylvain Chouleur 2016-07-15 21:36:30 +0200 115) goto out;
21b3ddd39feec (Sylvain Chouleur 2016-07-15 21:36:30 +0200 116)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 117) d_instantiate(dentry, inode);
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 118) dget(dentry);
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 119) out:
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 120) if (err) {
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 121) kfree(var);
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 122) if (inode)
ed8b0de5a33d2 (Peter Jones 2016-02-08 14:48:15 -0500 123) iput(inode);
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 124) }
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 125) return err;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 126) }
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 127)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 128) static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 129) {
2b0143b5c986b (David Howells 2015-03-17 22:25:59 +0000 130) struct efivar_entry *var = d_inode(dentry)->i_private;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 131)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 132) if (efivar_entry_delete(var))
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 133) return -EINVAL;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 134)
2b0143b5c986b (David Howells 2015-03-17 22:25:59 +0000 135) drop_nlink(d_inode(dentry));
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 136) dput(dentry);
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 137) return 0;
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 138) };
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 139)
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 140) const struct inode_operations efivarfs_dir_inode_operations = {
6e8cd2cb46e3c (Al Viro 2013-07-14 17:48:35 +0400 141) .lookup = simple_lookup,
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 142) .unlink = efivarfs_unlink,
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 143) .create = efivarfs_create,
d68772b7c83f4 (Matt Fleming 2013-02-08 16:27:24 +0000 144) };
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 145)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 146) static int
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 147) efivarfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 148) {
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 149) unsigned int i_flags;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 150) unsigned int flags = 0;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 151)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 152) i_flags = d_inode(dentry)->i_flags;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 153) if (i_flags & S_IMMUTABLE)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 154) flags |= FS_IMMUTABLE_FL;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 155)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 156) fileattr_fill_flags(fa, flags);
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 157)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 158) return 0;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 159) }
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 160)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 161) static int
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 162) efivarfs_fileattr_set(struct user_namespace *mnt_userns,
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 163) struct dentry *dentry, struct fileattr *fa)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 164) {
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 165) unsigned int i_flags = 0;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 166)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 167) if (fileattr_has_fsx(fa))
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 168) return -EOPNOTSUPP;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 169)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 170) if (fa->flags & ~FS_IMMUTABLE_FL)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 171) return -EOPNOTSUPP;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 172)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 173) if (fa->flags & FS_IMMUTABLE_FL)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 174) i_flags |= S_IMMUTABLE;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 175)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 176) inode_set_flags(d_inode(dentry), i_flags, S_IMMUTABLE);
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 177)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 178) return 0;
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 179) }
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 180)
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 181) static const struct inode_operations efivarfs_file_inode_operations = {
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 182) .fileattr_get = efivarfs_fileattr_get,
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 183) .fileattr_set = efivarfs_fileattr_set,
d701ea284cf90 (Miklos Szeredi 2021-04-07 14:36:44 +0200 184) };