From 652d5b8a8da8f05f7fb301067ffeef78b6f2eb01 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Fri, 23 Oct 2015 14:10:36 +0200 Subject: crypto: algif - Change some variable to size_t Some variable are set as int but store only positive values. Furthermore there are used in operation/function that wait for unsigned value. This patch set them as size_t. Signed-off-by: LABBE Corentin Signed-off-by: Herbert Xu --- crypto/algif_aead.c | 6 +++--- crypto/algif_skcipher.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 0aa6fdfb448a..f70bcf844975 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -213,7 +213,7 @@ static int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) } while (size) { - unsigned long len = size; + size_t len = size; struct scatterlist *sg = NULL; /* use the existing memory in an allocated page */ @@ -247,7 +247,7 @@ static int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) /* allocate a new page */ len = min_t(unsigned long, size, aead_sndbuf(sk)); while (len) { - int plen = 0; + size_t plen = 0; if (sgl->cur >= ALG_MAX_PAGES) { aead_put_sgl(sk); @@ -256,7 +256,7 @@ static int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) } sg = sgl->sg + sgl->cur; - plen = min_t(int, len, PAGE_SIZE); + plen = min_t(size_t, len, PAGE_SIZE); sg_assign_page(sg, alloc_page(GFP_KERNEL)); err = -ENOMEM; diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index af31a0ee4057..bbb1b66e969c 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -40,7 +40,7 @@ struct skcipher_ctx { struct af_alg_completion completion; atomic_t inflight; - unsigned used; + size_t used; unsigned int len; bool more; @@ -153,7 +153,7 @@ static int skcipher_alloc_sgl(struct sock *sk) return 0; } -static void skcipher_pull_sgl(struct sock *sk, int used, int put) +static void skcipher_pull_sgl(struct sock *sk, size_t used, int put) { struct alg_sock *ask = alg_sk(sk); struct skcipher_ctx *ctx = ask->private; @@ -167,7 +167,7 @@ static void skcipher_pull_sgl(struct sock *sk, int used, int put) sg = sgl->sg; for (i = 0; i < sgl->cur; i++) { - int plen = min_t(int, used, sg[i].length); + size_t plen = min_t(size_t, used, sg[i].length); if (!sg_page(sg + i)) continue; @@ -348,7 +348,7 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, while (size) { struct scatterlist *sg; unsigned long len = size; - int plen; + size_t plen; if (ctx->merge) { sgl = list_entry(ctx->tsgl.prev, @@ -390,7 +390,7 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, sg_unmark_end(sg + sgl->cur); do { i = sgl->cur; - plen = min_t(int, len, PAGE_SIZE); + plen = min_t(size_t, len, PAGE_SIZE); sg_assign_page(sg + i, alloc_page(GFP_KERNEL)); err = -ENOMEM; -- cgit v1.2.3 From 457e6f73a12bb713cc3eec2c979d707cb5716a07 Mon Sep 17 00:00:00 2001 From: Andrzej Zaborowski Date: Fri, 13 Nov 2015 12:01:33 +0100 Subject: crypto: rsa - only require output buffers as big as needed. rhe RSA operations explicitly left-align the integers being written skipping any leading zero bytes, but still require the output buffers to include just enough space for the integer + the leading zero bytes. Since the size of integer + the leading zero bytes (i.e. the key modulus size) can now be obtained more easily through crypto_akcipher_maxsize change the operations to only require as big a buffer as actually needed if the caller has that information. The semantics for request->dst_len don't change. Signed-off-by: Andrew Zaborowski Signed-off-by: Herbert Xu --- crypto/rsa.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'crypto') diff --git a/crypto/rsa.c b/crypto/rsa.c index 1093e041db03..58aad69a490c 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -91,12 +91,6 @@ static int rsa_enc(struct akcipher_request *req) goto err_free_c; } - if (req->dst_len < mpi_get_size(pkey->n)) { - req->dst_len = mpi_get_size(pkey->n); - ret = -EOVERFLOW; - goto err_free_c; - } - ret = -ENOMEM; m = mpi_read_raw_from_sgl(req->src, req->src_len); if (!m) @@ -136,12 +130,6 @@ static int rsa_dec(struct akcipher_request *req) goto err_free_m; } - if (req->dst_len < mpi_get_size(pkey->n)) { - req->dst_len = mpi_get_size(pkey->n); - ret = -EOVERFLOW; - goto err_free_m; - } - ret = -ENOMEM; c = mpi_read_raw_from_sgl(req->src, req->src_len); if (!c) @@ -180,12 +168,6 @@ static int rsa_sign(struct akcipher_request *req) goto err_free_s; } - if (req->dst_len < mpi_get_size(pkey->n)) { - req->dst_len = mpi_get_size(pkey->n); - ret = -EOVERFLOW; - goto err_free_s; - } - ret = -ENOMEM; m = mpi_read_raw_from_sgl(req->src, req->src_len); if (!m) @@ -225,12 +207,6 @@ static int rsa_verify(struct akcipher_request *req) goto err_free_m; } - if (req->dst_len < mpi_get_size(pkey->n)) { - req->dst_len = mpi_get_size(pkey->n); - ret = -EOVERFLOW; - goto err_free_m; - } - ret = -ENOMEM; s = mpi_read_raw_from_sgl(req->src, req->src_len); if (!s) { -- cgit v1.2.3 From 304e4818d4a45e83019ea30e4cfcb3ac2a8ce09a Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 16 Nov 2015 22:37:14 +0800 Subject: crypto: api - use list_first_entry_or_null and list_next_entry Simplify crypto_more_spawns() with list_first_entry_or_null() and list_next_entry(). Signed-off-by: Geliang Tang Signed-off-by: Herbert Xu --- crypto/algapi.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'crypto') diff --git a/crypto/algapi.c b/crypto/algapi.c index 59bf491fe3d8..7be76aa31579 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -93,16 +93,15 @@ static struct list_head *crypto_more_spawns(struct crypto_alg *alg, { struct crypto_spawn *spawn, *n; - if (list_empty(stack)) + spawn = list_first_entry_or_null(stack, struct crypto_spawn, list); + if (!spawn) return NULL; - spawn = list_first_entry(stack, struct crypto_spawn, list); - n = list_entry(spawn->list.next, struct crypto_spawn, list); + n = list_next_entry(spawn, list); if (spawn->alg && &n->list != stack && !n->alg) n->alg = (n->list.next == stack) ? alg : - &list_entry(n->list.next, struct crypto_spawn, - list)->inst->alg; + &list_next_entry(n, list)->inst->alg; list_move(&spawn->list, secondary_spawns); -- cgit v1.2.3 From 08346170d4483d58b8971fe9ff2a1318fd93d121 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 16 Nov 2015 22:37:15 +0800 Subject: crypto: mcryptd - use list_first_entry_or_null() Simplify mcryptd_opportunistic_flush() with list_first_entry_or_null(). Signed-off-by: Geliang Tang Signed-off-by: Herbert Xu --- crypto/mcryptd.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'crypto') diff --git a/crypto/mcryptd.c b/crypto/mcryptd.c index fe5b495a434d..f78d4fc4e38a 100644 --- a/crypto/mcryptd.c +++ b/crypto/mcryptd.c @@ -128,13 +128,9 @@ static void mcryptd_opportunistic_flush(void) flist = per_cpu_ptr(mcryptd_flist, smp_processor_id()); while (single_task_running()) { mutex_lock(&flist->lock); - if (list_empty(&flist->list)) { - mutex_unlock(&flist->lock); - return; - } - cstate = list_entry(flist->list.next, + cstate = list_first_entry_or_null(&flist->list, struct mcryptd_alg_cstate, flush_list); - if (!cstate->flusher_engaged) { + if (!cstate || !cstate->flusher_engaged) { mutex_unlock(&flist->lock); return; } -- cgit v1.2.3 From f18611da8683da19267e30187a191af7fa670206 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 17 Nov 2015 13:37:10 +0100 Subject: crypto: tcrypt - fix keysize argument of test_aead_speed for gcm(aes) The key sizes used by AES in GCM mode should be 128, 192 or 256 bits (16, 24 or 32 bytes). There is no additional 4byte nonce as for RFC 4106. Signed-off-by: Cyrille Pitchen Signed-off-by: Herbert Xu --- crypto/tcrypt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crypto') diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 46a4a757d478..270bc4b82bd9 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1789,7 +1789,7 @@ static int do_test(const char *alg, u32 type, u32 mask, int m) test_aead_speed("rfc4106(gcm(aes))", ENCRYPT, sec, NULL, 0, 16, 16, aead_speed_template_20); test_aead_speed("gcm(aes)", ENCRYPT, sec, - NULL, 0, 16, 8, aead_speed_template_20); + NULL, 0, 16, 8, speed_template_16_24_32); break; case 212: -- cgit v1.2.3 From c012a79d0ce95bd8488a5a44cd8c00c275774518 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Wed, 25 Nov 2015 23:48:28 +0600 Subject: crypto: cryptod - use crypto_skcipher_type() for getting skcipher type The provides inline function - crypto_skcipher_type(). Let's use it in the cryptd_alloc_ablkcipher() instead of direct calculation. Signed-off-by: Alexander Kuleshov Signed-off-by: Herbert Xu --- crypto/cryptd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'crypto') diff --git a/crypto/cryptd.c b/crypto/cryptd.c index c81861b1350b..c4af8aa1c304 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -887,8 +887,7 @@ struct cryptd_ablkcipher *cryptd_alloc_ablkcipher(const char *alg_name, if (snprintf(cryptd_alg_name, CRYPTO_MAX_ALG_NAME, "cryptd(%s)", alg_name) >= CRYPTO_MAX_ALG_NAME) return ERR_PTR(-EINVAL); - type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); - type |= CRYPTO_ALG_TYPE_BLKCIPHER; + type = crypto_skcipher_type(type); mask &= ~CRYPTO_ALG_TYPE_MASK; mask |= (CRYPTO_ALG_GENIV | CRYPTO_ALG_TYPE_BLKCIPHER_MASK); tfm = crypto_alloc_base(cryptd_alg_name, type, mask); -- cgit v1.2.3 From 1ce0bf50ae2233c7115a18c0c623662d177b434c Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 26 Nov 2015 13:55:39 +0800 Subject: net: Generalise wq_has_sleeper helper The memory barrier in the helper wq_has_sleeper is needed by just about every user of waitqueue_active. This patch generalises it by making it take a wait_queue_head_t directly. The existing helper is renamed to skwq_has_sleeper. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- crypto/algif_aead.c | 4 ++-- crypto/algif_skcipher.c | 4 ++-- include/linux/wait.h | 21 +++++++++++++++++++++ include/net/sock.h | 15 +++++---------- net/atm/common.c | 4 ++-- net/core/sock.c | 8 ++++---- net/core/stream.c | 2 +- net/dccp/output.c | 2 +- net/iucv/af_iucv.c | 2 +- net/rxrpc/af_rxrpc.c | 2 +- net/sctp/socket.c | 2 +- net/tipc/socket.c | 4 ++-- net/unix/af_unix.c | 2 +- 13 files changed, 44 insertions(+), 28 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 0aa6fdfb448a..fb99f30849d2 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -106,7 +106,7 @@ static void aead_wmem_wakeup(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLIN | POLLRDNORM | POLLRDBAND); @@ -157,7 +157,7 @@ static void aead_data_wakeup(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | POLLRDNORM | POLLRDBAND); diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index af31a0ee4057..0e6702e41472 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -238,7 +238,7 @@ static void skcipher_wmem_wakeup(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLIN | POLLRDNORM | POLLRDBAND); @@ -288,7 +288,7 @@ static void skcipher_data_wakeup(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | POLLRDNORM | POLLRDBAND); diff --git a/include/linux/wait.h b/include/linux/wait.h index 1e1bf9f963a9..6aa09a875fbd 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -107,6 +107,27 @@ static inline int waitqueue_active(wait_queue_head_t *q) return !list_empty(&q->task_list); } +/** + * wq_has_sleeper - check if there are any waiting processes + * @wq: wait queue head + * + * Returns true if wq has waiting processes + * + * Please refer to the comment for waitqueue_active. + */ +static inline bool wq_has_sleeper(wait_queue_head_t *wq) +{ + /* + * We need to be sure we are in sync with the + * add_wait_queue modifications to the wait queue. + * + * This memory barrier should be paired with one on the + * waiting side. + */ + smp_mb(); + return waitqueue_active(wq); +} + extern void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait); extern void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait); extern void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait); diff --git a/include/net/sock.h b/include/net/sock.h index 7f89e4ba18d1..62d35afcb3ac 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -58,6 +58,7 @@ #include #include #include +#include #include #include @@ -1879,12 +1880,12 @@ static inline bool sk_has_allocations(const struct sock *sk) } /** - * wq_has_sleeper - check if there are any waiting processes + * skwq_has_sleeper - check if there are any waiting processes * @wq: struct socket_wq * * Returns true if socket_wq has waiting processes * - * The purpose of the wq_has_sleeper and sock_poll_wait is to wrap the memory + * The purpose of the skwq_has_sleeper and sock_poll_wait is to wrap the memory * barrier call. They were added due to the race found within the tcp code. * * Consider following tcp code paths: @@ -1910,15 +1911,9 @@ static inline bool sk_has_allocations(const struct sock *sk) * data on the socket. * */ -static inline bool wq_has_sleeper(struct socket_wq *wq) +static inline bool skwq_has_sleeper(struct socket_wq *wq) { - /* We need to be sure we are in sync with the - * add_wait_queue modifications to the wait queue. - * - * This memory barrier is paired in the sock_poll_wait. - */ - smp_mb(); - return wq && waitqueue_active(&wq->wait); + return wq && wq_has_sleeper(&wq->wait); } /** diff --git a/net/atm/common.c b/net/atm/common.c index 49a872db7e42..6dc12305799e 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -96,7 +96,7 @@ static void vcc_def_wakeup(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up(&wq->wait); rcu_read_unlock(); } @@ -117,7 +117,7 @@ static void vcc_write_space(struct sock *sk) if (vcc_writable(sk)) { wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible(&wq->wait); sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); diff --git a/net/core/sock.c b/net/core/sock.c index 1e4dd54bfb5a..2769bd3a4d7c 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2283,7 +2283,7 @@ static void sock_def_wakeup(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_all(&wq->wait); rcu_read_unlock(); } @@ -2294,7 +2294,7 @@ static void sock_def_error_report(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_poll(&wq->wait, POLLERR); sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR); rcu_read_unlock(); @@ -2306,7 +2306,7 @@ static void sock_def_readable(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND); sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); @@ -2324,7 +2324,7 @@ static void sock_def_write_space(struct sock *sk) */ if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) { wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | POLLWRNORM | POLLWRBAND); diff --git a/net/core/stream.c b/net/core/stream.c index d70f77a0c889..8ff9d63b4265 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -35,7 +35,7 @@ void sk_stream_write_space(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_poll(&wq->wait, POLLOUT | POLLWRNORM | POLLWRBAND); if (wq && wq->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) diff --git a/net/dccp/output.c b/net/dccp/output.c index 4ce912e691d0..b66c84db0766 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -201,7 +201,7 @@ void dccp_write_space(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible(&wq->wait); /* Should agree with poll, otherwise some programs break */ if (sock_writeable(sk)) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index fcb2752419c6..4f0aa91470c6 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -303,7 +303,7 @@ static void iucv_sock_wake_msglim(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_all(&wq->wait); sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); rcu_read_unlock(); diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 1f8a144a5dc2..7e2d1057d8bc 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -67,7 +67,7 @@ static void rxrpc_write_space(struct sock *sk) if (rxrpc_writable(sk)) { struct socket_wq *wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible(&wq->wait); sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 897c01c029ca..ec10b66354b8 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6978,7 +6978,7 @@ void sctp_data_ready(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLIN | POLLRDNORM | POLLRDBAND); sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 552dbaba9cf3..525acf6dd1c6 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1492,7 +1492,7 @@ static void tipc_write_space(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | POLLWRNORM | POLLWRBAND); rcu_read_unlock(); @@ -1509,7 +1509,7 @@ static void tipc_data_ready(struct sock *sk) rcu_read_lock(); wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLIN | POLLRDNORM | POLLRDBAND); rcu_read_unlock(); diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 955ec152cb71..efb706e1d1c0 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -339,7 +339,7 @@ static void unix_write_space(struct sock *sk) rcu_read_lock(); if (unix_writable(sk)) { wq = rcu_dereference(sk->sk_wq); - if (wq_has_sleeper(wq)) + if (skwq_has_sleeper(wq)) wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | POLLWRNORM | POLLWRBAND); sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); -- cgit v1.2.3 From 1a07834024dfca5c4bed5de8f8714306e0a11836 Mon Sep 17 00:00:00 2001 From: "Wang, Rui Y" Date: Sun, 29 Nov 2015 22:45:34 +0800 Subject: crypto: cryptd - Assign statesize properly cryptd_create_hash() fails by returning -EINVAL. It is because after 8996eafdc ("crypto: ahash - ensure statesize is non-zero") all ahash drivers must have a non-zero statesize. This patch fixes the problem by properly assigning the statesize. Signed-off-by: Rui Wang Signed-off-by: Herbert Xu --- crypto/cryptd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'crypto') diff --git a/crypto/cryptd.c b/crypto/cryptd.c index c4af8aa1c304..7921251cdb13 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -637,6 +637,7 @@ static int cryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb, inst->alg.halg.base.cra_flags = type; inst->alg.halg.digestsize = salg->digestsize; + inst->alg.halg.statesize = salg->statesize; inst->alg.halg.base.cra_ctxsize = sizeof(struct cryptd_hash_ctx); inst->alg.halg.base.cra_init = cryptd_hash_init_tfm; -- cgit v1.2.3 From 28a4618ad14cf17009a87d8b5718132a5d4ef852 Mon Sep 17 00:00:00 2001 From: Andrzej Zaborowski Date: Sat, 5 Dec 2015 17:09:33 +0100 Subject: crypto: akcipher - add akcipher declarations needed by templates. Add a struct akcipher_instance and struct akcipher_spawn similar to how AEAD declares them and the macros for converting to/from crypto_instance/crypto_spawn. Also add register functions to avoid exposing crypto_akcipher_type. Signed-off-by: Andrew Zaborowski Signed-off-by: Herbert Xu --- crypto/akcipher.c | 34 ++++++++++++++++- include/crypto/internal/akcipher.h | 78 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) (limited to 'crypto') diff --git a/crypto/akcipher.c b/crypto/akcipher.c index 120ec042ec9e..def301ed1288 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "internal.h" #ifdef CONFIG_NET @@ -75,9 +76,17 @@ static int crypto_akcipher_init_tfm(struct crypto_tfm *tfm) return 0; } +static void crypto_akcipher_free_instance(struct crypto_instance *inst) +{ + struct akcipher_instance *akcipher = akcipher_instance(inst); + + akcipher->free(akcipher); +} + static const struct crypto_type crypto_akcipher_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_akcipher_init_tfm, + .free = crypto_akcipher_free_instance, #ifdef CONFIG_PROC_FS .show = crypto_akcipher_show, #endif @@ -88,6 +97,14 @@ static const struct crypto_type crypto_akcipher_type = { .tfmsize = offsetof(struct crypto_akcipher, base), }; +int crypto_grab_akcipher(struct crypto_akcipher_spawn *spawn, const char *name, + u32 type, u32 mask) +{ + spawn->base.frontend = &crypto_akcipher_type; + return crypto_grab_spawn(&spawn->base, name, type, mask); +} +EXPORT_SYMBOL_GPL(crypto_grab_akcipher); + struct crypto_akcipher *crypto_alloc_akcipher(const char *alg_name, u32 type, u32 mask) { @@ -95,13 +112,20 @@ struct crypto_akcipher *crypto_alloc_akcipher(const char *alg_name, u32 type, } EXPORT_SYMBOL_GPL(crypto_alloc_akcipher); -int crypto_register_akcipher(struct akcipher_alg *alg) +static void akcipher_prepare_alg(struct akcipher_alg *alg) { struct crypto_alg *base = &alg->base; base->cra_type = &crypto_akcipher_type; base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_AKCIPHER; +} + +int crypto_register_akcipher(struct akcipher_alg *alg) +{ + struct crypto_alg *base = &alg->base; + + akcipher_prepare_alg(alg); return crypto_register_alg(base); } EXPORT_SYMBOL_GPL(crypto_register_akcipher); @@ -112,5 +136,13 @@ void crypto_unregister_akcipher(struct akcipher_alg *alg) } EXPORT_SYMBOL_GPL(crypto_unregister_akcipher); +int akcipher_register_instance(struct crypto_template *tmpl, + struct akcipher_instance *inst) +{ + akcipher_prepare_alg(&inst->alg); + return crypto_register_instance(tmpl, akcipher_crypto_instance(inst)); +} +EXPORT_SYMBOL_GPL(akcipher_register_instance); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic public key cipher type"); diff --git a/include/crypto/internal/akcipher.h b/include/crypto/internal/akcipher.h index 9a2bda15e454..479a0078f0f7 100644 --- a/include/crypto/internal/akcipher.h +++ b/include/crypto/internal/akcipher.h @@ -13,6 +13,22 @@ #ifndef _CRYPTO_AKCIPHER_INT_H #define _CRYPTO_AKCIPHER_INT_H #include +#include + +struct akcipher_instance { + void (*free)(struct akcipher_instance *inst); + union { + struct { + char head[offsetof(struct akcipher_alg, base)]; + struct crypto_instance base; + } s; + struct akcipher_alg alg; + }; +}; + +struct crypto_akcipher_spawn { + struct crypto_spawn base; +}; /* * Transform internal helpers. @@ -38,6 +54,56 @@ static inline const char *akcipher_alg_name(struct crypto_akcipher *tfm) return crypto_akcipher_tfm(tfm)->__crt_alg->cra_name; } +static inline struct crypto_instance *akcipher_crypto_instance( + struct akcipher_instance *inst) +{ + return container_of(&inst->alg.base, struct crypto_instance, alg); +} + +static inline struct akcipher_instance *akcipher_instance( + struct crypto_instance *inst) +{ + return container_of(&inst->alg, struct akcipher_instance, alg.base); +} + +static inline struct akcipher_instance *akcipher_alg_instance( + struct crypto_akcipher *akcipher) +{ + return akcipher_instance(crypto_tfm_alg_instance(&akcipher->base)); +} + +static inline void *akcipher_instance_ctx(struct akcipher_instance *inst) +{ + return crypto_instance_ctx(akcipher_crypto_instance(inst)); +} + +static inline void crypto_set_akcipher_spawn( + struct crypto_akcipher_spawn *spawn, + struct crypto_instance *inst) +{ + crypto_set_spawn(&spawn->base, inst); +} + +int crypto_grab_akcipher(struct crypto_akcipher_spawn *spawn, const char *name, + u32 type, u32 mask); + +static inline struct crypto_akcipher *crypto_spawn_akcipher( + struct crypto_akcipher_spawn *spawn) +{ + return crypto_spawn_tfm2(&spawn->base); +} + +static inline void crypto_drop_akcipher(struct crypto_akcipher_spawn *spawn) +{ + crypto_drop_spawn(&spawn->base); +} + +static inline struct akcipher_alg *crypto_spawn_akcipher_alg( + struct crypto_akcipher_spawn *spawn) +{ + return container_of(spawn->base.alg, struct akcipher_alg, base); +} + /** * crypto_register_akcipher() -- Register public key algorithm * @@ -57,4 +123,16 @@ int crypto_register_akcipher(struct akcipher_alg *alg); * @alg: algorithm definition */ void crypto_unregister_akcipher(struct akcipher_alg *alg); + +/** + * akcipher_register_instance() -- Unregister public key template instance + * + * Function registers an implementation of an asymmetric key algorithm + * created from a template + * + * @tmpl: the template from which the algorithm was created + * @inst: the template instance + */ +int akcipher_register_instance(struct crypto_template *tmpl, + struct akcipher_instance *inst); #endif -- cgit v1.2.3 From 3d5b1ecdea6fb94f8c61554fcb2ba776a2d3d0e6 Mon Sep 17 00:00:00 2001 From: Andrzej Zaborowski Date: Sat, 5 Dec 2015 17:09:34 +0100 Subject: crypto: rsa - RSA padding algorithm This patch adds PKCS#1 v1.5 standard RSA padding as a separate template. This way an RSA cipher with padding can be obtained by instantiating "pkcs1pad(rsa)". The reason for adding this is that RSA is almost never used without this padding (or OAEP) so it will be needed for either certificate work in the kernel or the userspace, and I also hear that it is likely implemented by hardware RSA in which case hardware implementations of the whole of pkcs1pad(rsa) can be provided. Signed-off-by: Andrew Zaborowski Signed-off-by: Herbert Xu --- crypto/Makefile | 1 + crypto/rsa-pkcs1pad.c | 617 ++++++++++++++++++++++++++++++++++++++++++ crypto/rsa.c | 16 +- include/crypto/internal/rsa.h | 2 + 4 files changed, 635 insertions(+), 1 deletion(-) create mode 100644 crypto/rsa-pkcs1pad.c (limited to 'crypto') diff --git a/crypto/Makefile b/crypto/Makefile index f7aba923458d..2acdbbd30475 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -40,6 +40,7 @@ rsa_generic-y := rsapubkey-asn1.o rsa_generic-y += rsaprivkey-asn1.o rsa_generic-y += rsa.o rsa_generic-y += rsa_helper.o +rsa_generic-y += rsa-pkcs1pad.o obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o cryptomgr-y := algboss.o testmgr.o diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c new file mode 100644 index 000000000000..accc67d16686 --- /dev/null +++ b/crypto/rsa-pkcs1pad.c @@ -0,0 +1,617 @@ +/* + * RSA padding templates. + * + * Copyright (c) 2015 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct pkcs1pad_ctx { + struct crypto_akcipher *child; + + unsigned int key_size; +}; + +struct pkcs1pad_request { + struct akcipher_request child_req; + + struct scatterlist in_sg[3], out_sg[2]; + uint8_t *in_buf, *out_buf; +}; + +static int pkcs1pad_set_pub_key(struct crypto_akcipher *tfm, const void *key, + unsigned int keylen) +{ + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + int err, size; + + err = crypto_akcipher_set_pub_key(ctx->child, key, keylen); + + if (!err) { + /* Find out new modulus size from rsa implementation */ + size = crypto_akcipher_maxsize(ctx->child); + + ctx->key_size = size > 0 ? size : 0; + if (size <= 0) + err = size; + } + + return err; +} + +static int pkcs1pad_set_priv_key(struct crypto_akcipher *tfm, const void *key, + unsigned int keylen) +{ + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + int err, size; + + err = crypto_akcipher_set_priv_key(ctx->child, key, keylen); + + if (!err) { + /* Find out new modulus size from rsa implementation */ + size = crypto_akcipher_maxsize(ctx->child); + + ctx->key_size = size > 0 ? size : 0; + if (size <= 0) + err = size; + } + + return err; +} + +static int pkcs1pad_get_max_size(struct crypto_akcipher *tfm) +{ + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + + /* + * The maximum destination buffer size for the encrypt/sign operations + * will be the same as for RSA, even though it's smaller for + * decrypt/verify. + */ + + return ctx->key_size ?: -EINVAL; +} + +static void pkcs1pad_sg_set_buf(struct scatterlist *sg, void *buf, size_t len, + struct scatterlist *next) +{ + int nsegs = next ? 1 : 0; + + if (offset_in_page(buf) + len <= PAGE_SIZE) { + nsegs += 1; + sg_init_table(sg, nsegs); + sg_set_buf(sg, buf, len); + } else { + nsegs += 2; + sg_init_table(sg, nsegs); + sg_set_buf(sg + 0, buf, PAGE_SIZE - offset_in_page(buf)); + sg_set_buf(sg + 1, buf + PAGE_SIZE - offset_in_page(buf), + offset_in_page(buf) + len - PAGE_SIZE); + } + + if (next) + sg_chain(sg, nsegs, next); +} + +static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); + uint8_t zeros[ctx->key_size - req_ctx->child_req.dst_len]; + + if (!err) { + if (req_ctx->child_req.dst_len < ctx->key_size) { + memset(zeros, 0, sizeof(zeros)); + sg_copy_from_buffer(req->dst, + sg_nents_for_len(req->dst, + sizeof(zeros)), + zeros, sizeof(zeros)); + } + + sg_pcopy_from_buffer(req->dst, + sg_nents_for_len(req->dst, ctx->key_size), + req_ctx->out_buf, req_ctx->child_req.dst_len, + sizeof(zeros)); + } + req->dst_len = ctx->key_size; + + kfree(req_ctx->in_buf); + kzfree(req_ctx->out_buf); + + return err; +} + +static void pkcs1pad_encrypt_sign_complete_cb( + struct crypto_async_request *child_async_req, int err) +{ + struct akcipher_request *req = child_async_req->data; + struct crypto_async_request async_req; + + if (err == -EINPROGRESS) + return; + + async_req.data = req->base.data; + async_req.tfm = crypto_akcipher_tfm(crypto_akcipher_reqtfm(req)); + async_req.flags = child_async_req->flags; + req->base.complete(&async_req, + pkcs1pad_encrypt_sign_complete(req, err)); +} + +static int pkcs1pad_encrypt(struct akcipher_request *req) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); + int err; + unsigned int i, ps_end; + + if (!ctx->key_size) + return -EINVAL; + + if (req->src_len > ctx->key_size - 11) + return -EOVERFLOW; + + if (req->dst_len < ctx->key_size) { + req->dst_len = ctx->key_size; + return -EOVERFLOW; + } + + if (ctx->key_size > PAGE_SIZE) + return -ENOTSUPP; + + /* + * Replace both input and output to add the padding in the input and + * the potential missing leading zeros in the output. + */ + req_ctx->child_req.src = req_ctx->in_sg; + req_ctx->child_req.src_len = ctx->key_size - 1; + req_ctx->child_req.dst = req_ctx->out_sg; + req_ctx->child_req.dst_len = ctx->key_size; + + req_ctx->in_buf = kmalloc(ctx->key_size - 1 - req->src_len, + (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC); + if (!req_ctx->in_buf) + return -ENOMEM; + + ps_end = ctx->key_size - req->src_len - 2; + req_ctx->in_buf[0] = 0x02; + for (i = 1; i < ps_end; i++) + req_ctx->in_buf[i] = 1 + prandom_u32_max(255); + req_ctx->in_buf[ps_end] = 0x00; + + pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf, + ctx->key_size - 1 - req->src_len, req->src); + + req_ctx->out_buf = kmalloc(ctx->key_size, + (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC); + if (!req_ctx->out_buf) { + kfree(req_ctx->in_buf); + return -ENOMEM; + } + + pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf, + ctx->key_size, NULL); + + akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); + akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, + pkcs1pad_encrypt_sign_complete_cb, req); + + err = crypto_akcipher_encrypt(&req_ctx->child_req); + if (err != -EINPROGRESS && + (err != -EBUSY || + !(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))) + return pkcs1pad_encrypt_sign_complete(req, err); + + return err; +} + +static int pkcs1pad_decrypt_complete(struct akcipher_request *req, int err) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); + unsigned int pos; + + if (err == -EOVERFLOW) + /* Decrypted value had no leading 0 byte */ + err = -EINVAL; + + if (err) + goto done; + + if (req_ctx->child_req.dst_len != ctx->key_size - 1) { + err = -EINVAL; + goto done; + } + + if (req_ctx->out_buf[0] != 0x02) { + err = -EINVAL; + goto done; + } + for (pos = 1; pos < req_ctx->child_req.dst_len; pos++) + if (req_ctx->out_buf[pos] == 0x00) + break; + if (pos < 9 || pos == req_ctx->child_req.dst_len) { + err = -EINVAL; + goto done; + } + pos++; + + if (req->dst_len < req_ctx->child_req.dst_len - pos) + err = -EOVERFLOW; + req->dst_len = req_ctx->child_req.dst_len - pos; + + if (!err) + sg_copy_from_buffer(req->dst, + sg_nents_for_len(req->dst, req->dst_len), + req_ctx->out_buf + pos, req->dst_len); + +done: + kzfree(req_ctx->out_buf); + + return err; +} + +static void pkcs1pad_decrypt_complete_cb( + struct crypto_async_request *child_async_req, int err) +{ + struct akcipher_request *req = child_async_req->data; + struct crypto_async_request async_req; + + if (err == -EINPROGRESS) + return; + + async_req.data = req->base.data; + async_req.tfm = crypto_akcipher_tfm(crypto_akcipher_reqtfm(req)); + async_req.flags = child_async_req->flags; + req->base.complete(&async_req, pkcs1pad_decrypt_complete(req, err)); +} + +static int pkcs1pad_decrypt(struct akcipher_request *req) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); + int err; + + if (!ctx->key_size || req->src_len != ctx->key_size) + return -EINVAL; + + if (ctx->key_size > PAGE_SIZE) + return -ENOTSUPP; + + /* Reuse input buffer, output to a new buffer */ + req_ctx->child_req.src = req->src; + req_ctx->child_req.src_len = req->src_len; + req_ctx->child_req.dst = req_ctx->out_sg; + req_ctx->child_req.dst_len = ctx->key_size - 1; + + req_ctx->out_buf = kmalloc(ctx->key_size - 1, + (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC); + if (!req_ctx->out_buf) + return -ENOMEM; + + pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf, + ctx->key_size - 1, NULL); + + akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); + akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, + pkcs1pad_decrypt_complete_cb, req); + + err = crypto_akcipher_decrypt(&req_ctx->child_req); + if (err != -EINPROGRESS && + (err != -EBUSY || + !(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))) + return pkcs1pad_decrypt_complete(req, err); + + return err; +} + +static int pkcs1pad_sign(struct akcipher_request *req) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); + int err; + unsigned int ps_end; + + if (!ctx->key_size) + return -EINVAL; + + if (req->src_len > ctx->key_size - 11) + return -EOVERFLOW; + + if (req->dst_len < ctx->key_size) { + req->dst_len = ctx->key_size; + return -EOVERFLOW; + } + + if (ctx->key_size > PAGE_SIZE) + return -ENOTSUPP; + + /* + * Replace both input and output to add the padding in the input and + * the potential missing leading zeros in the output. + */ + req_ctx->child_req.src = req_ctx->in_sg; + req_ctx->child_req.src_len = ctx->key_size - 1; + req_ctx->child_req.dst = req_ctx->out_sg; + req_ctx->child_req.dst_len = ctx->key_size; + + req_ctx->in_buf = kmalloc(ctx->key_size - 1 - req->src_len, + (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC); + if (!req_ctx->in_buf) + return -ENOMEM; + + ps_end = ctx->key_size - req->src_len - 2; + req_ctx->in_buf[0] = 0x01; + memset(req_ctx->in_buf + 1, 0xff, ps_end - 1); + req_ctx->in_buf[ps_end] = 0x00; + + pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf, + ctx->key_size - 1 - req->src_len, req->src); + + req_ctx->out_buf = kmalloc(ctx->key_size, + (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC); + if (!req_ctx->out_buf) { + kfree(req_ctx->in_buf); + return -ENOMEM; + } + + pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf, + ctx->key_size, NULL); + + akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); + akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, + pkcs1pad_encrypt_sign_complete_cb, req); + + err = crypto_akcipher_sign(&req_ctx->child_req); + if (err != -EINPROGRESS && + (err != -EBUSY || + !(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))) + return pkcs1pad_encrypt_sign_complete(req, err); + + return err; +} + +static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); + unsigned int pos; + + if (err == -EOVERFLOW) + /* Decrypted value had no leading 0 byte */ + err = -EINVAL; + + if (err) + goto done; + + if (req_ctx->child_req.dst_len != ctx->key_size - 1) { + err = -EINVAL; + goto done; + } + + if (req_ctx->out_buf[0] != 0x01) { + err = -EINVAL; + goto done; + } + for (pos = 1; pos < req_ctx->child_req.dst_len; pos++) + if (req_ctx->out_buf[pos] != 0xff) + break; + if (pos < 9 || pos == req_ctx->child_req.dst_len || + req_ctx->out_buf[pos] != 0x00) { + err = -EINVAL; + goto done; + } + pos++; + + if (req->dst_len < req_ctx->child_req.dst_len - pos) + err = -EOVERFLOW; + req->dst_len = req_ctx->child_req.dst_len - pos; + + if (!err) + sg_copy_from_buffer(req->dst, + sg_nents_for_len(req->dst, req->dst_len), + req_ctx->out_buf + pos, req->dst_len); + +done: + kzfree(req_ctx->out_buf); + + return err; +} + +static void pkcs1pad_verify_complete_cb( + struct crypto_async_request *child_async_req, int err) +{ + struct akcipher_request *req = child_async_req->data; + struct crypto_async_request async_req; + + if (err == -EINPROGRESS) + return; + + async_req.data = req->base.data; + async_req.tfm = crypto_akcipher_tfm(crypto_akcipher_reqtfm(req)); + async_req.flags = child_async_req->flags; + req->base.complete(&async_req, pkcs1pad_verify_complete(req, err)); +} + +/* + * The verify operation is here for completeness similar to the verification + * defined in RFC2313 section 10.2 except that block type 0 is not accepted, + * as in RFC2437. RFC2437 section 9.2 doesn't define any operation to + * retrieve the DigestInfo from a signature, instead the user is expected + * to call the sign operation to generate the expected signature and compare + * signatures instead of the message-digests. + */ +static int pkcs1pad_verify(struct akcipher_request *req) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); + int err; + + if (!ctx->key_size || req->src_len != ctx->key_size) + return -EINVAL; + + if (ctx->key_size > PAGE_SIZE) + return -ENOTSUPP; + + /* Reuse input buffer, output to a new buffer */ + req_ctx->child_req.src = req->src; + req_ctx->child_req.src_len = req->src_len; + req_ctx->child_req.dst = req_ctx->out_sg; + req_ctx->child_req.dst_len = ctx->key_size - 1; + + req_ctx->out_buf = kmalloc(ctx->key_size - 1, + (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC); + if (!req_ctx->out_buf) + return -ENOMEM; + + pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf, + ctx->key_size - 1, NULL); + + akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); + akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, + pkcs1pad_verify_complete_cb, req); + + err = crypto_akcipher_verify(&req_ctx->child_req); + if (err != -EINPROGRESS && + (err != -EBUSY || + !(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG))) + return pkcs1pad_verify_complete(req, err); + + return err; +} + +static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm) +{ + struct akcipher_instance *inst = akcipher_alg_instance(tfm); + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + struct crypto_akcipher *child_tfm; + + child_tfm = crypto_spawn_akcipher(akcipher_instance_ctx(inst)); + if (IS_ERR(child_tfm)) + return PTR_ERR(child_tfm); + + ctx->child = child_tfm; + + return 0; +} + +static void pkcs1pad_exit_tfm(struct crypto_akcipher *tfm) +{ + struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); + + crypto_free_akcipher(ctx->child); +} + +static void pkcs1pad_free(struct akcipher_instance *inst) +{ + struct crypto_akcipher_spawn *spawn = akcipher_instance_ctx(inst); + + crypto_drop_akcipher(spawn); + + kfree(inst); +} + +static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct crypto_attr_type *algt; + struct akcipher_instance *inst; + struct crypto_akcipher_spawn *spawn; + struct akcipher_alg *rsa_alg; + const char *rsa_alg_name; + int err; + + algt = crypto_get_attr_type(tb); + if (IS_ERR(algt)) + return PTR_ERR(algt); + + if ((algt->type ^ CRYPTO_ALG_TYPE_AKCIPHER) & algt->mask) + return -EINVAL; + + rsa_alg_name = crypto_attr_alg_name(tb[1]); + if (IS_ERR(rsa_alg_name)) + return PTR_ERR(rsa_alg_name); + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + spawn = akcipher_instance_ctx(inst); + crypto_set_spawn(&spawn->base, akcipher_crypto_instance(inst)); + err = crypto_grab_akcipher(spawn, rsa_alg_name, 0, + crypto_requires_sync(algt->type, algt->mask)); + if (err) + goto out_free_inst; + + rsa_alg = crypto_spawn_akcipher_alg(spawn); + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.base.cra_name, + CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", + rsa_alg->base.cra_name) >= + CRYPTO_MAX_ALG_NAME || + snprintf(inst->alg.base.cra_driver_name, + CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", + rsa_alg->base.cra_driver_name) >= + CRYPTO_MAX_ALG_NAME) + goto out_drop_alg; + + inst->alg.base.cra_flags = rsa_alg->base.cra_flags & CRYPTO_ALG_ASYNC; + inst->alg.base.cra_priority = rsa_alg->base.cra_priority; + inst->alg.base.cra_ctxsize = sizeof(struct pkcs1pad_ctx); + + inst->alg.init = pkcs1pad_init_tfm; + inst->alg.exit = pkcs1pad_exit_tfm; + + inst->alg.encrypt = pkcs1pad_encrypt; + inst->alg.decrypt = pkcs1pad_decrypt; + inst->alg.sign = pkcs1pad_sign; + inst->alg.verify = pkcs1pad_verify; + inst->alg.set_pub_key = pkcs1pad_set_pub_key; + inst->alg.set_priv_key = pkcs1pad_set_priv_key; + inst->alg.max_size = pkcs1pad_get_max_size; + inst->alg.reqsize = sizeof(struct pkcs1pad_request) + rsa_alg->reqsize; + + inst->free = pkcs1pad_free; + + err = akcipher_register_instance(tmpl, inst); + if (err) + goto out_drop_alg; + + return 0; + +out_drop_alg: + crypto_drop_akcipher(spawn); +out_free_inst: + kfree(inst); + return err; +} + +struct crypto_template rsa_pkcs1pad_tmpl = { + .name = "pkcs1pad", + .create = pkcs1pad_create, + .module = THIS_MODULE, +}; diff --git a/crypto/rsa.c b/crypto/rsa.c index 58aad69a490c..77d737f52147 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -13,6 +13,7 @@ #include #include #include +#include /* * RSAEP function [RFC3447 sec 5.1.1] @@ -315,11 +316,24 @@ static struct akcipher_alg rsa = { static int rsa_init(void) { - return crypto_register_akcipher(&rsa); + int err; + + err = crypto_register_akcipher(&rsa); + if (err) + return err; + + err = crypto_register_template(&rsa_pkcs1pad_tmpl); + if (err) { + crypto_unregister_akcipher(&rsa); + return err; + } + + return 0; } static void rsa_exit(void) { + crypto_unregister_template(&rsa_pkcs1pad_tmpl); crypto_unregister_akcipher(&rsa); } diff --git a/include/crypto/internal/rsa.h b/include/crypto/internal/rsa.h index f997e2d29b5a..c7585bdecbc2 100644 --- a/include/crypto/internal/rsa.h +++ b/include/crypto/internal/rsa.h @@ -27,4 +27,6 @@ int rsa_parse_priv_key(struct rsa_key *rsa_key, const void *key, unsigned int key_len); void rsa_free_key(struct rsa_key *rsa_key); + +extern struct crypto_template rsa_pkcs1pad_tmpl; #endif -- cgit v1.2.3 From 161151d79ff4f7ed35d4ebb0eb7727a517c34ef2 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 6 Dec 2015 02:51:38 +0100 Subject: crypto: chacha20poly1305 - Skip encryption/decryption for 0-len If the length of the plaintext is zero, there's no need to waste cycles on encryption and decryption. Using the chacha20poly1305 construction for zero-length plaintexts is a common way of using a shared encryption key for AAD authentication. Signed-off-by: Jason A. Donenfeld Signed-off-by: Herbert Xu --- crypto/chacha20poly1305.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'crypto') diff --git a/crypto/chacha20poly1305.c b/crypto/chacha20poly1305.c index 99c3cce01290..7b6b935cef23 100644 --- a/crypto/chacha20poly1305.c +++ b/crypto/chacha20poly1305.c @@ -130,6 +130,9 @@ static int chacha_decrypt(struct aead_request *req) struct scatterlist *src, *dst; int err; + if (rctx->cryptlen == 0) + goto skip; + chacha_iv(creq->iv, req, 1); sg_init_table(rctx->src, 2); @@ -150,6 +153,7 @@ static int chacha_decrypt(struct aead_request *req) if (err) return err; +skip: return poly_verify_tag(req); } @@ -415,6 +419,9 @@ static int chacha_encrypt(struct aead_request *req) struct scatterlist *src, *dst; int err; + if (req->cryptlen == 0) + goto skip; + chacha_iv(creq->iv, req, 1); sg_init_table(rctx->src, 2); @@ -435,6 +442,7 @@ static int chacha_encrypt(struct aead_request *req) if (err) return err; +skip: return poly_genkey(req); } -- cgit v1.2.3 From e4bc02aced3731776c8828d34e13c02ebdec3088 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 7 Dec 2015 21:36:57 +0100 Subject: crypto: drbg - constify drbg_state_ops structures The drbg_state_ops structures are never modified, so declare them as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Herbert Xu --- crypto/drbg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crypto') diff --git a/crypto/drbg.c b/crypto/drbg.c index a7c23146b87f..ab6ef1d08568 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -626,7 +626,7 @@ out: return len; } -static struct drbg_state_ops drbg_ctr_ops = { +static const struct drbg_state_ops drbg_ctr_ops = { .update = drbg_ctr_update, .generate = drbg_ctr_generate, .crypto_init = drbg_init_sym_kernel, @@ -752,7 +752,7 @@ static int drbg_hmac_generate(struct drbg_state *drbg, return len; } -static struct drbg_state_ops drbg_hmac_ops = { +static const struct drbg_state_ops drbg_hmac_ops = { .update = drbg_hmac_update, .generate = drbg_hmac_generate, .crypto_init = drbg_init_hash_kernel, @@ -1032,7 +1032,7 @@ out: * scratchpad usage: as update and generate are used isolated, both * can use the scratchpad */ -static struct drbg_state_ops drbg_hash_ops = { +static const struct drbg_state_ops drbg_hash_ops = { .update = drbg_hash_update, .generate = drbg_hash_generate, .crypto_init = drbg_init_hash_kernel, -- cgit v1.2.3 From 1f6a9ab05ab500a033c1d5490c3a6bd993bfd602 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 9 Dec 2015 15:05:28 -0500 Subject: crypto: asymmetric_keys - signature.c does not need This file does not contain any modular related function calls. So get rid of module.h since it drags in a lot of other headers and adds to the preprocessing load. It does export some symbols though, so we'll need to ensure it has export.h present instead. Cc: Herbert Xu Cc: "David S. Miller" Cc: linux-crypto@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Herbert Xu --- crypto/asymmetric_keys/signature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crypto') diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c index 9441240f7d2a..004d5fc8e56b 100644 --- a/crypto/asymmetric_keys/signature.c +++ b/crypto/asymmetric_keys/signature.c @@ -13,7 +13,7 @@ #define pr_fmt(fmt) "SIG: "fmt #include -#include +#include #include #include #include "asymmetric_keys.h" -- cgit v1.2.3 From 41c89b64d7184a780f12f2cccdabe65cb2408893 Mon Sep 17 00:00:00 2001 From: Petko Manolov Date: Wed, 2 Dec 2015 17:47:55 +0200 Subject: IMA: create machine owner and blacklist keyrings This option creates IMA MOK and blacklist keyrings. IMA MOK is an intermediate keyring that sits between .system and .ima keyrings, effectively forming a simple CA hierarchy. To successfully import a key into .ima_mok it must be signed by a key which CA is in .system keyring. On turn any key that needs to go in .ima keyring must be signed by CA in either .system or .ima_mok keyrings. IMA MOK is empty at kernel boot. IMA blacklist keyring contains all revoked IMA keys. It is consulted before any other keyring. If the search is successful the requested operation is rejected and error is returned to the caller. Signed-off-by: Petko Manolov Signed-off-by: Mimi Zohar --- crypto/asymmetric_keys/x509_public_key.c | 2 ++ include/keys/system_keyring.h | 24 ++++++++++++++ security/integrity/digsig_asymmetric.c | 14 +++++++++ security/integrity/ima/Kconfig | 18 +++++++++++ security/integrity/ima/Makefile | 1 + security/integrity/ima/ima_mok.c | 54 ++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+) create mode 100644 security/integrity/ima/ima_mok.c (limited to 'crypto') diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 2a44b3752471..9e9e5a6a9ed6 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -321,6 +321,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) goto error_free_cert; } else if (!prep->trusted) { ret = x509_validate_trust(cert, get_system_trusted_keyring()); + if (ret) + ret = x509_validate_trust(cert, get_ima_mok_keyring()); if (!ret) prep->trusted = 1; } diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h index b20cd885c1fd..39fd38cfa8c9 100644 --- a/include/keys/system_keyring.h +++ b/include/keys/system_keyring.h @@ -35,4 +35,28 @@ extern int system_verify_data(const void *data, unsigned long len, enum key_being_used_for usage); #endif +#ifdef CONFIG_IMA_MOK_KEYRING +extern struct key *ima_mok_keyring; +extern struct key *ima_blacklist_keyring; + +static inline struct key *get_ima_mok_keyring(void) +{ + return ima_mok_keyring; +} +static inline struct key *get_ima_blacklist_keyring(void) +{ + return ima_blacklist_keyring; +} +#else +static inline struct key *get_ima_mok_keyring(void) +{ + return NULL; +} +static inline struct key *get_ima_blacklist_keyring(void) +{ + return NULL; +} +#endif /* CONFIG_IMA_MOK_KEYRING */ + + #endif /* _KEYS_SYSTEM_KEYRING_H */ diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 4fec1816a2b3..5ade2a7517a6 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "integrity.h" @@ -32,9 +33,22 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) pr_debug("key search: \"%s\"\n", name); + key = get_ima_blacklist_keyring(); + if (key) { + key_ref_t kref; + + kref = keyring_search(make_key_ref(key, 1), + &key_type_asymmetric, name); + if (!IS_ERR(kref)) { + pr_err("Key '%s' is in ima_blacklist_keyring\n", name); + return ERR_PTR(-EKEYREJECTED); + } + } + if (keyring) { /* search in specific keyring */ key_ref_t kref; + kref = keyring_search(make_key_ref(keyring, 1), &key_type_asymmetric, name); if (IS_ERR(kref)) diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index e74d66cbfe87..8d5e6e0e0937 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -145,6 +145,24 @@ config IMA_TRUSTED_KEYRING This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING +config IMA_MOK_KEYRING + bool "Create IMA machine owner keys (MOK) and blacklist keyrings" + depends on SYSTEM_TRUSTED_KEYRING + depends on IMA_TRUSTED_KEYRING + default n + help + This option creates IMA MOK and blacklist keyrings. IMA MOK is an + intermediate keyring that sits between .system and .ima keyrings, + effectively forming a simple CA hierarchy. To successfully import a + key into .ima_mok it must be signed by a key which CA is in .system + keyring. On turn any key that needs to go in .ima keyring must be + signed by CA in either .system or .ima_mok keyrings. IMA MOK is empty + at kernel boot. + + IMA blacklist keyring contains all revoked IMA keys. It is consulted + before any other keyring. If the search is successful the requested + operation is rejected and error is returned to the caller. + config IMA_LOAD_X509 bool "Load X509 certificate onto the '.ima' trusted keyring" depends on IMA_TRUSTED_KEYRING diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile index d79263d2fdbf..a8539f9e060f 100644 --- a/security/integrity/ima/Makefile +++ b/security/integrity/ima/Makefile @@ -8,3 +8,4 @@ obj-$(CONFIG_IMA) += ima.o ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \ ima_policy.o ima_template.o ima_template_lib.o ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o +obj-$(CONFIG_IMA_MOK_KEYRING) += ima_mok.o diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c new file mode 100644 index 000000000000..18e37f57f512 --- /dev/null +++ b/security/integrity/ima/ima_mok.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Juniper Networks, Inc. + * + * Author: + * Petko Manolov + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +struct key *ima_mok_keyring; +struct key *ima_blacklist_keyring; + +/* + * Allocate the IMA MOK and blacklist keyrings + */ +__init int ima_mok_init(void) +{ + pr_notice("Allocating IMA MOK and blacklist keyrings.\n"); + + ima_mok_keyring = keyring_alloc(".ima_mok", + KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ | + KEY_USR_WRITE | KEY_USR_SEARCH, + KEY_ALLOC_NOT_IN_QUOTA, NULL); + + ima_blacklist_keyring = keyring_alloc(".ima_blacklist", + KUIDT_INIT(0), KGIDT_INIT(0), current_cred(), + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ | + KEY_USR_WRITE | KEY_USR_SEARCH, + KEY_ALLOC_NOT_IN_QUOTA, NULL); + + if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring)) + panic("Can't allocate IMA MOK or blacklist keyrings."); + set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_mok_keyring->flags); + set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_blacklist_keyring->flags); + return 0; +} + +module_init(ima_mok_init); -- cgit v1.2.3 From 5ca4c20cfd37bac6486de040e9951b3b34755238 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Thu, 5 Nov 2015 21:43:06 +0200 Subject: keys, trusted: select hash algorithm for TPM2 chips Added 'hash=' option for selecting the hash algorithm for add_key() syscall and documentation for it. Added entry for sm3-256 to the following tables in order to support TPM_ALG_SM3_256: * hash_algo_name * hash_digest_size Includes support for the following hash algorithms: * sha1 * sha256 * sha384 * sha512 * sm3-256 Signed-off-by: Jarkko Sakkinen Tested-by: Colin Ian King Reviewed-by: James Morris Reviewed-by: Mimi Zohar Acked-by: Peter Huewe --- Documentation/security/keys-trusted-encrypted.txt | 3 ++ crypto/hash_info.c | 2 ++ drivers/char/tpm/tpm.h | 10 +++++-- drivers/char/tpm/tpm2-cmd.c | 36 +++++++++++++++++++++-- include/crypto/hash_info.h | 3 ++ include/keys/trusted-type.h | 1 + include/uapi/linux/hash_info.h | 1 + security/keys/Kconfig | 1 + security/keys/trusted.c | 27 ++++++++++++++++- 9 files changed, 77 insertions(+), 7 deletions(-) (limited to 'crypto') diff --git a/Documentation/security/keys-trusted-encrypted.txt b/Documentation/security/keys-trusted-encrypted.txt index e105ae97a4f5..fd2565b301e8 100644 --- a/Documentation/security/keys-trusted-encrypted.txt +++ b/Documentation/security/keys-trusted-encrypted.txt @@ -38,6 +38,9 @@ Usage: pcrlock= pcr number to be extended to "lock" blob migratable= 0|1 indicating permission to reseal to new PCR values, default 1 (resealing allowed) + hash= hash algorithm name as a string. For TPM 1.x the only + allowed value is sha1. For TPM 2.x the allowed values + are sha1, sha256, sha384, sha512 and sm3-256. "keyctl print" returns an ascii hex copy of the sealed key, which is in standard TPM_STORED_DATA format. The key length for new keys are always in bytes. diff --git a/crypto/hash_info.c b/crypto/hash_info.c index 3e7ff46f26e8..7b1e0b188ce6 100644 --- a/crypto/hash_info.c +++ b/crypto/hash_info.c @@ -31,6 +31,7 @@ const char *const hash_algo_name[HASH_ALGO__LAST] = { [HASH_ALGO_TGR_128] = "tgr128", [HASH_ALGO_TGR_160] = "tgr160", [HASH_ALGO_TGR_192] = "tgr192", + [HASH_ALGO_SM3_256] = "sm3-256", }; EXPORT_SYMBOL_GPL(hash_algo_name); @@ -52,5 +53,6 @@ const int hash_digest_size[HASH_ALGO__LAST] = { [HASH_ALGO_TGR_128] = TGR128_DIGEST_SIZE, [HASH_ALGO_TGR_160] = TGR160_DIGEST_SIZE, [HASH_ALGO_TGR_192] = TGR192_DIGEST_SIZE, + [HASH_ALGO_SM3_256] = SM3256_DIGEST_SIZE, }; EXPORT_SYMBOL_GPL(hash_digest_size); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 347fc615bcc9..542a80cbfd9c 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -83,16 +83,20 @@ enum tpm2_structures { }; enum tpm2_return_codes { - TPM2_RC_INITIALIZE = 0x0100, - TPM2_RC_TESTING = 0x090A, + TPM2_RC_HASH = 0x0083, /* RC_FMT1 */ + TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */ TPM2_RC_DISABLED = 0x0120, + TPM2_RC_TESTING = 0x090A, /* RC_WARN */ }; enum tpm2_algorithms { TPM2_ALG_SHA1 = 0x0004, TPM2_ALG_KEYEDHASH = 0x0008, TPM2_ALG_SHA256 = 0x000B, - TPM2_ALG_NULL = 0x0010 + TPM2_ALG_SHA384 = 0x000C, + TPM2_ALG_SHA512 = 0x000D, + TPM2_ALG_NULL = 0x0010, + TPM2_ALG_SM3_256 = 0x0012, }; enum tpm2_command_codes { diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index c12130485fc1..d9d082206f6e 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -16,6 +16,7 @@ */ #include "tpm.h" +#include #include enum tpm2_object_attributes { @@ -104,6 +105,19 @@ struct tpm2_cmd { union tpm2_cmd_params params; } __packed; +struct tpm2_hash { + unsigned int crypto_id; + unsigned int tpm_id; +}; + +static struct tpm2_hash tpm2_hash_map[] = { + {HASH_ALGO_SHA1, TPM2_ALG_SHA1}, + {HASH_ALGO_SHA256, TPM2_ALG_SHA256}, + {HASH_ALGO_SHA384, TPM2_ALG_SHA384}, + {HASH_ALGO_SHA512, TPM2_ALG_SHA512}, + {HASH_ALGO_SM3_256, TPM2_ALG_SM3_256}, +}; + /* * Array with one entry per ordinal defining the maximum amount * of time the chip could take to return the result. The values @@ -429,8 +443,20 @@ int tpm2_seal_trusted(struct tpm_chip *chip, { unsigned int blob_len; struct tpm_buf buf; + u32 hash; + int i; int rc; + for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) { + if (options->hash == tpm2_hash_map[i].crypto_id) { + hash = tpm2_hash_map[i].tpm_id; + break; + } + } + + if (i == ARRAY_SIZE(tpm2_hash_map)) + return -EINVAL; + rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE); if (rc) return rc; @@ -455,7 +481,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, tpm_buf_append_u16(&buf, 14); tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH); - tpm_buf_append_u16(&buf, TPM2_ALG_SHA256); + tpm_buf_append_u16(&buf, hash); tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH); tpm_buf_append_u16(&buf, 0); /* policy digest size */ tpm_buf_append_u16(&buf, TPM2_ALG_NULL); @@ -488,8 +514,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip, out: tpm_buf_destroy(&buf); - if (rc > 0) - rc = -EPERM; + if (rc > 0) { + if ((rc & TPM2_RC_HASH) == TPM2_RC_HASH) + rc = -EINVAL; + else + rc = -EPERM; + } return rc; } diff --git a/include/crypto/hash_info.h b/include/crypto/hash_info.h index e1e5a3e5dd1b..56f217d41f12 100644 --- a/include/crypto/hash_info.h +++ b/include/crypto/hash_info.h @@ -34,6 +34,9 @@ #define TGR160_DIGEST_SIZE 20 #define TGR192_DIGEST_SIZE 24 +/* not defined in include/crypto/ */ +#define SM3256_DIGEST_SIZE 32 + extern const char *const hash_algo_name[HASH_ALGO__LAST]; extern const int hash_digest_size[HASH_ALGO__LAST]; diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h index f91ecd9d1bb1..a6a100833ae9 100644 --- a/include/keys/trusted-type.h +++ b/include/keys/trusted-type.h @@ -36,6 +36,7 @@ struct trusted_key_options { uint32_t pcrinfo_len; unsigned char pcrinfo[MAX_PCRINFO_SIZE]; int pcrlock; + uint32_t hash; }; extern struct key_type key_type_trusted; diff --git a/include/uapi/linux/hash_info.h b/include/uapi/linux/hash_info.h index ca18c45f8304..ebf8fd885dd5 100644 --- a/include/uapi/linux/hash_info.h +++ b/include/uapi/linux/hash_info.h @@ -31,6 +31,7 @@ enum hash_algo { HASH_ALGO_TGR_128, HASH_ALGO_TGR_160, HASH_ALGO_TGR_192, + HASH_ALGO_SM3_256, HASH_ALGO__LAST }; diff --git a/security/keys/Kconfig b/security/keys/Kconfig index 72483b8f1be5..fe4d74e126a7 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -54,6 +54,7 @@ config TRUSTED_KEYS select CRYPTO select CRYPTO_HMAC select CRYPTO_SHA1 + select CRYPTO_HASH_INFO help This option provides support for creating, sealing, and unsealing keys in the kernel. Trusted keys are random number symmetric keys, diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 7c183c767a3a..8f1300cab38e 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -11,6 +11,7 @@ * See Documentation/security/keys-trusted-encrypted.txt */ +#include #include #include #include @@ -710,7 +711,8 @@ enum { Opt_err = -1, Opt_new, Opt_load, Opt_update, Opt_keyhandle, Opt_keyauth, Opt_blobauth, - Opt_pcrinfo, Opt_pcrlock, Opt_migratable + Opt_pcrinfo, Opt_pcrlock, Opt_migratable, + Opt_hash, }; static const match_table_t key_tokens = { @@ -723,6 +725,7 @@ static const match_table_t key_tokens = { {Opt_pcrinfo, "pcrinfo=%s"}, {Opt_pcrlock, "pcrlock=%s"}, {Opt_migratable, "migratable=%s"}, + {Opt_hash, "hash=%s"}, {Opt_err, NULL} }; @@ -737,6 +740,14 @@ static int getoptions(char *c, struct trusted_key_payload *pay, unsigned long handle; unsigned long lock; unsigned long token_mask = 0; + int i; + int tpm2; + + tpm2 = tpm_is_tpm2(TPM_ANY_NUM); + if (tpm2 < 0) + return tpm2; + + opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1; while ((p = strsep(&c, " \t"))) { if (*p == '\0' || *p == ' ' || *p == '\t') @@ -790,6 +801,20 @@ static int getoptions(char *c, struct trusted_key_payload *pay, return -EINVAL; opt->pcrlock = lock; break; + case Opt_hash: + for (i = 0; i < HASH_ALGO__LAST; i++) { + if (!strcmp(args[0].from, hash_algo_name[i])) { + opt->hash = i; + break; + } + } + if (i == HASH_ALGO__LAST) + return -EINVAL; + if (!tpm2 && i != HASH_ALGO_SHA1) { + pr_info("trusted_key: TPM 1.x only supports SHA-1.\n"); + return -EINVAL; + } + break; default: return -EINVAL; } -- cgit v1.2.3 From 5319216dcfee14886abb2b7090e8fcf2e2d8a611 Mon Sep 17 00:00:00 2001 From: Andrzej Zaborowski Date: Sat, 12 Dec 2015 00:03:51 -0500 Subject: crypto: rsa-pkcs1pad - don't allocate buffer on stack Avoid the s390 compile "warning: 'pkcs1pad_encrypt_sign_complete' uses dynamic stack allocation" reported by kbuild test robot. Don't use a flat zero-filled buffer, instead zero the contents of the SGL. Signed-off-by: Andrew Zaborowski Signed-off-by: Herbert Xu --- crypto/rsa-pkcs1pad.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'crypto') diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c index accc67d16686..50f5c97e1087 100644 --- a/crypto/rsa-pkcs1pad.c +++ b/crypto/rsa-pkcs1pad.c @@ -110,21 +110,32 @@ static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err) struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); - uint8_t zeros[ctx->key_size - req_ctx->child_req.dst_len]; + size_t pad_len = ctx->key_size - req_ctx->child_req.dst_len; + size_t chunk_len, pad_left; + struct sg_mapping_iter miter; if (!err) { - if (req_ctx->child_req.dst_len < ctx->key_size) { - memset(zeros, 0, sizeof(zeros)); - sg_copy_from_buffer(req->dst, - sg_nents_for_len(req->dst, - sizeof(zeros)), - zeros, sizeof(zeros)); + if (pad_len) { + sg_miter_start(&miter, req->dst, + sg_nents_for_len(req->dst, pad_len), + SG_MITER_ATOMIC | SG_MITER_TO_SG); + + pad_left = pad_len; + while (pad_left) { + sg_miter_next(&miter); + + chunk_len = min(miter.length, pad_left); + memset(miter.addr, 0, chunk_len); + pad_left -= chunk_len; + } + + sg_miter_stop(&miter); } sg_pcopy_from_buffer(req->dst, sg_nents_for_len(req->dst, ctx->key_size), req_ctx->out_buf, req_ctx->child_req.dst_len, - sizeof(zeros)); + pad_len); } req->dst_len = ctx->key_size; -- cgit v1.2.3 From 0c4c78de0417ced1da92351a3013e631860ea576 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Thu, 17 Dec 2015 13:45:39 +0100 Subject: crypto: hash - add zero length message hash for shax and md5 Some crypto drivers cannot process empty data message and return a precalculated hash for md5/sha1/sha224/sha256. This patch add thoses precalculated hash in include/crypto. Signed-off-by: LABBE Corentin Signed-off-by: Herbert Xu --- crypto/md5.c | 6 ++++++ crypto/sha1_generic.c | 7 +++++++ crypto/sha256_generic.c | 16 ++++++++++++++++ include/crypto/md5.h | 2 ++ include/crypto/sha.h | 6 ++++++ 5 files changed, 37 insertions(+) (limited to 'crypto') diff --git a/crypto/md5.c b/crypto/md5.c index 33d17e9a8702..2355a7c25c45 100644 --- a/crypto/md5.c +++ b/crypto/md5.c @@ -24,6 +24,12 @@ #include #include +const u8 md5_zero_message_hash[MD5_DIGEST_SIZE] = { + 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, + 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e, +}; +EXPORT_SYMBOL_GPL(md5_zero_message_hash); + /* XXX: this stuff can be optimized */ static inline void le32_to_cpu_array(u32 *buf, unsigned int words) { diff --git a/crypto/sha1_generic.c b/crypto/sha1_generic.c index 39e3acc438d9..6877cbb9105f 100644 --- a/crypto/sha1_generic.c +++ b/crypto/sha1_generic.c @@ -26,6 +26,13 @@ #include #include +const u8 sha1_zero_message_hash[SHA1_DIGEST_SIZE] = { + 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, + 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, + 0xaf, 0xd8, 0x07, 0x09 +}; +EXPORT_SYMBOL_GPL(sha1_zero_message_hash); + static void sha1_generic_block_fn(struct sha1_state *sst, u8 const *src, int blocks) { diff --git a/crypto/sha256_generic.c b/crypto/sha256_generic.c index 78431163ed3c..8f9c47e1a96e 100644 --- a/crypto/sha256_generic.c +++ b/crypto/sha256_generic.c @@ -27,6 +27,22 @@ #include #include +const u8 sha224_zero_message_hash[SHA224_DIGEST_SIZE] = { + 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47, + 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2, + 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4, + 0x2f +}; +EXPORT_SYMBOL_GPL(sha224_zero_message_hash); + +const u8 sha256_zero_message_hash[SHA256_DIGEST_SIZE] = { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 +}; +EXPORT_SYMBOL_GPL(sha256_zero_message_hash); + static inline u32 Ch(u32 x, u32 y, u32 z) { return z ^ (x & (y ^ z)); diff --git a/include/crypto/md5.h b/include/crypto/md5.h index 146af825eedb..327deac963c0 100644 --- a/include/crypto/md5.h +++ b/include/crypto/md5.h @@ -13,6 +13,8 @@ #define MD5_H2 0x98badcfeUL #define MD5_H3 0x10325476UL +extern const u8 md5_zero_message_hash[MD5_DIGEST_SIZE]; + struct md5_state { u32 hash[MD5_HASH_WORDS]; u32 block[MD5_BLOCK_WORDS]; diff --git a/include/crypto/sha.h b/include/crypto/sha.h index dd7905a3c22e..c94d3eb1cefd 100644 --- a/include/crypto/sha.h +++ b/include/crypto/sha.h @@ -64,6 +64,12 @@ #define SHA512_H6 0x1f83d9abfb41bd6bULL #define SHA512_H7 0x5be0cd19137e2179ULL +extern const u8 sha1_zero_message_hash[SHA1_DIGEST_SIZE]; + +extern const u8 sha224_zero_message_hash[SHA224_DIGEST_SIZE]; + +extern const u8 sha256_zero_message_hash[SHA256_DIGEST_SIZE]; + struct sha1_state { u32 state[SHA1_DIGEST_SIZE / 4]; u64 count; -- cgit v1.2.3 From dd504589577d8e8e70f51f997ad487a4cb6c026f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 25 Dec 2015 15:40:05 +0800 Subject: crypto: algif_skcipher - Require setkey before accept(2) Some cipher implementations will crash if you try to use them without calling setkey first. This patch adds a check so that the accept(2) call will fail with -ENOKEY if setkey hasn't been done on the socket yet. Cc: stable@vger.kernel.org Reported-by: Dmitry Vyukov Signed-off-by: Herbert Xu Tested-by: Dmitry Vyukov --- crypto/algif_skcipher.c | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 5c756b30e79b..f4431bc1ce43 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -31,6 +31,11 @@ struct skcipher_sg_list { struct scatterlist sg[0]; }; +struct skcipher_tfm { + struct crypto_skcipher *skcipher; + bool has_key; +}; + struct skcipher_ctx { struct list_head tsgl; struct af_alg_sgl rsgl; @@ -750,17 +755,41 @@ static struct proto_ops algif_skcipher_ops = { static void *skcipher_bind(const char *name, u32 type, u32 mask) { - return crypto_alloc_skcipher(name, type, mask); + struct skcipher_tfm *tfm; + struct crypto_skcipher *skcipher; + + tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); + if (!tfm) + return ERR_PTR(-ENOMEM); + + skcipher = crypto_alloc_skcipher(name, type, mask); + if (IS_ERR(skcipher)) { + kfree(tfm); + return ERR_CAST(skcipher); + } + + tfm->skcipher = skcipher; + + return tfm; } static void skcipher_release(void *private) { - crypto_free_skcipher(private); + struct skcipher_tfm *tfm = private; + + crypto_free_skcipher(tfm->skcipher); + kfree(tfm); } static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen) { - return crypto_skcipher_setkey(private, key, keylen); + struct skcipher_tfm *tfm = private; + int err; + + err = crypto_skcipher_setkey(tfm->skcipher, key, keylen); + tfm->has_key = !err; + + return err; } static void skcipher_wait(struct sock *sk) @@ -792,20 +821,25 @@ static int skcipher_accept_parent(void *private, struct sock *sk) { struct skcipher_ctx *ctx; struct alg_sock *ask = alg_sk(sk); - unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(private); + struct skcipher_tfm *tfm = private; + struct crypto_skcipher *skcipher = tfm->skcipher; + unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(skcipher); + + if (!tfm->has_key) + return -ENOKEY; ctx = sock_kmalloc(sk, len, GFP_KERNEL); if (!ctx) return -ENOMEM; - ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(private), + ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(skcipher), GFP_KERNEL); if (!ctx->iv) { sock_kfree_s(sk, ctx, len); return -ENOMEM; } - memset(ctx->iv, 0, crypto_skcipher_ivsize(private)); + memset(ctx->iv, 0, crypto_skcipher_ivsize(skcipher)); INIT_LIST_HEAD(&ctx->tsgl); ctx->len = len; @@ -818,7 +852,7 @@ static int skcipher_accept_parent(void *private, struct sock *sk) ask->private = ctx; - skcipher_request_set_tfm(&ctx->req, private); + skcipher_request_set_tfm(&ctx->req, skcipher); skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG, af_alg_complete, &ctx->completion); -- cgit v1.2.3 From c840ac6af3f8713a71b4d2363419145760bd6044 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 30 Dec 2015 11:47:53 +0800 Subject: crypto: af_alg - Disallow bind/setkey/... after accept(2) Each af_alg parent socket obtained by socket(2) corresponds to a tfm object once bind(2) has succeeded. An accept(2) call on that parent socket creates a context which then uses the tfm object. Therefore as long as any child sockets created by accept(2) exist the parent socket must not be modified or freed. This patch guarantees this by using locks and a reference count on the parent socket. Any attempt to modify the parent socket will fail with EBUSY. Cc: stable@vger.kernel.org Reported-by: Dmitry Vyukov Signed-off-by: Herbert Xu --- crypto/af_alg.c | 35 ++++++++++++++++++++++++++++++++--- include/crypto/if_alg.h | 8 +++----- 2 files changed, 35 insertions(+), 8 deletions(-) (limited to 'crypto') diff --git a/crypto/af_alg.c b/crypto/af_alg.c index a8e7aa3e257b..7b5b5926c767 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -125,6 +125,23 @@ int af_alg_release(struct socket *sock) } EXPORT_SYMBOL_GPL(af_alg_release); +void af_alg_release_parent(struct sock *sk) +{ + struct alg_sock *ask = alg_sk(sk); + bool last; + + sk = ask->parent; + ask = alg_sk(sk); + + lock_sock(sk); + last = !--ask->refcnt; + release_sock(sk); + + if (last) + sock_put(sk); +} +EXPORT_SYMBOL_GPL(af_alg_release_parent); + static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { const u32 forbidden = CRYPTO_ALG_INTERNAL; @@ -133,6 +150,7 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sockaddr_alg *sa = (void *)uaddr; const struct af_alg_type *type; void *private; + int err; if (sock->state == SS_CONNECTED) return -EINVAL; @@ -160,16 +178,22 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) return PTR_ERR(private); } + err = -EBUSY; lock_sock(sk); + if (ask->refcnt) + goto unlock; swap(ask->type, type); swap(ask->private, private); + err = 0; + +unlock: release_sock(sk); alg_do_release(type, private); - return 0; + return err; } static int alg_setkey(struct sock *sk, char __user *ukey, @@ -202,11 +226,15 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); const struct af_alg_type *type; - int err = -ENOPROTOOPT; + int err = -EBUSY; lock_sock(sk); + if (ask->refcnt) + goto unlock; + type = ask->type; + err = -ENOPROTOOPT; if (level != SOL_ALG || !type) goto unlock; @@ -264,7 +292,8 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) sk2->sk_family = PF_ALG; - sock_hold(sk); + if (!ask->refcnt++) + sock_hold(sk); alg_sk(sk2)->parent = sk; alg_sk(sk2)->type = type; diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 018afb264ac2..589716f2ee8a 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -30,6 +30,8 @@ struct alg_sock { struct sock *parent; + unsigned int refcnt; + const struct af_alg_type *type; void *private; }; @@ -67,6 +69,7 @@ int af_alg_register_type(const struct af_alg_type *type); int af_alg_unregister_type(const struct af_alg_type *type); int af_alg_release(struct socket *sock); +void af_alg_release_parent(struct sock *sk); int af_alg_accept(struct sock *sk, struct socket *newsock); int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len); @@ -83,11 +86,6 @@ static inline struct alg_sock *alg_sk(struct sock *sk) return (struct alg_sock *)sk; } -static inline void af_alg_release_parent(struct sock *sk) -{ - sock_put(alg_sk(sk)->parent); -} - static inline void af_alg_init_completion(struct af_alg_completion *completion) { init_completion(&completion->completion); -- cgit v1.2.3 From a383292c86663bbc31ac62cc0c04fc77504636a6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 30 Dec 2015 20:24:17 +0800 Subject: crypto: af_alg - Fix socket double-free when accept fails When we fail an accept(2) call we will end up freeing the socket twice, once due to the direct sk_free call and once again through newsock. This patch fixes this by removing the sk_free call. Cc: stable@vger.kernel.org Reported-by: Dmitry Vyukov Signed-off-by: Herbert Xu --- crypto/af_alg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'crypto') diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 7b5b5926c767..eaf98e287d89 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -285,10 +285,8 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) security_sk_clone(sk, sk2); err = type->accept(ask->private, sk2); - if (err) { - sk_free(sk2); + if (err) goto unlock; - } sk2->sk_family = PF_ALG; -- cgit v1.2.3 From 37766586c965d63758ad542325a96d5384f4a8c9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 4 Jan 2016 13:35:18 +0900 Subject: crypto: af_alg - Add nokey compatibility path This patch adds a compatibility path to support old applications that do acept(2) before setkey. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/af_alg.c | 13 ++++++++++++- include/crypto/if_alg.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'crypto') diff --git a/crypto/af_alg.c b/crypto/af_alg.c index eaf98e287d89..6566d2eb0142 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -76,6 +76,8 @@ int af_alg_register_type(const struct af_alg_type *type) goto unlock; type->ops->owner = THIS_MODULE; + if (type->ops_nokey) + type->ops_nokey->owner = THIS_MODULE; node->type = type; list_add(&node->list, &alg_types); err = 0; @@ -267,6 +269,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) const struct af_alg_type *type; struct sock *sk2; int err; + bool nokey; lock_sock(sk); type = ask->type; @@ -285,12 +288,17 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) security_sk_clone(sk, sk2); err = type->accept(ask->private, sk2); + + nokey = err == -ENOKEY; + if (nokey && type->accept_nokey) + err = type->accept_nokey(ask->private, sk2); + if (err) goto unlock; sk2->sk_family = PF_ALG; - if (!ask->refcnt++) + if (nokey || !ask->refcnt++) sock_hold(sk); alg_sk(sk2)->parent = sk; alg_sk(sk2)->type = type; @@ -298,6 +306,9 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) newsock->ops = type->ops; newsock->state = SS_CONNECTED; + if (nokey) + newsock->ops = type->ops_nokey; + err = 0; unlock: diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 589716f2ee8a..df8284415c56 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -52,9 +52,11 @@ struct af_alg_type { void (*release)(void *private); int (*setkey)(void *private, const u8 *key, unsigned int keylen); int (*accept)(void *private, struct sock *sk); + int (*accept_nokey)(void *private, struct sock *sk); int (*setauthsize)(void *private, unsigned int authsize); struct proto_ops *ops; + struct proto_ops *ops_nokey; struct module *owner; char name[14]; }; -- cgit v1.2.3 From a0fa2d037129a9849918a92d91b79ed6c7bd2818 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 4 Jan 2016 13:36:12 +0900 Subject: crypto: algif_skcipher - Add nokey compatibility path This patch adds a compatibility path to support old applications that do acept(2) before setkey. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/algif_skcipher.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 5 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index f4431bc1ce43..110bab499e43 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -753,6 +753,99 @@ static struct proto_ops algif_skcipher_ops = { .poll = skcipher_poll, }; +static int skcipher_check_key(struct socket *sock) +{ + int err; + struct sock *psk; + struct alg_sock *pask; + struct skcipher_tfm *tfm; + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + + if (ask->refcnt) + return 0; + + psk = ask->parent; + pask = alg_sk(ask->parent); + tfm = pask->private; + + err = -ENOKEY; + lock_sock(psk); + if (!tfm->has_key) + goto unlock; + + if (!pask->refcnt++) + sock_hold(psk); + + ask->refcnt = 1; + sock_put(psk); + + err = 0; + +unlock: + release_sock(psk); + + return err; +} + +static int skcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg, + size_t size) +{ + int err; + + err = skcipher_check_key(sock); + if (err) + return err; + + return skcipher_sendmsg(sock, msg, size); +} + +static ssize_t skcipher_sendpage_nokey(struct socket *sock, struct page *page, + int offset, size_t size, int flags) +{ + int err; + + err = skcipher_check_key(sock); + if (err) + return err; + + return skcipher_sendpage(sock, page, offset, size, flags); +} + +static int skcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg, + size_t ignored, int flags) +{ + int err; + + err = skcipher_check_key(sock); + if (err) + return err; + + return skcipher_recvmsg(sock, msg, ignored, flags); +} + +static struct proto_ops algif_skcipher_ops_nokey = { + .family = PF_ALG, + + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .getname = sock_no_getname, + .ioctl = sock_no_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .getsockopt = sock_no_getsockopt, + .mmap = sock_no_mmap, + .bind = sock_no_bind, + .accept = sock_no_accept, + .setsockopt = sock_no_setsockopt, + + .release = af_alg_release, + .sendmsg = skcipher_sendmsg_nokey, + .sendpage = skcipher_sendpage_nokey, + .recvmsg = skcipher_recvmsg_nokey, + .poll = skcipher_poll, +}; + static void *skcipher_bind(const char *name, u32 type, u32 mask) { struct skcipher_tfm *tfm; @@ -802,7 +895,7 @@ static void skcipher_wait(struct sock *sk) msleep(100); } -static void skcipher_sock_destruct(struct sock *sk) +static void skcipher_sock_destruct_common(struct sock *sk) { struct alg_sock *ask = alg_sk(sk); struct skcipher_ctx *ctx = ask->private; @@ -814,10 +907,33 @@ static void skcipher_sock_destruct(struct sock *sk) skcipher_free_sgl(sk); sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); sock_kfree_s(sk, ctx, ctx->len); +} + +static void skcipher_sock_destruct(struct sock *sk) +{ + skcipher_sock_destruct_common(sk); af_alg_release_parent(sk); } -static int skcipher_accept_parent(void *private, struct sock *sk) +static void skcipher_release_parent_nokey(struct sock *sk) +{ + struct alg_sock *ask = alg_sk(sk); + + if (!ask->refcnt) { + sock_put(ask->parent); + return; + } + + af_alg_release_parent(sk); +} + +static void skcipher_sock_destruct_nokey(struct sock *sk) +{ + skcipher_sock_destruct_common(sk); + skcipher_release_parent_nokey(sk); +} + +static int skcipher_accept_parent_common(void *private, struct sock *sk) { struct skcipher_ctx *ctx; struct alg_sock *ask = alg_sk(sk); @@ -825,9 +941,6 @@ static int skcipher_accept_parent(void *private, struct sock *sk) struct crypto_skcipher *skcipher = tfm->skcipher; unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(skcipher); - if (!tfm->has_key) - return -ENOKEY; - ctx = sock_kmalloc(sk, len, GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -861,12 +974,38 @@ static int skcipher_accept_parent(void *private, struct sock *sk) return 0; } +static int skcipher_accept_parent(void *private, struct sock *sk) +{ + struct skcipher_tfm *tfm = private; + + if (!tfm->has_key) + return -ENOKEY; + + return skcipher_accept_parent_common(private, sk); +} + +static int skcipher_accept_parent_nokey(void *private, struct sock *sk) +{ + int err; + + err = skcipher_accept_parent_common(private, sk); + if (err) + goto out; + + sk->sk_destruct = skcipher_sock_destruct_nokey; + +out: + return err; +} + static const struct af_alg_type algif_type_skcipher = { .bind = skcipher_bind, .release = skcipher_release, .setkey = skcipher_setkey, .accept = skcipher_accept_parent, + .accept_nokey = skcipher_accept_parent_nokey, .ops = &algif_skcipher_ops, + .ops_nokey = &algif_skcipher_ops_nokey, .name = "skcipher", .owner = THIS_MODULE }; -- cgit v1.2.3 From a5596d6332787fd383b3b5427b41f94254430827 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 8 Jan 2016 21:28:26 +0800 Subject: crypto: hash - Add crypto_ahash_has_setkey This patch adds a way for ahash users to determine whether a key is required by a crypto_ahash transform. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/ahash.c | 5 ++++- crypto/shash.c | 4 +++- include/crypto/hash.h | 6 ++++++ 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'crypto') diff --git a/crypto/ahash.c b/crypto/ahash.c index 9c1dc8d6106a..d19b52324cf5 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -451,6 +451,7 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) struct ahash_alg *alg = crypto_ahash_alg(hash); hash->setkey = ahash_nosetkey; + hash->has_setkey = false; hash->export = ahash_no_export; hash->import = ahash_no_import; @@ -463,8 +464,10 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) hash->finup = alg->finup ?: ahash_def_finup; hash->digest = alg->digest; - if (alg->setkey) + if (alg->setkey) { hash->setkey = alg->setkey; + hash->has_setkey = true; + } if (alg->export) hash->export = alg->export; if (alg->import) diff --git a/crypto/shash.c b/crypto/shash.c index ecb1e3d39bf0..88a27de79848 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -355,8 +355,10 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm) crt->finup = shash_async_finup; crt->digest = shash_async_digest; - if (alg->setkey) + if (alg->setkey) { crt->setkey = shash_async_setkey; + crt->has_setkey = true; + } if (alg->export) crt->export = shash_async_export; if (alg->import) diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 3d69c93d50e8..6361892ea737 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -204,6 +204,7 @@ struct crypto_ahash { unsigned int keylen); unsigned int reqsize; + bool has_setkey; struct crypto_tfm base; }; @@ -375,6 +376,11 @@ static inline void *ahash_request_ctx(struct ahash_request *req) int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen); +static inline bool crypto_ahash_has_setkey(struct crypto_ahash *tfm) +{ + return tfm->has_setkey; +} + /** * crypto_ahash_finup() - update and finalize message digest * @req: reference to the ahash_request handle that holds all information -- cgit v1.2.3 From 6de62f15b581f920ade22d758f4c338311c2f0d4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 8 Jan 2016 21:31:04 +0800 Subject: crypto: algif_hash - Require setkey before accept(2) Hash implementations that require a key may crash if you use them without setting a key. This patch adds the necessary checks so that if you do attempt to use them without a key that we return -ENOKEY instead of proceeding. This patch also adds a compatibility path to support old applications that do acept(2) before setkey. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/algif_hash.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 193 insertions(+), 8 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index b4c24fe3dcfb..46637bed4db8 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -34,6 +34,11 @@ struct hash_ctx { struct ahash_request req; }; +struct algif_hash_tfm { + struct crypto_ahash *hash; + bool has_key; +}; + static int hash_sendmsg(struct socket *sock, struct msghdr *msg, size_t ignored) { @@ -235,22 +240,151 @@ static struct proto_ops algif_hash_ops = { .accept = hash_accept, }; +static int hash_check_key(struct socket *sock) +{ + int err; + struct sock *psk; + struct alg_sock *pask; + struct algif_hash_tfm *tfm; + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + + if (ask->refcnt) + return 0; + + psk = ask->parent; + pask = alg_sk(ask->parent); + tfm = pask->private; + + err = -ENOKEY; + lock_sock(psk); + if (!tfm->has_key) + goto unlock; + + if (!pask->refcnt++) + sock_hold(psk); + + ask->refcnt = 1; + sock_put(psk); + + err = 0; + +unlock: + release_sock(psk); + + return err; +} + +static int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg, + size_t size) +{ + int err; + + err = hash_check_key(sock); + if (err) + return err; + + return hash_sendmsg(sock, msg, size); +} + +static ssize_t hash_sendpage_nokey(struct socket *sock, struct page *page, + int offset, size_t size, int flags) +{ + int err; + + err = hash_check_key(sock); + if (err) + return err; + + return hash_sendpage(sock, page, offset, size, flags); +} + +static int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg, + size_t ignored, int flags) +{ + int err; + + err = hash_check_key(sock); + if (err) + return err; + + return hash_recvmsg(sock, msg, ignored, flags); +} + +static int hash_accept_nokey(struct socket *sock, struct socket *newsock, + int flags) +{ + int err; + + err = hash_check_key(sock); + if (err) + return err; + + return hash_accept(sock, newsock, flags); +} + +static struct proto_ops algif_hash_ops_nokey = { + .family = PF_ALG, + + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .getname = sock_no_getname, + .ioctl = sock_no_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .getsockopt = sock_no_getsockopt, + .mmap = sock_no_mmap, + .bind = sock_no_bind, + .setsockopt = sock_no_setsockopt, + .poll = sock_no_poll, + + .release = af_alg_release, + .sendmsg = hash_sendmsg_nokey, + .sendpage = hash_sendpage_nokey, + .recvmsg = hash_recvmsg_nokey, + .accept = hash_accept_nokey, +}; + static void *hash_bind(const char *name, u32 type, u32 mask) { - return crypto_alloc_ahash(name, type, mask); + struct algif_hash_tfm *tfm; + struct crypto_ahash *hash; + + tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); + if (!tfm) + return ERR_PTR(-ENOMEM); + + hash = crypto_alloc_ahash(name, type, mask); + if (IS_ERR(hash)) { + kfree(tfm); + return ERR_CAST(hash); + } + + tfm->hash = hash; + + return tfm; } static void hash_release(void *private) { - crypto_free_ahash(private); + struct algif_hash_tfm *tfm = private; + + crypto_free_ahash(tfm->hash); + kfree(tfm); } static int hash_setkey(void *private, const u8 *key, unsigned int keylen) { - return crypto_ahash_setkey(private, key, keylen); + struct algif_hash_tfm *tfm = private; + int err; + + err = crypto_ahash_setkey(tfm->hash, key, keylen); + tfm->has_key = !err; + + return err; } -static void hash_sock_destruct(struct sock *sk) +static void hash_sock_destruct_common(struct sock *sk) { struct alg_sock *ask = alg_sk(sk); struct hash_ctx *ctx = ask->private; @@ -258,15 +392,40 @@ static void hash_sock_destruct(struct sock *sk) sock_kzfree_s(sk, ctx->result, crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req))); sock_kfree_s(sk, ctx, ctx->len); +} + +static void hash_sock_destruct(struct sock *sk) +{ + hash_sock_destruct_common(sk); af_alg_release_parent(sk); } -static int hash_accept_parent(void *private, struct sock *sk) +static void hash_release_parent_nokey(struct sock *sk) +{ + struct alg_sock *ask = alg_sk(sk); + + if (!ask->refcnt) { + sock_put(ask->parent); + return; + } + + af_alg_release_parent(sk); +} + +static void hash_sock_destruct_nokey(struct sock *sk) +{ + hash_sock_destruct_common(sk); + hash_release_parent_nokey(sk); +} + +static int hash_accept_parent_common(void *private, struct sock *sk) { struct hash_ctx *ctx; struct alg_sock *ask = alg_sk(sk); - unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(private); - unsigned ds = crypto_ahash_digestsize(private); + struct algif_hash_tfm *tfm = private; + struct crypto_ahash *hash = tfm->hash; + unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(hash); + unsigned ds = crypto_ahash_digestsize(hash); ctx = sock_kmalloc(sk, len, GFP_KERNEL); if (!ctx) @@ -286,7 +445,7 @@ static int hash_accept_parent(void *private, struct sock *sk) ask->private = ctx; - ahash_request_set_tfm(&ctx->req, private); + ahash_request_set_tfm(&ctx->req, hash); ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG, af_alg_complete, &ctx->completion); @@ -295,12 +454,38 @@ static int hash_accept_parent(void *private, struct sock *sk) return 0; } +static int hash_accept_parent(void *private, struct sock *sk) +{ + struct algif_hash_tfm *tfm = private; + + if (!tfm->has_key && crypto_ahash_has_setkey(tfm->hash)) + return -ENOKEY; + + return hash_accept_parent_common(private, sk); +} + +static int hash_accept_parent_nokey(void *private, struct sock *sk) +{ + int err; + + err = hash_accept_parent_common(private, sk); + if (err) + goto out; + + sk->sk_destruct = hash_sock_destruct_nokey; + +out: + return err; +} + static const struct af_alg_type algif_type_hash = { .bind = hash_bind, .release = hash_release, .setkey = hash_setkey, .accept = hash_accept_parent, + .accept_nokey = hash_accept_parent_nokey, .ops = &algif_hash_ops, + .ops_nokey = &algif_hash_ops_nokey, .name = "hash", .owner = THIS_MODULE }; -- cgit v1.2.3 From a1383cd86a062fc798899ab20f0ec2116cce39cb Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 11 Jan 2016 21:26:50 +0800 Subject: crypto: skcipher - Add crypto_skcipher_has_setkey This patch adds a way for skcipher users to determine whether a key is required by a transform. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/skcipher.c | 2 ++ include/crypto/skcipher.h | 7 +++++++ 2 files changed, 9 insertions(+) (limited to 'crypto') diff --git a/crypto/skcipher.c b/crypto/skcipher.c index 7591928be7ca..d199c0b1751c 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -118,6 +118,7 @@ static int crypto_init_skcipher_ops_blkcipher(struct crypto_tfm *tfm) skcipher->decrypt = skcipher_decrypt_blkcipher; skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher); + skcipher->has_setkey = calg->cra_blkcipher.max_keysize; return 0; } @@ -210,6 +211,7 @@ static int crypto_init_skcipher_ops_ablkcipher(struct crypto_tfm *tfm) skcipher->ivsize = crypto_ablkcipher_ivsize(ablkcipher); skcipher->reqsize = crypto_ablkcipher_reqsize(ablkcipher) + sizeof(struct ablkcipher_request); + skcipher->has_setkey = calg->cra_ablkcipher.max_keysize; return 0; } diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h index d8dd41fb034f..fd8742a40ff3 100644 --- a/include/crypto/skcipher.h +++ b/include/crypto/skcipher.h @@ -61,6 +61,8 @@ struct crypto_skcipher { unsigned int ivsize; unsigned int reqsize; + bool has_setkey; + struct crypto_tfm base; }; @@ -305,6 +307,11 @@ static inline int crypto_skcipher_setkey(struct crypto_skcipher *tfm, return tfm->setkey(tfm, key, keylen); } +static inline bool crypto_skcipher_has_setkey(struct crypto_skcipher *tfm) +{ + return tfm->has_setkey; +} + /** * crypto_skcipher_reqtfm() - obtain cipher handle from request * @req: skcipher_request out of which the cipher handle is to be obtained -- cgit v1.2.3 From 6e8d8ecf438792ecf7a3207488fb4eebc4edb040 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 11 Jan 2016 21:29:41 +0800 Subject: crypto: algif_skcipher - Add key check exception for cipher_null This patch adds an exception to the key check so that cipher_null users may continue to use algif_skcipher without setting a key. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/algif_skcipher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crypto') diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 110bab499e43..4a5bdb69fd49 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -978,7 +978,7 @@ static int skcipher_accept_parent(void *private, struct sock *sk) { struct skcipher_tfm *tfm = private; - if (!tfm->has_key) + if (!tfm->has_key && crypto_skcipher_has_setkey(tfm->skcipher)) return -ENOKEY; return skcipher_accept_parent_common(private, sk); -- cgit v1.2.3 From 6a935170a980024dd29199e9dbb5c4da4767a1b9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 13 Jan 2016 14:59:03 +0800 Subject: crypto: af_alg - Allow af_af_alg_release_parent to be called on nokey path This patch allows af_alg_release_parent to be called even for nokey sockets. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/af_alg.c | 9 ++++++++- include/crypto/if_alg.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'crypto') diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 6566d2eb0142..e7cb8367771d 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -133,6 +133,12 @@ void af_alg_release_parent(struct sock *sk) bool last; sk = ask->parent; + + if (ask->nokey_refcnt && !ask->refcnt) { + sock_put(sk); + return; + } + ask = alg_sk(sk); lock_sock(sk); @@ -268,8 +274,8 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) struct alg_sock *ask = alg_sk(sk); const struct af_alg_type *type; struct sock *sk2; + unsigned int nokey; int err; - bool nokey; lock_sock(sk); type = ask->type; @@ -302,6 +308,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) sock_hold(sk); alg_sk(sk2)->parent = sk; alg_sk(sk2)->type = type; + alg_sk(sk2)->nokey_refcnt = nokey; newsock->ops = type->ops; newsock->state = SS_CONNECTED; diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index df8284415c56..a2bfd7843f18 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -31,6 +31,7 @@ struct alg_sock { struct sock *parent; unsigned int refcnt; + unsigned int nokey_refcnt; const struct af_alg_type *type; void *private; -- cgit v1.2.3 From f1d84af1835846a5a2b827382c5848faf2bb0e75 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 13 Jan 2016 15:00:36 +0800 Subject: crypto: algif_hash - Remove custom release parent function This patch removes the custom release parent function as the generic af_alg_release_parent now works for nokey sockets too. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/algif_hash.c | 43 +++---------------------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index 46637bed4db8..3653ab60ec79 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -384,7 +384,7 @@ static int hash_setkey(void *private, const u8 *key, unsigned int keylen) return err; } -static void hash_sock_destruct_common(struct sock *sk) +static void hash_sock_destruct(struct sock *sk) { struct alg_sock *ask = alg_sk(sk); struct hash_ctx *ctx = ask->private; @@ -392,33 +392,10 @@ static void hash_sock_destruct_common(struct sock *sk) sock_kzfree_s(sk, ctx->result, crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req))); sock_kfree_s(sk, ctx, ctx->len); -} - -static void hash_sock_destruct(struct sock *sk) -{ - hash_sock_destruct_common(sk); - af_alg_release_parent(sk); -} - -static void hash_release_parent_nokey(struct sock *sk) -{ - struct alg_sock *ask = alg_sk(sk); - - if (!ask->refcnt) { - sock_put(ask->parent); - return; - } - af_alg_release_parent(sk); } -static void hash_sock_destruct_nokey(struct sock *sk) -{ - hash_sock_destruct_common(sk); - hash_release_parent_nokey(sk); -} - -static int hash_accept_parent_common(void *private, struct sock *sk) +static int hash_accept_parent_nokey(void *private, struct sock *sk) { struct hash_ctx *ctx; struct alg_sock *ask = alg_sk(sk); @@ -461,21 +438,7 @@ static int hash_accept_parent(void *private, struct sock *sk) if (!tfm->has_key && crypto_ahash_has_setkey(tfm->hash)) return -ENOKEY; - return hash_accept_parent_common(private, sk); -} - -static int hash_accept_parent_nokey(void *private, struct sock *sk) -{ - int err; - - err = hash_accept_parent_common(private, sk); - if (err) - goto out; - - sk->sk_destruct = hash_sock_destruct_nokey; - -out: - return err; + return hash_accept_parent_nokey(private, sk); } static const struct af_alg_type algif_type_hash = { -- cgit v1.2.3 From d7b65aee1e7b4c87922b0232eaba56a8a143a4a0 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 13 Jan 2016 15:01:06 +0800 Subject: crypto: algif_skcipher - Remove custom release parent function This patch removes the custom release parent function as the generic af_alg_release_parent now works for nokey sockets too. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/algif_skcipher.c | 43 +++---------------------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 4a5bdb69fd49..1f99d2d47715 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -895,7 +895,7 @@ static void skcipher_wait(struct sock *sk) msleep(100); } -static void skcipher_sock_destruct_common(struct sock *sk) +static void skcipher_sock_destruct(struct sock *sk) { struct alg_sock *ask = alg_sk(sk); struct skcipher_ctx *ctx = ask->private; @@ -907,33 +907,10 @@ static void skcipher_sock_destruct_common(struct sock *sk) skcipher_free_sgl(sk); sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); sock_kfree_s(sk, ctx, ctx->len); -} - -static void skcipher_sock_destruct(struct sock *sk) -{ - skcipher_sock_destruct_common(sk); - af_alg_release_parent(sk); -} - -static void skcipher_release_parent_nokey(struct sock *sk) -{ - struct alg_sock *ask = alg_sk(sk); - - if (!ask->refcnt) { - sock_put(ask->parent); - return; - } - af_alg_release_parent(sk); } -static void skcipher_sock_destruct_nokey(struct sock *sk) -{ - skcipher_sock_destruct_common(sk); - skcipher_release_parent_nokey(sk); -} - -static int skcipher_accept_parent_common(void *private, struct sock *sk) +static int skcipher_accept_parent_nokey(void *private, struct sock *sk) { struct skcipher_ctx *ctx; struct alg_sock *ask = alg_sk(sk); @@ -981,21 +958,7 @@ static int skcipher_accept_parent(void *private, struct sock *sk) if (!tfm->has_key && crypto_skcipher_has_setkey(tfm->skcipher)) return -ENOKEY; - return skcipher_accept_parent_common(private, sk); -} - -static int skcipher_accept_parent_nokey(void *private, struct sock *sk) -{ - int err; - - err = skcipher_accept_parent_common(private, sk); - if (err) - goto out; - - sk->sk_destruct = skcipher_sock_destruct_nokey; - -out: - return err; + return skcipher_accept_parent_nokey(private, sk); } static const struct af_alg_type algif_type_skcipher = { -- cgit v1.2.3 From a6a48c565f6f112c6983e2a02b1602189ed6e26e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 13 Jan 2016 15:03:32 +0800 Subject: crypto: af_alg - Forbid bind(2) when nokey child sockets are present This patch forbids the calling of bind(2) when there are child sockets created by accept(2) in existence, even if they are created on the nokey path. This is needed as those child sockets have references to the tfm object which bind(2) will destroy. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/af_alg.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'crypto') diff --git a/crypto/af_alg.c b/crypto/af_alg.c index e7cb8367771d..f5e18c2a4852 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -130,19 +130,16 @@ EXPORT_SYMBOL_GPL(af_alg_release); void af_alg_release_parent(struct sock *sk) { struct alg_sock *ask = alg_sk(sk); - bool last; + unsigned int nokey = ask->nokey_refcnt; + bool last = nokey && !ask->refcnt; sk = ask->parent; - - if (ask->nokey_refcnt && !ask->refcnt) { - sock_put(sk); - return; - } - ask = alg_sk(sk); lock_sock(sk); - last = !--ask->refcnt; + ask->nokey_refcnt -= nokey; + if (!last) + last = !--ask->refcnt; release_sock(sk); if (last) @@ -188,7 +185,7 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) err = -EBUSY; lock_sock(sk); - if (ask->refcnt) + if (ask->refcnt | ask->nokey_refcnt) goto unlock; swap(ask->type, type); @@ -306,6 +303,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock) if (nokey || !ask->refcnt++) sock_hold(sk); + ask->nokey_refcnt += nokey; alg_sk(sk2)->parent = sk; alg_sk(sk2)->type = type; alg_sk(sk2)->nokey_refcnt = nokey; -- cgit v1.2.3 From ad46d7e33219218605ea619e32553daf4f346b9f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 15 Jan 2016 22:01:08 +0800 Subject: crypto: algif_hash - Fix race condition in hash_check_key We need to lock the child socket in hash_check_key as otherwise two simultaneous calls can cause the parent socket to be freed. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/algif_hash.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index 3653ab60ec79..608a7562839d 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -242,22 +242,23 @@ static struct proto_ops algif_hash_ops = { static int hash_check_key(struct socket *sock) { - int err; + int err = 0; struct sock *psk; struct alg_sock *pask; struct algif_hash_tfm *tfm; struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); + lock_sock(sk); if (ask->refcnt) - return 0; + goto unlock_child; psk = ask->parent; pask = alg_sk(ask->parent); tfm = pask->private; err = -ENOKEY; - lock_sock(psk); + lock_sock_nested(psk, SINGLE_DEPTH_NESTING); if (!tfm->has_key) goto unlock; @@ -271,6 +272,8 @@ static int hash_check_key(struct socket *sock) unlock: release_sock(psk); +unlock_child: + release_sock(sk); return err; } -- cgit v1.2.3 From 1822793a523e5d5730b19cc21160ff1717421bc8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 15 Jan 2016 22:02:20 +0800 Subject: crypto: algif_skcipher - Fix race condition in skcipher_check_key We need to lock the child socket in skcipher_check_key as otherwise two simultaneous calls can cause the parent socket to be freed. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/algif_skcipher.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 1f99d2d47715..dfff8b0b56df 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -755,22 +755,23 @@ static struct proto_ops algif_skcipher_ops = { static int skcipher_check_key(struct socket *sock) { - int err; + int err = 0; struct sock *psk; struct alg_sock *pask; struct skcipher_tfm *tfm; struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); + lock_sock(sk); if (ask->refcnt) - return 0; + goto unlock_child; psk = ask->parent; pask = alg_sk(ask->parent); tfm = pask->private; err = -ENOKEY; - lock_sock(psk); + lock_sock_nested(psk, SINGLE_DEPTH_NESTING); if (!tfm->has_key) goto unlock; @@ -784,6 +785,8 @@ static int skcipher_check_key(struct socket *sock) unlock: release_sock(psk); +unlock_child: + release_sock(sk); return err; } -- cgit v1.2.3 From 4f0414e54e4d1893c6f08260693f8ef84c929293 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 18 Jan 2016 18:46:10 +0800 Subject: crypto: algif_skcipher - Load TX SG list after waiting We need to load the TX SG list in sendmsg(2) after waiting for incoming data, not before. Cc: stable@vger.kernel.org Reported-by: Dmitry Vyukov Signed-off-by: Herbert Xu Tested-by: Dmitry Vyukov --- crypto/algif_skcipher.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index dfff8b0b56df..df86fb47c3ae 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -647,13 +647,6 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg, lock_sock(sk); while (msg_data_left(msg)) { - sgl = list_first_entry(&ctx->tsgl, - struct skcipher_sg_list, list); - sg = sgl->sg; - - while (!sg->length) - sg++; - if (!ctx->used) { err = skcipher_wait_for_data(sk, flags); if (err) @@ -674,6 +667,13 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg, if (!used) goto free; + sgl = list_first_entry(&ctx->tsgl, + struct skcipher_sg_list, list); + sg = sgl->sg; + + while (!sg->length) + sg++; + skcipher_request_set_crypt(&ctx->req, sg, ctx->rsgl.sg, used, ctx->iv); -- cgit v1.2.3 From fd7f6727102a1ccf6b4c1dfcc631f9b546526b26 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 18 Jan 2016 17:06:05 +0100 Subject: crypto: crc32c - Fix crc32c soft dependency I don't think it makes sense for a module to have a soft dependency on itself. This seems quite cyclic by nature and I can't see what purpose it could serve. OTOH libcrc32c calls crypto_alloc_shash("crc32c", 0, 0) so it pretty much assumes that some incarnation of the "crc32c" hash algorithm has been loaded. Therefore it makes sense to have the soft dependency there (as crc-t10dif does.) Cc: stable@vger.kernel.org Cc: Tim Chen Cc: "David S. Miller" Signed-off-by: Jean Delvare Signed-off-by: Herbert Xu --- crypto/crc32c_generic.c | 1 - lib/libcrc32c.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'crypto') diff --git a/crypto/crc32c_generic.c b/crypto/crc32c_generic.c index 06f1b60f02b2..4c0a0e271876 100644 --- a/crypto/crc32c_generic.c +++ b/crypto/crc32c_generic.c @@ -172,4 +172,3 @@ MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CRYPTO("crc32c"); MODULE_ALIAS_CRYPTO("crc32c-generic"); -MODULE_SOFTDEP("pre: crc32c"); diff --git a/lib/libcrc32c.c b/lib/libcrc32c.c index 6a08ce7d6adc..acf9da449f81 100644 --- a/lib/libcrc32c.c +++ b/lib/libcrc32c.c @@ -74,3 +74,4 @@ module_exit(libcrc32c_mod_fini); MODULE_AUTHOR("Clay Haapala "); MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations"); MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: crc32c"); -- cgit v1.2.3 From 202736d99b7f29279db9da61587f11a08a04a9c6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 19 Jan 2016 21:23:57 +0800 Subject: crypto: algif_skcipher - sendmsg SG marking is off by one We mark the end of the SG list in sendmsg and sendpage and unmark it on the next send call. Unfortunately the unmarking in sendmsg is off-by-one, leading to an SG list that is too short. Fixes: 0f477b655a52 ("crypto: algif - Mark sgl end at the end of data") Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/algif_skcipher.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'crypto') diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index df86fb47c3ae..a81c10faf9c4 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -392,7 +392,8 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list); sg = sgl->sg; - sg_unmark_end(sg + sgl->cur); + if (sgl->cur) + sg_unmark_end(sg + sgl->cur - 1); do { i = sgl->cur; plen = min_t(size_t, len, PAGE_SIZE); -- cgit v1.2.3 From 7ee7014d0eb6bcac679c0bd5fe9ce65bc4325648 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Mon, 18 Jan 2016 10:49:58 -0500 Subject: PKCS#7: Don't require SpcSpOpusInfo in Authenticode pkcs7 signatures Dave Young reported: > Hi, > > I saw the warning "Missing required AuthAttr" when testing kexec, > known issue? Idea about how to fix it? > > The kernel is latest linus tree plus sevral patches from Toshi to > cleanup io resource structure. > > in function pkcs7_sig_note_set_of_authattrs(): > if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) || > !test_bit(sinfo_has_message_digest, &sinfo->aa_set) || > (ctx->msg->data_type == OID_msIndirectData && > !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) { > pr_warn("Missing required AuthAttr\n"); > return -EBADMSG; > } > > The third condition below is true: > (ctx->msg->data_type == OID_msIndirectData && > !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) > > I signed the kernel with redhat test key like below: > pesign -c 'Red Hat Test Certificate' -i arch/x86/boot/bzImage -o /boot/vmlinuz-4.4.0-rc8+ -s --force And right he is! The Authenticode specification is a paragon amongst technical documents, and has this pearl of wisdom to offer: --------------------------------- Authenticode-Specific SignerInfo UnauthenticatedAttributes Structures The following Authenticode-specific data structures are present in SignerInfo authenticated attributes. SpcSpOpusInfo SpcSpOpusInfo is identified by SPC_SP_OPUS_INFO_OBJID (1.3.6.1.4.1.311.2.1.12) and is defined as follows: SpcSpOpusInfo ::= SEQUENCE { programName [0] EXPLICIT SpcString OPTIONAL, moreInfo [1] EXPLICIT SpcLink OPTIONAL, } --#public-- SpcSpOpusInfo has two fields: programName This field contains the program description: If publisher chooses not to specify a description, the SpcString structure contains a zero-length program name. If the publisher chooses to specify a description, the SpcString structure contains a Unicode string. moreInfo This field is set to an SPCLink structure that contains a URL for a Web site with more information about the signer. The URL is an ASCII string. --------------------------------- Which is to say that this is an optional *unauthenticated* field which may be present in the Authenticated Attribute list. This is not how pkcs7 is supposed to work, so when David implemented this, he didn't appreciate the subtlety the original spec author was working with, and missed the part of the sublime prose that says this Authenticated Attribute is an Unauthenticated Attribute. As a result, the code in question simply takes as given that the Authenticated Attributes should be authenticated. But this one should not, individually. Because it says it's not authenticated. It still has to hash right so the TBS digest is correct. So it is both authenticated and unauthenticated, all at once. Truly, a wonder of technical accomplishment. Additionally, pesign's implementation has always attempted to be compatible with the signatures emitted from contemporary versions of Microsoft's signtool.exe. During the initial implementation, Microsoft signatures always produced the same values for SpcSpOpusInfo - {U"Microsoft Windows", "http://www.microsoft.com"} - without regard to who the signer was. Sometime between Windows 8 and Windows 8.1 they stopped including the field in their signatures altogether, and as such pesign stopped producing them in commits c0c4da6 and d79cb0c, sometime around June of 2012. The theory here is that anything that breaks with pesign signatures would also be breaking with signtool.exe sigs as well, and that'll be a more noticed problem for firmwares parsing it, so it'll get fixed. The fact that we've done exactly this bug in Linux code is first class, grade A irony. So anyway, we should not be checking this field for presence or any particular value: if the field exists, it should be at the right place, but aside from that, as long as the hash matches the field is good. Signed-off-by: Peter Jones Tested-by: Dave Young Signed-off-by: Herbert Xu --- crypto/asymmetric_keys/pkcs7_parser.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'crypto') diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 758acabf2d81..8f3056cd0399 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c @@ -547,9 +547,7 @@ int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, struct pkcs7_signed_info *sinfo = ctx->sinfo; if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) || - !test_bit(sinfo_has_message_digest, &sinfo->aa_set) || - (ctx->msg->data_type == OID_msIndirectData && - !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) { + !test_bit(sinfo_has_message_digest, &sinfo->aa_set)) { pr_warn("Missing required AuthAttr\n"); return -EBADMSG; } -- cgit v1.2.3 From 578c60fbeb913e0f2aa49f37a04d475b615c8a8d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 25 Jan 2016 17:51:21 +0100 Subject: crypto: ghash,poly1305 - select CRYPTO_HASH where needed The ghash and poly1305 hash implementations can be enabled when CONFIG_CRYPTO_HASH is turned off, causing a link error: crypto/built-in.o: In function `ghash_mod_init': (.init.text+0xd0): undefined reference to `crypto_register_shash' crypto/built-in.o: In function `ghash_mod_exit': (.exit.text+0xb4): undefined reference to `crypto_unregister_shash' crypto/built-in.o: In function `poly1305_mod_init': (.init.text+0xb4): undefined reference to `crypto_register_shash' crypto/built-in.o: In function `poly1305_mod_exit': (.exit.text+0x98): undefined reference to `crypto_unregister_shash' This adds an explicit 'select', like all other hashes have it. Signed-off-by: Arnd Bergmann Signed-off-by: Herbert Xu --- crypto/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'crypto') diff --git a/crypto/Kconfig b/crypto/Kconfig index 7240821137fd..3be07ad1d80d 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -472,11 +472,13 @@ config CRYPTO_CRCT10DIF_PCLMUL config CRYPTO_GHASH tristate "GHASH digest algorithm" select CRYPTO_GF128MUL + select CRYPTO_HASH help GHASH is message digest algorithm for GCM (Galois/Counter Mode). config CRYPTO_POLY1305 tristate "Poly1305 authenticator algorithm" + select CRYPTO_HASH help Poly1305 authenticator algorithm, RFC7539. -- cgit v1.2.3 From 00420a65fa2beb3206090ead86942484df2275f3 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 27 Jan 2016 00:16:37 +0800 Subject: crypto: shash - Fix has_key setting The has_key logic is wrong for shash algorithms as they always have a setkey function. So we should instead be testing against shash_no_setkey. Fixes: a5596d633278 ("crypto: hash - Add crypto_ahash_has_setkey") Cc: stable@vger.kernel.org Reported-by: Stephan Mueller Signed-off-by: Herbert Xu Tested-by: Stephan Mueller --- crypto/shash.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'crypto') diff --git a/crypto/shash.c b/crypto/shash.c index 88a27de79848..359754591653 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -354,11 +354,10 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm) crt->final = shash_async_final; crt->finup = shash_async_finup; crt->digest = shash_async_digest; + crt->setkey = shash_async_setkey; + + crt->has_setkey = alg->setkey != shash_no_setkey; - if (alg->setkey) { - crt->setkey = shash_async_setkey; - crt->has_setkey = true; - } if (alg->export) crt->export = shash_async_export; if (alg->import) -- cgit v1.2.3 From fe09786178f9df713a4b2dd6b93c0a722346bf5e Mon Sep 17 00:00:00 2001 From: "Wang, Rui Y" Date: Wed, 27 Jan 2016 17:08:37 +0800 Subject: crypto: algif_hash - wait for crypto_ahash_init() to complete hash_sendmsg/sendpage() need to wait for the completion of crypto_ahash_init() otherwise it can cause panic. Cc: stable@vger.kernel.org Signed-off-by: Rui Wang Signed-off-by: Herbert Xu --- crypto/algif_hash.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'crypto') diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index 608a7562839d..68a5ceaa04c8 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -54,7 +54,8 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg, lock_sock(sk); if (!ctx->more) { - err = crypto_ahash_init(&ctx->req); + err = af_alg_wait_for_completion(crypto_ahash_init(&ctx->req), + &ctx->completion); if (err) goto unlock; } @@ -125,6 +126,7 @@ static ssize_t hash_sendpage(struct socket *sock, struct page *page, } else { if (!ctx->more) { err = crypto_ahash_init(&ctx->req); + err = af_alg_wait_for_completion(err, &ctx->completion); if (err) goto unlock; } -- cgit v1.2.3 From 63e41ebc6630f39422d87f8a4bade1e793f37a01 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Mon, 1 Feb 2016 14:27:30 +0100 Subject: crypto: user - lock crypto_alg_list on alg dump We miss to take the crypto_alg_sem semaphore when traversing the crypto_alg_list for CRYPTO_MSG_GETALG dumps. This allows a race with crypto_unregister_alg() removing algorithms from the list while we're still traversing it, thereby leading to a use-after-free as show below: [ 3482.071639] general protection fault: 0000 [#1] SMP [ 3482.075639] Modules linked in: aes_x86_64 glue_helper lrw ablk_helper cryptd gf128mul ipv6 pcspkr serio_raw virtio_net microcode virtio_pci virtio_ring virtio sr_mod cdrom [last unloaded: aesni_intel] [ 3482.075639] CPU: 1 PID: 11065 Comm: crconf Not tainted 4.3.4-grsec+ #126 [ 3482.075639] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.7.5-20140531_083030-gandalf 04/01/2014 [ 3482.075639] task: ffff88001cd41a40 ti: ffff88001cd422c8 task.ti: ffff88001cd422c8 [ 3482.075639] RIP: 0010:[] [] strncpy+0x13/0x30 [ 3482.075639] RSP: 0018:ffff88001f713b60 EFLAGS: 00010202 [ 3482.075639] RAX: ffff88001f6c4430 RBX: ffff88001f6c43a0 RCX: ffff88001f6c4430 [ 3482.075639] RDX: 0000000000000040 RSI: fefefefefefeff16 RDI: ffff88001f6c4430 [ 3482.075639] RBP: ffff88001f713b60 R08: ffff88001f6c4470 R09: ffff88001f6c4480 [ 3482.075639] R10: 0000000000000002 R11: 0000000000000246 R12: ffff88001ce2aa28 [ 3482.075639] R13: ffff880000093700 R14: ffff88001f5e4bf8 R15: 0000000000003b20 [ 3482.075639] FS: 0000033826fa2700(0000) GS:ffff88001e900000(0000) knlGS:0000000000000000 [ 3482.075639] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 3482.075639] CR2: ffffffffff600400 CR3: 00000000139ec000 CR4: 00000000001606f0 [ 3482.075639] Stack: [ 3482.075639] ffff88001f713bd8 ffffffff936ccd00 ffff88001e5c4200 ffff880000093700 [ 3482.075639] ffff88001f713bd0 ffffffff938ef4bf 0000000000000000 0000000000003b20 [ 3482.075639] ffff88001f5e4bf8 ffff88001f5e4848 0000000000000000 0000000000003b20 [ 3482.075639] Call Trace: [ 3482.075639] [] crypto_report_alg+0xc0/0x3e0 [ 3482.075639] [] ? __alloc_skb+0x16f/0x300 [ 3482.075639] [] crypto_dump_report+0x6a/0x90 [ 3482.075639] [] netlink_dump+0x147/0x2e0 [ 3482.075639] [] __netlink_dump_start+0x159/0x190 [ 3482.075639] [] crypto_user_rcv_msg+0xc3/0x130 [ 3482.075639] [] ? crypto_report_alg+0x3e0/0x3e0 [ 3482.075639] [] ? alg_test_crc32c+0x120/0x120 [ 3482.075639] [] ? __netlink_lookup+0xd5/0x120 [ 3482.075639] [] ? crypto_add_alg+0x1d0/0x1d0 [ 3482.075639] [] netlink_rcv_skb+0xe1/0x130 [ 3482.075639] [] crypto_netlink_rcv+0x28/0x40 [ 3482.075639] [] netlink_unicast+0x108/0x180 [ 3482.075639] [] netlink_sendmsg+0x541/0x770 [ 3482.075639] [] sock_sendmsg+0x21/0x40 [ 3482.075639] [] SyS_sendto+0xf3/0x130 [ 3482.075639] [] ? bad_area_nosemaphore+0x13/0x20 [ 3482.075639] [] ? __do_page_fault+0x80/0x3a0 [ 3482.075639] [] entry_SYSCALL_64_fastpath+0x12/0x6e [ 3482.075639] Code: 88 4a ff 75 ed 5d 48 0f ba 2c 24 3f c3 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 85 d2 48 89 f8 48 89 f9 4c 8d 04 17 48 89 e5 74 15 <0f> b6 16 80 fa 01 88 11 48 83 de ff 48 83 c1 01 4c 39 c1 75 eb [ 3482.075639] RIP [] strncpy+0x13/0x30 To trigger the race run the following loops simultaneously for a while: $ while : ; do modprobe aesni-intel; rmmod aesni-intel; done $ while : ; do crconf show all > /dev/null; done Fix the race by taking the crypto_alg_sem read lock, thereby preventing crypto_unregister_alg() from modifying the algorithm list during the dump. This bug has been detected by the PaX memory sanitize feature. Cc: stable@vger.kernel.org Signed-off-by: Mathias Krause Cc: Steffen Klassert Cc: PaX Team Signed-off-by: Herbert Xu --- crypto/crypto_user.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'crypto') diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index 237f3795cfaa..43fe85f20d57 100644 --- a/crypto/crypto_user.c +++ b/crypto/crypto_user.c @@ -499,6 +499,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (link->dump == NULL) return -EINVAL; + down_read(&crypto_alg_sem); list_for_each_entry(alg, &crypto_alg_list, cra_list) dump_alloc += CRYPTO_REPORT_MAXSIZE; @@ -508,8 +509,11 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) .done = link->done, .min_dump_alloc = dump_alloc, }; - return netlink_dump_start(crypto_nlsk, skb, nlh, &c); + err = netlink_dump_start(crypto_nlsk, skb, nlh, &c); } + up_read(&crypto_alg_sem); + + return err; } err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX, -- cgit v1.2.3 From ec69bbfb9902c32a5c1492f2b1b8ad032a66d724 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 3 Feb 2016 21:39:24 +0800 Subject: crypto: algif_skcipher - Do not assume that req is unchanged The async path in algif_skcipher assumes that the crypto completion function will be called with the original request. This is not necessarily the case. In fact there is no need for this anyway since we already embed information into the request with struct skcipher_async_req. This patch adds a pointer to that struct and then passes it as the data to the callback function. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu Tested-by: Tadeusz Struk --- crypto/algif_skcipher.c | 60 +++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 38c1aa89d3a0..ec07a864b9c5 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -65,18 +65,10 @@ struct skcipher_async_req { struct skcipher_async_rsgl first_sgl; struct list_head list; struct scatterlist *tsg; - char iv[]; + atomic_t *inflight; + struct skcipher_request req; }; -#define GET_SREQ(areq, ctx) (struct skcipher_async_req *)((char *)areq + \ - crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req))) - -#define GET_REQ_SIZE(ctx) \ - crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req)) - -#define GET_IV_SIZE(ctx) \ - crypto_skcipher_ivsize(crypto_skcipher_reqtfm(&ctx->req)) - #define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \ sizeof(struct scatterlist) - 1) @@ -102,15 +94,12 @@ static void skcipher_free_async_sgls(struct skcipher_async_req *sreq) static void skcipher_async_cb(struct crypto_async_request *req, int err) { - struct sock *sk = req->data; - struct alg_sock *ask = alg_sk(sk); - struct skcipher_ctx *ctx = ask->private; - struct skcipher_async_req *sreq = GET_SREQ(req, ctx); + struct skcipher_async_req *sreq = req->data; struct kiocb *iocb = sreq->iocb; - atomic_dec(&ctx->inflight); + atomic_dec(sreq->inflight); skcipher_free_async_sgls(sreq); - kfree(req); + kzfree(sreq); iocb->ki_complete(iocb, err, err); } @@ -509,37 +498,42 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, { struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); + struct sock *psk = ask->parent; + struct alg_sock *pask = alg_sk(psk); struct skcipher_ctx *ctx = ask->private; + struct skcipher_tfm *skc = pask->private; + struct crypto_skcipher *tfm = skc->skcipher; struct skcipher_sg_list *sgl; struct scatterlist *sg; struct skcipher_async_req *sreq; struct skcipher_request *req; struct skcipher_async_rsgl *last_rsgl = NULL; unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx); - unsigned int reqlen = sizeof(struct skcipher_async_req) + - GET_REQ_SIZE(ctx) + GET_IV_SIZE(ctx); + unsigned int reqsize = crypto_skcipher_reqsize(tfm); + unsigned int ivsize = crypto_skcipher_ivsize(tfm); int err = -ENOMEM; bool mark = false; + char *iv; - lock_sock(sk); - req = kmalloc(reqlen, GFP_KERNEL); - if (unlikely(!req)) - goto unlock; + sreq = kzalloc(sizeof(*sreq) + reqsize + ivsize, GFP_KERNEL); + if (unlikely(!sreq)) + goto out; - sreq = GET_SREQ(req, ctx); + req = &sreq->req; + iv = (char *)(req + 1) + reqsize; sreq->iocb = msg->msg_iocb; - memset(&sreq->first_sgl, '\0', sizeof(struct skcipher_async_rsgl)); INIT_LIST_HEAD(&sreq->list); + sreq->inflight = &ctx->inflight; + + lock_sock(sk); sreq->tsg = kcalloc(tx_nents, sizeof(*sg), GFP_KERNEL); - if (unlikely(!sreq->tsg)) { - kfree(req); + if (unlikely(!sreq->tsg)) goto unlock; - } sg_init_table(sreq->tsg, tx_nents); - memcpy(sreq->iv, ctx->iv, GET_IV_SIZE(ctx)); - skcipher_request_set_tfm(req, crypto_skcipher_reqtfm(&ctx->req)); + memcpy(iv, ctx->iv, ivsize); + skcipher_request_set_tfm(req, tfm); skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - skcipher_async_cb, sk); + skcipher_async_cb, sreq); while (iov_iter_count(&msg->msg_iter)) { struct skcipher_async_rsgl *rsgl; @@ -615,20 +609,22 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, sg_mark_end(sreq->tsg + txbufs - 1); skcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg, - len, sreq->iv); + len, iv); err = ctx->enc ? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req); if (err == -EINPROGRESS) { atomic_inc(&ctx->inflight); err = -EIOCBQUEUED; + sreq = NULL; goto unlock; } free: skcipher_free_async_sgls(sreq); - kfree(req); unlock: skcipher_wmem_wakeup(sk); release_sock(sk); + kzfree(sreq); +out: return err; } -- cgit v1.2.3 From 6454c2b83f719057069777132b13949e4c6b6350 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 3 Feb 2016 21:39:26 +0800 Subject: crypto: algif_skcipher - Do not dereference ctx without socket lock Any access to non-constant bits of the private context must be done under the socket lock, in particular, this includes ctx->req. This patch moves such accesses under the lock, and fetches the tfm from the parent socket which is guaranteed to be constant, rather than from ctx->req. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/algif_skcipher.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index ec07a864b9c5..ef84353e0f24 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -295,8 +295,11 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, { struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); + struct sock *psk = ask->parent; + struct alg_sock *pask = alg_sk(psk); struct skcipher_ctx *ctx = ask->private; - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req); + struct skcipher_tfm *skc = pask->private; + struct crypto_skcipher *tfm = skc->skcipher; unsigned ivsize = crypto_skcipher_ivsize(tfm); struct skcipher_sg_list *sgl; struct af_alg_control con = {}; @@ -508,7 +511,7 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, struct skcipher_async_req *sreq; struct skcipher_request *req; struct skcipher_async_rsgl *last_rsgl = NULL; - unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx); + unsigned int txbufs = 0, len = 0, tx_nents; unsigned int reqsize = crypto_skcipher_reqsize(tfm); unsigned int ivsize = crypto_skcipher_ivsize(tfm); int err = -ENOMEM; @@ -526,6 +529,7 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, sreq->inflight = &ctx->inflight; lock_sock(sk); + tx_nents = skcipher_all_sg_nents(ctx); sreq->tsg = kcalloc(tx_nents, sizeof(*sg), GFP_KERNEL); if (unlikely(!sreq->tsg)) goto unlock; @@ -633,9 +637,12 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg, { struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); + struct sock *psk = ask->parent; + struct alg_sock *pask = alg_sk(psk); struct skcipher_ctx *ctx = ask->private; - unsigned bs = crypto_skcipher_blocksize(crypto_skcipher_reqtfm( - &ctx->req)); + struct skcipher_tfm *skc = pask->private; + struct crypto_skcipher *tfm = skc->skcipher; + unsigned bs = crypto_skcipher_blocksize(tfm); struct skcipher_sg_list *sgl; struct scatterlist *sg; int err = -EAGAIN; -- cgit v1.2.3 From dad41997063723eaf5f77bc2015606a5a9bce320 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 3 Feb 2016 21:39:27 +0800 Subject: crypto: algif_skcipher - Do not set MAY_BACKLOG on the async path The async path cannot use MAY_BACKLOG because it is not meant to block, which is what MAY_BACKLOG does. On the other hand, both the sync and async paths can make use of MAY_SLEEP. Cc: stable@vger.kernel.org Signed-off-by: Herbert Xu --- crypto/algif_skcipher.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'crypto') diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index ef84353e0f24..28556fce4267 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -536,7 +536,7 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg, sg_init_table(sreq->tsg, tx_nents); memcpy(iv, ctx->iv, ivsize); skcipher_request_set_tfm(req, tfm); - skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, skcipher_async_cb, sreq); while (iov_iter_count(&msg->msg_iter)) { @@ -950,7 +950,8 @@ static int skcipher_accept_parent_nokey(void *private, struct sock *sk) ask->private = ctx; skcipher_request_set_tfm(&ctx->req, skcipher); - skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG, + skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_SLEEP | + CRYPTO_TFM_REQ_MAY_BACKLOG, af_alg_complete, &ctx->completion); sk->sk_destruct = skcipher_sock_destruct; -- cgit v1.2.3