aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-27 19:17:42 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-27 19:17:42 -0500
commite3c4877de8b9d93bd47b6ee88eb594b1c1e10da5 (patch)
tree17ade3a3a13b1e7768abe3561b6808dc4980a5f6 /drivers/firmware
parent18a44a7ff1075ce5157ac07cde573aca6b5e9973 (diff)
parent6b59e366e074d3962e04f01efb8acc10a33c0e1e (diff)
Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/EFI changes from Peter Anvin: - Improve the initrd handling in the EFI boot stub by allowing forward slashes in the pathname - from Chun-Yi Lee. - Cleanup code duplication in the EFI mixed kernel/firmware code - from Satoru Takeuchi. - efivarfs bug fixes for more strict filename validation, with lots of input from Al Viro. * 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86, efi: remove duplicate code in setup_arch() by using, efi_is_native() efivarfs: guid part of filenames are case-insensitive efivarfs: Validate filenames much more aggressively efivarfs: Use sizeof() instead of magic number x86, efi: Allow slash in file path of initrd
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/efivars.c146
1 files changed, 138 insertions, 8 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index fed08b661711..7320bf891706 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -79,6 +79,7 @@
79#include <linux/device.h> 79#include <linux/device.h>
80#include <linux/slab.h> 80#include <linux/slab.h>
81#include <linux/pstore.h> 81#include <linux/pstore.h>
82#include <linux/ctype.h>
82 83
83#include <linux/fs.h> 84#include <linux/fs.h>
84#include <linux/ramfs.h> 85#include <linux/ramfs.h>
@@ -908,6 +909,48 @@ static struct inode *efivarfs_get_inode(struct super_block *sb,
908 return inode; 909 return inode;
909} 910}
910 911
912/*
913 * Return true if 'str' is a valid efivarfs filename of the form,
914 *
915 * VariableName-12345678-1234-1234-1234-1234567891bc
916 */
917static bool efivarfs_valid_name(const char *str, int len)
918{
919 static const char dashes[GUID_LEN] = {
920 [8] = 1, [13] = 1, [18] = 1, [23] = 1
921 };
922 const char *s = str + len - GUID_LEN;
923 int i;
924
925 /*
926 * We need a GUID, plus at least one letter for the variable name,
927 * plus the '-' separator
928 */
929 if (len < GUID_LEN + 2)
930 return false;
931
932 /* GUID should be right after the first '-' */
933 if (s - 1 != strchr(str, '-'))
934 return false;
935
936 /*
937 * Validate that 's' is of the correct format, e.g.
938 *
939 * 12345678-1234-1234-1234-123456789abc
940 */
941 for (i = 0; i < GUID_LEN; i++) {
942 if (dashes[i]) {
943 if (*s++ != '-')
944 return false;
945 } else {
946 if (!isxdigit(*s++))
947 return false;
948 }
949 }
950
951 return true;
952}
953
911static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid) 954static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid)
912{ 955{
913 guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]); 956 guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]);
@@ -936,11 +979,7 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
936 struct efivar_entry *var; 979 struct efivar_entry *var;
937 int namelen, i = 0, err = 0; 980 int namelen, i = 0, err = 0;
938 981
939 /* 982 if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
940 * We need a GUID, plus at least one letter for the variable name,
941 * plus the '-' separator
942 */
943 if (dentry->d_name.len < GUID_LEN + 2)
944 return -EINVAL; 983 return -EINVAL;
945 984
946 inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0); 985 inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
@@ -1012,6 +1051,84 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
1012 return -EINVAL; 1051 return -EINVAL;
1013}; 1052};
1014 1053
1054/*
1055 * Compare two efivarfs file names.
1056 *
1057 * An efivarfs filename is composed of two parts,
1058 *
1059 * 1. A case-sensitive variable name
1060 * 2. A case-insensitive GUID
1061 *
1062 * So we need to perform a case-sensitive match on part 1 and a
1063 * case-insensitive match on part 2.
1064 */
1065static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode,
1066 const struct dentry *dentry, const struct inode *inode,
1067 unsigned int len, const char *str,
1068 const struct qstr *name)
1069{
1070 int guid = len - GUID_LEN;
1071
1072 if (name->len != len)
1073 return 1;
1074
1075 /* Case-sensitive compare for the variable name */
1076 if (memcmp(str, name->name, guid))
1077 return 1;
1078
1079 /* Case-insensitive compare for the GUID */
1080 return strncasecmp(name->name + guid, str + guid, GUID_LEN);
1081}
1082
1083static int efivarfs_d_hash(const struct dentry *dentry,
1084 const struct inode *inode, struct qstr *qstr)
1085{
1086 unsigned long hash = init_name_hash();
1087 const unsigned char *s = qstr->name;
1088 unsigned int len = qstr->len;
1089
1090 if (!efivarfs_valid_name(s, len))
1091 return -EINVAL;
1092
1093 while (len-- > GUID_LEN)
1094 hash = partial_name_hash(*s++, hash);
1095
1096 /* GUID is case-insensitive. */
1097 while (len--)
1098 hash = partial_name_hash(tolower(*s++), hash);
1099
1100 qstr->hash = end_name_hash(hash);
1101 return 0;
1102}
1103
1104/*
1105 * Retaining negative dentries for an in-memory filesystem just wastes
1106 * memory and lookup time: arrange for them to be deleted immediately.
1107 */
1108static int efivarfs_delete_dentry(const struct dentry *dentry)
1109{
1110 return 1;
1111}
1112
1113static struct dentry_operations efivarfs_d_ops = {
1114 .d_compare = efivarfs_d_compare,
1115 .d_hash = efivarfs_d_hash,
1116 .d_delete = efivarfs_delete_dentry,
1117};
1118
1119static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
1120{
1121 struct qstr q;
1122
1123 q.name = name;
1124 q.len = strlen(name);
1125
1126 if (efivarfs_d_hash(NULL, NULL, &q))
1127 return NULL;
1128
1129 return d_alloc(parent, &q);
1130}
1131
1015static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) 1132static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1016{ 1133{
1017 struct inode *inode = NULL; 1134 struct inode *inode = NULL;
@@ -1027,6 +1144,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1027 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 1144 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
1028 sb->s_magic = EFIVARFS_MAGIC; 1145 sb->s_magic = EFIVARFS_MAGIC;
1029 sb->s_op = &efivarfs_ops; 1146 sb->s_op = &efivarfs_ops;
1147 sb->s_d_op = &efivarfs_d_ops;
1030 sb->s_time_gran = 1; 1148 sb->s_time_gran = 1;
1031 1149
1032 inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); 1150 inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
@@ -1067,7 +1185,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1067 if (!inode) 1185 if (!inode)
1068 goto fail_name; 1186 goto fail_name;
1069 1187
1070 dentry = d_alloc_name(root, name); 1188 dentry = efivarfs_alloc_dentry(root, name);
1071 if (!dentry) 1189 if (!dentry)
1072 goto fail_inode; 1190 goto fail_inode;
1073 1191
@@ -1084,7 +1202,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1084 1202
1085 mutex_lock(&inode->i_mutex); 1203 mutex_lock(&inode->i_mutex);
1086 inode->i_private = entry; 1204 inode->i_private = entry;
1087 i_size_write(inode, size+4); 1205 i_size_write(inode, size + sizeof(entry->var.Attributes));
1088 mutex_unlock(&inode->i_mutex); 1206 mutex_unlock(&inode->i_mutex);
1089 d_add(dentry, inode); 1207 d_add(dentry, inode);
1090 } 1208 }
@@ -1117,8 +1235,20 @@ static struct file_system_type efivarfs_type = {
1117 .kill_sb = efivarfs_kill_sb, 1235 .kill_sb = efivarfs_kill_sb,
1118}; 1236};
1119 1237
1238/*
1239 * Handle negative dentry.
1240 */
1241static struct dentry *efivarfs_lookup(struct inode *dir, struct dentry *dentry,
1242 unsigned int flags)
1243{
1244 if (dentry->d_name.len > NAME_MAX)
1245 return ERR_PTR(-ENAMETOOLONG);
1246 d_add(dentry, NULL);
1247 return NULL;
1248}
1249
1120static const struct inode_operations efivarfs_dir_inode_operations = { 1250static const struct inode_operations efivarfs_dir_inode_operations = {
1121 .lookup = simple_lookup, 1251 .lookup = efivarfs_lookup,
1122 .unlink = efivarfs_unlink, 1252 .unlink = efivarfs_unlink,
1123 .create = efivarfs_create, 1253 .create = efivarfs_create,
1124}; 1254};