Make WordPress Core

Opened 3 years ago

Last modified 2 months ago

#59588 new defect (bug)

False returned instead of default value on get_option with failure of unserializing data.

Reported by: cweberdc's profile cweberDC Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 6.3.2
Component: Widgets Keywords: has-patch has-unit-tests
Focuses: Cc:

Description

Hello, I noticed a bug with the ability to load the customize screen of any theme if there is a malformed option value set.

I noticed from wp-includes/class-wp-customize-widgets.php

<?php
customize_register();

this performs an array_merge which throws an error with the 3rd argument being returned is not an array and instead false

in wp-includes/widgets.php

<?php
wp_get_sidebars_widgets();

This calls

<?php
$sidebars_widgets = get_option( 'sidebars_widgets', array() );

I found that the end of the function in the apply_filters (line 255) is calling maybe_unserialize in the call. The issue with this is if the option value is malformed and the serializing returns False. That gets passed back to when it is trying to merge the arrays. I added some code as a test and it worked after I changed to the following

<?php
    $data = maybe_unserialize($value);

    if (!$data && $default_value !== false && gettype($data) !== gettype($default_value))
        $data = $default_value;

    return apply_filters( "option_{$option}", $data, $option );
}

The idea I tried to solve for is if a default value has been passed in but the value we are about to return is not what the receiving function is expecting then it should try to make sure it is at least passing back the expected type of the default value.

Attachments (1)

option.php (80.9 KB) - added by cweberDC 3 years ago.
option.php file with my code changes for example

Download all attachments as: .zip

Change History (3)

@cweberDC
3 years ago

option.php file with my code changes for example

This ticket was mentioned in PR #11500 on WordPress/wordpress-develop by @kalpeshh.


2 months ago
#1

  • Keywords has-patch has-unit-tests added; needs-patch removed

## Problem

When an option exists in the DB with corrupted/truncated serialized data,
@unserialize() returns false, which get_option() passes back to the
caller instead of the provided $default_value.


## Solution


After calling maybe_unserialize(), detect a failed unserialization:
stored value is serialized + result is false + value is not b:0;
(the valid serialization of boolean false). In that case, fall back to
$default_value via the default_option_{$option} filter.


## Tests


Two new cases in tests/phpunit/tests/option/option.php:

  • Corrupted serialized data → default value is returned.
  • b:0; stored value → false is correctly returned, not the default.


Trac: https://core.trac.wordpress.org/ticket/59588

#2 @kalpeshh
2 months ago

I've created a patch for this issue.

The fix saves the raw DB value before calling maybe_unserialize(), then checks if unserialization failed (result is false, value was serialized, and value is not b:0; — the valid serialization of boolean false). In that case, $default_value is returned instead.

Two tests are included: one for corrupted serialized data returning the default, and one confirming a legitimately stored false still returns false.

PR: https://github.com/WordPress/wordpress-develop/pull/11500

Note: See TracTickets for help on using tickets.