]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/tls/tls_sw.c
sock: fix sg page frag coalescing in sk_alloc_sg
[mirror_ubuntu-bionic-kernel.git] / net / tls / tls_sw.c
index 61f394d369bf86d69c44b84950632cd5c3519905..b1d2a9892d0ea18cd0075b702dfc1aaaba7309c2 100644 (file)
@@ -119,9 +119,10 @@ static int alloc_sg(struct sock *sk, int len, struct scatterlist *sg,
                pfrag->offset += use;
 
                sge = sg + num_elem - 1;
-               if (num_elem > first_coalesce && sg_page(sg) == pfrag->page &&
-                   sg->offset + sg->length == orig_offset) {
-                       sg->length += use;
+
+               if (num_elem > first_coalesce && sg_page(sge) == pfrag->page &&
+                   sge->offset + sge->length == orig_offset) {
+                       sge->length += use;
                } else {
                        sge++;
                        sg_unmark_end(sge);
@@ -195,18 +196,12 @@ static void tls_free_both_sg(struct sock *sk)
 }
 
 static int tls_do_encryption(struct tls_context *tls_ctx,
-                            struct tls_sw_context *ctx, size_t data_len,
-                            gfp_t flags)
+                            struct tls_sw_context *ctx,
+                            struct aead_request *aead_req,
+                            size_t data_len)
 {
-       unsigned int req_size = sizeof(struct aead_request) +
-               crypto_aead_reqsize(ctx->aead_send);
-       struct aead_request *aead_req;
        int rc;
 
-       aead_req = kzalloc(req_size, flags);
-       if (!aead_req)
-               return -ENOMEM;
-
        ctx->sg_encrypted_data[0].offset += tls_ctx->prepend_size;
        ctx->sg_encrypted_data[0].length -= tls_ctx->prepend_size;
 
@@ -219,7 +214,6 @@ static int tls_do_encryption(struct tls_context *tls_ctx,
        ctx->sg_encrypted_data[0].offset -= tls_ctx->prepend_size;
        ctx->sg_encrypted_data[0].length += tls_ctx->prepend_size;
 
-       kfree(aead_req);
        return rc;
 }
 
@@ -228,8 +222,14 @@ static int tls_push_record(struct sock *sk, int flags,
 {
        struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_sw_context *ctx = tls_sw_ctx(tls_ctx);
+       struct aead_request *req;
        int rc;
 
+       req = kzalloc(sizeof(struct aead_request) +
+                     crypto_aead_reqsize(ctx->aead_send), sk->sk_allocation);
+       if (!req)
+               return -ENOMEM;
+
        sg_mark_end(ctx->sg_plaintext_data + ctx->sg_plaintext_num_elem - 1);
        sg_mark_end(ctx->sg_encrypted_data + ctx->sg_encrypted_num_elem - 1);
 
@@ -245,15 +245,14 @@ static int tls_push_record(struct sock *sk, int flags,
        tls_ctx->pending_open_record_frags = 0;
        set_bit(TLS_PENDING_CLOSED_RECORD, &tls_ctx->flags);
 
-       rc = tls_do_encryption(tls_ctx, ctx, ctx->sg_plaintext_size,
-                              sk->sk_allocation);
+       rc = tls_do_encryption(tls_ctx, ctx, req, ctx->sg_plaintext_size);
        if (rc < 0) {
                /* If we are called from write_space and
                 * we fail, we need to set this SOCK_NOSPACE
                 * to trigger another write_space in the future.
                 */
                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
-               return rc;
+               goto out_req;
        }
 
        free_sg(sk, ctx->sg_plaintext_data, &ctx->sg_plaintext_num_elem,
@@ -268,6 +267,8 @@ static int tls_push_record(struct sock *sk, int flags,
                tls_err_abort(sk);
 
        tls_advance_record_sn(sk, tls_ctx);
+out_req:
+       kfree(req);
        return rc;
 }
 
@@ -433,7 +434,7 @@ alloc_encrypted:
                        ret = tls_push_record(sk, msg->msg_flags, record_type);
                        if (!ret)
                                continue;
-                       if (ret == -EAGAIN)
+                       if (ret < 0)
                                goto send_end;
 
                        copied -= try_to_copy;
@@ -577,6 +578,8 @@ alloc_payload:
                get_page(page);
                sg = ctx->sg_plaintext_data + ctx->sg_plaintext_num_elem;
                sg_set_page(sg, page, copy, offset);
+               sg_unmark_end(sg);
+
                ctx->sg_plaintext_num_elem++;
 
                sk_mem_charge(sk, copy);