aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-02-01 06:02:28 -0500
committerMatt Fleming <matt.fleming@intel.com>2013-02-12 07:41:54 -0500
commitda27a24383b2b10bf6ebd0db29b325548aafecb4 (patch)
treedb48f001f62af527e832fe2c1cd302b30e794b6a
parent47f531e8ba3bc3901a0c493f4252826c41dea1a1 (diff)
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>
-rw-r--r--drivers/firmware/efivars.c95
1 files changed, 93 insertions, 2 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 868cea5cd4b8..8bcb5958f21a 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -1043,6 +1043,84 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
1043 return -EINVAL; 1043 return -EINVAL;
1044}; 1044};
1045 1045
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 */
1057static 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
1075static 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 */
1100static int efivarfs_delete_dentry(const struct dentry *dentry)
1101{
1102 return 1;
1103}
1104
1105static 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
1111static 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
1046static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) 1124static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1047{ 1125{
1048 struct inode *inode = NULL; 1126 struct inode *inode = NULL;
@@ -1058,6 +1136,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1058 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 1136 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
1059 sb->s_magic = EFIVARFS_MAGIC; 1137 sb->s_magic = EFIVARFS_MAGIC;
1060 sb->s_op = &efivarfs_ops; 1138 sb->s_op = &efivarfs_ops;
1139 sb->s_d_op = &efivarfs_d_ops;
1061 sb->s_time_gran = 1; 1140 sb->s_time_gran = 1;
1062 1141
1063 inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); 1142 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)
1098 if (!inode) 1177 if (!inode)
1099 goto fail_name; 1178 goto fail_name;
1100 1179
1101 dentry = d_alloc_name(root, name); 1180 dentry = efivarfs_alloc_dentry(root, name);
1102 if (!dentry) 1181 if (!dentry)
1103 goto fail_inode; 1182 goto fail_inode;
1104 1183
@@ -1148,8 +1227,20 @@ static struct file_system_type efivarfs_type = {
1148 .kill_sb = efivarfs_kill_sb, 1227 .kill_sb = efivarfs_kill_sb,
1149}; 1228};
1150 1229
1230/*
1231 * Handle negative dentry.
1232 */
1233static 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
1151static const struct inode_operations efivarfs_dir_inode_operations = { 1242static const struct inode_operations efivarfs_dir_inode_operations = {
1152 .lookup = simple_lookup, 1243 .lookup = efivarfs_lookup,
1153 .unlink = efivarfs_unlink, 1244 .unlink = efivarfs_unlink,
1154 .create = efivarfs_create, 1245 .create = efivarfs_create,
1155}; 1246};