summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNoah Misch <noah@leadboat.com>2015-10-05 10:06:29 -0400
committerNoah Misch <noah@leadboat.com>2015-10-05 10:06:34 -0400
commitf8862172e6519b82e66c51baa5b87e29847db2b9 (patch)
treee72cb14f7bf272f0e2e3b3d8056bdba9f20c58d2 /src
parentcc1210f0aa441cd0825380ed3fddfeadb6f6533f (diff)
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.c7
-rw-r--r--src/test/regress/expected/json.out9
-rw-r--r--src/test/regress/expected/json_1.out9
-rw-r--r--src/test/regress/sql/json.sql6
4 files changed, 31 insertions, 0 deletions
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 0566b926fed..61088a24339 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -21,6 +21,7 @@
#include "lib/stringinfo.h"
#include "libpq/pqformat.h"
#include "mb/pg_wchar.h"
+#include "miscadmin.h"
#include "parser/parse_coerce.h"
#include "utils/array.h"
#include "utils/builtins.h"
@@ -427,6 +428,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);
@@ -505,6 +508,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);
@@ -1338,6 +1343,8 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
char *outputstr;
text *jsontext;
+ check_stack_depth();
+
if (is_null)
{
appendStringInfoString(result, "null");
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index 0e1d79121f9..a43c9e01bef 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 f19acf755a2..075c3f0e0fa 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/sql/json.sql b/src/test/regress/sql/json.sql
index 2de144bbaf7..f1f898418dd 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