1
0
Fork 0
mirror of https://github.com/composer/composer synced 2025-05-10 17:12:51 +00:00

Fix Composer autoloader being hijackable by script/plugin event handlers (#11955)

This commit is contained in:
Jordi Boggiano 2024-04-29 11:41:33 +02:00 committed by GitHub
parent d4396a85bf
commit bcab1c4b8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 50 additions and 22 deletions

View file

@ -194,6 +194,8 @@ class EventDispatcher
$this->pushEvent($event);
$autoloadersBefore = spl_autoload_functions();
try {
$returnMax = 0;
foreach ($listeners as $callable) {
@ -411,6 +413,26 @@ class EventDispatcher
}
} finally {
$this->popEvent();
$knownIdentifiers = [];
foreach ($autoloadersBefore as $key => $cb) {
$knownIdentifiers[$this->getCallbackIdentifier($cb)] = ['key' => $key, 'callback' => $cb];
}
foreach (spl_autoload_functions() as $cb) {
// once we get to the first known autoloader, we can leave any appended autoloader without problems
if (isset($knownIdentifiers[$this->getCallbackIdentifier($cb)]) && $knownIdentifiers[$this->getCallbackIdentifier($cb)]['key'] === 0) {
break;
}
// other newly appeared prepended autoloaders should be appended instead to ensure Composer loads its classes first
if ($cb instanceof ClassLoader) {
$cb->unregister();
$cb->register(false);
} else {
spl_autoload_unregister($cb);
spl_autoload_register($cb);
}
}
}
return $returnMax;
@ -638,4 +660,20 @@ class EventDispatcher
}
}
}
private function getCallbackIdentifier(callable $cb): string
{
if (is_string($cb)) {
return 'fn:'.$cb;
}
if (is_object($cb)) {
return 'obj:'.spl_object_hash($cb);
}
if (is_array($cb)) {
return 'array:'.(is_string($cb[0]) ? $cb[0] : get_class($cb[0]) .'#'.spl_object_hash($cb[0])).'::'.$cb[1];
}
// not great but also do not want to break everything here
return 'unsupported';
}
}