summaryrefslogtreecommitdiff
path: root/ext/json/parser
diff options
context:
space:
mode:
authorJean Boussier <[email protected]>2024-10-24 16:51:25 +0200
committerHiroshi SHIBATA <[email protected]>2024-11-01 13:04:24 +0900
commitf2b8829df0092409c944aafeac03f72ab2a6e7ac (patch)
tree69914ee130dcb936246fcf7d48fe1711d954561c /ext/json/parser
parentcc2e67a138d258290f727f5797bdc14fbc5a6e52 (diff)
Deprecate unsafe default options of `JSON.load`
[Feature #19528] Ref: https://bugs.ruby-lang.org/issues/19528 `load` is understood as the default method for serializer kind of libraries, and the default options of `JSON.load` has caused many security vulnerabilities over the years. The plan is to do like YAML/Psych, deprecate these default options and direct users toward using `JSON.unsafe_load` so at least it's obvious it should be used against untrusted data.
Diffstat (limited to 'ext/json/parser')
-rw-r--r--ext/json/parser/parser.c135
-rw-r--r--ext/json/parser/parser.h1
-rw-r--r--ext/json/parser/parser.rl15
3 files changed, 85 insertions, 66 deletions
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c
index a6d8ff2cc5..38c546b46b 100644
--- a/ext/json/parser/parser.c
+++ b/ext/json/parser/parser.c
@@ -474,6 +474,9 @@ case 26:
if (!NIL_P(klassname)) {
VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
+ if (json->deprecated_create_additions) {
+ rb_warn("JSON.load implicit support for `create_additions: true` is deprecated and will be removed in 3.0, use JSON.unsafe_load or explicitly pass `create_additions: true`");
+ }
*result = rb_funcall(klass, i_json_create, 1, *result);
}
}
@@ -486,7 +489,7 @@ case 26:
-#line 490 "parser.c"
+#line 493 "parser.c"
enum {JSON_value_start = 1};
enum {JSON_value_first_final = 29};
enum {JSON_value_error = 0};
@@ -494,7 +497,7 @@ enum {JSON_value_error = 0};
enum {JSON_value_en_main = 1};
-#line 287 "parser.rl"
+#line 290 "parser.rl"
static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
@@ -502,14 +505,14 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul
int cs = EVIL;
-#line 506 "parser.c"
+#line 509 "parser.c"
{
cs = JSON_value_start;
}
-#line 294 "parser.rl"
+#line 297 "parser.rl"
-#line 513 "parser.c"
+#line 516 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -543,14 +546,14 @@ st0:
cs = 0;
goto _out;
tr2:
-#line 239 "parser.rl"
+#line 242 "parser.rl"
{
char *np = JSON_parse_string(json, p, pe, result);
if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;}
}
goto st29;
tr3:
-#line 244 "parser.rl"
+#line 247 "parser.rl"
{
char *np;
if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) {
@@ -570,7 +573,7 @@ tr3:
}
goto st29;
tr7:
-#line 262 "parser.rl"
+#line 265 "parser.rl"
{
char *np;
np = JSON_parse_array(json, p, pe, result, current_nesting + 1);
@@ -578,7 +581,7 @@ tr7:
}
goto st29;
tr11:
-#line 268 "parser.rl"
+#line 271 "parser.rl"
{
char *np;
np = JSON_parse_object(json, p, pe, result, current_nesting + 1);
@@ -586,7 +589,7 @@ tr11:
}
goto st29;
tr25:
-#line 232 "parser.rl"
+#line 235 "parser.rl"
{
if (json->allow_nan) {
*result = CInfinity;
@@ -596,7 +599,7 @@ tr25:
}
goto st29;
tr27:
-#line 225 "parser.rl"
+#line 228 "parser.rl"
{
if (json->allow_nan) {
*result = CNaN;
@@ -606,19 +609,19 @@ tr27:
}
goto st29;
tr31:
-#line 219 "parser.rl"
+#line 222 "parser.rl"
{
*result = Qfalse;
}
goto st29;
tr34:
-#line 216 "parser.rl"
+#line 219 "parser.rl"
{
*result = Qnil;
}
goto st29;
tr37:
-#line 222 "parser.rl"
+#line 225 "parser.rl"
{
*result = Qtrue;
}
@@ -627,9 +630,9 @@ st29:
if ( ++p == pe )
goto _test_eof29;
case 29:
-#line 274 "parser.rl"
+#line 277 "parser.rl"
{ p--; {p++; cs = 29; goto _out;} }
-#line 633 "parser.c"
+#line 636 "parser.c"
switch( (*p) ) {
case 13: goto st29;
case 32: goto st29;
@@ -870,7 +873,7 @@ case 28:
_out: {}
}
-#line 295 "parser.rl"
+#line 298 "parser.rl"
if (json->freeze) {
OBJ_FREEZE(*result);
@@ -884,7 +887,7 @@ case 28:
}
-#line 888 "parser.c"
+#line 891 "parser.c"
enum {JSON_integer_start = 1};
enum {JSON_integer_first_final = 3};
enum {JSON_integer_error = 0};
@@ -892,7 +895,7 @@ enum {JSON_integer_error = 0};
enum {JSON_integer_en_main = 1};
-#line 315 "parser.rl"
+#line 318 "parser.rl"
static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
@@ -900,15 +903,15 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
int cs = EVIL;
-#line 904 "parser.c"
+#line 907 "parser.c"
{
cs = JSON_integer_start;
}
-#line 322 "parser.rl"
+#line 325 "parser.rl"
json->memo = p;
-#line 912 "parser.c"
+#line 915 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -942,14 +945,14 @@ case 3:
goto st0;
goto tr4;
tr4:
-#line 312 "parser.rl"
+#line 315 "parser.rl"
{ p--; {p++; cs = 4; goto _out;} }
goto st4;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
-#line 953 "parser.c"
+#line 956 "parser.c"
goto st0;
st5:
if ( ++p == pe )
@@ -968,7 +971,7 @@ case 5:
_out: {}
}
-#line 324 "parser.rl"
+#line 327 "parser.rl"
if (cs >= JSON_integer_first_final) {
long len = p - json->memo;
@@ -983,7 +986,7 @@ case 5:
}
-#line 987 "parser.c"
+#line 990 "parser.c"
enum {JSON_float_start = 1};
enum {JSON_float_first_final = 8};
enum {JSON_float_error = 0};
@@ -991,7 +994,7 @@ enum {JSON_float_error = 0};
enum {JSON_float_en_main = 1};
-#line 349 "parser.rl"
+#line 352 "parser.rl"
static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
@@ -999,15 +1002,15 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
int cs = EVIL;
-#line 1003 "parser.c"
+#line 1006 "parser.c"
{
cs = JSON_float_start;
}
-#line 356 "parser.rl"
+#line 359 "parser.rl"
json->memo = p;
-#line 1011 "parser.c"
+#line 1014 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -1065,14 +1068,14 @@ case 8:
goto st0;
goto tr9;
tr9:
-#line 343 "parser.rl"
+#line 346 "parser.rl"
{ p--; {p++; cs = 9; goto _out;} }
goto st9;
st9:
if ( ++p == pe )
goto _test_eof9;
case 9:
-#line 1076 "parser.c"
+#line 1079 "parser.c"
goto st0;
st5:
if ( ++p == pe )
@@ -1133,7 +1136,7 @@ case 7:
_out: {}
}
-#line 358 "parser.rl"
+#line 361 "parser.rl"
if (cs >= JSON_float_first_final) {
VALUE mod = Qnil;
@@ -1186,7 +1189,7 @@ case 7:
-#line 1190 "parser.c"
+#line 1193 "parser.c"
enum {JSON_array_start = 1};
enum {JSON_array_first_final = 17};
enum {JSON_array_error = 0};
@@ -1194,7 +1197,7 @@ enum {JSON_array_error = 0};
enum {JSON_array_en_main = 1};
-#line 438 "parser.rl"
+#line 441 "parser.rl"
static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
@@ -1208,14 +1211,14 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
*result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
-#line 1212 "parser.c"
+#line 1215 "parser.c"
{
cs = JSON_array_start;
}
-#line 451 "parser.rl"
+#line 454 "parser.rl"
-#line 1219 "parser.c"
+#line 1222 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -1254,7 +1257,7 @@ case 2:
goto st2;
goto st0;
tr2:
-#line 415 "parser.rl"
+#line 418 "parser.rl"
{
VALUE v = Qnil;
char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
@@ -1274,7 +1277,7 @@ st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
-#line 1278 "parser.c"
+#line 1281 "parser.c"
switch( (*p) ) {
case 13: goto st3;
case 32: goto st3;
@@ -1374,14 +1377,14 @@ case 12:
goto st3;
goto st12;
tr4:
-#line 430 "parser.rl"
+#line 433 "parser.rl"
{ p--; {p++; cs = 17; goto _out;} }
goto st17;
st17:
if ( ++p == pe )
goto _test_eof17;
case 17:
-#line 1385 "parser.c"
+#line 1388 "parser.c"
goto st0;
st13:
if ( ++p == pe )
@@ -1437,7 +1440,7 @@ case 16:
_out: {}
}
-#line 452 "parser.rl"
+#line 455 "parser.rl"
if(cs >= JSON_array_first_final) {
return p + 1;
@@ -1598,7 +1601,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
}
-#line 1602 "parser.c"
+#line 1605 "parser.c"
enum {JSON_string_start = 1};
enum {JSON_string_first_final = 8};
enum {JSON_string_error = 0};
@@ -1606,7 +1609,7 @@ enum {JSON_string_error = 0};
enum {JSON_string_en_main = 1};
-#line 630 "parser.rl"
+#line 633 "parser.rl"
static int
@@ -1627,15 +1630,15 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
VALUE match_string;
-#line 1631 "parser.c"
+#line 1634 "parser.c"
{
cs = JSON_string_start;
}
-#line 650 "parser.rl"
+#line 653 "parser.rl"
json->memo = p;
-#line 1639 "parser.c"
+#line 1642 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -1660,7 +1663,7 @@ case 2:
goto st0;
goto st2;
tr2:
-#line 617 "parser.rl"
+#line 620 "parser.rl"
{
*result = json_string_unescape(json->memo + 1, p, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
if (NIL_P(*result)) {
@@ -1670,14 +1673,14 @@ tr2:
{p = (( p + 1))-1;}
}
}
-#line 627 "parser.rl"
+#line 630 "parser.rl"
{ p--; {p++; cs = 8; goto _out;} }
goto st8;
st8:
if ( ++p == pe )
goto _test_eof8;
case 8:
-#line 1681 "parser.c"
+#line 1684 "parser.c"
goto st0;
st3:
if ( ++p == pe )
@@ -1753,7 +1756,7 @@ case 7:
_out: {}
}
-#line 652 "parser.rl"
+#line 655 "parser.rl"
if (json->create_additions && RTEST(match_string = json->match_string)) {
VALUE klass;
@@ -1888,10 +1891,16 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
}
tmp = ID2SYM(i_create_additions);
if (option_given_p(opts, tmp)) {
- json->create_additions = RTEST(rb_hash_aref(opts, tmp));
- } else {
- json->create_additions = 0;
+ tmp = rb_hash_aref(opts, tmp);
+ if (NIL_P(tmp)) {
+ json->create_additions = 1;
+ json->deprecated_create_additions = 1;
+ } else {
+ json->create_additions = RTEST(tmp);
+ json->deprecated_create_additions = 0;
+ }
}
+
if (json->symbolize_names && json->create_additions) {
rb_raise(rb_eArgError,
"options :symbolize_names and :create_additions cannot be "
@@ -1946,7 +1955,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
}
-#line 1950 "parser.c"
+#line 1959 "parser.c"
enum {JSON_start = 1};
enum {JSON_first_final = 10};
enum {JSON_error = 0};
@@ -1954,7 +1963,7 @@ enum {JSON_error = 0};
enum {JSON_en_main = 1};
-#line 858 "parser.rl"
+#line 867 "parser.rl"
/*
@@ -1972,16 +1981,16 @@ static VALUE cParser_parse(VALUE self)
GET_PARSER;
-#line 1976 "parser.c"
+#line 1985 "parser.c"
{
cs = JSON_start;
}
-#line 875 "parser.rl"
+#line 884 "parser.rl"
p = json->source;
pe = p + json->len;
-#line 1985 "parser.c"
+#line 1994 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -2015,7 +2024,7 @@ st0:
cs = 0;
goto _out;
tr2:
-#line 850 "parser.rl"
+#line 859 "parser.rl"
{
char *np = JSON_parse_value(json, p, pe, &result, 0);
if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
@@ -2025,7 +2034,7 @@ st10:
if ( ++p == pe )
goto _test_eof10;
case 10:
-#line 2029 "parser.c"
+#line 2038 "parser.c"
switch( (*p) ) {
case 13: goto st10;
case 32: goto st10;
@@ -2114,7 +2123,7 @@ case 9:
_out: {}
}
-#line 878 "parser.rl"
+#line 887 "parser.rl"
if (cs >= JSON_first_final && p == pe) {
return result;
diff --git a/ext/json/parser/parser.h b/ext/json/parser/parser.h
index 2a5b13856a..6bf21aab52 100644
--- a/ext/json/parser/parser.h
+++ b/ext/json/parser/parser.h
@@ -26,6 +26,7 @@ typedef struct JSON_ParserStruct {
char symbolize_names;
char freeze;
char create_additions;
+ char deprecated_create_additions;
} JSON_Parser;
#define GET_PARSER \
diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl
index 499cc693a3..441e58e7ba 100644
--- a/ext/json/parser/parser.rl
+++ b/ext/json/parser/parser.rl
@@ -196,6 +196,9 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
if (!NIL_P(klassname)) {
VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
+ if (json->deprecated_create_additions) {
+ rb_warn("JSON.load implicit support for `create_additions: true` is deprecated and will be removed in 3.0, use JSON.unsafe_load or explicitly pass `create_additions: true`");
+ }
*result = rb_funcall(klass, i_json_create, 1, *result);
}
}
@@ -783,10 +786,16 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
}
tmp = ID2SYM(i_create_additions);
if (option_given_p(opts, tmp)) {
- json->create_additions = RTEST(rb_hash_aref(opts, tmp));
- } else {
- json->create_additions = 0;
+ tmp = rb_hash_aref(opts, tmp);
+ if (NIL_P(tmp)) {
+ json->create_additions = 1;
+ json->deprecated_create_additions = 1;
+ } else {
+ json->create_additions = RTEST(tmp);
+ json->deprecated_create_additions = 0;
+ }
}
+
if (json->symbolize_names && json->create_additions) {
rb_raise(rb_eArgError,
"options :symbolize_names and :create_additions cannot be "