-
Notifications
You must be signed in to change notification settings - Fork 5
Description
Problem
I have a wiki running on 1.35 with $wgUseInstantCommons = true, so that Wiki Commons' assets can be referenced (e.g. State flag SVGs and more). I recently attempted an upgrade to 1.43, and while everything else looked fine, whenever visiting a page that referenced a Commons asset, the page would return back with an internal error message with the following backtrace:
[848e99a21dff03dbf92ee905] /wiki/Main_Page Error: Call to undefined method GuzzleHttp\Utils::chooseHandler()
Backtrace:
from /var/www/html/w/vendor/guzzlehttp/guzzle/src/functions.php(61)
#0 /var/www/html/forums/vendor/guzzlehttp/guzzle/src/HandlerStack.php(42): GuzzleHttp\choose_handler()
#1 /var/www/html/w/includes/http/GuzzleHttpRequest.php(164): GuzzleHttp\HandlerStack::create()
#2 /var/www/html/w/includes/filerepo/ForeignAPIRepo.php(555): GuzzleHttpRequest->execute()
#3 /var/www/html/w/includes/filerepo/ForeignAPIRepo.php(602): ForeignAPIRepo::httpGet()
#4 /var/www/html/w/includes/libs/objectcache/WANObjectCache.php(1808): ForeignAPIRepo->{closure}()
#5 /var/www/html/w/includes/libs/objectcache/WANObjectCache.php(1623): Wikimedia\ObjectCache\WANObjectCache-
>fetchOrRegenerate()
#6 /var/www/html/w/includes/filerepo/ForeignAPIRepo.php(595): Wikimedia\ObjectCache\WANObjectCache-
>getWithSetCallback()
#7 /var/www/html/w/includes/filerepo/ForeignAPIRepo.php(221): ForeignAPIRepo->httpGetCached()
#8 /var/www/html/w/includes/filerepo/file/ForeignAPIFile.php(62): ForeignAPIRepo->fetchImageQuery()
#9 /var/www/html/w/includes/filerepo/FileRepo.php(439): ForeignAPIFile::newFromTitle()
#10 /var/www/html/w/includes/filerepo/ForeignAPIRepo.php(134): FileRepo->newFile()
#11 /var/www/html/w/includes/filerepo/FileRepo.php(480): ForeignAPIRepo->newFile()
#12 /var/www/html/w/includes/filerepo/RepoGroup.php(147): FileRepo->findFile()
#13 /var/www/html/w/includes/parser/Parser.php(3825): RepoGroup->findFile()
#14 /var/www/html/w/includes/parser/Parser.php(3791): MediaWiki\Parser\Parser->fetchFileNoRegister()
#15 /var/www/html/w/includes/parser/Parser.php(5399): MediaWiki\Parser\Parser->fetchFileAndTitle()
#16 /var/www/html/w/includes/parser/Parser.php(2715): MediaWiki\Parser\Parser->makeImage()
#17 /var/www/html/w/includes/parser/Parser.php(2462): MediaWiki\Parser\Parser->handleInternalLinks2()
#18 /var/www/html/w/includes/parser/Parser.php(1627): MediaWiki\Parser\Parser->handleInternalLinks()
#19 /var/www/html/w/includes/parser/Parser.php(701): MediaWiki\Parser\Parser->internalParse()
#20 /var/www/html/w/includes/content/WikitextContentHandler.php(384): MediaWiki\Parser\Parser->parse()
#21 /var/www/html/w/includes/content/ContentHandler.php(1691): MediaWiki\Content\WikitextContentHandler-
>fillParserOutput()
#22 /var/www/html/w/includes/content/Renderer/ContentRenderer.php(79): MediaWiki\Content\ContentHandler-
>getParserOutput()
#23 /var/www/html/w/includes/Revision/RenderedRevision.php(263): MediaWiki\Content\Renderer\ContentRenderer-
>getParserOutput()
#24 /var/www/html/w/includes/Revision/RenderedRevision.php(236): MediaWiki\Revision\RenderedRevision-
>getSlotParserOutputUncached()
#25 /var/www/html/w/includes/Revision/RevisionRenderer.php(239): MediaWiki\Revision\RenderedRevision-
>getSlotParserOutput()
#26 /var/www/html/w/includes/Revision/RevisionRenderer.php(172): MediaWiki\Revision\RevisionRenderer-
>combineSlotOutput()
#27 [internal function]: MediaWiki\Revision\RevisionRenderer->MediaWiki\Revision\{closure}()
#28 /var/www/html/w/includes/Revision/RenderedRevision.php(199): call_user_func()
#29 /var/www/html/w/includes/poolcounter/PoolWorkArticleView.php(106): MediaWiki\Revision\RenderedRevision-
>getRevisionParserOutput()
#30 /var/www/html/w/includes/poolcounter/PoolWorkArticleViewCurrent.php(123):
MediaWiki\PoolCounter\PoolWorkArticleView->renderRevision()
#31 /var/www/html/w/includes/poolcounter/PoolCounterWork.php(171): MediaWiki\PoolCounter\PoolWorkArticleViewCurrent-
>doWork()
#32 /var/www/html/w/includes/page/ParserOutputAccess.php(362): MediaWiki\PoolCounter\PoolCounterWork->execute()
#33 /var/www/html/w/includes/page/Article.php(827): MediaWiki\Page\ParserOutputAccess->getParserOutput()
#34 /var/www/html/w/includes/page/Article.php(547): Article->generateContentOutput()
#35 /var/www/html/w/includes/actions/ViewAction.php(78): Article->view()
#36 /var/www/html/w/includes/actions/ActionEntryPoint.php(733): ViewAction->show()
#37 /var/www/html/w/includes/actions/ActionEntryPoint.php(510): MediaWiki\Actions\ActionEntryPoint->performAction()
#38 /var/www/html/w/includes/actions/ActionEntryPoint.php(146): MediaWiki\Actions\ActionEntryPoint->performRequest()
#39 /var/www/html/w/includes/MediaWikiEntryPoint.php(200): MediaWiki\Actions\ActionEntryPoint->execute()
#40 /var/www/html/w/index.php(58): MediaWiki\MediaWikiEntryPoint->run()
#41 {main}
Basic Repro Steps
- Use PHPBB 3.3.14 and MW 1.43 (MW 1.39 should work as well) with the following minimal
LocalSettings.phpconfig below. Please read the comments to see what to change:
<?php
if ( !defined( 'MEDIAWIKI' ) ) {
exit;
}
$wgSitename = "My Wiki";
$wgScriptExtension = ".php";
$wgScriptPath = "/w";
$wgScript = "/w/index.php";
$wgArticlePath = "/wiki/$1";
$wgUsePathInfo = true;
$wgServer = "http://192.168.42.149"; // Change to be your server host
$wgStylePath = "$wgScriptPath/skins";
$wgLogo = "$wgScriptPath/resources/assets/wiki.png";
// This just contains `$database_password`, which is an array of username to password mappings
require("/nonweb/database-passwords.php");
$wgDBtype = "mysql";
$wgDBserver = "localhost";
$wgDBname = "wiki";
$wgDBuser = "wiki";
$wgDBpassword = $database_password[$wgDBuser];
$wgDBprefix = "wiki_";
$wgDBTableOptions = "ENGINE=InnoDB, DEFAULT CHARSET=binary";
$wgDBmysql5 = false;
/*
* If you do load Phpbbauth, then turning this to false will prevent the error, but
* loading a page that requires WikiCommons resources will result in no image.
*/
$wgUseInstantCommons = true;
wfLoadSkin('Vector');
$wgDefaultSkin="vector-2022";
$wgShowExceptionDetails = true;
wfLoadExtension( 'Auth_remoteuser' );
$wgGroupPermissions['*']['createaccount'] = false;
$wgGroupPermissions['*']['autocreateaccount'] = true;
/*
* Uncommenting the two commented lines to load the extension causes the error.
* In step 2, you will uncomment those two lines to produce the error.
*/
// wfLoadExtension( 'Phpbbauth' );
$wgPhpbbAuthForumDirectory = '/var/www/html/forums/';
$wgPhpbbAuthAbsolutePath = '/forums/';
$wgPhpbbAuthNameFormat = 'phpbb';
// require_once "$IP/extensions/Phpbbauth/PhpbbAuth.php";
wfLoadExtension( 'ParserFunctions' );
Use Auth_remoteuser 2.1.1(c985d52) (use respective version for 1.39), which should be the version that the ExtensionDistributor should give for REL1_43. For phpbbauth, use master. Verify that everything works so far by going to Special:Version.
- Ensure that Commons' assets are loading on the newly installed Wiki (e.g.
[[File:State of California.svg]]), and make a page referencing them. You can also make another page without any Commons' references (e.g.Special:Version) to test the difference. You can check the file page for these Commons' assets and there should be some text stating:This file is from Wikimedia Commons and may be used by other projects. - Enable
Phpbbauthby loading it inside yourLocalSettings.php. You can do so by uncommenting thewfLoadExtensionandrequire_oncelines. If you revisit and refresh the pages that reference the Commons' asset, then the page results in the error message above. You can go and visit pages that don't reference Commons' assets and they should be able to load fine.
The Likely Cause
Looking at the backtrace, we can see the following line:
#0 /var/www/html/forums/vendor/guzzlehttp/guzzle/src/HandlerStack.php(42): GuzzleHttp\choose_handler()
#1 /var/www/html/w/includes/http/GuzzleHttpRequest.php(164): GuzzleHttp\HandlerStack::create()
which shows MW is calling a dependency within PHPBB.
Looking into the dependencies of phpBB and MW:
- phpBB 3.3.x requires
guzzlehttp/guzzle: ~6.3 - MW 1.35 strictly uses
guzzlehttp/guzzle: 6.5.8which fits ~6.3 and looking at phpBB's lock file, guzzle is pinned to6.5.8in version 3.3.14. - MW 1.39 strictly uses
guzzlehttp/guzzle: 7.4.5 - MW 1.43 strictly uses
guzzlehttp/guzzle: 7.9.2
So, looking at this, it explains why MW works on 1.35, but not 1.43, and presumably also 1.39.
I moved /forums to trigger an error to figure out who was first initializing phpBB, and it led to:
Line 31 in 763f0aa
| require $phpbb_root_path . 'common.' . $phpEx; |
And looking into phpBB's
/common.php, we can see:https://github.com/phpbb/phpbb/blob/72ae28d583dcb248fdd3d672378bfc32515facc5/phpBB/common.php#L23-L24
https://github.com/phpbb/phpbb/blob/72ae28d583dcb248fdd3d672378bfc32515facc5/phpBB/includes/startup.php#L66-L84
Basically a case where two autoloaders are being run. but have dependencies of different versions which is UB:
composer/composer#12087 (comment)
Some potential solutions
- Set env var
PHPBB_NO_COMPOSER_AUTOLOAD=1before callingcommon.php
There is some preamble about autoloading in phpBB within includes/startup.php:
// Autoloading of dependencies.
// Three options are supported:
// 1. If dependencies are installed with Composer, Composer will create a
// vendor/autoload.php. If this file exists it will be
// automatically used by phpBB. This is the default mode that phpBB
// will use when shipped.
// 2. To disable composer autoloading, PHPBB_NO_COMPOSER_AUTOLOAD can be specified.
// Additionally specify PHPBB_AUTOLOAD=/path/to/autoload.php in the
// environment. This is useful for running CLI scripts and tests.
// /path/to/autoload.php should define and register class loaders
// for all of phpBB's dependencies.
// 3. You can also set PHPBB_NO_COMPOSER_AUTOLOAD without setting PHPBB_AUTOLOAD.
// In this case autoloading needs to be defined before running any phpBB
// script. This might be useful in cases when phpBB is integrated into a
// larger program.
Might be a good place to start, but it might not be the only change that gets made.
- Handle session management manually
It is technically possible to simply handle session management manually since we should have access to phpBB's database. The big drawback that this comes with a lot of security implcations because simply checking if the session id exists and has a non-bot user id in the sessions table is simply not good enough. sid would then become a vulnerable secret if it were to be leaked without the IP, user-agent, and referrer checks, and looking at the User::session_begin() functions show a lot of business logic to simply validate a session.