Re: [RFC 1/1] net/tls(TLS_SW): Handle -ENOSPC error return from device/AES-NI

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 7 Oct 2020 15:19:47 -0400 Pooja Trivedi wrote:
> When an -ENOSPC error code is returned by the crypto device or AES-NI
> layer, TLS SW path sets an EBADMSG on the socket causing the
> application to fail.  In an attempt to address the -ENOSPC in the TLS
> SW path, changes were made in tls_sw_sendpage path to trim current
> payload off the plain and encrypted messages, and send a 'zero bytes
> copied' return to the application.  The following diff shows those
> changes:
> 
> diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
> index 9a3d9fedd7aa..4dce4668cb07 100644
> --- a/net/tls/tls_sw.c
> +++ b/net/tls/tls_sw.c
> @@ -762,7 +762,7 @@ static int tls_push_record(struct sock *sk, int flags,
>   rc = tls_do_encryption(sk, tls_ctx, ctx, req,
>         msg_pl->sg.size + prot->tail_size, i);
>   if (rc < 0) {
> -               if (rc != -EINPROGRESS) {
> +              if ((rc != -EINPROGRESS) && (rc != -ENOSPC)) {
>                             tls_err_abort(sk, EBADMSG);
>                             if (split) {
> 
> tls_ctx->pending_open_record_frags = true;
> 
> @@ -1073,8 +1073,15 @@ int tls_sw_sendmsg(struct sock *sk, struct
> msghdr *msg, size_t size)
>   else if (ret == -ENOMEM)
>                goto wait_for_memory;
>   else if (ret != -EAGAIN) {
> -              if (ret == -ENOSPC)
> +             if (ret == -ENOSPC) {
>                           ret = 0;
>                           copied -= try_to_copy;
>                           iov_iter_revert(&msg->msg_iter,
> msg_pl->sg.size - orig_size);
>                           tls_trim_both_msgs(sk, orig_size);
>                }
>                goto send_end;
>      }
>   }
> 
> @@ -1150,6 +1157,7 @@ static int tls_sw_do_sendpage(struct sock *sk,
> struct page *page,
>   ssize_t copied = 0;
>   bool full_record;
>   int record_room;
> + int orig_size;
>   int ret = 0;
>   bool eor;
> 
> @@ -1175,7 +1183,7 @@ static int tls_sw_do_sendpage(struct sock *sk,
> struct page *page,
>   }
> 
>   msg_pl = &rec->msg_plaintext;
> -
> + orig_size = msg_pl->sg.size;
>   full_record = false;
>   record_room = TLS_MAX_PAYLOAD_SIZE - msg_pl->sg.size;
>   copy = size;
> 
> @@ -1219,8 +1227,12 @@ static int tls_sw_do_sendpage(struct sock *sk,
> struct page *page,
> 
>   else if (ret == -ENOMEM)
>              goto wait_for_memory;
>   else if (ret != -EAGAIN) {
> -            if (ret == -ENOSPC)
> +           if (ret == -ENOSPC) {
> +                      tls_trim_both_msgs(sk, orig_size);
>                         copied -= copy;
>                         ret = 0;
>               }
>               goto sendpage_end;
>    }
>   }
> 
> 
> However, when above patch was tried, the application tried to send
> remaining data based on the offset as expected, but encryption failed
> due to data integrity issues.  Further debugging revealed that
> sk_msg_trim(), called by tls_trim_both_msgs() does not update the page
> frag offset.  It seems like sk_msg_trim() needs to subtract the trim
> length from the pfrag->offset corresponding to how the sk_msg_alloc()
> call increments the pfrag-->offset with the length it charges to the
> socket via sk_mem_charge().
> When sk_msg_trim() calls sk_mem_uncharge() to uncharge trim length off
> the socket, it should also perform
>            pfrag->offset -= trim;

Let's CC netdev. It's a bit surprising to me that pfrag->offset matters
here, we're basically "wasting" a bit of the page but why would that
cause data integrity issues?

> While the sk_msg_trim() pfrag->offset subtraction change hasn't been
> tried yet, the following hack in TLS layer has been tried and has
> correctly worked. This proves that the above observation/theory
> regarding pfrag->offset update would be the fix:
> 
> 
> +                                       if (ret == -ENOSPC) {
> +                                               struct page_frag *pfrag;
> +                                               tls_trim_both_msgs(sk,
> orig_size);
> +
> +                                               copied -= copy;
> +                                               pfrag = sk_page_frag(sk);
> +                                               pfrag->offset -= copy;
> 
> 
> What are your thoughts on the best way to fix the issue?
> sk_msg_trim() seems like the most logical place, but
> suggestions/comments/questions are welcome.
> 
> Another thing to think about is whether -EBUSY should be handled
> similarly. Vendors have differences and the conditions under which
> these error codes are returned are not very consistent when the sidecar
> device path is involved.

Why would the driver return EBUSY from an async API? What's the caller
supposed to do with that?


While we have you - weren't you sending a sendpage() fix at some point?
Did that get lost?



[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux