Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Please unblock package symfony It cherry-picks to security fixes from upstrem: symfony (2.3.21+dfsg-4) unstable; urgency=medium * Backport security fixes from 2.3.27: - Esi Code Injection [CVE-2015-2308] - Unsafe methods in the Request class [CVE-2015-2309] -- David Prévot <taf...@debian.org> Wed, 01 Apr 2015 16:53:00 -0400 unblock symfony/2.3.21+dfsg-4 Thanks in advance. Regards David
diff -Nru symfony-2.3.21+dfsg/debian/changelog symfony-2.3.21+dfsg/debian/changelog --- symfony-2.3.21+dfsg/debian/changelog 2015-01-30 09:22:17.000000000 -0400 +++ symfony-2.3.21+dfsg/debian/changelog 2015-04-01 16:53:36.000000000 -0400 @@ -1,3 +1,11 @@ +symfony (2.3.21+dfsg-4) unstable; urgency=medium + + * Backport security fixes from 2.3.27: + - Esi Code Injection [CVE-2015-2308] + - Unsafe methods in the Request class [CVE-2015-2309] + + -- David Prévot <taf...@debian.org> Wed, 01 Apr 2015 16:53:00 -0400 + symfony (2.3.21+dfsg-3) unstable; urgency=medium [ Daniel Beyer ] diff -Nru symfony-2.3.21+dfsg/debian/patches/0007-isFromTrustedProxy-to-confirm-request-came-from-a-tr.patch symfony-2.3.21+dfsg/debian/patches/0007-isFromTrustedProxy-to-confirm-request-came-from-a-tr.patch --- symfony-2.3.21+dfsg/debian/patches/0007-isFromTrustedProxy-to-confirm-request-came-from-a-tr.patch 1969-12-31 20:00:00.000000000 -0400 +++ symfony-2.3.21+dfsg/debian/patches/0007-isFromTrustedProxy-to-confirm-request-came-from-a-tr.patch 2015-04-01 16:44:25.000000000 -0400 @@ -0,0 +1,140 @@ +From: James Gilliland <jgillil...@apqc.org> +Date: Tue, 17 Feb 2015 11:56:59 -0600 +Subject: isFromTrustedProxy to confirm request came from a trusted proxy. + +Origin: upstream, https://github.com/symfony/symfony/commit/6c73f0ce9302a0091bbfbb96f317e400ce16ef84 +--- + src/Symfony/Component/HttpFoundation/Request.php | 13 +++++--- + .../Component/HttpFoundation/Tests/RequestTest.php | 38 ++++++++++++++-------- + 2 files changed, 34 insertions(+), 17 deletions(-) + +diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php +index 9fd02cc..00fdbc4 100644 +--- a/src/Symfony/Component/HttpFoundation/Request.php ++++ b/src/Symfony/Component/HttpFoundation/Request.php +@@ -763,7 +763,7 @@ class Request + { + $ip = $this->server->get('REMOTE_ADDR'); + +- if (!self::$trustedProxies) { ++ if (!$this->isFromTrustedProxy()) { + return array($ip); + } + +@@ -924,7 +924,7 @@ class Request + */ + public function getPort() + { +- if (self::$trustedProxies) { ++ if ($this->isFromTrustedProxy()) { + if (self::$trustedHeaders[self::HEADER_CLIENT_PORT] && $port = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PORT])) { + return $port; + } +@@ -1105,7 +1105,7 @@ class Request + */ + public function isSecure() + { +- if (self::$trustedProxies && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) { ++ if ($this->isFromTrustedProxy() && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) { + return in_array(strtolower(current(explode(',', $proto))), array('https', 'on', 'ssl', '1')); + } + +@@ -1133,7 +1133,7 @@ class Request + */ + public function getHost() + { +- if (self::$trustedProxies && self::$trustedHeaders[self::HEADER_CLIENT_HOST] && $host = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_HOST])) { ++ if ($this->isFromTrustedProxy() && self::$trustedHeaders[self::HEADER_CLIENT_HOST] && $host = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_HOST])) { + $elements = explode(',', $host); + + $host = $elements[count($elements) - 1]; +@@ -1819,4 +1819,9 @@ class Request + + return false; + } ++ ++ private function isFromTrustedProxy() ++ { ++ return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR'), self::$trustedProxies); ++ } + } +diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +index 6059969..e57f702 100644 +--- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php ++++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +@@ -707,35 +707,37 @@ class RequestTest extends \PHPUnit_Framework_TestCase + 'HTTP_X_FORWARDED_PROTO' => 'https', + 'HTTP_X_FORWARDED_PORT' => '8443', + )); +- $port = $request->getPort(); +- +- $this->assertEquals(8443, $port, 'With PROTO and PORT set PORT takes precedence.'); ++ $this->assertEquals(80, $request->getPort(), 'With PROTO and PORT on untrusted connection server value takes precedence.'); ++ $request->server->set('REMOTE_ADDR', '1.1.1.1'); ++ $this->assertEquals(8443, $request->getPort(), 'With PROTO and PORT set PORT takes precedence.'); + + $request = Request::create('http://example.com', 'GET', array(), array(), array(), array( + 'HTTP_X_FORWARDED_PROTO' => 'https', + )); +- $port = $request->getPort(); +- +- $this->assertEquals(443, $port, 'With only PROTO set getPort() defaults to 443.'); ++ $this->assertEquals(80, $request->getPort(), 'With only PROTO set getPort() ignores trusted headers on untrusted connection.'); ++ $request->server->set('REMOTE_ADDR', '1.1.1.1'); ++ $this->assertEquals(443, $request->getPort(), 'With only PROTO set getPort() defaults to 443.'); + + $request = Request::create('http://example.com', 'GET', array(), array(), array(), array( + 'HTTP_X_FORWARDED_PROTO' => 'http', + )); +- $port = $request->getPort(); +- +- $this->assertEquals(80, $port, 'If X_FORWARDED_PROTO is set to HTTP return 80.'); ++ $this->assertEquals(80, $request->getPort(), 'If X_FORWARDED_PROTO is set to HTTP getPort() ignores trusted headers on untrusted connection.'); ++ $request->server->set('REMOTE_ADDR', '1.1.1.1'); ++ $this->assertEquals(80, $request->getPort(), 'If X_FORWARDED_PROTO is set to HTTP getPort() returns port of the original request.'); + + $request = Request::create('http://example.com', 'GET', array(), array(), array(), array( + 'HTTP_X_FORWARDED_PROTO' => 'On', + )); +- $port = $request->getPort(); +- $this->assertEquals(443, $port, 'With only PROTO set and value is On, getPort() defaults to 443.'); ++ $this->assertEquals(80, $request->getPort(), 'With only PROTO set and value is On, getPort() ignores trusted headers on untrusted connection.'); ++ $request->server->set('REMOTE_ADDR', '1.1.1.1'); ++ $this->assertEquals(443, $request->getPort(), 'With only PROTO set and value is On, getPort() defaults to 443.'); + + $request = Request::create('http://example.com', 'GET', array(), array(), array(), array( + 'HTTP_X_FORWARDED_PROTO' => '1', + )); +- $port = $request->getPort(); +- $this->assertEquals(443, $port, 'With only PROTO set and value is 1, getPort() defaults to 443.'); ++ $this->assertEquals(80, $request->getPort(), 'With only PROTO set and value is 1, getPort() ignores trusted headers on untrusted connection.'); ++ $request->server->set('REMOTE_ADDR', '1.1.1.1'); ++ $this->assertEquals(443, $request->getPort(), 'With only PROTO set and value is 1, getPort() defaults to 443.'); + + $request = Request::create('http://example.com', 'GET', array(), array(), array(), array( + 'HTTP_X_FORWARDED_PROTO' => 'something-else', +@@ -1002,6 +1004,8 @@ class RequestTest extends \PHPUnit_Framework_TestCase + $request->headers->set('X_FORWARDED_PROTO', 'https'); + + Request::setTrustedProxies(array('1.1.1.1')); ++ $this->assertFalse($request->isSecure()); ++ $request->server->set('REMOTE_ADDR', '1.1.1.1'); + $this->assertTrue($request->isSecure()); + Request::setTrustedProxies(array()); + +@@ -1437,7 +1441,15 @@ class RequestTest extends \PHPUnit_Framework_TestCase + $this->assertEquals(443, $request->getPort()); + $this->assertTrue($request->isSecure()); + ++ // trusted proxy via setTrustedProxies() ++ Request::setTrustedProxies(array('3.3.3.4', '2.2.2.2')); ++ $this->assertEquals('3.3.3.3', $request->getClientIp()); ++ $this->assertEquals('example.com', $request->getHost()); ++ $this->assertEquals(80, $request->getPort()); ++ $this->assertFalse($request->isSecure()); ++ + // check various X_FORWARDED_PROTO header values ++ Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2')); + $request->headers->set('X_FORWARDED_PROTO', 'ssl'); + $this->assertTrue($request->isSecure()); + diff -Nru symfony-2.3.21+dfsg/debian/patches/0008-Safe-escaping-of-fragments-for-eval.patch symfony-2.3.21+dfsg/debian/patches/0008-Safe-escaping-of-fragments-for-eval.patch --- symfony-2.3.21+dfsg/debian/patches/0008-Safe-escaping-of-fragments-for-eval.patch 1969-12-31 20:00:00.000000000 -0400 +++ symfony-2.3.21+dfsg/debian/patches/0008-Safe-escaping-of-fragments-for-eval.patch 2015-04-01 16:44:25.000000000 -0400 @@ -0,0 +1,113 @@ +From: Nicolas Grekas <nicolas.gre...@gmail.com> +Date: Mon, 16 Mar 2015 15:12:02 +0100 +Subject: Safe escaping of fragments for eval() + +https://github.com/symfony/symfony/commit/195c57e1f50765aff33137689b16e126a689056a +--- + src/Symfony/Component/HttpKernel/HttpCache/Esi.php | 62 +++++++++++----------- + .../HttpKernel/Tests/HttpCache/EsiTest.php | 4 +- + 2 files changed, 33 insertions(+), 33 deletions(-) + +diff --git a/src/Symfony/Component/HttpKernel/HttpCache/Esi.php b/src/Symfony/Component/HttpKernel/HttpCache/Esi.php +index 9dd99d6..ad63267 100644 +--- a/src/Symfony/Component/HttpKernel/HttpCache/Esi.php ++++ b/src/Symfony/Component/HttpKernel/HttpCache/Esi.php +@@ -29,6 +29,10 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; + class Esi + { + private $contentTypes; ++ private $phpEscapeMap = array( ++ array('<?', '<%', '<s', '<S'), ++ array('<?php echo "<?"; ?>', '<?php echo "<%"; ?>', '<?php echo "<s"; ?>', '<?php echo "<S"; ?>'), ++ ); + + /** + * Constructor. +@@ -158,10 +162,34 @@ class Esi + + // we don't use a proper XML parser here as we can have ESI tags in a plain text response + $content = $response->getContent(); +- $content = str_replace(array('<?', '<%'), array('<?php echo "<?"; ?>', '<?php echo "<%"; ?>'), $content); +- $content = preg_replace_callback('#<esi\:include\s+(.*?)\s*(?:/|</esi\:include)>#', array($this, 'handleEsiIncludeTag'), $content); +- $content = preg_replace('#<esi\:comment[^>]*(?:/|</esi\:comment)>#', '', $content); + $content = preg_replace('#<esi\:remove>.*?</esi\:remove>#', '', $content); ++ $content = preg_replace('#<esi\:comment[^>]*(?:/|</esi\:comment)>#', '', $content); ++ ++ $chunks = preg_split('#<esi\:include\s+(.*?)\s*(?:/|</esi\:include)>#', $content, -1, PREG_SPLIT_DELIM_CAPTURE); ++ $chunks[0] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[0]); ++ ++ $i = 1; ++ while (isset($chunks[$i])) { ++ $options = array(); ++ preg_match_all('/(src|onerror|alt)="([^"]*?)"/', $chunks[$i], $matches, PREG_SET_ORDER); ++ foreach ($matches as $set) { ++ $options[$set[1]] = $set[2]; ++ } ++ ++ if (!isset($options['src'])) { ++ throw new \RuntimeException('Unable to process an ESI tag without a "src" attribute.'); ++ } ++ ++ $chunks[$i] = sprintf('<?php echo $this->esi->handle($this, %s, %s, %s) ?>'."\n", ++ var_export($options['src'], true), ++ var_export(isset($options['alt']) ? $options['alt'] : '', true), ++ isset($options['onerror']) && 'continue' == $options['onerror'] ? 'true' : 'false' ++ ); ++ ++$i; ++ $chunks[$i] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[$i]); ++ ++$i; ++ } ++ $content = implode('', $chunks); + + $response->setContent($content); + $response->headers->set('X-Body-Eval', 'ESI'); +@@ -214,32 +242,4 @@ class Esi + } + } + } +- +- /** +- * Handles an ESI include tag (called internally). +- * +- * @param array $attributes An array containing the attributes. +- * +- * @return string The response content for the include. +- * +- * @throws \RuntimeException +- */ +- private function handleEsiIncludeTag($attributes) +- { +- $options = array(); +- preg_match_all('/(src|onerror|alt)="([^"]*?)"/', $attributes[1], $matches, PREG_SET_ORDER); +- foreach ($matches as $set) { +- $options[$set[1]] = $set[2]; +- } +- +- if (!isset($options['src'])) { +- throw new \RuntimeException('Unable to process an ESI tag without a "src" attribute.'); +- } +- +- return sprintf('<?php echo $this->esi->handle($this, %s, %s, %s) ?>'."\n", +- var_export($options['src'], true), +- var_export(isset($options['alt']) ? $options['alt'] : '', true), +- isset($options['onerror']) && 'continue' == $options['onerror'] ? 'true' : 'false' +- ); +- } + } +diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/EsiTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/EsiTest.php +index 23e256e..8ab3d47 100644 +--- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/EsiTest.php ++++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/EsiTest.php +@@ -131,10 +131,10 @@ class EsiTest extends \PHPUnit_Framework_TestCase + $esi = new Esi(); + + $request = Request::create('/'); +- $response = new Response('foo <?php die("foo"); ?><%= "lala" %>'); ++ $response = new Response('<?php <? <% <script language=php>'); + $esi->process($request, $response); + +- $this->assertEquals('foo <?php echo "<?"; ?>php die("foo"); ?><?php echo "<%"; ?>= "lala" %>', $response->getContent()); ++ $this->assertEquals('<?php echo "<?"; ?>php <?php echo "<?"; ?> <?php echo "<%"; ?> <?php echo "<s"; ?>cript language=php>', $response->getContent()); + } + + /** diff -Nru symfony-2.3.21+dfsg/debian/patches/series symfony-2.3.21+dfsg/debian/patches/series --- symfony-2.3.21+dfsg/debian/patches/series 2015-01-30 09:17:03.000000000 -0400 +++ symfony-2.3.21+dfsg/debian/patches/series 2015-04-01 16:44:25.000000000 -0400 @@ -4,3 +4,5 @@ 0004-Add-more-tests-to-group-tty.patch 0005-Process-Make-test-AbstractProcessTest-testStartAfter.patch 0006-Increasing-timeout-in-test-AbstractProcessTest-testS.patch +0007-isFromTrustedProxy-to-confirm-request-came-from-a-tr.patch +0008-Safe-escaping-of-fragments-for-eval.patch
signature.asc
Description: Digital signature