diff options
| author | Milan Broz <mbroz@redhat.com> | 2010-08-11 23:14:07 -0400 |
|---|---|---|
| committer | Alasdair G Kergon <agk@redhat.com> | 2010-08-11 23:14:07 -0400 |
| commit | 5ebaee6d290279d1df6ce45d6d54de8cfc473273 (patch) | |
| tree | 9fa2693bcd1f46827e90f1aff1d36fd1d6da4ea6 /drivers | |
| parent | 28513fccf0ceefb8171ddc0cefa429b82e92a2c9 (diff) | |
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>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/md/dm-crypt.c | 185 |
1 files changed, 104 insertions, 81 deletions
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 139bbe2254cd..6401bfa0adff 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
| @@ -107,11 +107,10 @@ struct crypt_config { | |||
| 107 | struct workqueue_struct *io_queue; | 107 | struct workqueue_struct *io_queue; |
| 108 | struct workqueue_struct *crypt_queue; | 108 | struct workqueue_struct *crypt_queue; |
| 109 | 109 | ||
| 110 | /* | 110 | char *cipher; |
| 111 | * crypto related data | 111 | char *cipher_mode; |
| 112 | */ | 112 | |
| 113 | struct crypt_iv_operations *iv_gen_ops; | 113 | struct crypt_iv_operations *iv_gen_ops; |
| 114 | char *iv_mode; | ||
| 115 | union { | 114 | union { |
| 116 | struct iv_essiv_private essiv; | 115 | struct iv_essiv_private essiv; |
| 117 | struct iv_benbi_private benbi; | 116 | struct iv_benbi_private benbi; |
| @@ -135,8 +134,6 @@ struct crypt_config { | |||
| 135 | unsigned int dmreq_start; | 134 | unsigned int dmreq_start; |
| 136 | struct ablkcipher_request *req; | 135 | struct ablkcipher_request *req; |
| 137 | 136 | ||
| 138 | char cipher[CRYPTO_MAX_ALG_NAME]; | ||
| 139 | char chainmode[CRYPTO_MAX_ALG_NAME]; | ||
| 140 | struct crypto_ablkcipher *tfm; | 137 | struct crypto_ablkcipher *tfm; |
| 141 | unsigned long flags; | 138 | unsigned long flags; |
| 142 | unsigned int key_size; | 139 | unsigned int key_size; |
| @@ -1032,90 +1029,102 @@ static void crypt_dtr(struct dm_target *ti) | |||
| 1032 | if (cc->dev) | 1029 | if (cc->dev) |
| 1033 | dm_put_device(ti, cc->dev); | 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 | /* Must zero key material before freeing */ | 1035 | /* Must zero key material before freeing */ |
| 1038 | kzfree(cc); | 1036 | kzfree(cc); |
| 1039 | } | 1037 | } |
| 1040 | 1038 | ||
| 1041 | /* | 1039 | static int crypt_ctr_cipher(struct dm_target *ti, |
| 1042 | * Construct an encryption mapping: | 1040 | char *cipher_in, char *key) |
| 1043 | * <cipher> <key> <iv_offset> <dev_path> <start> | ||
| 1044 | */ | ||
| 1045 | static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | ||
| 1046 | { | 1041 | { |
| 1047 | struct crypt_config *cc; | 1042 | struct crypt_config *cc = ti->private; |
| 1048 | char *tmp; | 1043 | char *tmp, *cipher, *chainmode, *ivmode, *ivopts; |
| 1049 | char *cipher; | 1044 | char *cipher_api = NULL; |
| 1050 | char *chainmode; | ||
| 1051 | char *ivmode; | ||
| 1052 | char *ivopts; | ||
| 1053 | unsigned int key_size; | ||
| 1054 | unsigned long long tmpll; | ||
| 1055 | int ret = -EINVAL; | 1045 | int ret = -EINVAL; |
| 1056 | 1046 | ||
| 1057 | if (argc != 5) { | 1047 | /* Convert to crypto api definition? */ |
| 1058 | ti->error = "Not enough arguments"; | 1048 | if (strchr(cipher_in, '(')) { |
| 1049 | ti->error = "Bad cipher specification"; | ||
| 1059 | return -EINVAL; | 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 | cipher = strsep(&tmp, "-"); | 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 | chainmode = strsep(&tmp, "-"); | 1070 | chainmode = strsep(&tmp, "-"); |
| 1065 | ivopts = strsep(&tmp, "-"); | 1071 | ivopts = strsep(&tmp, "-"); |
| 1066 | ivmode = strsep(&ivopts, ":"); | 1072 | ivmode = strsep(&ivopts, ":"); |
| 1067 | 1073 | ||
| 1068 | if (tmp) | 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; | 1077 | /* Compatibility mode for old dm-crypt mappings */ |
| 1072 | 1078 | if (!chainmode || (!strcmp(chainmode, "plain") && !ivmode)) { | |
| 1073 | cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); | 1079 | kfree(cc->cipher_mode); |
| 1074 | if (!cc) { | 1080 | cc->cipher_mode = kstrdup("cbc-plain", GFP_KERNEL); |
| 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)) { | ||
| 1083 | chainmode = "cbc"; | 1081 | chainmode = "cbc"; |
| 1084 | ivmode = "plain"; | 1082 | ivmode = "plain"; |
| 1085 | } | 1083 | } |
| 1086 | 1084 | ||
| 1087 | if (strcmp(chainmode, "ecb") && !ivmode) { | 1085 | if (strcmp(chainmode, "ecb") && !ivmode) { |
| 1088 | ti->error = "This chaining mode requires an IV mechanism"; | 1086 | ti->error = "IV mechanism required"; |
| 1089 | goto bad; | 1087 | return -EINVAL; |
| 1090 | } | 1088 | } |
| 1091 | 1089 | ||
| 1092 | ret = -ENOMEM; | 1090 | cipher_api = kmalloc(CRYPTO_MAX_ALG_NAME, GFP_KERNEL); |
| 1093 | if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)", | 1091 | if (!cipher_api) |
| 1094 | chainmode, cipher) >= CRYPTO_MAX_ALG_NAME) { | 1092 | goto bad_mem; |
| 1095 | ti->error = "Chain mode + cipher name is too long"; | 1093 | |
| 1096 | goto bad; | 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 | if (IS_ERR(cc->tfm)) { | 1103 | if (IS_ERR(cc->tfm)) { |
| 1104 | ret = PTR_ERR(cc->tfm); | ||
| 1101 | ti->error = "Error allocating crypto tfm"; | 1105 | ti->error = "Error allocating crypto tfm"; |
| 1102 | goto bad; | 1106 | goto bad; |
| 1103 | } | 1107 | } |
| 1104 | 1108 | ||
| 1105 | strcpy(cc->cipher, cipher); | 1109 | /* Initialize and set key */ |
| 1106 | strcpy(cc->chainmode, chainmode); | 1110 | ret = crypt_set_key(cc, key); |
| 1107 | |||
| 1108 | ret = crypt_set_key(cc, argv[1]); | ||
| 1109 | if (ret < 0) { | 1111 | if (ret < 0) { |
| 1110 | ti->error = "Error decoding and setting key"; | 1112 | ti->error = "Error decoding and setting key"; |
| 1111 | goto bad; | 1113 | goto bad; |
| 1112 | } | 1114 | } |
| 1113 | 1115 | ||
| 1114 | /* | 1116 | /* Initialize IV */ |
| 1115 | * Choose ivmode. Valid modes: "plain", "essiv:<esshash>", "benbi". | 1117 | cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm); |
| 1116 | * See comments at iv code | 1118 | if (cc->iv_size) |
| 1117 | */ | 1119 | /* at least a 64 bit sector number should fit in our buffer */ |
| 1118 | ret = -EINVAL; | 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 | if (ivmode == NULL) | 1128 | if (ivmode == NULL) |
| 1120 | cc->iv_gen_ops = NULL; | 1129 | cc->iv_gen_ops = NULL; |
| 1121 | else if (strcmp(ivmode, "plain") == 0) | 1130 | else if (strcmp(ivmode, "plain") == 0) |
| @@ -1129,6 +1138,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
| 1129 | else if (strcmp(ivmode, "null") == 0) | 1138 | else if (strcmp(ivmode, "null") == 0) |
| 1130 | cc->iv_gen_ops = &crypt_iv_null_ops; | 1139 | cc->iv_gen_ops = &crypt_iv_null_ops; |
| 1131 | else { | 1140 | else { |
| 1141 | ret = -EINVAL; | ||
| 1132 | ti->error = "Invalid IV mode"; | 1142 | ti->error = "Invalid IV mode"; |
| 1133 | goto bad; | 1143 | goto bad; |
| 1134 | } | 1144 | } |
| @@ -1151,20 +1161,45 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
| 1151 | } | 1161 | } |
| 1152 | } | 1162 | } |
| 1153 | 1163 | ||
| 1154 | cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm); | 1164 | ret = 0; |
| 1155 | if (cc->iv_size) | 1165 | bad: |
| 1156 | /* at least a 64 bit sector number should fit in our buffer */ | 1166 | kfree(cipher_api); |
| 1157 | cc->iv_size = max(cc->iv_size, | 1167 | return ret; |
| 1158 | (unsigned int)(sizeof(u64) / sizeof(u8))); | 1168 | |
| 1159 | else { | 1169 | bad_mem: |
| 1160 | if (cc->iv_gen_ops) { | 1170 | ti->error = "Cannot allocate cipher strings"; |
| 1161 | DMWARN("Selected cipher does not support IVs"); | 1171 | return -ENOMEM; |
| 1162 | if (cc->iv_gen_ops->dtr) | 1172 | } |
| 1163 | cc->iv_gen_ops->dtr(cc); | 1173 | |
| 1164 | cc->iv_gen_ops = NULL; | 1174 | /* |
| 1165 | } | 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 | ret = -ENOMEM; | 1203 | ret = -ENOMEM; |
| 1169 | cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool); | 1204 | cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool); |
| 1170 | if (!cc->io_pool) { | 1205 | if (!cc->io_pool) { |
| @@ -1217,17 +1252,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
| 1217 | cc->start = tmpll; | 1252 | cc->start = tmpll; |
| 1218 | 1253 | ||
| 1219 | ret = -ENOMEM; | 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 | cc->io_queue = create_singlethread_workqueue("kcryptd_io"); | 1255 | cc->io_queue = create_singlethread_workqueue("kcryptd_io"); |
| 1232 | if (!cc->io_queue) { | 1256 | if (!cc->io_queue) { |
| 1233 | ti->error = "Couldn't create kcryptd io queue"; | 1257 | ti->error = "Couldn't create kcryptd io queue"; |
| @@ -1273,7 +1297,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio, | |||
| 1273 | static int crypt_status(struct dm_target *ti, status_type_t type, | 1297 | static int crypt_status(struct dm_target *ti, status_type_t type, |
| 1274 | char *result, unsigned int maxlen) | 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 | unsigned int sz = 0; | 1301 | unsigned int sz = 0; |
| 1278 | 1302 | ||
| 1279 | switch (type) { | 1303 | switch (type) { |
| @@ -1282,11 +1306,10 @@ static int crypt_status(struct dm_target *ti, status_type_t type, | |||
| 1282 | break; | 1306 | break; |
| 1283 | 1307 | ||
| 1284 | case STATUSTYPE_TABLE: | 1308 | case STATUSTYPE_TABLE: |
| 1285 | if (cc->iv_mode) | 1309 | if (cc->cipher_mode) |
| 1286 | DMEMIT("%s-%s-%s ", cc->cipher, cc->chainmode, | 1310 | DMEMIT("%s-%s ", cc->cipher, cc->cipher_mode); |
| 1287 | cc->iv_mode); | ||
| 1288 | else | 1311 | else |
| 1289 | DMEMIT("%s-%s ", cc->cipher, cc->chainmode); | 1312 | DMEMIT("%s ", cc->cipher); |
| 1290 | 1313 | ||
| 1291 | if (cc->key_size > 0) { | 1314 | if (cc->key_size > 0) { |
| 1292 | if ((maxlen - sz) < ((cc->key_size << 1) + 1)) | 1315 | if ((maxlen - sz) < ((cc->key_size << 1) + 1)) |
