-
Notifications
You must be signed in to change notification settings - Fork 85
Fix infinite recursion in Outbox::add() causing OOM #3146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: patch | ||
| Type: fixed | ||
|
|
||
| Fix an infinite loop when saving activities to the outbox on sites where the outbox post type passes through content filters. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -429,6 +429,70 @@ public function undo_object_provider() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Test that Outbox::add() does not cause infinite recursion via Post::triage(). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * When wp_insert_post() fires inside Outbox::add(), it triggers wp_after_insert_post, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * which could re-enter Post::triage() → add_to_outbox() → Outbox::add() in an infinite | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * loop if the triage hook is not temporarily removed. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @covers ::add | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public function test_add_does_not_recurse_via_post_triage() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Ensure the triage hook is registered as a baseline. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| \add_action( 'wp_after_insert_post', array( \Activitypub\Scheduler\Post::class, 'triage' ), 33, 4 ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $triage_hooked_during_insert = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check whether Post::triage is hooked when wp_after_insert_post fires | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // during the outbox insert. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| \add_action( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'wp_after_insert_post', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function ( $post_id ) use ( &$triage_hooked_during_insert ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( Outbox::POST_TYPE === \get_post_type( $post_id ) ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $triage_hooked_during_insert = \has_action( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'wp_after_insert_post', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| array( \Activitypub\Scheduler\Post::class, 'triage' ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 0 // Run before priority 33 to inspect hook state. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $object = new Base_Object(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $object->set_id( 'https://example.com/recursion-test' ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $object->set_type( 'Note' ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $object->set_content( '<p>Recursion test</p>' ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $id = \Activitypub\add_to_outbox( $object, 'Create', self::$user_id ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $this->assertIsInt( $id ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| $this->assertFalse( $triage_hooked_during_insert, 'Post::triage should be unhooked during Outbox::add() to prevent recursion.' ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+446
to
+470
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check whether Post::triage is hooked when wp_after_insert_post fires | |
| // during the outbox insert. | |
| \add_action( | |
| 'wp_after_insert_post', | |
| function ( $post_id ) use ( &$triage_hooked_during_insert ) { | |
| if ( Outbox::POST_TYPE === \get_post_type( $post_id ) ) { | |
| $triage_hooked_during_insert = \has_action( | |
| 'wp_after_insert_post', | |
| array( \Activitypub\Scheduler\Post::class, 'triage' ) | |
| ); | |
| } | |
| }, | |
| 0 // Run before priority 33 to inspect hook state. | |
| ); | |
| $object = new Base_Object(); | |
| $object->set_id( 'https://example.com/recursion-test' ); | |
| $object->set_type( 'Note' ); | |
| $object->set_content( '<p>Recursion test</p>' ); | |
| $id = \Activitypub\add_to_outbox( $object, 'Create', self::$user_id ); | |
| $this->assertIsInt( $id ); | |
| $this->assertFalse( $triage_hooked_during_insert, 'Post::triage should be unhooked during Outbox::add() to prevent recursion.' ); | |
| $inspect_triage_hook = function ( $post_id ) use ( &$triage_hooked_during_insert ) { | |
| if ( Outbox::POST_TYPE === \get_post_type( $post_id ) ) { | |
| $triage_hooked_during_insert = \has_action( | |
| 'wp_after_insert_post', | |
| array( \Activitypub\Scheduler\Post::class, 'triage' ) | |
| ); | |
| } | |
| }; | |
| // Check whether Post::triage is hooked when wp_after_insert_post fires | |
| // during the outbox insert. | |
| \add_action( | |
| 'wp_after_insert_post', | |
| $inspect_triage_hook, | |
| 0 // Run before priority 33 to inspect hook state. | |
| ); | |
| try { | |
| $object = new Base_Object(); | |
| $object->set_id( 'https://example.com/recursion-test' ); | |
| $object->set_type( 'Note' ); | |
| $object->set_content( '<p>Recursion test</p>' ); | |
| $id = \Activitypub\add_to_outbox( $object, 'Create', self::$user_id ); | |
| $this->assertIsInt( $id ); | |
| $this->assertFalse( $triage_hooked_during_insert, 'Post::triage should be unhooked during Outbox::add() to prevent recursion.' ); | |
| } finally { | |
| \remove_action( 'wp_after_insert_post', $inspect_triage_hook, 0 ); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$has_triageis derived fromhas_action(), but the removal is hard-coded to priority 33. IfPost::triageis attached at a different priority (or multiple priorities), this will leave it hooked and the recursion/OOM can still occur; additionally, the re-add always forces priority 33 even if it was different before. Consider capturing the priority returned byhas_action()and removing/restoring at that priority (and/or removing all priorities where the callback is registered).