From 854cf56a7dfcd457a485e80ffb78c6b04d412aea Mon Sep 17 00:00:00 2001 From: markjaquith Date: Thu, 12 Oct 2006 23:54:36 +0000 Subject: [PATCH] Prevent users from entering strings that will be interpreted as serialized arrays/objects on the way out. fixes #2591 git-svn-id: http://svn.automattic.com/wordpress/trunk@4382 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/admin-functions.php | 18 ++++++++++++++-- wp-admin/options.php | 32 +++++++++++++++++---------- wp-admin/wp-admin.css | 4 ++++ wp-includes/functions.php | 42 +++++++++++++++++++++++++++++------- wp-includes/pluggable.php | 8 ++----- wp-includes/post.php | 17 +++++++-------- wp-includes/user.php | 7 +++--- 7 files changed, 89 insertions(+), 39 deletions(-) diff --git a/wp-admin/admin-functions.php b/wp-admin/admin-functions.php index fe222adc64..20688f7cec 100644 --- a/wp-admin/admin-functions.php +++ b/wp-admin/admin-functions.php @@ -981,6 +981,18 @@ function list_meta($meta) { $style = ''; if ('_' == $entry['meta_key'] { 0 }) $style .= ' hidden'; + + if ( is_serialized($entry['meta_value']) ) { + if ( 's' == $entry['meta_value']{0} ) { + // this is a serialized string, so we should display it + $entry['meta_value'] = maybe_unserialize($entry['meta_value']); + } else { + // this is a serialized array/object so we should NOT display it + --$count; + continue; + } + } + $key_js = js_escape($entry['meta_key']); $entry['meta_key'] = wp_specialchars( $entry['meta_key'], true ); $entry['meta_value'] = wp_specialchars( $entry['meta_value'], true ); @@ -1056,7 +1068,8 @@ function add_meta($post_ID) { $metakeyselect = $wpdb->escape(stripslashes(trim($_POST['metakeyselect']))); $metakeyinput = $wpdb->escape(stripslashes(trim($_POST['metakeyinput']))); - $metavalue = $wpdb->escape(stripslashes(trim($_POST['metavalue']))); + $metavalue = prepare_data(stripslashes((trim($_POST['metavalue'])))); + $metavalue = $wpdb->escape($metavalue); if ( ('0' === $metavalue || !empty ($metavalue)) && ((('#NONE#' != $metakeyselect) && !empty ($metakeyselect)) || !empty ($metakeyinput)) ) { // We have a key/value pair. If both the select and the @@ -1087,8 +1100,9 @@ function delete_meta($mid) { function update_meta($mid, $mkey, $mvalue) { global $wpdb; + if ( is_serialized(stripslashes($mvalue)) ) // $mvalue looks to be already serialized, so we should serialize it again to prevent the data from coming out in a different form than it came in + $mvalue = serialize($mvalue); $mid = (int) $mid; - return $wpdb->query("UPDATE $wpdb->postmeta SET meta_key = '$mkey', meta_value = '$mvalue' WHERE meta_id = '$mid'"); } diff --git a/wp-admin/options.php b/wp-admin/options.php index c0f47b7847..aaf79cb4f2 100644 --- a/wp-admin/options.php +++ b/wp-admin/options.php @@ -124,23 +124,32 @@ default: get_results("SELECT * FROM $wpdb->options ORDER BY option_name"); -foreach ( (array) $options as $option ) - $options_to_update[] = $option->option_name; -$options_to_update = implode(',', $options_to_update); -?> - - -option_value, 'single'); + $disabled = ''; + if ( is_serialized($option->option_value) ) { + if ( 's' == $option->option_value{0} ) { + // this is a serialized string, so we should display it + $value = wp_specialchars(maybe_unserialize($option->option_value), 'single'); + $options_to_update[] = $option->option_name; + $class = 'all-options'; + } else { + $value = 'SERIALIZED DATA'; + $disabled = ' disabled="disabled"'; + $class = 'all-options disabled'; + } + } else { + $value = wp_specialchars($option->option_value, 'single'); + $options_to_update[] = $option->option_name; + $class = 'all-options'; + } echo " @@ -148,7 +157,8 @@ foreach ( (array) $options as $option) : endforeach; ?>
"; - if (stristr($value, "\n")) echo ""; - else echo ""; + if (stristr($value, "\n")) echo ""; + else echo ""; echo " $option->option_description
-

+ +

