Alexandre Julliard : secur32: Pre-allocate the token buffer for handshake() on the PE side.

Alexandre Julliard julliard at winehq.org
Mon Dec 6 16:07:58 CST 2021


Module: wine
Branch: master
Commit: 1cf48b46845c1364e5d032924a700f372f7b0628
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=1cf48b46845c1364e5d032924a700f372f7b0628

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri Dec  3 18:24:24 2021 +0100

secur32: Pre-allocate the token buffer for handshake() on the PE side.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/secur32/schannel.c        | 17 ++++++++++++++++-
 dlls/secur32/schannel_gnutls.c | 41 +++++++----------------------------------
 dlls/secur32/secur32_priv.h    |  4 ++--
 3 files changed, 25 insertions(+), 37 deletions(-)

diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c
index 432c35cdfde..14645080f38 100644
--- a/dlls/secur32/schannel.c
+++ b/dlls/secur32/schannel.c
@@ -689,12 +689,14 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
  PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
  PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
 {
+    const ULONG extra_size = 0x10000;
     struct schan_context *ctx;
     struct schan_buffers *out_buffers;
     struct schan_credentials *cred;
     SIZE_T expected_size = ~0UL;
     SECURITY_STATUS ret;
     SecBuffer *buffer;
+    SecBuffer alloc_buffer = { 0 };
     int idx;
 
     TRACE("%p %p %s 0x%08x %d %d %p %d %p %p %p %p\n", phCredential, phContext,
@@ -814,19 +816,32 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
     ctx->req_ctx_attr = fContextReq;
 
     /* Perform the TLS handshake */
-    ret = schan_funcs->handshake(ctx->transport.session, pInput, expected_size, pOutput, fContextReq);
+    if (fContextReq & ISC_REQ_ALLOCATE_MEMORY)
+    {
+        alloc_buffer.cbBuffer = extra_size;
+        alloc_buffer.BufferType = SECBUFFER_TOKEN;
+        alloc_buffer.pvBuffer = RtlAllocateHeap( GetProcessHeap(), 0, extra_size );
+    }
+    ret = schan_funcs->handshake(ctx->transport.session, pInput, expected_size, pOutput, &alloc_buffer);
 
     out_buffers = &ctx->transport.out;
     if (out_buffers->current_buffer_idx != -1)
     {
         SecBuffer *buffer = &out_buffers->desc->pBuffers[out_buffers->current_buffer_idx];
         buffer->cbBuffer = out_buffers->offset;
+        if (buffer->pvBuffer == alloc_buffer.pvBuffer)
+        {
+            RtlReAllocateHeap( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY,
+                               buffer->pvBuffer, buffer->cbBuffer );
+            alloc_buffer.pvBuffer = NULL;
+        }
     }
     else if (out_buffers->desc && out_buffers->desc->cBuffers > 0)
     {
         SecBuffer *buffer = &out_buffers->desc->pBuffers[0];
         buffer->cbBuffer = 0;
     }
+    RtlFreeHeap( GetProcessHeap(), 0, alloc_buffer.pvBuffer );
 
     if(ctx->transport.in.offset && ctx->transport.in.offset != pInput->pBuffers[0].cbBuffer) {
         if(pInput->cBuffers<2 || pInput->pBuffers[1].BufferType!=SECBUFFER_EMPTY)
diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c
index e4da13c9b3e..d832c353fcd 100644
--- a/dlls/secur32/schannel_gnutls.c
+++ b/dlls/secur32/schannel_gnutls.c
@@ -204,7 +204,7 @@ static void init_schan_buffers(struct schan_buffers *s, const PSecBufferDesc des
     s->limit = ~0UL;
     s->desc = desc;
     s->current_buffer_idx = -1;
-    s->allow_buffer_resize = FALSE;
+    s->alloc_buffer = NULL;
     s->get_next_buffer = get_next_buffer;
 }
 
@@ -240,10 +240,9 @@ static int handshake_get_next_buffer_alloc(const struct schan_transport *t, stru
             idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_EMPTY);
             if (idx != -1) s->desc->pBuffers[idx].BufferType = SECBUFFER_TOKEN;
         }
-        if (idx != -1 && !s->desc->pBuffers[idx].pvBuffer)
+        if (idx != -1 && !s->desc->pBuffers[idx].pvBuffer && s->alloc_buffer)
         {
-            s->desc->pBuffers[idx].cbBuffer = 0;
-            s->allow_buffer_resize = TRUE;
+            s->desc->pBuffers[idx] = *s->alloc_buffer;
         }
         return idx;
     }
@@ -302,31 +301,6 @@ static int recv_message_get_next_buffer(const struct schan_transport *t, struct
     return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA);
 }
 
