From 23151ed1380c3212b9647c62f2385da00a6fe379 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Fri, 24 May 2019 12:09:27 +0200 Subject: [PATCH 01/12] Use constant time comparison in UriSigner --- src/Symfony/Component/HttpKernel/UriSigner.php | 2 +- src/Symfony/Component/HttpKernel/composer.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/UriSigner.php b/src/Symfony/Component/HttpKernel/UriSigner.php index 481270da519e1..ffe31a212157b 100644 --- a/src/Symfony/Component/HttpKernel/UriSigner.php +++ b/src/Symfony/Component/HttpKernel/UriSigner.php @@ -79,7 +79,7 @@ public function check($uri) $hash = $params[$this->parameter]; unset($params[$this->parameter]); - return $this->computeHash($this->buildUrl($url, $params)) === $hash; + return hash_equals($this->computeHash($this->buildUrl($url, $params)), $hash); } private function computeHash($uri) diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index f47f1162d1cdc..7f471c680ed40 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -21,6 +21,7 @@ "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", "symfony/debug": "^3.3.3|~4.0", "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php56": "~1.8", "psr/log": "~1.0" }, "require-dev": { From 150741390d93f67a92295edc4d699a2237fec545 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 16 Jul 2019 11:30:28 +0200 Subject: [PATCH 02/12] [Cache] forbid serializing AbstractAdapter and TagAwareAdapter instances --- .../Component/Cache/Adapter/AbstractAdapter.php | 10 ++++++++++ .../Component/Cache/Adapter/TagAwareAdapter.php | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index 0868c16d47cf8..df5280b42dca7 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -276,6 +276,16 @@ public function commit() return $ok; } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { if ($this->deferred) { diff --git a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php index 362aceed0eb18..7b726237bf772 100644 --- a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php @@ -273,6 +273,16 @@ public function commit() return $this->invalidateTags([]); } + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + public function __destruct() { $this->commit(); From d446d7733abd8807ff43e7a689065e6ebc48e32a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 9 Apr 2019 12:03:18 +0200 Subject: [PATCH 03/12] [VarExporter] fix exporting some strings --- .../VarExporter/Internal/Exporter.php | 37 ++++++++++--------- .../Tests/Fixtures/lf-ending-string.php | 4 ++ .../Tests/Fixtures/multiline-string.php | 3 +- .../VarExporter/Tests/VarExporterTest.php | 1 + 4 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 src/Symfony/Component/VarExporter/Tests/Fixtures/lf-ending-string.php diff --git a/src/Symfony/Component/VarExporter/Internal/Exporter.php b/src/Symfony/Component/VarExporter/Internal/Exporter.php index c0b7fa17f44ce..06d747e1385e2 100644 --- a/src/Symfony/Component/VarExporter/Internal/Exporter.php +++ b/src/Symfony/Component/VarExporter/Internal/Exporter.php @@ -212,27 +212,28 @@ public static function export($value, $indent = '') $subIndent = $indent.' '; if (\is_string($value)) { - $code = var_export($value, true); - - if (false !== strpos($value, "\n") || false !== strpos($value, "\r")) { - $code = strtr($code, [ - "\r\n" => "'.\"\\r\\n\"\n".$subIndent.".'", - "\r" => "'.\"\\r\"\n".$subIndent.".'", - "\n" => "'.\"\\n\"\n".$subIndent.".'", - ]); - } + $code = sprintf("'%s'", addcslashes($value, "'\\")); - if (false !== strpos($value, "\0")) { - $code = str_replace('\' . "\0" . \'', '\'."\0".\'', $code); - $code = str_replace('".\'\'."', '', $code); - } + $code = preg_replace_callback('/([\0\r\n]++)(.)/', function ($m) use ($subIndent) { + $m[1] = sprintf('\'."%s".\'', str_replace( + ["\0", "\r", "\n", '\n\\'], + ['\0', '\r', '\n', '\n"'."\n".$subIndent.'."\\'], + $m[1] + )); - if (false !== strpos($code, "''.")) { - $code = str_replace("''.", '', $code); - } + if ("'" === $m[2]) { + return substr($m[1], 0, -2); + } + + if ('n".\'' === substr($m[1], -4)) { + return substr_replace($m[1], "\n".$subIndent.".'".$m[2], -2); + } + + return $m[1].$m[2]; + }, $code, -1, $count); - if (".''" === substr($code, -3)) { - $code = rtrim(substr($code, 0, -3)); + if ($count && 0 === strpos($code, "''.")) { + $code = substr($code, 3); } return $code; diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/lf-ending-string.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/lf-ending-string.php new file mode 100644 index 0000000000000..f6bcf84976344 --- /dev/null +++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/lf-ending-string.php @@ -0,0 +1,4 @@ + 'B'."\r" - .'C'."\n" + .'A' => 'B'."\r".'C'."\n" ."\n", ]; diff --git a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php index d80c2858ee91e..1e328d8a5028d 100644 --- a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php +++ b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php @@ -112,6 +112,7 @@ public function testExport(string $testName, $value, bool $staticValueExpected = public function provideExport() { yield ['multiline-string', ["\0\0\r\nA" => "B\rC\n\n"], true]; + yield ['lf-ending-string', "'BOOM'\n.var_dump(123)//'", true]; yield ['bool', true, true]; yield ['simple-array', [123, ['abc']], true]; From 6be5cc75a4817657c5574553a41bdd0193d4fe51 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 19 Apr 2019 14:48:43 +0200 Subject: [PATCH 04/12] [HttpFoundation] fix guessing mime-types of files with leading dash --- .../File/MimeType/FileBinaryMimeTypeGuesser.php | 4 ++-- .../HttpFoundation/Tests/File/Fixtures/-test | Bin 0 -> 35 bytes .../Tests/File/MimeType/MimeTypeTest.php | 11 ++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/HttpFoundation/Tests/File/Fixtures/-test diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php index cfa76843cc4f7..7045e94df673f 100644 --- a/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php +++ b/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php @@ -31,7 +31,7 @@ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface * * @param string $cmd The command to run to get the mime type of a file */ - public function __construct($cmd = 'file -b --mime %s 2>/dev/null') + public function __construct($cmd = 'file -b --mime -- %s 2>/dev/null') { $this->cmd = $cmd; } @@ -80,7 +80,7 @@ public function guess($path) ob_start(); // need to use --mime instead of -i. see #6641 - passthru(sprintf($this->cmd, escapeshellarg($path)), $return); + passthru(sprintf($this->cmd, escapeshellarg((0 === strpos($path, '-') ? './' : '').$path)), $return); if ($return > 0) { ob_end_clean(); diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/Fixtures/-test b/src/Symfony/Component/HttpFoundation/Tests/File/Fixtures/-test new file mode 100644 index 0000000000000000000000000000000000000000..b636f4b8df536b0a85e7cea1a6cf3f0bd3179b96 GIT binary patch literal 35 jcmZ?wbh9u|WMp7uXkcLY4+c66KmZb9U}AD%WUvMRyAlZ1 literal 0 HcmV?d00001 diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php index 3960988a6a654..0418726b5b905 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php @@ -20,7 +20,16 @@ */ class MimeTypeTest extends TestCase { - protected $path; + public function testGuessWithLeadingDash() + { + $cwd = getcwd(); + chdir(__DIR__.'/../Fixtures'); + try { + $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess('-test')); + } finally { + chdir($cwd); + } + } public function testGuessImageWithoutExtension() { From 77ddabf2e785ea85860d2720cc86f7c5d8967ed5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 19 Apr 2019 14:48:43 +0200 Subject: [PATCH 05/12] [Mime] fix guessing mime-types of files with leading dash --- .../Component/Mime/FileBinaryMimeTypeGuesser.php | 4 ++-- .../Mime/Tests/AbstractMimeTypeGuesserTest.php | 15 +++++++++++++++ .../Mime/Tests/Fixtures/mimetypes/-test | Bin 0 -> 35 bytes 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/-test diff --git a/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php b/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php index e00ce6525b71a..59e55f795bf4a 100644 --- a/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php +++ b/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php @@ -33,7 +33,7 @@ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface * * @param string $cmd The command to run to get the MIME type of a file */ - public function __construct(string $cmd = 'file -b --mime %s 2>/dev/null') + public function __construct(string $cmd = 'file -b --mime -- %s 2>/dev/null') { $this->cmd = $cmd; } @@ -76,7 +76,7 @@ public function guessMimeType(string $path): ?string ob_start(); // need to use --mime instead of -i. see #6641 - passthru(sprintf($this->cmd, escapeshellarg($path)), $return); + passthru(sprintf($this->cmd, escapeshellarg((0 === strpos($path, '-') ? './' : '').$path)), $return); if ($return > 0) { ob_end_clean(); diff --git a/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php b/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php index 3ac9382f84bc6..70e419c847d16 100644 --- a/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php +++ b/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php @@ -27,6 +27,21 @@ public static function tearDownAfterClass(): void abstract protected function getGuesser(): MimeTypeGuesserInterface; + public function testGuessWithLeadingDash() + { + if (!$this->getGuesser()->isGuesserSupported()) { + $this->markTestSkipped('Guesser is not supported'); + } + + $cwd = getcwd(); + chdir(__DIR__.'/Fixtures/mimetypes'); + try { + $this->assertEquals('image/gif', $this->getGuesser()->guessMimeType('-test')); + } finally { + chdir($cwd); + } + } + public function testGuessImageWithoutExtension() { if (!$this->getGuesser()->isGuesserSupported()) { diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/-test b/src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/-test new file mode 100644 index 0000000000000000000000000000000000000000..b636f4b8df536b0a85e7cea1a6cf3f0bd3179b96 GIT binary patch literal 35 jcmZ?wbh9u|WMp7uXkcLY4+c66KmZb9U}AD%WUvMRyAlZ1 literal 0 HcmV?d00001 From bcfc282d42798860ac6a81c062ee6ff2ce65c80f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 26 May 2019 23:06:57 +0200 Subject: [PATCH 06/12] [Security\Core] throw AccessDeniedException when switch user fails --- .../Tests/Functional/SwitchUserTest.php | 2 +- .../Bundle/SecurityBundle/composer.json | 2 +- .../Http/Firewall/SwitchUserListener.php | 22 ++++++- .../Tests/Firewall/SwitchUserListenerTest.php | 62 ++++++++++++++----- 4 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php index 31f99da2a08f2..0ccacf583fe57 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php @@ -68,7 +68,7 @@ public function getTestParameters() return [ 'unauthorized_user_cannot_switch' => ['user_cannot_switch_1', 'user_cannot_switch_1', 'user_cannot_switch_1', 403], 'authorized_user_can_switch' => ['user_can_switch', 'user_cannot_switch_1', 'user_cannot_switch_1', 200], - 'authorized_user_cannot_switch_to_non_existent' => ['user_can_switch', 'user_does_not_exist', 'user_can_switch', 500], + 'authorized_user_cannot_switch_to_non_existent' => ['user_can_switch', 'user_does_not_exist', 'user_can_switch', 403], 'authorized_user_can_switch_to_himself' => ['user_can_switch', 'user_can_switch', 'user_can_switch', 200], ]; } diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index a727e480bcf64..e864dcec876b4 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -24,7 +24,7 @@ "symfony/security-core": "~4.3", "symfony/security-csrf": "~4.2", "symfony/security-guard": "~4.2", - "symfony/security-http": "^4.3" + "symfony/security-http": "^4.3.8" }, "require-dev": { "symfony/asset": "~3.4|~4.0", diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php index e18fdd492e1d7..e383b48768d82 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php @@ -105,7 +105,8 @@ public function __invoke(RequestEvent $event) try { $this->tokenStorage->setToken($this->attemptSwitchUser($request, $username)); } catch (AuthenticationException $e) { - throw new \LogicException(sprintf('Switch User failed: "%s"', $e->getMessage())); + // Generate 403 in any conditions to prevent user enumeration vulnerabilities + throw new AccessDeniedException('Switch User failed: '.$e->getMessage(), $e); } } @@ -142,7 +143,24 @@ private function attemptSwitchUser(Request $request, $username) throw new \LogicException(sprintf('You are already switched to "%s" user.', $token->getUsername())); } - $user = $this->provider->loadUserByUsername($username); + $currentUsername = $token->getUsername(); + $nonExistentUsername = '_'.md5(random_bytes(8).$username); + + // To protect against user enumeration via timing measurements + // we always load both successfully and unsuccessfully + try { + $user = $this->provider->loadUserByUsername($username); + + try { + $this->provider->loadUserByUsername($nonExistentUsername); + throw new \LogicException('AuthenticationException expected'); + } catch (AuthenticationException $e) { + } + } catch (AuthenticationException $e) { + $this->provider->loadUserByUsername($currentUsername); + + throw $e; + } if (false === $this->accessDecisionManager->decide($token, [$this->role], $user)) { $exception = new AccessDeniedException(); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php index 4ca0553259014..44e957d0d5a5e 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; +use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\Role\SwitchUserRole; use Symfony\Component\Security\Core\User\User; use Symfony\Component\Security\Http\Event\SwitchUserEvent; @@ -174,6 +175,7 @@ public function testSwitchUserIsDisallowed() { $this->expectException('Symfony\Component\Security\Core\Exception\AccessDeniedException'); $token = new UsernamePasswordToken('username', '', 'key', ['ROLE_FOO']); + $user = new User('username', 'password', []); $this->tokenStorage->setToken($token); $this->request->query->set('_switch_user', 'kuba'); @@ -182,6 +184,31 @@ public function testSwitchUserIsDisallowed() ->method('decide')->with($token, ['ROLE_ALLOWED_TO_SWITCH']) ->willReturn(false); + $this->userProvider->expects($this->exactly(2)) + ->method('loadUserByUsername') + ->withConsecutive(['kuba']) + ->will($this->onConsecutiveCalls($user, $this->throwException(new UsernameNotFoundException()))); + + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); + $listener($this->event); + } + + public function testSwitchUserTurnsAuthenticationExceptionTo403() + { + $this->expectException('Symfony\Component\Security\Core\Exception\AccessDeniedException'); + $token = new UsernamePasswordToken('username', '', 'key', ['ROLE_ALLOWED_TO_SWITCH']); + + $this->tokenStorage->setToken($token); + $this->request->query->set('_switch_user', 'kuba'); + + $this->accessDecisionManager->expects($this->never()) + ->method('decide'); + + $this->userProvider->expects($this->exactly(2)) + ->method('loadUserByUsername') + ->withConsecutive(['kuba'], ['username']) + ->will($this->onConsecutiveCalls($this->throwException(new UsernameNotFoundException()))); + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener($this->event); } @@ -198,9 +225,10 @@ public function testSwitchUser() ->method('decide')->with($token, ['ROLE_ALLOWED_TO_SWITCH'], $user) ->willReturn(true); - $this->userProvider->expects($this->once()) - ->method('loadUserByUsername')->with('kuba') - ->willReturn($user); + $this->userProvider->expects($this->exactly(2)) + ->method('loadUserByUsername') + ->withConsecutive(['kuba']) + ->will($this->onConsecutiveCalls($user, $this->throwException(new UsernameNotFoundException()))); $this->userChecker->expects($this->once()) ->method('checkPostAuth')->with($user); @@ -224,9 +252,10 @@ public function testSwitchUserWorksWithFalsyUsernames() ->method('decide')->with($token, ['ROLE_ALLOWED_TO_SWITCH']) ->willReturn(true); - $this->userProvider->expects($this->once()) - ->method('loadUserByUsername')->with('0') - ->willReturn($user); + $this->userProvider->expects($this->exactly(2)) + ->method('loadUserByUsername') + ->withConsecutive(['0']) + ->will($this->onConsecutiveCalls($user, $this->throwException(new UsernameNotFoundException()))); $this->userChecker->expects($this->once()) ->method('checkPostAuth')->with($user); @@ -254,9 +283,10 @@ public function testSwitchUserKeepsOtherQueryStringParameters() ->method('decide')->with($token, ['ROLE_ALLOWED_TO_SWITCH'], $user) ->willReturn(true); - $this->userProvider->expects($this->once()) - ->method('loadUserByUsername')->with('kuba') - ->willReturn($user); + $this->userProvider->expects($this->exactly(2)) + ->method('loadUserByUsername') + ->withConsecutive(['kuba']) + ->will($this->onConsecutiveCalls($user, $this->throwException(new UsernameNotFoundException()))); $this->userChecker->expects($this->once()) ->method('checkPostAuth')->with($user); @@ -282,9 +312,10 @@ public function testSwitchUserWithReplacedToken() ->method('decide')->with($token, ['ROLE_ALLOWED_TO_SWITCH'], $user) ->willReturn(true); - $this->userProvider->expects($this->any()) - ->method('loadUserByUsername')->with('kuba') - ->willReturn($user); + $this->userProvider->expects($this->exactly(2)) + ->method('loadUserByUsername') + ->withConsecutive(['kuba']) + ->will($this->onConsecutiveCalls($user, $this->throwException(new UsernameNotFoundException()))); $dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $dispatcher @@ -329,9 +360,10 @@ public function testSwitchUserStateless() ->method('decide')->with($token, ['ROLE_ALLOWED_TO_SWITCH'], $user) ->willReturn(true); - $this->userProvider->expects($this->once()) - ->method('loadUserByUsername')->with('kuba') - ->willReturn($user); + $this->userProvider->expects($this->exactly(2)) + ->method('loadUserByUsername') + ->withConsecutive(['kuba']) + ->will($this->onConsecutiveCalls($user, $this->throwException(new UsernameNotFoundException()))); $this->userChecker->expects($this->once()) ->method('checkPostAuth')->with($user); From 839c6b4256190da99ed7b64e119c5b35e0c2712b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 12 Nov 2019 18:50:34 +0100 Subject: [PATCH 07/12] bumped Symfony version to 4.4.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 29756fe66c1ea..952d3a0b4f7c4 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -74,12 +74,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.4.0-BETA1'; + const VERSION = '4.4.0-DEV'; const VERSION_ID = 40400; const MAJOR_VERSION = 4; const MINOR_VERSION = 4; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'BETA1'; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2022'; const END_OF_LIFE = '11/2023'; From 1c8edc55ad7d88c876c3facb8811c20db320fe18 Mon Sep 17 00:00:00 2001 From: Teoh Han Hui Date: Tue, 12 Nov 2019 18:51:12 +0100 Subject: [PATCH 08/12] Allow returning null from NormalizerInterface::normalize --- .../Component/Serializer/Normalizer/NormalizerInterface.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php b/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php index 02a2118584923..4e0fbfb7a6b14 100644 --- a/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php +++ b/src/Symfony/Component/Serializer/Normalizer/NormalizerInterface.php @@ -30,9 +30,9 @@ interface NormalizerInterface * @param string $format Format the normalization result will be encoded as * @param array $context Context options for the normalizer * - * @return array|string|int|float|bool + * @return array|string|int|float|bool|null * - * @throws InvalidArgumentException Occurs when the object given is not an attempted type for the normalizer + * @throws InvalidArgumentException Occurs when the object given is not a supported type for the normalizer * @throws CircularReferenceException Occurs when the normalizer detects a circular reference when no circular * reference handler can fix it * @throws LogicException Occurs when the normalizer is not called in an expected context From 5db0981fd922ccb0e4c5e0f00dde7ddf57916a7c Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Tue, 12 Nov 2019 14:08:04 -0500 Subject: [PATCH 09/12] Add missing conflict with symfony/serializer <4.4 --- src/Symfony/Bundle/FrameworkBundle/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index a8d0066ec9b86..cb778933005df 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -79,7 +79,7 @@ "symfony/mime": "<4.4", "symfony/property-info": "<3.4", "symfony/security-bundle": "<4.4", - "symfony/serializer": "<4.2", + "symfony/serializer": "<4.4", "symfony/stopwatch": "<3.4", "symfony/translation": "<4.4", "symfony/twig-bridge": "<4.1.1", From bb8c82c0b5d89969aadd44d44873f69976d0233e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 5 Nov 2019 16:00:49 +0100 Subject: [PATCH 10/12] [Console] Constant STDOUT might be undefined. --- src/Symfony/Component/Console/Terminal.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Terminal.php b/src/Symfony/Component/Console/Terminal.php index 53a0f7890b6ff..43a31826270bc 100644 --- a/src/Symfony/Component/Console/Terminal.php +++ b/src/Symfony/Component/Console/Terminal.php @@ -79,7 +79,9 @@ private static function initDimensions() // or [w, h] from "wxh" self::$width = (int) $matches[1]; self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2]; - } elseif (self::hasSttyAvailable()) { + } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) { + // only use stty on Windows if the terminal does not support vt100 (e.g. Windows 7 + git-bash) + // testing for stty in a Windows 10 vt100-enabled console will implicitly disable vt100 support on STDOUT self::initDimensionsUsingStty(); } elseif (null !== $dimensions = self::getConsoleMode()) { // extract [w, h] from "wxh" @@ -91,6 +93,17 @@ private static function initDimensions() } } + /** + * Returns whether STDOUT has vt100 support (some Windows 10+ configurations). + */ + private static function hasVt100Support() + { + return \function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(fopen('php://stdout', 'w')); + } + + /** + * Initializes dimensions using the output of an stty columns line. + */ private static function initDimensionsUsingStty() { if ($sttyString = self::getSttyColumns()) { From e8325ed818818bf9ce47ee903fe234111afbd444 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 13 Nov 2019 10:13:29 +0100 Subject: [PATCH 11/12] updated CHANGELOG for 4.4.0-BETA2 --- CHANGELOG-4.4.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG-4.4.md b/CHANGELOG-4.4.md index 3d198692f7360..facb38ff1c67b 100644 --- a/CHANGELOG-4.4.md +++ b/CHANGELOG-4.4.md @@ -7,6 +7,16 @@ in 4.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.4.0...v4.4.1 +* 4.4.0-BETA2 (2019-11-13) + + * bug #34344 [Console] Constant STDOUT might be undefined (nicolas-grekas) + * security #cve-2019-18886 [Security\Core] throw AccessDeniedException when switch user fails (nicolas-grekas) + * security #cve-2019-18888 [Mime] fix guessing mime-types of files with leading dash (nicolas-grekas) + * security #cve-2019-11325 [VarExporter] fix exporting some strings (nicolas-grekas) + * security #cve-2019-18889 [Cache] forbid serializing AbstractAdapter and TagAwareAdapter instances (nicolas-grekas) + * security #cve-2019-18888 [HttpFoundation] fix guessing mime-types of files with leading dash (nicolas-grekas) + * security #cve-2019-18887 [HttpKernel] Use constant time comparison in UriSigner (stof) + * 4.4.0-BETA1 (2019-11-12) * feature #34333 Revert "feature #34329 [ExpressionLanguage] add XOR operator (ottaviano)" (nicolas-grekas) From 8c47650d531f92f61a6751e01f9bb06c5f1ee18b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 13 Nov 2019 10:13:36 +0100 Subject: [PATCH 12/12] updated VERSION for 4.4.0-BETA2 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 952d3a0b4f7c4..2b43c038a4d53 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -74,12 +74,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.4.0-DEV'; + const VERSION = '4.4.0-BETA2'; const VERSION_ID = 40400; const MAJOR_VERSION = 4; const MINOR_VERSION = 4; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = 'BETA2'; const END_OF_MAINTENANCE = '11/2022'; const END_OF_LIFE = '11/2023';