Skip to content

Commit f886217

Browse files
committed
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
1 parent cc1210f commit f886217

File tree

4 files changed

+31
-0
lines changed

4 files changed

+31
-0
lines changed

src/backend/utils/adt/json.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "lib/stringinfo.h"
2222
#include "libpq/pqformat.h"
2323
#include "mb/pg_wchar.h"
24+
#include "miscadmin.h"
2425
#include "parser/parse_coerce.h"
2526
#include "utils/array.h"
2627
#include "utils/builtins.h"
@@ -427,6 +428,8 @@ parse_object(JsonLexContext *lex, JsonSemAction *sem)
427428
json_struct_action oend = sem->object_end;
428429
JsonTokenType tok;
429430

431+
check_stack_depth();
432+
430433
if (ostart != NULL)
431434
(*ostart) (sem->semstate);
432435

@@ -505,6 +508,8 @@ parse_array(JsonLexContext *lex, JsonSemAction *sem)
505508
json_struct_action astart = sem->array_start;
506509
json_struct_action aend = sem->array_end;
507510

511+
check_stack_depth();
512+
508513
if (astart != NULL)
509514
(*astart) (sem->semstate);
510515

@@ -1338,6 +1343,8 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
13381343
char *outputstr;
13391344
text *jsontext;
13401345

1346+
check_stack_depth();
1347+
13411348
if (is_null)
13421349
{
13431350
appendStringInfoString(result, "null");

src/test/regress/expected/json.out

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,15 @@ LINE 1: SELECT '{"abc":1,3}'::json;
231231
^
232232
DETAIL: Expected string, but found "3".
233233
CONTEXT: JSON data, line 1: {"abc":1,3...
234+
-- Recursion.
235+
SET max_stack_depth = '100kB';
236+
SELECT repeat('[', 1000)::json;
237+
ERROR: stack depth limit exceeded
238+
HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate.
239+
SELECT repeat('{"a":', 1000)::json;
240+
ERROR: stack depth limit exceeded
241+
HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate.
242+
RESET max_stack_depth;
234243
-- Miscellaneous stuff.
235244
SELECT 'true'::json; -- OK
236245
json

src/test/regress/expected/json_1.out

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,15 @@ LINE 1: SELECT '{"abc":1,3}'::json;
231231
^
232232
DETAIL: Expected string, but found "3".
233233
CONTEXT: JSON data, line 1: {"abc":1,3...
234+
-- Recursion.
235+
SET max_stack_depth = '100kB';
236+
SELECT repeat('[', 1000)::json;
237+
ERROR: stack depth limit exceeded
238+
HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate.
239+
SELECT repeat('{"a":', 1000)::json;
240+
ERROR: stack depth limit exceeded
241+
HINT: Increase the configuration parameter "max_stack_depth" (currently 100kB), after ensuring the platform's stack depth limit is adequate.
242+
RESET max_stack_depth;
234243
-- Miscellaneous stuff.
235244
SELECT 'true'::json; -- OK
236245
json

src/test/regress/sql/json.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ SELECT '{"abc":1,"def":2,"ghi":[3,4],"hij":{"klm":5,"nop":[6]}}'::json; -- OK
4545
SELECT '{"abc":1:2}'::json; -- ERROR, colon in wrong spot
4646
SELECT '{"abc":1,3}'::json; -- ERROR, no value
4747

48+
-- Recursion.
49+
SET max_stack_depth = '100kB';
50+
SELECT repeat('[', 1000)::json;
51+
SELECT repeat('{"a":', 1000)::json;
52+
RESET max_stack_depth;
53+
4854
-- Miscellaneous stuff.
4955
SELECT 'true'::json; -- OK
5056
SELECT 'false'::json; -- OK

0 commit comments

Comments
 (0)