diff --git a/core/core.services.yml b/core/core.services.yml
index 0b18c3b..97b3aff 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -655,6 +655,9 @@ services:
     class: Symfony\Component\HttpFoundation\RequestStack
     tags:
       - { name: persist }
+  wrapped_request_stack:
+    class: Drupal\Core\StackMiddleware\RequestStackWrapper
+    arguments: ['@request_stack']
   current_route_match:
      class: Drupal\Core\Routing\CurrentRouteMatch
      arguments: ['@request_stack']
@@ -692,8 +695,10 @@ services:
   http_kernel:
     class: Stack\StackedHttpKernel
   http_kernel.basic:
-    class: Symfony\Component\HttpKernel\HttpKernel
+    class: Drupal\Core\StackMiddleware\HttpKernelWrapper
     arguments: ['@event_dispatcher', '@controller_resolver', '@request_stack']
+    calls:
+      - [setRequestStack, ['@wrapped_request_stack']]
   http_middleware.negotiation:
     class: Drupal\Core\StackMiddleware\NegotiationMiddleware
     tags:
@@ -719,6 +724,11 @@ services:
      arguments: ['%cors.config%']
      tags:
        - { name: http_middleware }
+  http_middleware.stack_middleware_subscriber:
+    class: Drupal\Core\EventSubscriber\StackMiddlewareSubscriber
+    arguments: ['@request_stack']
+    tags:
+      - { name: event_subscriber }
   psr7.http_foundation_factory:
     class: Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory
   psr7.http_message_factory:
