Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

crypto: api - Use test infrastructure

This patch makes use of the new testing infrastructure by requiring
algorithms to pass a run-time test before they're made available to
users.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

+267 -42
+123 -20
crypto/algapi.c
··· 21 21 22 22 #include "internal.h" 23 23 24 + static void crypto_remove_final(struct list_head *list); 25 + 24 26 static LIST_HEAD(crypto_template_list); 25 27 26 28 void crypto_larval_error(const char *name, u32 type, u32 mask) ··· 128 126 } 129 127 } 130 128 131 - static int __crypto_register_alg(struct crypto_alg *alg, 132 - struct list_head *list) 129 + static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg) 133 130 { 134 131 struct crypto_alg *q; 132 + struct crypto_larval *larval; 135 133 int ret = -EAGAIN; 136 134 137 135 if (crypto_is_dead(alg)) 138 - goto out; 136 + goto err; 139 137 140 138 INIT_LIST_HEAD(&alg->cra_users); 139 + 140 + /* No cheating! */ 141 + alg->cra_flags &= ~CRYPTO_ALG_TESTED; 141 142 142 143 ret = -EEXIST; 143 144 144 145 atomic_set(&alg->cra_refcnt, 1); 145 146 list_for_each_entry(q, &crypto_alg_list, cra_list) { 146 147 if (q == alg) 147 - goto out; 148 + goto err; 149 + 150 + if (crypto_is_larval(q)) { 151 + if (!strcmp(alg->cra_driver_name, q->cra_driver_name)) 152 + goto err; 153 + continue; 154 + } 155 + 156 + if (!strcmp(q->cra_driver_name, alg->cra_name) || 157 + !strcmp(q->cra_name, alg->cra_driver_name)) 158 + goto err; 159 + } 160 + 161 + larval = crypto_larval_alloc(alg->cra_name, 162 + alg->cra_flags | CRYPTO_ALG_TESTED, 0); 163 + if (IS_ERR(larval)) 164 + goto out; 165 + 166 + ret = -ENOENT; 167 + larval->adult = crypto_mod_get(alg); 168 + if (!larval->adult) 169 + goto free_larval; 170 + 171 + atomic_set(&larval->alg.cra_refcnt, 1); 172 + memcpy(larval->alg.cra_driver_name, alg->cra_driver_name, 173 + CRYPTO_MAX_ALG_NAME); 174 + larval->alg.cra_priority = alg->cra_priority; 175 + 176 + list_add(&alg->cra_list, &crypto_alg_list); 177 + list_add(&larval->alg.cra_list, &crypto_alg_list); 178 + 179 + out: 180 + return larval; 181 + 182 + free_larval: 183 + kfree(larval); 184 + err: 185 + larval = ERR_PTR(ret); 186 + goto out; 187 + } 188 + 189 + void crypto_alg_tested(const char *name, int err) 190 + { 191 + struct crypto_larval *test; 192 + struct crypto_alg *alg; 193 + struct crypto_alg *q; 194 + LIST_HEAD(list); 195 + 196 + down_write(&crypto_alg_sem); 197 + list_for_each_entry(q, &crypto_alg_list, cra_list) { 198 + if (!crypto_is_larval(q)) 199 + continue; 200 + 201 + test = (struct crypto_larval *)q; 202 + 203 + if (!strcmp(q->cra_driver_name, name)) 204 + goto found; 205 + } 206 + 207 + printk(KERN_ERR "alg: Unexpected test result for %s: %d\n", name, err); 208 + goto unlock; 209 + 210 + found: 211 + alg = test->adult; 212 + if (err || list_empty(&alg->cra_list)) 213 + goto complete; 214 + 215 + alg->cra_flags |= CRYPTO_ALG_TESTED; 216 + 217 + list_for_each_entry(q, &crypto_alg_list, cra_list) { 218 + if (q == alg) 219 + continue; 148 220 149 221 if (crypto_is_moribund(q)) 150 222 continue; ··· 254 178 q->cra_priority > alg->cra_priority) 255 179 continue; 256 180 257 - crypto_remove_spawns(&q->cra_users, list, alg->cra_flags); 181 + crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags); 258 182 } 259 - 260 - list_add(&alg->cra_list, &crypto_alg_list); 261 183 262 - crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg); 263 - ret = 0; 184 + complete: 185 + complete_all(&test->completion); 264 186 265 - out: 266 - return ret; 187 + unlock: 188 + up_write(&crypto_alg_sem); 189 + 190 + crypto_remove_final(&list); 267 191 } 192 + EXPORT_SYMBOL_GPL(crypto_alg_tested); 268 193 269 194 static void crypto_remove_final(struct list_head *list) 270 195 { ··· 278 201 } 279 202 } 280 203 204 + static void crypto_wait_for_test(struct crypto_larval *larval) 205 + { 206 + int err; 207 + 208 + err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult); 209 + if (err != NOTIFY_STOP) { 210 + if (WARN_ON(err != NOTIFY_DONE)) 211 + goto out; 212 + crypto_alg_tested(larval->alg.cra_driver_name, 0); 213 + } 214 + 215 + err = wait_for_completion_interruptible(&larval->completion); 216 + WARN_ON(err); 217 + 218 + out: 219 + crypto_larval_kill(&larval->alg); 220 + } 221 + 281 222 int crypto_register_alg(struct crypto_alg *alg) 282 223 { 283 - LIST_HEAD(list); 224 + struct crypto_larval *larval; 284 225 int err; 285 226 286 227 err = crypto_check_alg(alg); ··· 306 211 return err; 307 212 308 213 down_write(&crypto_alg_sem); 309 - err = __crypto_register_alg(alg, &list); 214 + larval = __crypto_register_alg(alg); 310 215 up_write(&crypto_alg_sem); 311 216 312 - crypto_remove_final(&list); 313 - return err; 217 + if (IS_ERR(larval)) 218 + return PTR_ERR(larval); 219 + 220 + crypto_wait_for_test(larval); 221 + return 0; 314 222 } 315 223 EXPORT_SYMBOL_GPL(crypto_register_alg); 316 224 ··· 431 333 int crypto_register_instance(struct crypto_template *tmpl, 432 334 struct crypto_instance *inst) 433 335 { 434 - LIST_HEAD(list); 435 - int err = -EINVAL; 336 + struct crypto_larval *larval; 337 + int err; 436 338 437 339 err = crypto_check_alg(&inst->alg); 438 340 if (err) ··· 442 344 443 345 down_write(&crypto_alg_sem); 444 346 445 - err = __crypto_register_alg(&inst->alg, &list); 446 - if (err) 347 + larval = __crypto_register_alg(&inst->alg); 348 + if (IS_ERR(larval)) 447 349 goto unlock; 448 350 449 351 hlist_add_head(&inst->list, &tmpl->instances); ··· 452 354 unlock: 453 355 up_write(&crypto_alg_sem); 454 356 455 - crypto_remove_final(&list); 357 + err = PTR_ERR(larval); 358 + if (IS_ERR(larval)) 359 + goto err; 360 + 361 + crypto_wait_for_test(larval); 362 + err = 0; 456 363 457 364 err: 458 365 return err;
+70 -5
crypto/algboss.c
··· 45 45 46 46 char larval[CRYPTO_MAX_ALG_NAME]; 47 47 char template[CRYPTO_MAX_ALG_NAME]; 48 + 49 + u32 otype; 50 + u32 omask; 51 + }; 52 + 53 + struct crypto_test_param { 54 + char driver[CRYPTO_MAX_ALG_NAME]; 55 + char alg[CRYPTO_MAX_ALG_NAME]; 56 + u32 type; 48 57 }; 49 58 50 59 static int cryptomgr_probe(void *data) ··· 85 76 module_put_and_exit(0); 86 77 87 78 err: 88 - crypto_larval_error(param->larval, param->type.data.type, 89 - param->type.data.mask); 79 + crypto_larval_error(param->larval, param->otype, param->omask); 90 80 goto out; 91 81 } 92 82 ··· 177 169 178 170 param->type.attr.rta_len = sizeof(param->type); 179 171 param->type.attr.rta_type = CRYPTOA_TYPE; 180 - param->type.data.type = larval->alg.cra_flags; 181 - param->type.data.mask = larval->mask; 172 + param->type.data.type = larval->alg.cra_flags & ~CRYPTO_ALG_TESTED; 173 + param->type.data.mask = larval->mask & ~CRYPTO_ALG_TESTED; 182 174 param->tb[0] = &param->type.attr; 175 + 176 + param->otype = larval->alg.cra_flags; 177 + param->omask = larval->mask; 183 178 184 179 memcpy(param->larval, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME); 185 180 186 - thread = kthread_run(cryptomgr_probe, param, "cryptomgr"); 181 + thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe"); 182 + if (IS_ERR(thread)) 183 + goto err_free_param; 184 + 185 + return NOTIFY_STOP; 186 + 187 + err_free_param: 188 + kfree(param); 189 + err_put_module: 190 + module_put(THIS_MODULE); 191 + err: 192 + return NOTIFY_OK; 193 + } 194 + 195 + static int cryptomgr_test(void *data) 196 + { 197 + struct crypto_test_param *param = data; 198 + u32 type = param->type; 199 + int err = 0; 200 + 201 + if (!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) & 202 + CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV)) 203 + goto skiptest; 204 + 205 + if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) 206 + goto skiptest; 207 + 208 + err = alg_test(param->driver, param->alg, 0, CRYPTO_ALG_TESTED); 209 + 210 + skiptest: 211 + crypto_alg_tested(param->driver, err); 212 + 213 + kfree(param); 214 + module_put_and_exit(0); 215 + } 216 + 217 + static int cryptomgr_schedule_test(struct crypto_alg *alg) 218 + { 219 + struct task_struct *thread; 220 + struct crypto_test_param *param; 221 + 222 + if (!try_module_get(THIS_MODULE)) 223 + goto err; 224 + 225 + param = kzalloc(sizeof(*param), GFP_KERNEL); 226 + if (!param) 227 + goto err_put_module; 228 + 229 + memcpy(param->driver, alg->cra_driver_name, sizeof(param->driver)); 230 + memcpy(param->alg, alg->cra_name, sizeof(param->alg)); 231 + param->type = alg->cra_flags; 232 + 233 + thread = kthread_run(cryptomgr_test, param, "cryptomgr_test"); 187 234 if (IS_ERR(thread)) 188 235 goto err_free_param; 189 236 ··· 258 195 switch (msg) { 259 196 case CRYPTO_MSG_ALG_REQUEST: 260 197 return cryptomgr_schedule_probe(data); 198 + case CRYPTO_MSG_ALG_REGISTER: 199 + return cryptomgr_schedule_test(data); 261 200 } 262 201 263 202 return NOTIFY_DONE;
+58 -15
crypto/api.c
··· 55 55 } 56 56 EXPORT_SYMBOL_GPL(crypto_mod_put); 57 57 58 + static inline int crypto_is_test_larval(struct crypto_larval *larval) 59 + { 60 + return larval->alg.cra_driver_name[0]; 61 + } 62 + 58 63 static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, 59 64 u32 mask) 60 65 { ··· 76 71 continue; 77 72 78 73 if (crypto_is_larval(q) && 74 + !crypto_is_test_larval((struct crypto_larval *)q) && 79 75 ((struct crypto_larval *)q)->mask != mask) 80 76 continue; 81 77 ··· 110 104 kfree(larval); 111 105 } 112 106 113 - static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type, 114 - u32 mask) 107 + struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask) 115 108 { 116 - struct crypto_alg *alg; 117 109 struct crypto_larval *larval; 118 110 119 111 larval = kzalloc(sizeof(*larval), GFP_KERNEL); ··· 123 119 larval->alg.cra_priority = -1; 124 120 larval->alg.cra_destroy = crypto_larval_destroy; 125 121 126 - atomic_set(&larval->alg.cra_refcnt, 2); 127 122 strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME); 128 123 init_completion(&larval->completion); 124 + 125 + return larval; 126 + } 127 + EXPORT_SYMBOL_GPL(crypto_larval_alloc); 128 + 129 + static struct crypto_alg *crypto_larval_add(const char *name, u32 type, 130 + u32 mask) 131 + { 132 + struct crypto_alg *alg; 133 + struct crypto_larval *larval; 134 + 135 + larval = crypto_larval_alloc(name, type, mask); 136 + if (IS_ERR(larval)) 137 + return ERR_CAST(larval); 138 + 139 + atomic_set(&larval->alg.cra_refcnt, 2); 129 140 130 141 down_write(&crypto_alg_sem); 131 142 alg = __crypto_alg_lookup(name, type, mask); ··· 171 152 static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) 172 153 { 173 154 struct crypto_larval *larval = (void *)alg; 155 + long timeout; 174 156 175 - wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ); 157 + timeout = wait_for_completion_interruptible_timeout( 158 + &larval->completion, 60 * HZ); 159 + 176 160 alg = larval->adult; 177 - if (alg) { 178 - if (!crypto_mod_get(alg)) 179 - alg = ERR_PTR(-EAGAIN); 180 - } else 161 + if (timeout < 0) 162 + alg = ERR_PTR(-EINTR); 163 + else if (!timeout) 164 + alg = ERR_PTR(-ETIMEDOUT); 165 + else if (!alg) 181 166 alg = ERR_PTR(-ENOENT); 167 + else if (crypto_is_test_larval(larval) && 168 + !(alg->cra_flags & CRYPTO_ALG_TESTED)) 169 + alg = ERR_PTR(-EAGAIN); 170 + else if (!crypto_mod_get(alg)) 171 + alg = ERR_PTR(-EAGAIN); 182 172 crypto_mod_put(&larval->alg); 183 173 184 174 return alg; ··· 220 192 if (alg) 221 193 return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; 222 194 223 - return crypto_larval_alloc(name, type, mask); 195 + return crypto_larval_add(name, type, mask); 224 196 } 225 197 EXPORT_SYMBOL_GPL(crypto_larval_lookup); 198 + 199 + int crypto_probing_notify(unsigned long val, void *v) 200 + { 201 + int ok; 202 + 203 + ok = blocking_notifier_call_chain(&crypto_chain, val, v); 204 + if (ok == NOTIFY_DONE) { 205 + request_module("cryptomgr"); 206 + ok = blocking_notifier_call_chain(&crypto_chain, val, v); 207 + } 208 + 209 + return ok; 210 + } 211 + EXPORT_SYMBOL_GPL(crypto_probing_notify); 226 212 227 213 struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) 228 214 { ··· 244 202 struct crypto_alg *larval; 245 203 int ok; 246 204 205 + if (!(mask & CRYPTO_ALG_TESTED)) { 206 + type |= CRYPTO_ALG_TESTED; 207 + mask |= CRYPTO_ALG_TESTED; 208 + } 209 + 247 210 larval = crypto_larval_lookup(name, type, mask); 248 211 if (IS_ERR(larval) || !crypto_is_larval(larval)) 249 212 return larval; 250 213 251 - ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); 252 - if (ok == NOTIFY_DONE) { 253 - request_module("cryptomgr"); 254 - ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); 255 - } 214 + ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval); 256 215 257 216 if (ok == NOTIFY_STOP) 258 217 alg = crypto_larval_wait(larval);
+5 -2
crypto/internal.h
··· 94 94 void crypto_exit_cipher_ops(struct crypto_tfm *tfm); 95 95 void crypto_exit_compress_ops(struct crypto_tfm *tfm); 96 96 97 + struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask); 97 98 void crypto_larval_kill(struct crypto_alg *alg); 98 99 struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask); 99 100 void crypto_larval_error(const char *name, u32 type, u32 mask); 101 + void crypto_alg_tested(const char *name, int err); 100 102 101 103 void crypto_shoot_alg(struct crypto_alg *alg); 102 104 struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, ··· 109 107 110 108 int crypto_register_notifier(struct notifier_block *nb); 111 109 int crypto_unregister_notifier(struct notifier_block *nb); 110 + int crypto_probing_notify(unsigned long val, void *v); 112 111 113 112 int __init testmgr_init(void); 114 113 void testmgr_exit(void); ··· 145 142 return alg->cra_flags & (CRYPTO_ALG_DEAD | CRYPTO_ALG_DYING); 146 143 } 147 144 148 - static inline int crypto_notify(unsigned long val, void *v) 145 + static inline void crypto_notify(unsigned long val, void *v) 149 146 { 150 - return blocking_notifier_call_chain(&crypto_chain, val, v); 147 + blocking_notifier_call_chain(&crypto_chain, val, v); 151 148 } 152 149 153 150 #endif /* _CRYPTO_INTERNAL_H */
+3
crypto/proc.c
··· 46 46 seq_printf(m, "module : %s\n", module_name(alg->cra_module)); 47 47 seq_printf(m, "priority : %d\n", alg->cra_priority); 48 48 seq_printf(m, "refcnt : %d\n", atomic_read(&alg->cra_refcnt)); 49 + seq_printf(m, "selftest : %s\n", 50 + (alg->cra_flags & CRYPTO_ALG_TESTED) ? 51 + "passed" : "unknown"); 49 52 50 53 switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) { 51 54 case CRYPTO_ALG_TYPE_CIPHER:
+8
include/linux/crypto.h
··· 61 61 #define CRYPTO_ALG_GENIV 0x00000200 62 62 63 63 /* 64 + * Set if the algorithm has passed automated run-time testing. Note that 65 + * if there is no run-time testing for a given algorithm it is considered 66 + * to have passed. 67 + */ 68 + 69 + #define CRYPTO_ALG_TESTED 0x00000400 70 + 71 + /* 64 72 * Transform masks and values (for crt_flags). 65 73 */ 66 74 #define CRYPTO_TFM_REQ_MASK 0x000fff00