From 062d2ee6f798205c3046730d0d348cfd0d0bc09d Mon Sep 17 00:00:00 2001 From: naruse Date: Tue, 12 Feb 2013 03:05:45 +0000 Subject: * ext/json: merge JSON 1.7.7. This includes security fix. [CVE-2013-0269] https://github.com/flori/json/commit/d0a62f3ced7560daba2ad546d83f0479a5ae2cf2 https://groups.google.com/d/topic/rubyonrails-security/4_YvCpLzL58/discussion git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@39208 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/json/fbuffer/fbuffer.h | 8 ++--- ext/json/generator/generator.c | 62 ++++++++++++++++++++++++++++--------- ext/json/generator/generator.h | 9 +++++- ext/json/lib/json/add/bigdecimal.rb | 7 +++++ ext/json/lib/json/common.rb | 25 +++++++++------ ext/json/lib/json/generic_object.rb | 22 +++++++++++++ ext/json/lib/json/version.rb | 2 +- ext/json/parser/parser.c | 8 ++--- ext/json/parser/parser.rl | 8 ++--- 9 files changed, 112 insertions(+), 39 deletions(-) (limited to 'ext/json') diff --git a/ext/json/fbuffer/fbuffer.h b/ext/json/fbuffer/fbuffer.h index b5e47eec42..af74187566 100644 --- a/ext/json/fbuffer/fbuffer.h +++ b/ext/json/fbuffer/fbuffer.h @@ -3,7 +3,6 @@ #define _FBUFFER_H_ #include "ruby.h" -#include #ifndef RHASH_SIZE #define RHASH_SIZE(hsh) (RHASH(hsh)->tbl->num_entries) @@ -166,11 +165,8 @@ static FBuffer *fbuffer_dup(FBuffer *fb) unsigned long len = fb->len; FBuffer *result; - assert(len > 0); - if (len > 0) { - result = fbuffer_alloc(len); - fbuffer_append(result, FBUFFER_PAIR(fb)); - } + result = fbuffer_alloc(len); + fbuffer_append(result, FBUFFER_PAIR(fb)); return result; } diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c index 3cff87d7d5..ae4593c940 100644 --- a/ext/json/generator/generator.c +++ b/ext/json/generator/generator.c @@ -522,7 +522,7 @@ static VALUE cState_configure(VALUE self, VALUE opts) unsigned long len; Check_Type(tmp, T_STRING); len = RSTRING_LEN(tmp); - state->indent = fstrndup(RSTRING_PTR(tmp), len); + state->indent = fstrndup(RSTRING_PTR(tmp), len + 1); state->indent_len = len; } tmp = rb_hash_aref(opts, ID2SYM(i_space)); @@ -530,7 +530,7 @@ static VALUE cState_configure(VALUE self, VALUE opts) unsigned long len; Check_Type(tmp, T_STRING); len = RSTRING_LEN(tmp); - state->space = fstrndup(RSTRING_PTR(tmp), len); + state->space = fstrndup(RSTRING_PTR(tmp), len + 1); state->space_len = len; } tmp = rb_hash_aref(opts, ID2SYM(i_space_before)); @@ -538,7 +538,7 @@ static VALUE cState_configure(VALUE self, VALUE opts) unsigned long len; Check_Type(tmp, T_STRING); len = RSTRING_LEN(tmp); - state->space_before = fstrndup(RSTRING_PTR(tmp), len); + state->space_before = fstrndup(RSTRING_PTR(tmp), len + 1); state->space_before_len = len; } tmp = rb_hash_aref(opts, ID2SYM(i_array_nl)); @@ -546,7 +546,7 @@ static VALUE cState_configure(VALUE self, VALUE opts) unsigned long len; Check_Type(tmp, T_STRING); len = RSTRING_LEN(tmp); - state->array_nl = fstrndup(RSTRING_PTR(tmp), len); + state->array_nl = fstrndup(RSTRING_PTR(tmp), len + 1); state->array_nl_len = len; } tmp = rb_hash_aref(opts, ID2SYM(i_object_nl)); @@ -554,11 +554,11 @@ static VALUE cState_configure(VALUE self, VALUE opts) unsigned long len; Check_Type(tmp, T_STRING); len = RSTRING_LEN(tmp); - state->object_nl = fstrndup(RSTRING_PTR(tmp), len); + state->object_nl = fstrndup(RSTRING_PTR(tmp), len + 1); state->object_nl_len = len; } tmp = ID2SYM(i_max_nesting); - state->max_nesting = 19; + state->max_nesting = 100; if (option_given_p(opts, tmp)) { VALUE max_nesting = rb_hash_aref(opts, tmp); if (RTEST(max_nesting)) { @@ -598,6 +598,18 @@ static VALUE cState_configure(VALUE self, VALUE opts) return self; } +static void set_state_ivars(VALUE hash, VALUE state) +{ + VALUE ivars = rb_obj_instance_variables(state); + int i = 0; + for (i = 0; i < RARRAY_LEN(ivars); i++) { + VALUE key = rb_funcall(rb_ary_entry(ivars, i), i_to_s, 0); + long key_len = RSTRING_LEN(key); + VALUE value = rb_iv_get(state, StringValueCStr(key)); + rb_hash_aset(hash, rb_str_intern(rb_str_substr(key, 1, key_len - 1)), value); + } +} + /* * call-seq: to_h * @@ -608,6 +620,7 @@ static VALUE cState_to_h(VALUE self) { VALUE result = rb_hash_new(); GET_STATE(self); + set_state_ivars(result, self); rb_hash_aset(result, ID2SYM(i_indent), rb_str_new(state->indent, state->indent_len)); rb_hash_aset(result, ID2SYM(i_space), rb_str_new(state->space, state->space_len)); rb_hash_aset(result, ID2SYM(i_space_before), rb_str_new(state->space_before, state->space_before_len)); @@ -629,14 +642,33 @@ static VALUE cState_to_h(VALUE self) */ static VALUE cState_aref(VALUE self, VALUE name) { - GET_STATE(self); + name = rb_funcall(name, i_to_s, 0); if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) { return rb_funcall(self, i_send, 1, name); } else { - return Qnil; + return rb_ivar_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name))); } } +/* +* call-seq: []=(name, value) +* +* Set the attribute name to value. +*/ +static VALUE cState_aset(VALUE self, VALUE name, VALUE value) +{ + VALUE name_writer; + + name = rb_funcall(name, i_to_s, 0); + name_writer = rb_str_cat2(rb_str_dup(name), "="); + if (RTEST(rb_funcall(self, i_respond_to_p, 1, name_writer))) { + return rb_funcall(self, i_send, 2, name_writer, value); + } else { + rb_ivar_set(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)), value); + } + return Qnil; +} + static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj) { char *object_nl = state->object_nl; @@ -908,7 +940,7 @@ static VALUE cState_initialize(int argc, VALUE *argv, VALUE self) { VALUE opts; GET_STATE(self); - state->max_nesting = 19; + state->max_nesting = 100; state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT; rb_scan_args(argc, argv, "01", &opts); if (!NIL_P(opts)) cState_configure(self, opts); @@ -970,7 +1002,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts) static VALUE cState_indent(VALUE self) { GET_STATE(self); - return state->indent ? rb_str_new2(state->indent) : rb_str_new2(""); + return state->indent ? rb_str_new(state->indent, state->indent_len) : rb_str_new2(""); } /* @@ -1007,7 +1039,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent) static VALUE cState_space(VALUE self) { GET_STATE(self); - return state->space ? rb_str_new2(state->space) : rb_str_new2(""); + return state->space ? rb_str_new(state->space, state->space_len) : rb_str_new2(""); } /* @@ -1044,7 +1076,7 @@ static VALUE cState_space_set(VALUE self, VALUE space) static VALUE cState_space_before(VALUE self) { GET_STATE(self); - return state->space_before ? rb_str_new2(state->space_before) : rb_str_new2(""); + return state->space_before ? rb_str_new(state->space_before, state->space_before_len) : rb_str_new2(""); } /* @@ -1081,7 +1113,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before) static VALUE cState_object_nl(VALUE self) { GET_STATE(self); - return state->object_nl ? rb_str_new2(state->object_nl) : rb_str_new2(""); + return state->object_nl ? rb_str_new(state->object_nl, state->object_nl_len) : rb_str_new2(""); } /* @@ -1117,7 +1149,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl) static VALUE cState_array_nl(VALUE self) { GET_STATE(self); - return state->array_nl ? rb_str_new2(state->array_nl) : rb_str_new2(""); + return state->array_nl ? rb_str_new(state->array_nl, state->array_nl_len) : rb_str_new2(""); } /* @@ -1327,7 +1359,9 @@ void Init_generator() rb_define_method(cState, "configure", cState_configure, 1); rb_define_alias(cState, "merge", "configure"); rb_define_method(cState, "to_h", cState_to_h, 0); + rb_define_alias(cState, "to_hash", "to_h"); rb_define_method(cState, "[]", cState_aref, 1); + rb_define_method(cState, "[]=", cState_aset, 2); rb_define_method(cState, "generate", cState_generate, 1); mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods"); diff --git a/ext/json/generator/generator.h b/ext/json/generator/generator.h index 7d429d512c..b58cc4bc2f 100644 --- a/ext/json/generator/generator.h +++ b/ext/json/generator/generator.h @@ -2,7 +2,6 @@ #define _GENERATOR_H_ #include -#include #include #include @@ -14,6 +13,14 @@ #include "re.h" #endif +#ifndef rb_intern_str +#define rb_intern_str(string) SYM2ID(rb_str_intern(string)) +#endif + +#ifndef rb_obj_instance_variables +#define rb_obj_instance_variables(object) rb_funcall(object, rb_intern("instance_variables"), 0) +#endif + #define option_given_p(opts, key) RTEST(rb_funcall(opts, i_key_p, 1, key)) /* unicode defintions */ diff --git a/ext/json/lib/json/add/bigdecimal.rb b/ext/json/lib/json/add/bigdecimal.rb index 4aafe537ab..0ef69f12e0 100644 --- a/ext/json/lib/json/add/bigdecimal.rb +++ b/ext/json/lib/json/add/bigdecimal.rb @@ -4,10 +4,16 @@ end defined?(::BigDecimal) or require 'bigdecimal' class BigDecimal + # Import a JSON Marshalled object. + # + # method used for JSON marshalling support. def self.json_create(object) BigDecimal._load object['b'] end + # Marshal the object to JSON. + # + # method used for JSON marshalling support. def as_json(*) { JSON.create_id => self.class.name, @@ -15,6 +21,7 @@ class BigDecimal } end + # return the JSON value def to_json(*) as_json.to_json end diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb index 3349501337..65a74a1aa4 100644 --- a/ext/json/lib/json/common.rb +++ b/ext/json/lib/json/common.rb @@ -139,7 +139,7 @@ module JSON # keys: # * *max_nesting*: The maximum depth of nesting allowed in the parsed data # structures. Disable depth checking with :max_nesting => false. It defaults - # to 19. + # to 100. # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in # defiance of RFC 4627 to be parsed by the Parser. This option defaults # to false. @@ -199,7 +199,7 @@ module JSON # encountered. This options defaults to false. # * *max_nesting*: The maximum depth of nesting allowed in the data # structures from which JSON is to be generated. Disable depth checking - # with :max_nesting => false, it defaults to 19. + # with :max_nesting => false, it defaults to 100. # # See also the fast_generate for the fastest creation method with the least # amount of sanity checks, and the pretty_generate method for some @@ -299,21 +299,28 @@ module JSON attr_accessor :load_default_options end self.load_default_options = { - :max_nesting => false, - :allow_nan => true, - :quirks_mode => true, + :max_nesting => false, + :allow_nan => true, + :quirks_mode => true, + :create_additions => true, } # Load a ruby data structure from a JSON _source_ and return it. A source can # either be a string-like object, an IO-like object, or an object responding # to the read method. If _proc_ was given, it will be called with any nested - # Ruby object as an argument recursively in depth first order. The default - # options for the parser can be changed via the load_default_options method. + # Ruby object as an argument recursively in depth first order. To modify the + # default options pass in the optional _options_ argument as well. + # + # BEWARE: This method is meant to serialise data from trusted user input, + # like from your own database server or clients under your control, it could + # be dangerous to allow untrusted users to pass JSON sources into it. The + # default options for the parser can be changed via the load_default_options + # method. # # This method is part of the implementation of the load/dump interface of # Marshal and YAML. - def load(source, proc = nil) - opts = load_default_options + def load(source, proc = nil, options = {}) + opts = load_default_options.merge options if source.respond_to? :to_str source = source.to_str elsif source.respond_to? :to_io diff --git a/ext/json/lib/json/generic_object.rb b/ext/json/lib/json/generic_object.rb index 7f3dbbd78d..8b1074c941 100644 --- a/ext/json/lib/json/generic_object.rb +++ b/ext/json/lib/json/generic_object.rb @@ -5,12 +5,34 @@ module JSON class << self alias [] new + def json_creatable? + @json_creatable + end + + attr_writer :json_creatable + def json_create(data) data = data.dup data.delete JSON.create_id self[data] end + + def from_hash(object) + case + when object.respond_to?(:to_hash) + result = new + object.to_hash.each do |key, value| + result[key] = from_hash(value) + end + result + when object.respond_to?(:to_ary) + object.to_ary.map { |a| from_hash(a) } + else + object + end + end end + self.json_creatable = false def to_hash table diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb index 45af03fd40..1de3d696f2 100644 --- a/ext/json/lib/json/version.rb +++ b/ext/json/lib/json/version.rb @@ -1,6 +1,6 @@ module JSON # JSON version - VERSION = '1.7.5' + VERSION = '1.7.7' VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc: VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc: VERSION_MINOR = VERSION_ARRAY[1] # :nodoc: diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index c140fdb2fe..df89f2c58b 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -1618,7 +1618,7 @@ static VALUE convert_encoding(VALUE source) * _opts_ can have the following keys: * * *max_nesting*: The maximum depth of nesting allowed in the parsed data * structures. Disable depth checking with :max_nesting => false|nil|0, it - * defaults to 19. + * defaults to 100. * * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in * defiance of RFC 4627 to be parsed by the Parser. This option defaults to * false. @@ -1655,7 +1655,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) json->max_nesting = 0; } } else { - json->max_nesting = 19; + json->max_nesting = 100; } tmp = ID2SYM(i_allow_nan); if (option_given_p(opts, tmp)) { @@ -1680,7 +1680,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) if (option_given_p(opts, tmp)) { json->create_additions = RTEST(rb_hash_aref(opts, tmp)); } else { - json->create_additions = 1; + json->create_additions = 0; } tmp = ID2SYM(i_create_id); if (option_given_p(opts, tmp)) { @@ -1709,7 +1709,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } } } else { - json->max_nesting = 19; + json->max_nesting = 100; json->allow_nan = 0; json->create_additions = 1; json->create_id = rb_funcall(mJSON, i_create_id, 0); diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl index 20ecc486e1..ab8d318173 100644 --- a/ext/json/parser/parser.rl +++ b/ext/json/parser/parser.rl @@ -602,7 +602,7 @@ static VALUE convert_encoding(VALUE source) * _opts_ can have the following keys: * * *max_nesting*: The maximum depth of nesting allowed in the parsed data * structures. Disable depth checking with :max_nesting => false|nil|0, it - * defaults to 19. + * defaults to 100. * * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in * defiance of RFC 4627 to be parsed by the Parser. This option defaults to * false. @@ -639,7 +639,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) json->max_nesting = 0; } } else { - json->max_nesting = 19; + json->max_nesting = 100; } tmp = ID2SYM(i_allow_nan); if (option_given_p(opts, tmp)) { @@ -664,7 +664,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) if (option_given_p(opts, tmp)) { json->create_additions = RTEST(rb_hash_aref(opts, tmp)); } else { - json->create_additions = 1; + json->create_additions = 0; } tmp = ID2SYM(i_create_id); if (option_given_p(opts, tmp)) { @@ -693,7 +693,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } } } else { - json->max_nesting = 19; + json->max_nesting = 100; json->allow_nan = 0; json->create_additions = 1; json->create_id = rb_funcall(mJSON, i_create_id, 0); -- cgit v1.2.3