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/md | |
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/md')
-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 139bbe2254c..6401bfa0adf 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)) |