[wp-trac] [WordPress Trac] #53986: Problematic error-handling in sanitize_option()

WordPress Trac noreply at wordpress.org
Mon Aug 23 21:25:14 UTC 2021


#53986: Problematic error-handling in sanitize_option()
--------------------------------+-----------------------------
 Reporter:  iCaleb              |      Owner:  (none)
     Type:  defect (bug)        |     Status:  new
 Priority:  normal              |  Milestone:  Awaiting Review
Component:  Options, Meta APIs  |    Version:  trunk
 Severity:  normal              |   Keywords:
  Focuses:                      |
--------------------------------+-----------------------------
 Given a very unfortunate series of events, it's possible for a site to
 brick itself from a call to `update_option()` on even a FE request that
 should have just resulted in no update (option value was not changing).
 Introduced in https://core.trac.wordpress.org/ticket/32350

 == What happens

 1. Error is thrown here due to a query failure:
 https://github.com/WordPress/WordPress/blob/270f2011f8ec7265c3f4ddce39c77ef5b496ed1c
 /wp-includes/wp-db.php#L2776
 2. Error is eventually returned here for say `category_base`:
 https://github.com/WordPress/WordPress/blob/b60a512de42c0a2ce2fa258e9be70bedb29b337c
 /wp-includes/formatting.php#L4853-L4855
 3. But this fails to catch the error:
 https://github.com/WordPress/WordPress/blob/b60a512de42c0a2ce2fa258e9be70bedb29b337c
 /wp-includes/formatting.php#L4890

 Why you ask?

 {{{
 $value = new WP_Error( 'wpdb_get_table_charset_failure' );
 $error = $value->get_error_message();
 => string(0) ""
 }}}

 == Replicating

 Replicating the true process of how things go badly is not very easy, as
 you need certain queries to pass along the way and very specific ones to
 fail. But an easier replication can be done like so:

 {{{
 wp shell

 $option_value = new WP_Error( 'wpdb_get_table_charset_failure' );
 update_option( 'category_base', $option_value );
 }}}

 Note that this will immediately brick the site. To cleanup, will need to
 delete the options from the database manually:

 {{{
 delete from wp_options where option_name = 'rewrite_rules';
 delete from wp_options where option_name = 'category_base';
 }}}

 And if using object cache, need to clear that out as well. Comment out
 this line
 https://github.com/WordPress/WordPress/blob/94c655c89286fdf43e5bab82d4108fb679e46a7a
 /wp-includes/default-filters.php#L580, and `wp cache flush`.

 == Resolution

 Patch incoming, but defaulting the $error to `null` in sanitize_option()
 and checking against that specifically will help future-proof this. And
 then to be more descriptive in the error handling, can also add error
 descriptions to `WP_Error`'s where needed.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/53986>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list