From patchwork Fri Sep 14 20:01:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Fastabend X-Patchwork-Id: 970075 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42Bmd334K3z9s4V for ; Sat, 15 Sep 2018 06:01:59 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727745AbeIOBRu (ORCPT ); Fri, 14 Sep 2018 21:17:50 -0400 Received: from [184.63.162.180] ([184.63.162.180]:40090 "EHLO john-Precision-Tower-5810" rhost-flags-FAIL-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726891AbeIOBRu (ORCPT ); Fri, 14 Sep 2018 21:17:50 -0400 Received: from [127.0.1.1] (localhost [127.0.0.1]) by john-Precision-Tower-5810 (Postfix) with ESMTP id E0A6BD477F3; Fri, 14 Sep 2018 13:01:46 -0700 (PDT) Subject: [net-next PATCH] tls: async support causes out-of-bounds access in crypto APIs From: John Fastabend To: vakul.garg@nxp.com, davejwatson@fb.com Cc: doronrk@fb.com, netdev@vger.kernel.org, alexei.starovoitov@gmail.com, daniel@iogearbox.net, davem@davemloft.net Date: Fri, 14 Sep 2018 13:01:46 -0700 Message-ID: <20180914200146.6302.50472.stgit@john-Precision-Tower-5810> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org When async support was added it needed to access the sk from the async callback to report errors up the stack. The patch tried to use space after the aead request struct by directly setting the reqsize field in aead_request. This is an internal field that should not be used outside the crypto APIs. It is used by the crypto code to define extra space for private structures used in the crypto context. Users of the API then use crypto_aead_reqsize() and add the returned amount of bytes to the end of the request memory allocation before posting the request to encrypt/decrypt APIs. So this breaks (with general protection fault and KASAN error, if enabled) because the request sent to decrypt is shorter than required causing the crypto API out-of-bounds errors. Also it seems unlikely the sk is even valid by the time it gets to the callback because of memset in crypto layer. Anyways, fix this by holding the sk in the skb->sk field when the callback is set up and because the skb is already passed through to the callback handler via void* we can access it in the handler. Then in the handler we need to be careful to NULL the pointer again before kfree_skb. I added comments on both the setup (in tls_do_decryption) and when we clear it from the crypto callback handler tls_decrypt_done(). After this selftests pass again and fixes KASAN errors/warnings. Fixes: 94524d8fc965 ("net/tls: Add support for async decryption of tls records") Signed-off-by: John Fastabend Reviewed-by: Vakul Garg --- include/net/tls.h | 4 ---- net/tls/tls_sw.c | 39 +++++++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index cd0a65b..8630d28 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -128,10 +128,6 @@ struct tls_sw_context_rx { bool async_notify; }; -struct decrypt_req_ctx { - struct sock *sk; -}; - struct tls_record_info { struct list_head list; u32 end_seq; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index be4f2e9..cef69b6 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -122,25 +122,32 @@ static int skb_nsg(struct sk_buff *skb, int offset, int len) static void tls_decrypt_done(struct crypto_async_request *req, int err) { struct aead_request *aead_req = (struct aead_request *)req; - struct decrypt_req_ctx *req_ctx = - (struct decrypt_req_ctx *)(aead_req + 1); - struct scatterlist *sgout = aead_req->dst; - - struct tls_context *tls_ctx = tls_get_ctx(req_ctx->sk); - struct tls_sw_context_rx *ctx = tls_sw_ctx_rx(tls_ctx); - int pending = atomic_dec_return(&ctx->decrypt_pending); + struct tls_sw_context_rx *ctx; + struct tls_context *tls_ctx; struct scatterlist *sg; + struct sk_buff *skb; unsigned int pages; + int pending; + + skb = (struct sk_buff *)req->data; + tls_ctx = tls_get_ctx(skb->sk); + ctx = tls_sw_ctx_rx(tls_ctx); + pending = atomic_dec_return(&ctx->decrypt_pending); /* Propagate if there was an err */ if (err) { ctx->async_wait.err = err; - tls_err_abort(req_ctx->sk, err); + tls_err_abort(skb->sk, err); } + /* After using skb->sk to propagate sk through crypto async callback + * we need to NULL it again. + */ + skb->sk = NULL; + /* Release the skb, pages and memory allocated for crypto req */ - kfree_skb(req->data); + kfree_skb(skb); /* Skip the first S/G entry as it points to AAD */ for_each_sg(sg_next(sgout), sg, UINT_MAX, pages) { @@ -175,11 +182,13 @@ static int tls_do_decryption(struct sock *sk, (u8 *)iv_recv); if (async) { - struct decrypt_req_ctx *req_ctx; - - req_ctx = (struct decrypt_req_ctx *)(aead_req + 1); - req_ctx->sk = sk; - + /* Using skb->sk to push sk through to crypto async callback + * handler. This allows propagating errors up to the socket + * if needed. It _must_ be cleared in the async handler + * before kfree_skb is called. We _know_ skb->sk is NULL + * because it is a clone from strparser. + */ + skb->sk = sk; aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, tls_decrypt_done, skb); @@ -1455,8 +1464,6 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx) goto free_aead; if (sw_ctx_rx) { - (*aead)->reqsize = sizeof(struct decrypt_req_ctx); - /* Set up strparser */ memset(&cb, 0, sizeof(cb)); cb.rcv_msg = tls_queue;