Page MenuHomePhabricator

Attempting to block a locked/hidden user causes Fatal TypeError from DatabaseBlock::equals()
Closed, ResolvedPublicPRODUCTION ERROR

Description

Hello,

I got the following exception:

[ecd6466c-929a-4f51-a1c4-f3fb65e75675] 2020-07-30 05:10:41: Fatal exception of type "TypeError"

I was trying to locally suppress block a user, who was already globally locked and hidden. I knew they were glocked, but not that they were hidden, the user interface in this area is not terribly clear or consistent. If this is intended to throw an error, that's fine, but it should throw a real error explaining the situation and not an exception.

Error

error
Fatal TypeError:  Argument 1 passed to MediaWiki\Block\DatabaseBlock::equals() must be an instance of MediaWiki\Block\DatabaseBlock, null given
trace
#0 /srv/mediawiki/php-1.36.0-wmf.1/includes/specials/SpecialBlock.php(969): MediaWiki\Block\DatabaseBlock->equals(NULL)
#1 /srv/mediawiki/php-1.36.0-wmf.1/includes/specials/SpecialBlock.php(1235): SpecialBlock::processForm(array, RequestContext)
#2 /srv/mediawiki/php-1.36.0-wmf.1/includes/htmlform/HTMLForm.php(707): SpecialBlock->onSubmit(array, OOUIHTMLForm)
#3 /srv/mediawiki/php-1.36.0-wmf.1/includes/htmlform/HTMLForm.php(597): HTMLForm->trySubmit()
#4 /srv/mediawiki/php-1.36.0-wmf.1/includes/htmlform/HTMLForm.php(613): HTMLForm->tryAuthorizedSubmit()
#5 /srv/mediawiki/php-1.36.0-wmf.1/includes/specialpage/FormSpecialPage.php(187): HTMLForm->show()
#6 /srv/mediawiki/php-1.36.0-wmf.1/includes/specialpage/SpecialPage.php(600): FormSpecialPage->execute(string)
#7 /srv/mediawiki/php-1.36.0-wmf.1/includes/specialpage/SpecialPageFactory.php(635): SpecialPage->run(string)
#8 /srv/mediawiki/php-1.36.0-wmf.1/includes/MediaWiki.php(307): MediaWiki\SpecialPage\SpecialPageFactory->executePath(Title, RequestContext)
#9 /srv/mediawiki/php-1.36.0-wmf.1/includes/MediaWiki.php(940): MediaWiki->performRequest()
#10 /srv/mediawiki/php-1.36.0-wmf.1/includes/MediaWiki.php(543): MediaWiki->main()
#11 /srv/mediawiki/php-1.36.0-wmf.1/index.php(53): MediaWiki->run()
#12 /srv/mediawiki/php-1.36.0-wmf.1/index.php(46): wfIndexMain()
#13 /srv/mediawiki/w/index.php(3): require(string)
#14 {main}
`

Event Timeline

JJMC89 changed the subtype of this task from "Task" to "Production Error".Jul 30 2020, 5:50 AM
Aklapper renamed this task from Attempting to block a user that is already locked and hidden causes an exception to Attempting to block a user already locked and hidden causes exception: Argument 1 passed to MediaWiki\Block\DatabaseBlock::equals() must be an instance of MediaWiki\Block\DatabaseBlock, null given, called in includes/specials/SpecialBlock.php:969.Jul 30 2020, 8:08 AM
Aklapper set Request URL to https://www.mediawiki.org/wiki/Special:Block/Username.
Aklapper set Request ID to ecd6466c-929a-4f51-a1c4-f3fb65e75675.
Aklapper edited Stack Trace. (Show Details)
Aklapper set Phatality ID to fb8436701e5fed81958460aeb2ae8eaf89ffb540c5be4c99df3ae34d62f69d77.

Looks to me like a one-off failure (though can handling can still be imporoved). Or are you able to reproduce it deterministically @ST47?

I can reliably reproduce it, it does not seem to be intermittent or one-off.

[d612231b-0f01-4ad0-8a5d-6d3f8fcd2690] 2020-08-04 06:54:29: Fatal exception of type "TypeError"

[ccf90188-6d78-4926-8718-9e4bc8c61f99] 2020-08-04 06:55:26: Fatal exception of type "TypeError"

Ammarpad triaged this task as Medium priority.EditedAug 4 2020, 7:48 AM

OK thanks. I guess the issue is rare because it's not common that we want locally block a globally locked and hidden user. But still this needs to be handled garcefully.

The problem comes from assuming in SpecialBlock that DatabaseBlock::newFromTarget always retrieves a block if a block against that target couldn't be inserted: https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/ecced5cc1bfab4d41c62b8c6062935742b28a974/includes/specials/SpecialBlock.php#969

We should check that $currentBlock is a block before passing it to equals. If it is not, we should display an error message... The question is what this should say.

I can't reproduce this locally by trying to locally suppress a user who is globally blocked and hidden, so I'm not sure if it's specific to that case.

@ST47 Was the existing block new at the time? It could be that the block existed on the primary database, but did not yet exist on the replicas, in which case the insert would not be possible, but no block would be retrieved either.

Change 619436 had a related patch set uploaded (by Tchanders; owner: Tchanders):
[mediawiki/core@master] SpecialBlock: Show error if a block could not be inserted or found

https://gerrit.wikimedia.org/r/619436

@Tchanders The first time, yes, but when I re-tested it on august 4th, I used the same account as when I originally reported the bug. So it would have been blocked for several days at that point.

Is it possible that the account was already blocked, but because the block log was suppressed, DatabaseBlock::newFromTarget( $target ) fails to return it?

Change 619436 merged by jenkins-bot:
[mediawiki/core@master] SpecialBlock: Show error if a block could not be inserted or found

https://gerrit.wikimedia.org/r/619436

Change 620034 had a related patch set uploaded (by Reedy; owner: Tchanders):
[mediawiki/core@REL1_35] SpecialBlock: Show error if a block could not be inserted or found

https://gerrit.wikimedia.org/r/620034

Change 620034 merged by jenkins-bot:
[mediawiki/core@REL1_35] SpecialBlock: Show error if a block could not be inserted or found

https://gerrit.wikimedia.org/r/620034

@ST47 Thanks for the additional info. The log suppression shouldn't make a difference (it was also suppressed in my local test).

Another possibility is that there is no existing block, but that the block insert is failing for another reason. Does the block definitely exist?

The patch above fixes the error, but the message displayed to the user assumes that the error is caused by databases being out of sync. Until we can work out where the problem arose from in @ST47's case, this isn't entirely resolved.

@Tchanders I guess I don't know. On the contributions page, there are links to "change block" or "unblock" (rather than "block"). However, there is no block log that I can see. The username is hidden for good reason, but the user ID (on enwiki, at least) is 39840215.

I think the core cause of this is T260485.

I agree - in this case, the block exists but can't be loaded properly because of T260485: CentralAuth uses wrong actor ID when locally suppressing the user (CVE-2020-25869).

Does this error always come from T260485?

According to logstash the error has been encountered on a few wikis, since May 2020. Most of those wikis have blocks with the wrong actor ID (examples in T260485#6389423).

However, hewiktionary threw this error but has no blocks like this. It's perhaps unlikely that there was a block that was since deleted, since these blocks can't be deleted via the UI.

This might mean that the error can be encountered in situations other than T260485.

What should we do?

So far, we've merged a patch that:

  • Stops an error being thrown
  • Shows an error message to the user, saying the databases may be out of sync

Now we know more, I think we should:

  • Log a warning to logstash
  • Change the error message to say that the block could not be inserted, but an existing block could not be loaded. I'm not sure what the call to action should be though...

The call to action should be "create a task at Phabricator", because no one but sysadmins can fix this issue, I'm afraid. I agree with your proposal.

Change 620747 had a related patch set uploaded (by Tchanders; owner: Tchanders):
[mediawiki/core@master] SpecialBlock: Make error more generic if block not inserted/found

https://gerrit.wikimedia.org/r/620747

Change 620747 merged by jenkins-bot:
[mediawiki/core@master] SpecialBlock: Make error more generic if block not inserted/found

https://gerrit.wikimedia.org/r/620747

Change 621505 had a related patch set uploaded (by Reedy; owner: Tchanders):
[mediawiki/core@REL1_35] SpecialBlock: Make error more generic if block not inserted/found

https://gerrit.wikimedia.org/r/621505

Change 621505 merged by jenkins-bot:
[mediawiki/core@REL1_35] SpecialBlock: Make error more generic if block not inserted/found

https://gerrit.wikimedia.org/r/621505

dom_walden subscribed.

I cannot reproduce the bug on beta (MediaWiki 1.36.0-alpha (9aac9cb) 10:09, 24 August 2020) using the below steps:

  1. Went to https://en.wikipedia.beta.wmflabs.org/w/index.php?title=Special:CentralAuth&target=Drwpr and set status to "Account is hidden completely"
  2. Went to https://en.wikivoyage.beta.wmflabs.org/wiki/Special:BlockList and checked that the block is not listed (i.e. it has an incorrect ipb_by_actor and so cannot be loaded)
  3. Went to https://en.wikivoyage.beta.wmflabs.org/wiki/Special:Block and attempted to hide/suppress Drwpr

After checking the Confirm box, the form returns the validation message: The block could not be made, but no existing block was found for "Drwpr". If this problem persists, please report it. (with the "report it" link going to https://www.mediawiki.org/wiki/Help_talk:Blocking_users)

On my local vagrant (MediaWiki 1.36.0-alpha (3e92cf9)), I attempted to reproduce with a few different types of blocks. I didn't see any exceptions on the page or in the logs. The Special:Block form always returned a reasonable error.

I also tried to reproduce with API:Block, which returned: ipb-block-not-found: The block could not be made, but no existing block was found for "$user". If this problem persists, please [https://www.mediawiki.org/wiki/Special:MyLanguage/Help_talk:Blocking_users report it].

I also confirmed that when the new error appears the logs record: [BlockManager] Block could not be inserted. No existing block was found.

Krinkle renamed this task from Attempting to block a user already locked and hidden causes exception: Argument 1 passed to MediaWiki\Block\DatabaseBlock::equals() must be an instance of MediaWiki\Block\DatabaseBlock, null given, called in includes/specials/SpecialBlock.php:969 to Attempting to block a locked/hidden user causes Fatal TypeError from DatabaseBlock::equals().Sep 22 2020, 1:03 AM
Krinkle updated the task description. (Show Details)
Krinkle edited Stack Trace. (Show Details)