VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   32 Branches   54 Tags
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) };