Commit 5ebaee6d290279d1df6ce45d6d54de8cfc473273
Committed by
Alasdair G Kergon
1 parent
28513fccf0
Exists in
master
and in
7 other branches
dm crypt: simplify crypt_ctr
Allocate cipher strings indpendently of struct crypt_config and move cipher parsing and allocation into a separate function to prepare for supporting the cryptoapi format e.g. "xts(aes)". No functional change in this patch. Signed-off-by: Milan Broz <mbroz@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Showing 1 changed file with 104 additions and 81 deletions Side-by-side Diff
drivers/md/dm-crypt.c
... | ... | @@ -107,11 +107,10 @@ |
107 | 107 | struct workqueue_struct *io_queue; |
108 | 108 | struct workqueue_struct *crypt_queue; |
109 | 109 | |
110 | - /* | |
111 | - * crypto related data | |
112 | - */ | |
110 | + char *cipher; | |
111 | + char *cipher_mode; | |
112 | + | |
113 | 113 | struct crypt_iv_operations *iv_gen_ops; |
114 | - char *iv_mode; | |
115 | 114 | union { |
116 | 115 | struct iv_essiv_private essiv; |
117 | 116 | struct iv_benbi_private benbi; |
... | ... | @@ -135,8 +134,6 @@ |
135 | 134 | unsigned int dmreq_start; |
136 | 135 | struct ablkcipher_request *req; |
137 | 136 | |
138 | - char cipher[CRYPTO_MAX_ALG_NAME]; | |
139 | - char chainmode[CRYPTO_MAX_ALG_NAME]; | |
140 | 137 | struct crypto_ablkcipher *tfm; |
141 | 138 | unsigned long flags; |
142 | 139 | unsigned int key_size; |
143 | 140 | |
144 | 141 | |
145 | 142 | |
146 | 143 | |
147 | 144 | |
148 | 145 | |
149 | 146 | |
150 | 147 | |
151 | 148 | |
152 | 149 | |
153 | 150 | |
154 | 151 | |
155 | 152 | |
... | ... | @@ -1032,90 +1029,102 @@ |
1032 | 1029 | if (cc->dev) |
1033 | 1030 | dm_put_device(ti, cc->dev); |
1034 | 1031 | |
1035 | - kfree(cc->iv_mode); | |
1032 | + kzfree(cc->cipher); | |
1033 | + kzfree(cc->cipher_mode); | |
1036 | 1034 | |
1037 | 1035 | /* Must zero key material before freeing */ |
1038 | 1036 | kzfree(cc); |
1039 | 1037 | } |
1040 | 1038 | |
1041 | -/* | |
1042 | - * Construct an encryption mapping: | |
1043 | - * <cipher> <key> <iv_offset> <dev_path> <start> | |
1044 | - */ | |
1045 | -static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |
1039 | +static int crypt_ctr_cipher(struct dm_target *ti, | |
1040 | + char *cipher_in, char *key) | |
1046 | 1041 | { |
1047 | - struct crypt_config *cc; | |
1048 | - char *tmp; | |
1049 | - char *cipher; | |
1050 | - char *chainmode; | |
1051 | - char *ivmode; | |
1052 | - char *ivopts; | |
1053 | - unsigned int key_size; | |
1054 | - unsigned long long tmpll; | |
1042 | + struct crypt_config *cc = ti->private; | |
1043 | + char *tmp, *cipher, *chainmode, *ivmode, *ivopts; | |
1044 | + char *cipher_api = NULL; | |
1055 | 1045 | int ret = -EINVAL; |
1056 | 1046 | |
1057 | - if (argc != 5) { | |
1058 | - ti->error = "Not enough arguments"; | |
1047 | + /* Convert to crypto api definition? */ | |
1048 | + if (strchr(cipher_in, '(')) { | |
1049 | + ti->error = "Bad cipher specification"; | |
1059 | 1050 | return -EINVAL; |
1060 | 1051 | } |
1061 | 1052 | |
1062 | - tmp = argv[0]; | |
1053 | + /* | |
1054 | + * Legacy dm-crypt cipher specification | |
1055 | + * cipher-mode-iv:ivopts | |
1056 | + */ | |
1057 | + tmp = cipher_in; | |
1063 | 1058 | cipher = strsep(&tmp, "-"); |
1059 | + | |
1060 | + cc->cipher = kstrdup(cipher, GFP_KERNEL); | |
1061 | + if (!cc->cipher) | |
1062 | + goto bad_mem; | |
1063 | + | |
1064 | + if (tmp) { | |
1065 | + cc->cipher_mode = kstrdup(tmp, GFP_KERNEL); | |
1066 | + if (!cc->cipher_mode) | |
1067 | + goto bad_mem; | |
1068 | + } | |
1069 | + | |
1064 | 1070 | chainmode = strsep(&tmp, "-"); |
1065 | 1071 | ivopts = strsep(&tmp, "-"); |
1066 | 1072 | ivmode = strsep(&ivopts, ":"); |
1067 | 1073 | |
1068 | 1074 | if (tmp) |
1069 | - DMWARN("Unexpected additional cipher options"); | |
1075 | + DMWARN("Ignoring unexpected additional cipher options"); | |
1070 | 1076 | |
1071 | - key_size = strlen(argv[1]) >> 1; | |
1072 | - | |
1073 | - cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); | |
1074 | - if (!cc) { | |
1075 | - ti->error = "Cannot allocate transparent encryption context"; | |
1076 | - return -ENOMEM; | |
1077 | - } | |
1078 | - | |
1079 | - ti->private = cc; | |
1080 | - | |
1081 | - /* Compatibility mode for old dm-crypt cipher strings */ | |
1082 | - if (!chainmode || (strcmp(chainmode, "plain") == 0 && !ivmode)) { | |
1077 | + /* Compatibility mode for old dm-crypt mappings */ | |
1078 | + if (!chainmode || (!strcmp(chainmode, "plain") && !ivmode)) { | |
1079 | + kfree(cc->cipher_mode); | |
1080 | + cc->cipher_mode = kstrdup("cbc-plain", GFP_KERNEL); | |
1083 | 1081 | chainmode = "cbc"; |
1084 | 1082 | ivmode = "plain"; |
1085 | 1083 | } |
1086 | 1084 | |
1087 | 1085 | if (strcmp(chainmode, "ecb") && !ivmode) { |
1088 | - ti->error = "This chaining mode requires an IV mechanism"; | |
1089 | - goto bad; | |
1086 | + ti->error = "IV mechanism required"; | |
1087 | + return -EINVAL; | |
1090 | 1088 | } |
1091 | 1089 | |
1092 | - ret = -ENOMEM; | |
1093 | - if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)", | |
1094 | - chainmode, cipher) >= CRYPTO_MAX_ALG_NAME) { | |
1095 | - ti->error = "Chain mode + cipher name is too long"; | |
1096 | - goto bad; | |
1090 | + cipher_api = kmalloc(CRYPTO_MAX_ALG_NAME, GFP_KERNEL); | |
1091 | + if (!cipher_api) | |
1092 | + goto bad_mem; | |
1093 | + | |
1094 | + ret = snprintf(cipher_api, CRYPTO_MAX_ALG_NAME, | |
1095 | + "%s(%s)", chainmode, cipher); | |
1096 | + if (ret < 0) { | |
1097 | + kfree(cipher_api); | |
1098 | + goto bad_mem; | |
1097 | 1099 | } |
1098 | 1100 | |
1099 | - cc->tfm = crypto_alloc_ablkcipher(cc->cipher, 0, 0); | |
1101 | + /* Allocate cipher */ | |
1102 | + cc->tfm = crypto_alloc_ablkcipher(cipher_api, 0, 0); | |
1100 | 1103 | if (IS_ERR(cc->tfm)) { |
1104 | + ret = PTR_ERR(cc->tfm); | |
1101 | 1105 | ti->error = "Error allocating crypto tfm"; |
1102 | 1106 | goto bad; |
1103 | 1107 | } |
1104 | 1108 | |
1105 | - strcpy(cc->cipher, cipher); | |
1106 | - strcpy(cc->chainmode, chainmode); | |
1107 | - | |
1108 | - ret = crypt_set_key(cc, argv[1]); | |
1109 | + /* Initialize and set key */ | |
1110 | + ret = crypt_set_key(cc, key); | |
1109 | 1111 | if (ret < 0) { |
1110 | 1112 | ti->error = "Error decoding and setting key"; |
1111 | 1113 | goto bad; |
1112 | 1114 | } |
1113 | 1115 | |
1114 | - /* | |
1115 | - * Choose ivmode. Valid modes: "plain", "essiv:<esshash>", "benbi". | |
1116 | - * See comments at iv code | |
1117 | - */ | |
1118 | - ret = -EINVAL; | |
1116 | + /* Initialize IV */ | |
1117 | + cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm); | |
1118 | + if (cc->iv_size) | |
1119 | + /* at least a 64 bit sector number should fit in our buffer */ | |
1120 | + cc->iv_size = max(cc->iv_size, | |
1121 | + (unsigned int)(sizeof(u64) / sizeof(u8))); | |
1122 | + else if (ivmode) { | |
1123 | + DMWARN("Selected cipher does not support IVs"); | |
1124 | + ivmode = NULL; | |
1125 | + } | |
1126 | + | |
1127 | + /* Choose ivmode, see comments at iv code. */ | |
1119 | 1128 | if (ivmode == NULL) |
1120 | 1129 | cc->iv_gen_ops = NULL; |
1121 | 1130 | else if (strcmp(ivmode, "plain") == 0) |
... | ... | @@ -1129,6 +1138,7 @@ |
1129 | 1138 | else if (strcmp(ivmode, "null") == 0) |
1130 | 1139 | cc->iv_gen_ops = &crypt_iv_null_ops; |
1131 | 1140 | else { |
1141 | + ret = -EINVAL; | |
1132 | 1142 | ti->error = "Invalid IV mode"; |
1133 | 1143 | goto bad; |
1134 | 1144 | } |
1135 | 1145 | |
... | ... | @@ -1151,20 +1161,45 @@ |
1151 | 1161 | } |
1152 | 1162 | } |
1153 | 1163 | |
1154 | - cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm); | |
1155 | - if (cc->iv_size) | |
1156 | - /* at least a 64 bit sector number should fit in our buffer */ | |
1157 | - cc->iv_size = max(cc->iv_size, | |
1158 | - (unsigned int)(sizeof(u64) / sizeof(u8))); | |
1159 | - else { | |
1160 | - if (cc->iv_gen_ops) { | |
1161 | - DMWARN("Selected cipher does not support IVs"); | |
1162 | - if (cc->iv_gen_ops->dtr) | |
1163 | - cc->iv_gen_ops->dtr(cc); | |
1164 | - cc->iv_gen_ops = NULL; | |
1165 | - } | |
1164 | + ret = 0; | |
1165 | +bad: | |
1166 | + kfree(cipher_api); | |
1167 | + return ret; | |
1168 | + | |
1169 | +bad_mem: | |
1170 | + ti->error = "Cannot allocate cipher strings"; | |
1171 | + return -ENOMEM; | |
1172 | +} | |
1173 | + | |
1174 | +/* | |
1175 | + * Construct an encryption mapping: | |
1176 | + * <cipher> <key> <iv_offset> <dev_path> <start> | |
1177 | + */ | |
1178 | +static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |
1179 | +{ | |
1180 | + struct crypt_config *cc; | |
1181 | + unsigned int key_size; | |
1182 | + unsigned long long tmpll; | |
1183 | + int ret; | |
1184 | + | |
1185 | + if (argc != 5) { | |
1186 | + ti->error = "Not enough arguments"; | |
1187 | + return -EINVAL; | |
1166 | 1188 | } |
1167 | 1189 | |
1190 | + key_size = strlen(argv[1]) >> 1; | |
1191 | + | |
1192 | + cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); | |
1193 | + if (!cc) { | |
1194 | + ti->error = "Cannot allocate encryption context"; | |
1195 | + return -ENOMEM; | |
1196 | + } | |
1197 | + | |
1198 | + ti->private = cc; | |
1199 | + ret = crypt_ctr_cipher(ti, argv[0], argv[1]); | |
1200 | + if (ret < 0) | |
1201 | + goto bad; | |
1202 | + | |
1168 | 1203 | ret = -ENOMEM; |
1169 | 1204 | cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool); |
1170 | 1205 | if (!cc->io_pool) { |
... | ... | @@ -1217,17 +1252,6 @@ |
1217 | 1252 | cc->start = tmpll; |
1218 | 1253 | |
1219 | 1254 | ret = -ENOMEM; |
1220 | - if (ivmode && cc->iv_gen_ops) { | |
1221 | - if (ivopts) | |
1222 | - *(ivopts - 1) = ':'; | |
1223 | - cc->iv_mode = kstrdup(ivmode, GFP_KERNEL); | |
1224 | - if (!cc->iv_mode) { | |
1225 | - ti->error = "Error kmallocing iv_mode string"; | |
1226 | - goto bad; | |
1227 | - } | |
1228 | - } else | |
1229 | - cc->iv_mode = NULL; | |
1230 | - | |
1231 | 1255 | cc->io_queue = create_singlethread_workqueue("kcryptd_io"); |
1232 | 1256 | if (!cc->io_queue) { |
1233 | 1257 | ti->error = "Couldn't create kcryptd io queue"; |
... | ... | @@ -1273,7 +1297,7 @@ |
1273 | 1297 | static int crypt_status(struct dm_target *ti, status_type_t type, |
1274 | 1298 | char *result, unsigned int maxlen) |
1275 | 1299 | { |
1276 | - struct crypt_config *cc = (struct crypt_config *) ti->private; | |
1300 | + struct crypt_config *cc = ti->private; | |
1277 | 1301 | unsigned int sz = 0; |
1278 | 1302 | |
1279 | 1303 | switch (type) { |
1280 | 1304 | |
... | ... | @@ -1282,11 +1306,10 @@ |
1282 | 1306 | break; |
1283 | 1307 | |
1284 | 1308 | case STATUSTYPE_TABLE: |
1285 | - if (cc->iv_mode) | |
1286 | - DMEMIT("%s-%s-%s ", cc->cipher, cc->chainmode, | |
1287 | - cc->iv_mode); | |
1309 | + if (cc->cipher_mode) | |
1310 | + DMEMIT("%s-%s ", cc->cipher, cc->cipher_mode); | |
1288 | 1311 | else |
1289 | - DMEMIT("%s-%s ", cc->cipher, cc->chainmode); | |
1312 | + DMEMIT("%s ", cc->cipher); | |
1290 | 1313 | |
1291 | 1314 | if (cc->key_size > 0) { |
1292 | 1315 | if ((maxlen - sz) < ((cc->key_size << 1) + 1)) |