From a93e5a49e3d04c2f72e320040a15121e4d88b5d3 Mon Sep 17 00:00:00 2001
From: Craig Tiller <ctiller@google.com>
Date: Tue, 26 Apr 2016 21:47:49 -0700
Subject: [PATCH] Fix use-after-free

---
 .../chttp2/transport/chttp2_transport.c       | 20 +++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 24448714a8..fcf2abfe66 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -1668,6 +1668,14 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
  * BYTE STREAM
  */
 
+static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_incoming_byte_stream *bs) {
+  if (gpr_unref(&bs->refs)) {
+    gpr_slice_buffer_destroy(&bs->slices);
+    gpr_free(bs);
+  }
+}
+
 static void incoming_byte_stream_update_flow_control(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
@@ -1738,6 +1746,7 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
     bs->on_next = arg->on_complete;
     bs->next = arg->slice;
   }
+  incoming_byte_stream_unref(exec_ctx, bs);
 }
 
 static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
@@ -1747,20 +1756,13 @@ static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
   grpc_chttp2_incoming_byte_stream *bs =
       (grpc_chttp2_incoming_byte_stream *)byte_stream;
   incoming_byte_stream_next_arg arg = {bs, slice, max_size_hint, on_complete};
+  gpr_ref(&bs->refs);
   grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
                                    incoming_byte_stream_next_locked, &arg,
                                    sizeof(arg));
   return 0;
 }
 
-static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
-                                       grpc_chttp2_incoming_byte_stream *bs) {
-  if (gpr_unref(&bs->refs)) {
-    gpr_slice_buffer_destroy(&bs->slices);
-    gpr_free(bs);
-  }
-}
-
 static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
                                          grpc_byte_stream *byte_stream);
 
@@ -1801,12 +1803,14 @@ static void incoming_byte_stream_push_locked(grpc_exec_ctx *exec_ctx,
   } else {
     gpr_slice_buffer_add(&bs->slices, arg->slice);
   }
+  incoming_byte_stream_unref(exec_ctx, bs);
 }
 
 void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
                                            grpc_chttp2_incoming_byte_stream *bs,
                                            gpr_slice slice) {
   incoming_byte_stream_push_arg arg = {bs, slice};
+  gpr_ref(&bs->refs);
   grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
                                    incoming_byte_stream_push_locked, &arg,
                                    sizeof(arg));
-- 
GitLab