Skip to content

Commit da27a24

Browse files
author
Matt Fleming
committed
efivarfs: guid part of filenames are case-insensitive
It makes no sense to treat the following filenames as unique, VarName-abcdefab-abcd-abcd-abcd-abcdefabcdef VarName-ABCDEFAB-ABCD-ABCD-ABCD-ABCDEFABCDEF VarName-ABcDEfAB-ABcD-ABcD-ABcD-ABcDEfABcDEf VarName-aBcDEfAB-aBcD-aBcD-aBcD-aBcDEfaBcDEf ... etc ... since the guid will be converted into a binary representation, which has no case. Roll our own dentry operations so that we can treat the variable name part of filenames ("VarName" in the above example) as case-sensitive, but the guid portion as case-insensitive. That way, efivarfs will refuse to create the above files if any one already exists. Reported-by: Lingzhu Xiang <lxiang@redhat.com> Cc: Matthew Garrett <mjg59@srcf.ucam.org> Cc: Jeremy Kerr <jeremy.kerr@canonical.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
1 parent 47f531e commit da27a24

File tree

1 file changed

+93
-2
lines changed

1 file changed

+93
-2
lines changed

drivers/firmware/efivars.c

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,84 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
10431043
return -EINVAL;
10441044
};
10451045

1046+
/*
1047+
* Compare two efivarfs file names.
1048+
*
1049+
* An efivarfs filename is composed of two parts,
1050+
*
1051+
* 1. A case-sensitive variable name
1052+
* 2. A case-insensitive GUID
1053+
*
1054+
* So we need to perform a case-sensitive match on part 1 and a
1055+
* case-insensitive match on part 2.
1056+
*/
1057+
static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode,
1058+
const struct dentry *dentry, const struct inode *inode,
1059+
unsigned int len, const char *str,
1060+
const struct qstr *name)
1061+
{
1062+
int guid = len - GUID_LEN;
1063+
1064+
if (name->len != len)
1065+
return 1;
1066+
1067+
/* Case-sensitive compare for the variable name */
1068+
if (memcmp(str, name->name, guid))
1069+
return 1;
1070+
1071+
/* Case-insensitive compare for the GUID */
1072+
return strncasecmp(name->name + guid, str + guid, GUID_LEN);
1073+
}
1074+
1075+
static int efivarfs_d_hash(const struct dentry *dentry,
1076+
const struct inode *inode, struct qstr *qstr)
1077+
{
1078+
unsigned long hash = init_name_hash();
1079+
const unsigned char *s = qstr->name;
1080+
unsigned int len = qstr->len;
1081+
1082+
if (!efivarfs_valid_name(s, len))
1083+
return -EINVAL;
1084+
1085+
while (len-- > GUID_LEN)
1086+
hash = partial_name_hash(*s++, hash);
1087+
1088+
/* GUID is case-insensitive. */
1089+
while (len--)
1090+
hash = partial_name_hash(tolower(*s++), hash);
1091+
1092+
qstr->hash = end_name_hash(hash);
1093+
return 0;
1094+
}
1095+
1096+
/*
1097+
* Retaining negative dentries for an in-memory filesystem just wastes
1098+
* memory and lookup time: arrange for them to be deleted immediately.
1099+
*/
1100+
static int efivarfs_delete_dentry(const struct dentry *dentry)
1101+
{
1102+
return 1;
1103+
}
1104+
1105+
static struct dentry_operations efivarfs_d_ops = {
1106+
.d_compare = efivarfs_d_compare,
1107+
.d_hash = efivarfs_d_hash,
1108+
.d_delete = efivarfs_delete_dentry,
1109+
};
1110+
1111+
static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
1112+
{
1113+
struct qstr q;
1114+
1115+
q.name = name;
1116+
q.len = strlen(name);
1117+
1118+
if (efivarfs_d_hash(NULL, NULL, &q))
1119+
return NULL;
1120+
1121+
return d_alloc(parent, &q);
1122+
}
1123+
10461124
static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
10471125
{
10481126
struct inode *inode = NULL;
@@ -1058,6 +1136,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
10581136
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
10591137
sb->s_magic = EFIVARFS_MAGIC;
10601138
sb->s_op = &efivarfs_ops;
1139+
sb->s_d_op = &efivarfs_d_ops;
10611140
sb->s_time_gran = 1;
10621141

10631142
inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
@@ -1098,7 +1177,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
10981177
if (!inode)
10991178
goto fail_name;
11001179

1101-
dentry = d_alloc_name(root, name);
1180+
dentry = efivarfs_alloc_dentry(root, name);
11021181
if (!dentry)
11031182
goto fail_inode;
11041183

@@ -1148,8 +1227,20 @@ static struct file_system_type efivarfs_type = {
11481227
.kill_sb = efivarfs_kill_sb,
11491228
};
11501229

1230+
/*
1231+
* Handle negative dentry.
1232+
*/
1233+
static struct dentry *efivarfs_lookup(struct inode *dir, struct dentry *dentry,
1234+
unsigned int flags)
1235+
{
1236+
if (dentry->d_name.len > NAME_MAX)
1237+
return ERR_PTR(-ENAMETOOLONG);
1238+
d_add(dentry, NULL);
1239+
return NULL;
1240+
}
1241+
11511242
static const struct inode_operations efivarfs_dir_inode_operations = {
1152-
.lookup = simple_lookup,
1243+
.lookup = efivarfs_lookup,
11531244
.unlink = efivarfs_unlink,
11541245
.create = efivarfs_create,
11551246
};

0 commit comments

Comments
 (0)