1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2012 Red Hat, Inc.
4 * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
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>
17 static const struct inode_operations efivarfs_file_inode_operations
;
19 struct inode
*efivarfs_get_inode(struct super_block
*sb
,
20 const struct inode
*dir
, int mode
,
21 dev_t dev
, bool is_removable
)
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
;
28 inode
->i_uid
= opts
->uid
;
29 inode
->i_gid
= opts
->gid
;
30 inode
->i_ino
= get_next_ino();
32 simple_inode_init_ts(inode
);
33 inode
->i_flags
= is_removable
? 0 : S_IMMUTABLE
;
34 switch (mode
& S_IFMT
) {
36 inode
->i_op
= &efivarfs_file_inode_operations
;
37 inode
->i_fop
= &efivarfs_file_operations
;
40 inode
->i_op
= &efivarfs_dir_inode_operations
;
41 inode
->i_fop
= &simple_dir_operations
;
50 * Return true if 'str' is a valid efivarfs filename of the form,
52 * VariableName-12345678-1234-1234-1234-1234567891bc
54 static bool efivarfs_valid_name(const char *str
, int len
)
56 const char *s
= str
+ len
- EFI_VARIABLE_GUID_LEN
;
59 * We need a GUID, plus at least one letter for the variable name,
60 * plus the '-' separator
62 if (len
< EFI_VARIABLE_GUID_LEN
+ 2)
65 /* GUID must be preceded by a '-' */
70 * Validate that 's' is of the correct format, e.g.
72 * 12345678-1234-1234-1234-123456789abc
74 return uuid_is_valid(s
);
77 static int efivarfs_create(struct mnt_idmap
*idmap
, struct inode
*dir
,
78 struct dentry
*dentry
, umode_t mode
, bool excl
)
80 struct inode
*inode
= NULL
;
81 struct efivar_entry
*var
;
82 int namelen
, i
= 0, err
= 0;
83 bool is_removable
= false;
86 if (!efivarfs_valid_name(dentry
->d_name
.name
, dentry
->d_name
.len
))
89 /* length of the variable name itself: remove GUID and separator */
90 namelen
= dentry
->d_name
.len
- EFI_VARIABLE_GUID_LEN
- 1;
92 err
= guid_parse(dentry
->d_name
.name
+ namelen
+ 1, &vendor
);
95 if (guid_equal(&vendor
, &LINUX_EFI_RANDOM_SEED_TABLE_GUID
))
98 if (efivar_variable_is_removable(vendor
,
99 dentry
->d_name
.name
, namelen
))
102 inode
= efivarfs_get_inode(dir
->i_sb
, dir
, mode
, 0, is_removable
);
105 var
= efivar_entry(inode
);
107 var
->var
.VendorGuid
= vendor
;
109 for (i
= 0; i
< namelen
; i
++)
110 var
->var
.VariableName
[i
] = dentry
->d_name
.name
[i
];
112 var
->var
.VariableName
[i
] = '\0';
114 inode
->i_private
= var
;
116 d_instantiate(dentry
, inode
);
122 static int efivarfs_unlink(struct inode
*dir
, struct dentry
*dentry
)
124 struct efivar_entry
*var
= d_inode(dentry
)->i_private
;
126 if (efivar_entry_delete(var
))
129 drop_nlink(d_inode(dentry
));
134 const struct inode_operations efivarfs_dir_inode_operations
= {
135 .lookup
= simple_lookup
,
136 .unlink
= efivarfs_unlink
,
137 .create
= efivarfs_create
,
141 efivarfs_fileattr_get(struct dentry
*dentry
, struct fileattr
*fa
)
143 unsigned int i_flags
;
144 unsigned int flags
= 0;
146 i_flags
= d_inode(dentry
)->i_flags
;
147 if (i_flags
& S_IMMUTABLE
)
148 flags
|= FS_IMMUTABLE_FL
;
150 fileattr_fill_flags(fa
, flags
);
156 efivarfs_fileattr_set(struct mnt_idmap
*idmap
,
157 struct dentry
*dentry
, struct fileattr
*fa
)
159 unsigned int i_flags
= 0;
161 if (fileattr_has_fsx(fa
))
164 if (fa
->flags
& ~FS_IMMUTABLE_FL
)
167 if (fa
->flags
& FS_IMMUTABLE_FL
)
168 i_flags
|= S_IMMUTABLE
;
170 inode_set_flags(d_inode(dentry
), i_flags
, S_IMMUTABLE
);
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
,
179 struct inode
*inode
= d_inode(dentry
);
182 error
= setattr_prepare(idmap
, dentry
, iattr
);
186 setattr_copy(idmap
, inode
, iattr
);
187 mark_inode_dirty(inode
);
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
,