aboutsummaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorRabin Vincent <rabin.vincent@axis.com>2014-12-19 13:36:08 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-01-08 10:30:27 -0800
commitfa06c84a8c67ab9baf8195d0435f0264c520d46e (patch)
tree3c173464b5da0ba772600aa596150eae4f859cca /crypto
parent3d7c0c1f6092ae814a5c7190cc382daa3543033a (diff)
downloadlinux-linaro-stable-fa06c84a8c67ab9baf8195d0435f0264c520d46e.tar.gz
crypto: af_alg - fix backlog handling
commit 7e77bdebff5cb1e9876c561f69710b9ab8fa1f7e upstream. If a request is backlogged, it's complete() handler will get called twice: once with -EINPROGRESS, and once with the final error code. af_alg's complete handler, unlike other users, does not handle the -EINPROGRESS but instead always completes the completion that recvmsg() is waiting on. This can lead to a return to user space while the request is still pending in the driver. If userspace closes the sockets before the requests are handled by the driver, this will lead to use-after-frees (and potential crashes) in the kernel due to the tfm having been freed. The crashes can be easily reproduced (for example) by reducing the max queue length in cryptod.c and running the following (from http://www.chronox.de/libkcapi.html) on AES-NI capable hardware: $ while true; do kcapi -x 1 -e -c '__ecb-aes-aesni' \ -k 00000000000000000000000000000000 \ -p 00000000000000000000000000000000 >/dev/null & done Signed-off-by: Rabin Vincent <rabin.vincent@axis.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/af_alg.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 6a3ad8011585..1de4beeb25f8 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -449,6 +449,9 @@ void af_alg_complete(struct crypto_async_request *req, int err)
{
struct af_alg_completion *completion = req->data;
+ if (err == -EINPROGRESS)
+ return;
+
completion->err = err;
complete(&completion->completion);
}