diff --git a/wp-admin/wp-admin.css b/wp-admin/wp-admin.css index 039fb6ff4d..ae42c611e1 100644 --- a/wp-admin/wp-admin.css +++ b/wp-admin/wp-admin.css @@ -445,6 +445,10 @@ textarea.all-options, input.all-options { width: 250px; } +input.disabled, textarea.disabled { + background: #ccc; +} + #adminmenu { background: #83B4D8; border-top: 3px solid #448abd; diff --git a/wp-includes/functions.php b/wp-includes/functions.php index 858a10cccd..a1d76ec665 100644 --- a/wp-includes/functions.php +++ b/wp-includes/functions.php @@ -156,10 +156,28 @@ function get_lastpostmodified($timezone = 'server') { } function maybe_unserialize($original) { - if ( false !== $gm = @ unserialize($original) ) - return $gm; - else - return $original; + if ( is_serialized($original) ) // don't attempt to unserialize data that wasn't serialized going in + if ( false !== $gm = @ unserialize($original) ) + return $gm; + return $original; +} + +function is_serialized($data) { + if ( !is_string($data) ) // if it isn't a string, it isn't serialized + return false; + $data = trim($data); + if ( preg_match("/^[adobis]:[0-9]+:.*[;}]/si",$data) ) // this should fetch all legitimately serialized data + return true; + return false; +} + +function is_serialized_string($data) { + if ( !is_string($data) ) // if it isn't a string, it isn't a serialized string + return false; + $data = trim($data); + if ( preg_match("/^s:[0-9]+:.*[;}]/si",$data) ) // this should fetch all serialized strings + return true; + return false; } /* Options functions */ @@ -239,8 +257,7 @@ function update_option($option_name, $newvalue) { } $_newvalue = $newvalue; - if ( is_array($newvalue) || is_object($newvalue) ) - $newvalue = serialize($newvalue); + $newvalue = prepare_data($newvalue); wp_cache_set($option_name, $newvalue, 'options'); @@ -262,8 +279,7 @@ function add_option($name, $value = '', $description = '', $autoload = 'yes') { if ( false !== get_option($name) ) return; - if ( is_array($value) || is_object($value) ) - $value = serialize($value); + $value = prepare_data($value); wp_cache_set($name, $value, 'options'); @@ -285,6 +301,16 @@ function delete_option($name) { return true; } +function prepare_data($data) { + if ( is_string($data) ) + $data = trim($data); + elseif ( is_array($data) || is_object($data) ) + return serialize($data); + if ( is_serialized($data) ) + return serialize($data); + return $data; +} + function gzip_compression() { if ( !get_option('gzipcompression') ) return false; diff --git a/wp-includes/pluggable.php b/wp-includes/pluggable.php index 6766d2acd7..f733359ad8 100644 --- a/wp-includes/pluggable.php +++ b/wp-includes/pluggable.php @@ -78,9 +78,7 @@ function get_userdata( $user_id ) { if ($metavalues) { foreach ( $metavalues as $meta ) { - @ $value = unserialize($meta->meta_value); - if ($value === FALSE) - $value = $meta->meta_value; + $value = maybe_unserialize($meta->meta_value); $user->{$meta->meta_key} = $value; // We need to set user_level from meta, not row @@ -131,9 +129,7 @@ function get_userdatabylogin($user_login) { if ($metavalues) { foreach ( $metavalues as $meta ) { - @ $value = unserialize($meta->meta_value); - if ($value === FALSE) - $value = $meta->meta_value; + $value = maybe_unserialize($meta->meta_value); $user->{$meta->meta_key} = $value; // We need to set user_level from meta, not row diff --git a/wp-includes/post.php b/wp-includes/post.php index 92dc8d6eba..e790a03609 100644 --- a/wp-includes/post.php +++ b/wp-includes/post.php @@ -229,14 +229,13 @@ function add_post_meta($post_id, $key, $value, $unique = false) { } } - $original = $value; - if ( is_array($value) || is_object($value) ) - $value = $wpdb->escape(serialize($value)); + $post_meta_cache[$post_id][$key][] = $value; + + $value = prepare_data($value); + $value = $wpdb->escape($value); $wpdb->query("INSERT INTO $wpdb->postmeta (post_id,meta_key,meta_value) VALUES ('$post_id','$key','$value')"); - $post_meta_cache[$post_id][$key][] = $original; - return true; } @@ -311,12 +310,12 @@ function update_post_meta($post_id, $key, $value, $prev_value = '') { $post_id = (int) $post_id; $original_value = $value; - if ( is_array($value) || is_object($value) ) - $value = $wpdb->escape(serialize($value)); + $value = prepare_data($value); + $value = $wpdb->escape($value); $original_prev = $prev_value; - if ( is_array($prev_value) || is_object($prev_value) ) - $prev_value = $wpdb->escape(serialize($prev_value)); + $prev_value = prepare_data($prev_value); + $prev_value = $wpdb->escape($prev_value); if (! $wpdb->get_var("SELECT meta_key FROM $wpdb->postmeta WHERE meta_key = '$key' AND post_id = '$post_id'") ) { return false; diff --git a/wp-includes/user.php b/wp-includes/user.php index bdf537dfee..8c4c58ad65 100644 --- a/wp-includes/user.php +++ b/wp-includes/user.php @@ -114,9 +114,10 @@ function update_usermeta( $user_id, $meta_key, $meta_value ) { return false; $meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key); - if ( is_array($meta_value) || is_object($meta_value) ) - $meta_value = serialize($meta_value); - $meta_value = trim( $meta_value ); + // FIXME: usermeta data is assumed to be already escaped + $meta_value = stripslashes($meta_value); + $meta_value = prepare_data($meta_value); + $meta_value = $wpdb->escape($meta_value); if (empty($meta_value)) { return delete_usermeta($user_id, $meta_key);