0001
0002
0003
0004
0005
0006
0007 #include <linux/efi.h>
0008 #include <linux/fs.h>
0009 #include <linux/ctype.h>
0010 #include <linux/kmemleak.h>
0011 #include <linux/slab.h>
0012 #include <linux/uuid.h>
0013 #include <linux/fileattr.h>
0014
0015 #include "internal.h"
0016
0017 static const struct inode_operations efivarfs_file_inode_operations;
0018
0019 struct inode *efivarfs_get_inode(struct super_block *sb,
0020 const struct inode *dir, int mode,
0021 dev_t dev, bool is_removable)
0022 {
0023 struct inode *inode = new_inode(sb);
0024
0025 if (inode) {
0026 inode->i_ino = get_next_ino();
0027 inode->i_mode = mode;
0028 inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
0029 inode->i_flags = is_removable ? 0 : S_IMMUTABLE;
0030 switch (mode & S_IFMT) {
0031 case S_IFREG:
0032 inode->i_op = &efivarfs_file_inode_operations;
0033 inode->i_fop = &efivarfs_file_operations;
0034 break;
0035 case S_IFDIR:
0036 inode->i_op = &efivarfs_dir_inode_operations;
0037 inode->i_fop = &simple_dir_operations;
0038 inc_nlink(inode);
0039 break;
0040 }
0041 }
0042 return inode;
0043 }
0044
0045
0046
0047
0048
0049
0050 bool efivarfs_valid_name(const char *str, int len)
0051 {
0052 const char *s = str + len - EFI_VARIABLE_GUID_LEN;
0053
0054
0055
0056
0057
0058 if (len < EFI_VARIABLE_GUID_LEN + 2)
0059 return false;
0060
0061
0062 if (*(s - 1) != '-')
0063 return false;
0064
0065
0066
0067
0068
0069
0070 return uuid_is_valid(s);
0071 }
0072
0073 static int efivarfs_create(struct user_namespace *mnt_userns, struct inode *dir,
0074 struct dentry *dentry, umode_t mode, bool excl)
0075 {
0076 struct inode *inode = NULL;
0077 struct efivar_entry *var;
0078 int namelen, i = 0, err = 0;
0079 bool is_removable = false;
0080
0081 if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
0082 return -EINVAL;
0083
0084 var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
0085 if (!var)
0086 return -ENOMEM;
0087
0088
0089 namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
0090
0091 err = guid_parse(dentry->d_name.name + namelen + 1, &var->var.VendorGuid);
0092 if (err)
0093 goto out;
0094
0095 if (efivar_variable_is_removable(var->var.VendorGuid,
0096 dentry->d_name.name, namelen))
0097 is_removable = true;
0098
0099 inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable);
0100 if (!inode) {
0101 err = -ENOMEM;
0102 goto out;
0103 }
0104
0105 for (i = 0; i < namelen; i++)
0106 var->var.VariableName[i] = dentry->d_name.name[i];
0107
0108 var->var.VariableName[i] = '\0';
0109
0110 inode->i_private = var;
0111 kmemleak_ignore(var);
0112
0113 err = efivar_entry_add(var, &efivarfs_list);
0114 if (err)
0115 goto out;
0116
0117 d_instantiate(dentry, inode);
0118 dget(dentry);
0119 out:
0120 if (err) {
0121 kfree(var);
0122 if (inode)
0123 iput(inode);
0124 }
0125 return err;
0126 }
0127
0128 static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
0129 {
0130 struct efivar_entry *var = d_inode(dentry)->i_private;
0131
0132 if (efivar_entry_delete(var))
0133 return -EINVAL;
0134
0135 drop_nlink(d_inode(dentry));
0136 dput(dentry);
0137 return 0;
0138 };
0139
0140 const struct inode_operations efivarfs_dir_inode_operations = {
0141 .lookup = simple_lookup,
0142 .unlink = efivarfs_unlink,
0143 .create = efivarfs_create,
0144 };
0145
0146 static int
0147 efivarfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
0148 {
0149 unsigned int i_flags;
0150 unsigned int flags = 0;
0151
0152 i_flags = d_inode(dentry)->i_flags;
0153 if (i_flags & S_IMMUTABLE)
0154 flags |= FS_IMMUTABLE_FL;
0155
0156 fileattr_fill_flags(fa, flags);
0157
0158 return 0;
0159 }
0160
0161 static int
0162 efivarfs_fileattr_set(struct user_namespace *mnt_userns,
0163 struct dentry *dentry, struct fileattr *fa)
0164 {
0165 unsigned int i_flags = 0;
0166
0167 if (fileattr_has_fsx(fa))
0168 return -EOPNOTSUPP;
0169
0170 if (fa->flags & ~FS_IMMUTABLE_FL)
0171 return -EOPNOTSUPP;
0172
0173 if (fa->flags & FS_IMMUTABLE_FL)
0174 i_flags |= S_IMMUTABLE;
0175
0176 inode_set_flags(d_inode(dentry), i_flags, S_IMMUTABLE);
0177
0178 return 0;
0179 }
0180
0181 static const struct inode_operations efivarfs_file_inode_operations = {
0182 .fileattr_get = efivarfs_fileattr_get,
0183 .fileattr_set = efivarfs_fileattr_set,
0184 };