From 1e1229940045a537c61fb69f86010a8774e576d0 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Thu, 29 Mar 2012 09:03:47 +0200 Subject: crypto: user - Fix lookup of algorithms with IV generator We lookup algorithms with crypto_alg_mod_lookup() when instantiating via crypto_add_alg(). However, algorithms that are wrapped by an IV genearator (e.g. aead or genicv type algorithms) need special care. The userspace process hangs until it gets a timeout when we use crypto_alg_mod_lookup() to lookup these algorithms. So export the lookup functions for these algorithms and use them in crypto_add_alg(). Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu --- crypto/crypto_user.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) (limited to 'crypto/crypto_user.c') diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index f76e42bcc6e7..e91c16111ed3 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -21,9 +21,13 @@ #include #include #include +#include #include #include #include +#include +#include + #include "internal.h" DEFINE_MUTEX(crypto_cfg_mutex); @@ -301,6 +305,60 @@ static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh, return crypto_unregister_instance(alg); } +static struct crypto_alg *crypto_user_skcipher_alg(const char *name, u32 type, + u32 mask) +{ + int err; + struct crypto_alg *alg; + + type = crypto_skcipher_type(type); + mask = crypto_skcipher_mask(mask); + + for (;;) { + alg = crypto_lookup_skcipher(name, type, mask); + if (!IS_ERR(alg)) + return alg; + + err = PTR_ERR(alg); + if (err != -EAGAIN) + break; + if (signal_pending(current)) { + err = -EINTR; + break; + } + } + + return ERR_PTR(err); +} + +static struct crypto_alg *crypto_user_aead_alg(const char *name, u32 type, + u32 mask) +{ + int err; + struct crypto_alg *alg; + + type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + type |= CRYPTO_ALG_TYPE_AEAD; + mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + mask |= CRYPTO_ALG_TYPE_MASK; + + for (;;) { + alg = crypto_lookup_aead(name, type, mask); + if (!IS_ERR(alg)) + return alg; + + err = PTR_ERR(alg); + if (err != -EAGAIN) + break; + if (signal_pending(current)) { + err = -EINTR; + break; + } + } + + return ERR_PTR(err); +} + static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { @@ -325,7 +383,19 @@ static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh, else name = p->cru_name; - alg = crypto_alg_mod_lookup(name, p->cru_type, p->cru_mask); + switch (p->cru_type & p->cru_mask & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_AEAD: + alg = crypto_user_aead_alg(name, p->cru_type, p->cru_mask); + break; + case CRYPTO_ALG_TYPE_GIVCIPHER: + case CRYPTO_ALG_TYPE_BLKCIPHER: + case CRYPTO_ALG_TYPE_ABLKCIPHER: + alg = crypto_user_skcipher_alg(name, p->cru_type, p->cru_mask); + break; + default: + alg = crypto_alg_mod_lookup(name, p->cru_type, p->cru_mask); + } + if (IS_ERR(alg)) return PTR_ERR(alg); -- cgit v1.2.3-59-g8ed1b From 5219a5342ab13650ae0f0c62319407268c48d0ab Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Thu, 29 Mar 2012 09:04:46 +0200 Subject: crypto: user - Fix size of netlink dump message The default netlink message size limit might be exceeded when dumping a lot of algorithms to userspace. As a result, not all of the instantiated algorithms dumped to userspace. So calculate an upper bound on the message size and call netlink_dump_start() with that value. Signed-off-by: Steffen Klassert Signed-off-by: Herbert Xu --- crypto/crypto_user.c | 8 ++++++++ include/linux/cryptouser.h | 3 +++ 2 files changed, 11 insertions(+) (limited to 'crypto/crypto_user.c') diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index e91c16111ed3..f1ea0a064135 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -457,12 +457,20 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) && (nlh->nlmsg_flags & NLM_F_DUMP))) { + struct crypto_alg *alg; + u16 dump_alloc = 0; + if (link->dump == NULL) return -EINVAL; + + list_for_each_entry(alg, &crypto_alg_list, cra_list) + dump_alloc += CRYPTO_REPORT_MAXSIZE; + { struct netlink_dump_control c = { .dump = link->dump, .done = link->done, + .min_dump_alloc = dump_alloc, }; return netlink_dump_start(crypto_nlsk, skb, nlh, &c); } diff --git a/include/linux/cryptouser.h b/include/linux/cryptouser.h index 532fb58f16bf..4abf2ea6a887 100644 --- a/include/linux/cryptouser.h +++ b/include/linux/cryptouser.h @@ -100,3 +100,6 @@ struct crypto_report_rng { char type[CRYPTO_MAX_NAME]; unsigned int seedsize; }; + +#define CRYPTO_REPORT_MAXSIZE (sizeof(struct crypto_user_alg) + \ + sizeof(struct crypto_report_blkcipher)) -- cgit v1.2.3-59-g8ed1b