diff --git a/core/lib/Drupal/Core/EventSubscriber/StackMiddlewareSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/StackMiddlewareSubscriber.php
new file mode 100644
index 0000000..f8c39ac
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/StackMiddlewareSubscriber.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\Core\EventSubscriber;
+
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\HttpKernel\Event\PostResponseEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+
+/**
+ * KernelEvents::TERMINATE subscriber, to pop
+ * the current Request object from the request stack at the end
+ * of the execution cycle.
+ */
+class StackMiddlewareSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The request stack.
+   *
+   * @var \Symfony\Component\HttpFoundation\RequestStack
+   */
+  protected $requestStack;
+
+  /**
+   * Constructs a new StackMiddlewareSubscriber instance.
+   *
+   * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
+   *   The request stack.
+   */
+  public function __construct(RequestStack $requestStack) {
+    $this->requestStack = $requestStack;
+  }
+
+  /**
+   * Pop the current Request object from the request stack.
+   *
+   * This ensures the request stack is populated until the very end of the
+   * execution cycle, right before any __destruct() functions are run.
+   *
+   * @param \Symfony\Component\HttpKernel\Event\PostResponseEvent $event
+   */
+  public function onKernelTerminate(PostResponseEvent $event) {
+    $this->requestStack->pop();
+  }
+
+  /**
+   *
+   */
+  public static function getSubscribedEvents() {
+    /**
+     * To be called last, this must be the lowest numbered TERMINATE subscriber.
+     * The lowest numbered Symfony TERMINATE subscriber is ProfilerListener,
+     * with priority -1024.
+     */
+    return array(
+      KernelEvents::TERMINATE => array('onKernelTerminate', -4096),
+    );
+  }
+
+}
diff --git a/core/lib/Drupal/Core/StackMiddleware/HttpKernelWrapper.php b/core/lib/Drupal/Core/StackMiddleware/HttpKernelWrapper.php
new file mode 100644
index 0000000..8863888
--- /dev/null
+++ b/core/lib/Drupal/Core/StackMiddleware/HttpKernelWrapper.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Drupal\Core\StackMiddleware;
+
+use Symfony\Component\HttpKernel\HttpKernel;
+
+/**
+ * HttpKernel notifies events to convert a Request object to a Response one.
+ *
+ * This version wraps HttpKernel to add a setter function to allow requestStack
+ * to be overwritten with a RequestStackWrapper. RequestStackWrapped prevents
+ * HttpKernel from pushing / popping to the normal request stack.
+ */
+class HttpKernelWrapper extends HttpKernel {
+
+  /**
+   * @param \Drupal\Core\StackMiddleware\RequestStackWrapper $requestStack
+   *   The wrapped request stack.
+   */
+  public function setRequestStack(RequestStackWrapper $requestStack) {
+    $this->requestStack = $requestStack;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/StackMiddleware/RequestStackWrapper.php b/core/lib/Drupal/Core/StackMiddleware/RequestStackWrapper.php
new file mode 100644
index 0000000..f7be60d
--- /dev/null
+++ b/core/lib/Drupal/Core/StackMiddleware/RequestStackWrapper.php
@@ -0,0 +1,105 @@
+<?php
+
+namespace Drupal\Core\StackMiddleware;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * Request stack that controls the lifecycle of requests.
+ *
+ * This version wraps the RequestStack push() and pop() functions to prevent the
+ * caller from pushing / popping to the normal request stack. The other
+ * functions of RequestStack work as normal.
+ *
+ * RequestStackWrapper is injected into Symfony's HttpKernel via a setter
+ * function in the HttpKernelWrapper service.
+ *
+ * This is necessary because Drupal needs the request stack to be populated
+ * before HttpKernel::handleRaw() calls push() and after
+ * HttpKernel::finishRequest() calls pop(). This also prevents both Drupal and
+ * Symfony pushing the same request to RequestStack twice and only popping the
+ * request once.
+ *
+ * Drupal pushes to RequestStack in DrupalKernel::preHandle(), called from
+ * KernelPreHandle::handle(). Drupal pops from RequestStack in
+ * StackMiddleWareSubscriber, the very last subscriber to
+ * KernelEvents::TERMINATE, called right before end of the execution cycle.
+ */
+class RequestStackWrapper extends RequestStack {
+
+  /**
+   * The wrapped request stack.
+   *
+   * @var \Symfony\Component\HttpFoundation\RequestStack
+   */
+  private $wrappedRequestStack;
+
+  /**
+   * Local request stack.
+   *
+   * @var \Symfony\Component\HttpFoundation\Request[]
+   */
+  private $localRequests = array();
+
+  /**
+   * Constructs a new RequestStackWrapper.
+   *
+   * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
+   *   The request stack.
+   */
+  public function __construct(RequestStack $requestStack) {
+    $this->wrappedRequestStack = $requestStack ?: new RequestStack();
+  }
+
+  /**
+   * Pushes a Request on the local stack.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object.
+   */
+  public function push(Request $request) {
+    $this->localRequests[] = $request;
+  }
+
+  /**
+   * Pops a Request from the local stack.
+   *
+   * @return Request|null
+   */
+  public function pop() {
+    if (!$this->localRequests) {
+      return NULL;
+    }
+
+    return array_pop($this->localRequests);
+  }
+
+  /**
+   * Call getCurrentRequest() on the wrapped request stack.
+   *
+   * @return Request|null
+   */
+  public function getCurrentRequest() {
+    return $this->wrappedRequestStack->getCurrentRequest();
+  }
+
+  /**
+   * Call getMasterRequest() on the wrapped request stack.
+   *
+   * @return Request|null
+   */
+  public function getMasterRequest() {
+    return $this->wrappedRequestStack->getMasterRequest();
+  }
+
+  /**
+   * Call getMasterRequest() on the wrapped request stack.
+   *
+   * @return Request|null
+   */
+  public function getParentRequest() {
+    return $this->wrappedRequestStack->getParentRequest();
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/StackMiddleware/RequestStackMiddlewareTest.php b/core/tests/Drupal/Tests/Core/StackMiddleware/RequestStackMiddlewareTest.php
new file mode 100644
index 0000000..d17a4f8
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/StackMiddleware/RequestStackMiddlewareTest.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace Drupal\Tests\Core\StackMiddleware;
+
+use Drupal\Core\Url;
+use Drupal\KernelTests\KernelTestBase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * Tests the usage of the request stack as part of request processing.
+ *
+ * @group StackMiddleware
+ */
+class RequestStackMiddlewareTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['httpkernel_test', 'system'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installSchema('system', 'router');
+    \Drupal::service('router.builder')->rebuild();
+  }
+
+  /**
+   * Tests the StackedHttpKernel::handle() does a RequestStack::push()
+   * and StackedHttpKernel::terminate() does a RequestStack::pop().
+   *
+   * It compares master, current and parent Request objects
+   * before and after StackedHttpKernel::handle(),
+   * StackedHttpKernel::terminate(), and some simple
+   * push() & pop() calls.
+   */
+  public function testRequest() {
+    /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */
+    $request_stack = \Drupal::service('request_stack');
+
+    /** @var \Stack\StackedHttpKernel $http_kernel */
+    $http_kernel = \Drupal::service('http_kernel');
+
+    $request_1 = Request::create('/user/login');
+    $request_2 = Request::create('/');
+    $request_3 = Request::create((new Url('httpkernel_test.empty'))->toString());
+
+    $request_stack->push($request_1);
+
+    $master_1 = $request_stack->getMasterRequest();
+    $current_1 = $request_stack->getCurrentRequest();
+
+    $request_stack->push($request_2);
+
+    $master_2 = $request_stack->getMasterRequest();
+    $current_2 = $request_stack->getCurrentRequest();
+    $parent_2 = $request_stack->getParentRequest();
+
+    $request_stack->pop();
+
+    $master_3 = $request_stack->getMasterRequest();
+    $current_3 = $request_stack->getCurrentRequest();
+
+    $response = $http_kernel->handle($request_3, HttpKernelInterface::MASTER_REQUEST);
+
+    $master_4 = $request_stack->getMasterRequest();
+    $current_4 = $request_stack->getCurrentRequest();
+    $parent_4 = $request_stack->getParentRequest();
+
+    $http_kernel->terminate($request_3, $response);
+
+    $master_5 = $request_stack->getMasterRequest();
+    $current_5 = $request_stack->getCurrentRequest();
+
+    $this->assertSame($master_1, $master_2);
+    $this->assertSame($master_1, $master_3);
+    $this->assertSame($master_1, $master_4);
+    $this->assertSame($master_1, $master_5);
+
+    $this->assertSame($current_1, $request_1);
+    $this->assertSame($current_2, $request_2);
+    $this->assertSame($current_3, $request_1);
+    $this->assertSame($current_4, $request_3);
+    $this->assertSame($current_5, $request_1);
+
+    $this->assertSame($parent_2, $request_1);
+    $this->assertSame($parent_4, $request_1);
+  }
+
+}
