[wp-trac] [WordPress Trac] #34392: calling update_option("siteurl", $newval) can overwrite it with an instance of WP_Error.

WordPress Trac noreply at wordpress.org
Wed Oct 21 17:41:52 UTC 2015


#34392: calling update_option("siteurl", $newval) can overwrite it with an instance
of WP_Error.
--------------------------+-----------------------------
 Reporter:  pbogdan       |      Owner:
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  General       |    Version:  4.3.1
 Severity:  normal        |   Keywords:
  Focuses:                |
--------------------------+-----------------------------
 Hello,

 under admittedly somewhat obscure circumstances a call to
 update_option("siteurl", ...) can overwrite its value with an instance of
 WP_Error class.

 When being updated `siteurl` is subject to some additional checks in
 `sanitize_option()` function, and the bug is due its handling of
 WP_Error's.

 In particular the code at
 https://github.com/WordPress/WordPress/blob/4.3.1/wp-
 includes/formatting.php#L3609-L3612:

 - overwrites the `$value` variable with result of the call to
   `$wpdb->strip_invalid_text_for_column()` -
 - will only create the `$error` variable if the WP_Error received from the
 call
   to `$wpdb->strip_invalid_text_for_column()` contains the optional error
   message

 If `$wpdb->strip_invalid_text_for_column()` returns an instance of
 WP_Error
 without an error message we end up with `$value` containing a WP_Error
 instance
 but empty `$error` variable.

 Then the check at
 https://github.com/WordPress/WordPress/blob/4.3.1/wp-
 includes/formatting.php#L3720
 fails due to empty `$error`, and the WP_Error `$value` propagates upwards
 as the
 return result of `sanitize_option()`, to be written into the database. As
 most
 places trust get_option("siteurl") to return a string rather than an
 object this
 results in fatal errors as WP_Error can't be converted to a string.

 In the specific case I observed, the WP_Error instance without an error
 message
 was originating from `wpdb::get_table_charset()` function -
 https://github.com/WordPress/WordPress/blob/4.3.1/wp-includes/wp-
 db.php#L2306-L2308. From
 what I gather `wpdb::strip_invalid_text_for_column()` needs to know the
 database
 charset for the database column to determine valid input, this will
 eventually
 call out to `wpdb::get_table_charset()` and if the query in that function
 fails
 for some reason the resulting WP_Error propagates all the way up to
 `sanitize_option()`.

 As this was tracked down retrospectively I don't know what exact
 conditions
 allowed the query in `wpdb::get_table_charset()` to fail while allowing
 any
 subsequent queries to succeed, however it can be reproduced with a test
 case at
 https://gist.github.com/pbogdan/9827a8f2358cf9e8ca71

 I have not reviewed the logic for other options handled by
 `sanitize_option()`
 but it's possible some of them could be affected if they use the same
 logic for
 dealing with WP_Error's - which relies on the WP_Error having the optional
 error
 message.

 I might be bit slow to respond but let me know if there is any additional
 information I can provide.


 Thanks,
 Piotr

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


More information about the wp-trac mailing list