1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2012 Red Hat, Inc. 4 * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com> 5 */ 6 7 #include <linux/efi.h> 8 #include <linux/fs.h> 9 #include <linux/ctype.h> 10 #include <linux/kmemleak.h> 11 #include <linux/slab.h> 12 #include <linux/uuid.h> 13 #include <linux/fileattr.h> 14 15 #include "internal.h" 16 17 static const struct inode_operations efivarfs_file_inode_operations; 18 19 struct inode *efivarfs_get_inode(struct super_block *sb, 20 const struct inode *dir, int mode, 21 dev_t dev, bool is_removable) 22 { 23 struct inode *inode = new_inode(sb); 24 struct efivarfs_fs_info *fsi = sb->s_fs_info; 25 struct efivarfs_mount_opts *opts = &fsi->mount_opts; 26 27 if (inode) { 28 inode->i_uid = opts->uid; 29 inode->i_gid = opts->gid; 30 inode->i_ino = get_next_ino(); 31 inode->i_mode = mode; 32 simple_inode_init_ts(inode); 33 inode->i_flags = is_removable ? 0 : S_IMMUTABLE; 34 switch (mode & S_IFMT) { 35 case S_IFREG: 36 inode->i_op = &efivarfs_file_inode_operations; 37 inode->i_fop = &efivarfs_file_operations; 38 break; 39 case S_IFDIR: 40 inode->i_op = &efivarfs_dir_inode_operations; 41 inode->i_fop = &simple_dir_operations; 42 inc_nlink(inode); 43 break; 44 } 45 } 46 return inode; 47 } 48 49 /* 50 * Return true if 'str' is a valid efivarfs filename of the form, 51 * 52 * VariableName-12345678-1234-1234-1234-1234567891bc 53 */ 54 static bool efivarfs_valid_name(const char *str, int len) 55 { 56 const char *s = str + len - EFI_VARIABLE_GUID_LEN; 57 58 /* 59 * We need a GUID, plus at least one letter for the variable name, 60 * plus the '-' separator 61 */ 62 if (len < EFI_VARIABLE_GUID_LEN + 2) 63 return false; 64 65 /* GUID must be preceded by a '-' */ 66 if (*(s - 1) != '-') 67 return false; 68 69 /* 70 * Validate that 's' is of the correct format, e.g. 71 * 72 * 12345678-1234-1234-1234-123456789abc 73 */ 74 return uuid_is_valid(s); 75 } 76 77 static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir, 78 struct dentry *dentry, umode_t mode, bool excl) 79 { 80 struct inode *inode = NULL; 81 struct efivar_entry *var; 82 int namelen, i = 0, err = 0; 83 bool is_removable = false; 84 efi_guid_t vendor; 85 86 if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len)) 87 return -EINVAL; 88 89 /* length of the variable name itself: remove GUID and separator */ 90 namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; 91 92 err = guid_parse(dentry->d_name.name + namelen + 1, &vendor); 93 if (err) 94 return err; 95 if (guid_equal(&vendor, &LINUX_EFI_RANDOM_SEED_TABLE_GUID)) 96 return -EPERM; 97 98 if (efivar_variable_is_removable(vendor, 99 dentry->d_name.name, namelen)) 100 is_removable = true; 101 102 inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable); 103 if (!inode) 104 return -ENOMEM; 105 var = efivar_entry(inode); 106 107 var->var.VendorGuid = vendor; 108 109 for (i = 0; i < namelen; i++) 110 var->var.VariableName[i] = dentry->d_name.name[i]; 111 112 var->var.VariableName[i] = '\0'; 113 114 inode->i_private = var; 115 116 d_instantiate(dentry, inode); 117 dget(dentry); 118 119 return 0; 120 } 121 122 static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) 123 { 124 struct efivar_entry *var = d_inode(dentry)->i_private; 125 126 if (efivar_entry_delete(var)) 127 return -EINVAL; 128 129 drop_nlink(d_inode(dentry)); 130 dput(dentry); 131 return 0; 132 }; 133 134 const struct inode_operations efivarfs_dir_inode_operations = { 135 .lookup = simple_lookup, 136 .unlink = efivarfs_unlink, 137 .create = efivarfs_create, 138 }; 139 140 static int 141 efivarfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 142 { 143 unsigned int i_flags; 144 unsigned int flags = 0; 145 146 i_flags = d_inode(dentry)->i_flags; 147 if (i_flags & S_IMMUTABLE) 148 flags |= FS_IMMUTABLE_FL; 149 150 fileattr_fill_flags(fa, flags); 151 152 return 0; 153 } 154 155 static int 156 efivarfs_fileattr_set(struct mnt_idmap *idmap, 157 struct dentry *dentry, struct fileattr *fa) 158 { 159 unsigned int i_flags = 0; 160 161 if (fileattr_has_fsx(fa)) 162 return -EOPNOTSUPP; 163 164 if (fa->flags & ~FS_IMMUTABLE_FL) 165 return -EOPNOTSUPP; 166 167 if (fa->flags & FS_IMMUTABLE_FL) 168 i_flags |= S_IMMUTABLE; 169 170 inode_set_flags(d_inode(dentry), i_flags, S_IMMUTABLE); 171 172 return 0; 173 } 174 175 /* copy of simple_setattr except that it doesn't do i_size updates */ 176 static int efivarfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 177 struct iattr *iattr) 178 { 179 struct inode *inode = d_inode(dentry); 180 int error; 181 182 error = setattr_prepare(idmap, dentry, iattr); 183 if (error) 184 return error; 185 186 setattr_copy(idmap, inode, iattr); 187 mark_inode_dirty(inode); 188 return 0; 189 } 190 191 static const struct inode_operations efivarfs_file_inode_operations = { 192 .fileattr_get = efivarfs_fileattr_get, 193 .fileattr_set = efivarfs_fileattr_set, 194 .setattr = efivarfs_setattr, 195 }; 196