diff options
author | Noah Misch <noah@leadboat.com> | 2015-10-05 10:06:29 -0400 |
---|---|---|
committer | Noah Misch <noah@leadboat.com> | 2015-10-05 10:06:34 -0400 |
commit | 16d58b5b534fa783e2259b407c237fc166ebf7e4 (patch) | |
tree | 5e3c003c8ef56fdcb83fe58c17816fb6ba6391ee /src | |
parent | 4d95419e8a2006e91a4356b8bb49c1563933f139 (diff) | |
download | postgresql-16d58b5b534fa783e2259b407c237fc166ebf7e4.tar.gz postgresql-16d58b5b534fa783e2259b407c237fc166ebf7e4.zip |
Prevent stack overflow in json-related functions.
Sufficiently-deep recursion heretofore elicited a SIGSEGV. If an
application constructs PostgreSQL json or jsonb values from arbitrary
user input, application users could have exploited this to terminate all
active database connections. That applies to 9.3, where the json parser
adopted recursive descent, and later versions. Only row_to_json() and
array_to_json() were at risk in 9.2, both in a non-security capacity.
Back-patch to 9.2, where the json type was introduced.
Oskari Saarenmaa, reviewed by Michael Paquier.
Security: CVE-2015-5289
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/utils/adt/json.c | 6 | ||||
-rw-r--r-- | src/test/regress/expected/json.out | 9 | ||||
-rw-r--r-- | src/test/regress/expected/json_1.out | 9 | ||||
-rw-r--r-- | src/test/regress/expected/jsonb.out | 9 | ||||
-rw-r--r-- | src/test/regress/expected/jsonb_1.out | 9 | ||||
-rw-r--r-- | src/test/regress/sql/json.sql | 6 | ||||
-rw-r--r-- | src/test/regress/sql/jsonb.sql | 6 |
7 files changed, 54 insertions, 0 deletions
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index d8052eec4de..679315b6587 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -443,6 +443,8 @@ parse_object(JsonLexContext *lex, JsonSemAction *sem) json_struct_action oend = sem->object_end; JsonTokenType tok; + check_stack_depth(); + if (ostart != NULL) (*ostart) (sem->semstate); @@ -521,6 +523,8 @@ parse_array(JsonLexContext *lex, JsonSemAction *sem) json_struct_action astart = sem->array_start; json_struct_action aend = sem->array_end; + check_stack_depth(); + if (astart != NULL) (*astart) (sem->semstate); @@ -1376,6 +1380,8 @@ datum_to_json(Datum val, bool is_null, StringInfo result, char *outputstr; text *jsontext; + check_stack_depth(); + /* callers are expected to ensure that null keys are not passed in */ Assert(!(key_scalar && is_null)); diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out index bc64512eb10..8bd0fb19692 100644 --- a/src/test/regress/expected/json.out +++ b/src/test/regress/expected/json.out @@ -231,6 +231,15 @@ LINE 1: SELECT '{"abc":1,3}'::json; ^ DETAIL: Expected string, but found "3". CONTEXT: JSON data, line 1: {"abc":1,3... +-- Recursion. +SET max_stack_depth = '100kB'; +SELECT repeat('[', 1000)::json; +ERROR: stack depth limit exceeded +HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate. +SELECT repeat('{"a":', 1000)::json; +ERROR: stack depth limit exceeded +HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate. +RESET max_stack_depth; -- Miscellaneous stuff. SELECT 'true'::json; -- OK json diff --git a/src/test/regress/expected/json_1.out b/src/test/regress/expected/json_1.out index 2738485e5fa..e103f1e8233 100644 --- a/src/test/regress/expected/json_1.out +++ b/src/test/regress/expected/json_1.out @@ -231,6 +231,15 @@ LINE 1: SELECT '{"abc":1,3}'::json; ^ DETAIL: Expected string, but found "3". CONTEXT: JSON data, line 1: {"abc":1,3... +-- Recursion. +SET max_stack_depth = '100kB'; +SELECT repeat('[', 1000)::json; +ERROR: stack depth limit exceeded +HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate. +SELECT repeat('{"a":', 1000)::json; +ERROR: stack depth limit exceeded +HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate. +RESET max_stack_depth; -- Miscellaneous stuff. SELECT 'true'::json; -- OK json diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index 26dc1bf086b..e4b782270d0 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -239,6 +239,15 @@ LINE 1: SELECT '{"abc":1,3}'::jsonb; ^ DETAIL: Expected string, but found "3". CONTEXT: JSON data, line 1: {"abc":1,3... +-- Recursion. +SET max_stack_depth = '100kB'; +SELECT repeat('[', 1000)::jsonb; +ERROR: stack depth limit exceeded +HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate. +SELECT repeat('{"a":', 1000)::jsonb; +ERROR: stack depth limit exceeded +HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate. +RESET max_stack_depth; -- Miscellaneous stuff. SELECT 'true'::jsonb; -- OK jsonb diff --git a/src/test/regress/expected/jsonb_1.out b/src/test/regress/expected/jsonb_1.out index 3cd65ae9382..7c10d76478b 100644 --- a/src/test/regress/expected/jsonb_1.out +++ b/src/test/regress/expected/jsonb_1.out @@ -239,6 +239,15 @@ LINE 1: SELECT '{"abc":1,3}'::jsonb; ^ DETAIL: Expected string, but found "3". CONTEXT: JSON data, line 1: {"abc":1,3... +-- Recursion. +SET max_stack_depth = '100kB'; +SELECT repeat('[', 1000)::jsonb; +ERROR: stack depth limit exceeded +HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate. +SELECT repeat('{"a":', 1000)::jsonb; +ERROR: stack depth limit exceeded +HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate. +RESET max_stack_depth; -- Miscellaneous stuff. SELECT 'true'::jsonb; -- OK jsonb diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql index ab2dd2ed0d5..ad8f7fe0cc9 100644 --- a/src/test/regress/sql/json.sql +++ b/src/test/regress/sql/json.sql @@ -45,6 +45,12 @@ SELECT '{"abc":1,"def":2,"ghi":[3,4],"hij":{"klm":5,"nop":[6]}}'::json; -- OK SELECT '{"abc":1:2}'::json; -- ERROR, colon in wrong spot SELECT '{"abc":1,3}'::json; -- ERROR, no value +-- Recursion. +SET max_stack_depth = '100kB'; +SELECT repeat('[', 1000)::json; +SELECT repeat('{"a":', 1000)::json; +RESET max_stack_depth; + -- Miscellaneous stuff. SELECT 'true'::json; -- OK SELECT 'false'::json; -- OK diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql index 284b981e500..ecd3f6913d7 100644 --- a/src/test/regress/sql/jsonb.sql +++ b/src/test/regress/sql/jsonb.sql @@ -48,6 +48,12 @@ SELECT '{"abc":1,"def":2,"ghi":[3,4],"hij":{"klm":5,"nop":[6]}}'::jsonb; -- OK SELECT '{"abc":1:2}'::jsonb; -- ERROR, colon in wrong spot SELECT '{"abc":1,3}'::jsonb; -- ERROR, no value +-- Recursion. +SET max_stack_depth = '100kB'; +SELECT repeat('[', 1000)::jsonb; +SELECT repeat('{"a":', 1000)::jsonb; +RESET max_stack_depth; + -- Miscellaneous stuff. SELECT 'true'::jsonb; -- OK SELECT 'false'::jsonb; -- OK |