-static void resize_current_buffer(const struct schan_buffers *s, SIZE_T min_size)
-{
-    SecBuffer *b = &s->desc->pBuffers[s->current_buffer_idx];
-    SIZE_T new_size = b->cbBuffer ? b->cbBuffer * 2 : 128;
-    void *new_data;
-
-    if (b->cbBuffer >= min_size || !s->allow_buffer_resize || min_size > UINT_MAX / 2) return;
-
-    while (new_size < min_size) new_size *= 2;
-
-    if (b->pvBuffer) /* freed with FreeContextBuffer */
-        new_data = RtlReAllocateHeap(GetProcessHeap(), 0, b->pvBuffer, new_size);
-    else
-        new_data = RtlAllocateHeap(GetProcessHeap(), 0, new_size);
-
-    if (!new_data)
-    {
-        TRACE("Failed to resize %p from %d to %ld\n", b->pvBuffer, b->cbBuffer, new_size);
-        return;
-    }
-
-    b->cbBuffer = new_size;
-    b->pvBuffer = new_data;
-}
-
 static char *get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count)
 {
     SIZE_T max_count;
@@ -353,7 +327,6 @@ static char *get_buffer(const struct schan_transport *t, struct schan_buffers *s
     buffer = &s->desc->pBuffers[s->current_buffer_idx];
     TRACE("Using buffer %d: cbBuffer %d, BufferType %#x, pvBuffer %p\n", s->current_buffer_idx, buffer->cbBuffer, buffer->BufferType, buffer->pvBuffer);
 
-    resize_current_buffer(s, s->offset + *count);
     max_count = buffer->cbBuffer - s->offset;
     if (s->limit != ~0UL && s->limit < max_count)
         max_count = s->limit;
@@ -362,7 +335,6 @@ static char *get_buffer(const struct schan_transport *t, struct schan_buffers *s
     {
         int buffer_idx;
 
-        s->allow_buffer_resize = FALSE;
         buffer_idx = s->get_next_buffer(t, s);
         if (buffer_idx == -1)
         {
@@ -580,7 +552,8 @@ static void CDECL schan_set_session_target(schan_session session, const char *ta
 }
 
 static SECURITY_STATUS CDECL schan_handshake(schan_session session, SecBufferDesc *input,
-                                             SIZE_T input_size, SecBufferDesc *output, ULONG flags )
+                                             SIZE_T input_size, SecBufferDesc *output,
+                                             SecBuffer *alloc_buffer )
 {
     gnutls_session_t s = (gnutls_session_t)session;
     struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
@@ -588,8 +561,8 @@ static SECURITY_STATUS CDECL schan_handshake(schan_session session, SecBufferDes
 
     init_schan_buffers(&t->in, input, handshake_get_next_buffer);
     t->in.limit = input_size;
-    init_schan_buffers(&t->out, output, (flags & ISC_REQ_ALLOCATE_MEMORY) ?
-                       handshake_get_next_buffer_alloc : handshake_get_next_buffer );
+    init_schan_buffers(&t->out, output, handshake_get_next_buffer_alloc );
+    t->out.alloc_buffer = alloc_buffer;
 
     while(1) {
         err = pgnutls_handshake(s);
diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h
index 9970c0847e3..6bfa1ff7a26 100644
--- a/dlls/secur32/secur32_priv.h
+++ b/dlls/secur32/secur32_priv.h
@@ -95,8 +95,8 @@ struct schan_buffers
     SIZE_T offset;
     SIZE_T limit;
     const SecBufferDesc *desc;
+    SecBuffer *alloc_buffer;
     int current_buffer_idx;
-    BOOL allow_buffer_resize;
     int (*get_next_buffer)(const struct schan_transport *, struct schan_buffers *);
 };
 
@@ -122,7 +122,7 @@ struct schan_funcs
     unsigned int (CDECL *get_session_cipher_block_size)(schan_session);
     SECURITY_STATUS (CDECL *get_session_peer_certificate)(schan_session, CERT_BLOB *, ULONG *, ULONG *);
     SECURITY_STATUS (CDECL *get_unique_channel_binding)(schan_session, void *, ULONG *);
-    SECURITY_STATUS (CDECL *handshake)(schan_session, SecBufferDesc *, SIZE_T, SecBufferDesc *, ULONG );
+    SECURITY_STATUS (CDECL *handshake)(schan_session, SecBufferDesc *, SIZE_T, SecBufferDesc *, SecBuffer * );
     SECURITY_STATUS (CDECL *recv)(schan_session, SecBufferDesc *, SIZE_T, void *, SIZE_T *);
     SECURITY_STATUS (CDECL *send)(schan_session, SecBufferDesc *, const void *, SIZE_T *);
     void (CDECL *set_application_protocols)(schan_session, unsigned char *, unsigned int);




More information about the wine-cvs mailing list