| @@ -173,16 +173,31 @@ | ||
| 173 | 173 | |
| 174 | 174 | /** |
| 175 | 175 | * Constructs the object. |
| 176 | 176 | * |
| 177 | - * {@internal The magic methods take precedence over the Serializable interface. | |
| 178 | - * This means that in practice, this method will now only be called on PHP < 7.4. | |
| 179 | - * For PHP 7.4 and higher, the magic methods will be used instead.} | |
| 177 | + * {@internal Unlike `serialize()` above, this method is NOT superseded by its magic counterpart | |
| 178 | + * on PHP 7.4 and higher, so it is live code on every supported PHP version. PHP selects the | |
| 179 | + * handler based on the *format* of the payload being read, not on the PHP version: `O:`-format | |
| 180 | + * payloads are routed to `__unserialize()`, whereas `C:`-format payloads are dispatched here, | |
| 181 | + * because this class implements `Serializable`. Verified on PHP 7.4 through 8.3. | |
| 182 | + * There is no call to this method anywhere in the codebase; the engine invokes it.} | |
| 180 | 183 | * |
| 184 | + * {@internal `$data` must be treated as untrusted. `C:`-format payloads survive WordPress | |
| 185 | + * unaltered on the way into the database, because `is_serialized()` has no case for `C` and | |
| 186 | + * `maybe_serialize()` therefore stores such a string verbatim rather than escaping it. Any code | |
| 187 | + * path that unserializes third-party data can consequently reach this method with a crafted | |
| 188 | + * payload. | |
| 189 | + * The nested call is restricted with `allowed_classes => false` for that reason: a legitimate | |
| 190 | + * payload only ever contains the two strings produced by `__serialize()`, so instantiating a | |
| 191 | + * class here is never valid, and permitting it turns this method into an object-injection sink | |
| 192 | + * that ends in an arbitrary `__destruct()`. Do not relax that restriction.} | |
| 193 | + * | |
| 181 | 194 | * {@internal The Serializable interface is being phased out, in favour of the magic methods. |
| 182 | - * This method should be deprecated and removed and the class should no longer | |
| 183 | - * implement the `Serializable` interface. | |
| 184 | - * This change, however, can't be made until the minimum PHP version goes up to PHP 7.4 or higher.} | |
| 195 | + * This method should be deprecated and removed and the class should no longer implement the | |
| 196 | + * `Serializable` interface. The minimum supported PHP version has since risen to 7.4, so that is | |
| 197 | + * now possible, but it is deliberately left as a separate change: dropping the interface alters | |
| 198 | + * how sitemap caches originally written on PHP < 7.4 are handled, as PHP then returns an empty | |
| 199 | + * instance for those payloads instead of a populated one.} | |
| 185 | 200 | * |
| 186 | 201 | * @link http://php.net/manual/en/serializable.unserialize.php |
| 187 | 202 | * @link https://wiki.php.net/rfc/phase_out_serializable |
| 188 | 203 | * |
| @@ -187,14 +202,15 @@ | ||
| 187 | 202 | * @link https://wiki.php.net/rfc/phase_out_serializable |
| 188 | 203 | * |
| 189 | 204 | * @since 5.1.0 |
| 190 | 205 | * |
| 191 | - * @param string $data The string representation of the object in C or O-format. | |
| 206 | + * @param string $data Untrusted serialized representation of the data array, as carried in the | |
| 207 | + * body of a `C:`-format payload naming this class. | |
| 192 | 208 | * |
| 193 | 209 | * @return void |
| 194 | 210 | */ |
| 195 | 211 | public function unserialize( $data ) { |
| 196 | 212 | |
| 197 | - $data = unserialize( $data ); | |
| 213 | + $data = unserialize( $data, [ 'allowed_classes' => false ] ); | |
| 198 | 214 | $this->__unserialize( $data ); |
| 199 | 215 | } |
| 200 | 216 | } |