From 40fe496eda529fd1d933b56a1022ec32d3cd0b12 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Wed, 24 Jul 2024 23:54:09 +0200 Subject: [PATCH 1/2] Fix regression introduced in `GHSA-cjcc-p67m-7qxm` while attaching behavior defined by `__class` array key --- framework/CHANGELOG.md | 3 +-- framework/base/Component.php | 2 +- tests/framework/base/ComponentTest.php | 3 +++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 96f41456dc..0185dbb783 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,8 +4,7 @@ Yii Framework 2 Change Log 2.0.52 under development ------------------------ -- no changes in this release. - +- Bug #20232: Fix regression introduced in `GHSA-cjcc-p67m-7qxm` while attaching behavior defined by `__class` array key (erickskrauch) 2.0.51 July 18, 2024 -------------------- diff --git a/framework/base/Component.php b/framework/base/Component.php index 2ad62f3259..7cee3b0720 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -190,7 +190,7 @@ class Component extends BaseObject $name = trim(substr($name, 3)); if ($value instanceof Behavior) { $this->attachBehavior($name, $value); - } elseif (isset($value['class']) && is_subclass_of($value['class'], Behavior::class, true)) { + } elseif ((isset($value['class']) && is_subclass_of($value['class'], Behavior::class)) || (isset($value['__class']) && is_subclass_of($value['__class'], Behavior::class))) { $this->attachBehavior($name, Yii::createObject($value)); } elseif (is_string($value) && is_subclass_of($value, Behavior::class, true)) { $this->attachBehavior($name, Yii::createObject($value)); diff --git a/tests/framework/base/ComponentTest.php b/tests/framework/base/ComponentTest.php index f01d21476f..dca3c37bd9 100644 --- a/tests/framework/base/ComponentTest.php +++ b/tests/framework/base/ComponentTest.php @@ -341,6 +341,9 @@ class ComponentTest extends TestCase $this->assertTrue($component->hasProperty('p')); $component->test(); $this->assertTrue($component->behaviorCalled); + + $component->{'as c'} = ['__class' => NewBehavior::class]; + $this->assertNotNull($component->getBehavior('c')); } public function testAttachBehaviors() From 4b75427011376ebf7de93a11c366835fe464338e Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Wed, 14 Aug 2024 16:49:26 +0200 Subject: [PATCH 2/2] Fix regression of regression introduced in `GHSA-cjcc-p67m-7qxm` and #20232 --- framework/base/Component.php | 4 ++- tests/framework/base/ComponentTest.php | 36 ++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/framework/base/Component.php b/framework/base/Component.php index 7cee3b0720..7838f4b1da 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -190,7 +190,9 @@ class Component extends BaseObject $name = trim(substr($name, 3)); if ($value instanceof Behavior) { $this->attachBehavior($name, $value); - } elseif ((isset($value['class']) && is_subclass_of($value['class'], Behavior::class)) || (isset($value['__class']) && is_subclass_of($value['__class'], Behavior::class))) { + } elseif (isset($value['__class']) && is_subclass_of($value['__class'], Behavior::class)) { + $this->attachBehavior($name, Yii::createObject($value)); + } elseif (!isset($value['__class']) && isset($value['class']) && is_subclass_of($value['class'], Behavior::class)) { $this->attachBehavior($name, Yii::createObject($value)); } elseif (is_string($value) && is_subclass_of($value, Behavior::class, true)) { $this->attachBehavior($name, Yii::createObject($value)); diff --git a/tests/framework/base/ComponentTest.php b/tests/framework/base/ComponentTest.php index dca3c37bd9..d16671a5fa 100644 --- a/tests/framework/base/ComponentTest.php +++ b/tests/framework/base/ComponentTest.php @@ -10,6 +10,8 @@ namespace yiiunit\framework\base; use yii\base\Behavior; use yii\base\Component; use yii\base\Event; +use yii\base\InvalidConfigException; +use yii\base\UnknownMethodException; use yiiunit\TestCase; function globalEventHandler($event) @@ -331,19 +333,39 @@ class ComponentTest extends TestCase $this->assertSame($behavior, $component->detachBehavior('a')); $this->assertFalse($component->hasProperty('p')); - $this->expectException('yii\base\UnknownMethodException'); - $component->test(); + try { + $component->test(); + $this->fail('Expected exception ' . UnknownMethodException::class . " wasn't thrown"); + } catch (UnknownMethodException $e) { + // Expected + } - $p = 'as b'; $component = new NewComponent(); - $component->$p = ['class' => 'NewBehavior']; - $this->assertSame($behavior, $component->getBehavior('a')); + $component->{'as b'} = ['class' => NewBehavior::class]; + $this->assertInstanceOf(NewBehavior::class, $component->getBehavior('b')); $this->assertTrue($component->hasProperty('p')); $component->test(); $this->assertTrue($component->behaviorCalled); $component->{'as c'} = ['__class' => NewBehavior::class]; $this->assertNotNull($component->getBehavior('c')); + + $component->{'as d'} = [ + '__class' => NewBehavior2::class, + 'class' => NewBehavior::class, + ]; + $this->assertInstanceOf(NewBehavior2::class, $component->getBehavior('d')); + + // CVE-2024-4990 + try { + $component->{'as e'} = [ + '__class' => 'NotExistsBehavior', + 'class' => NewBehavior::class, + ]; + $this->fail('Expected exception ' . InvalidConfigException::class . " wasn't thrown"); + } catch (InvalidConfigException $e) { + $this->assertSame('Class is not of type yii\base\Behavior or its subclasses', $e->getMessage()); + } } public function testAttachBehaviors() @@ -546,6 +568,10 @@ class NewBehavior extends Behavior } } +class NewBehavior2 extends Behavior +{ +} + class NewComponent2 extends Component { public $a;