Package: release.debian.org
Severity: normal
User: release.debian.org@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 <taffit@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 <taffit@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 <jgilliland@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.grekas@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
Attachment:
signature.asc
Description: Digital signature