From: drh Date: Tue, 11 Apr 2017 18:55:05 +0000 (+0000) Subject: Limit the depth of recursion for valid JSON in the JSON1 extension in order X-Git-Tag: version-3.19.0~71 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ff6d50e973f597c1ab3ead0ea7d553d41b608a8d;p=thirdparty%2Fsqlite.git Limit the depth of recursion for valid JSON in the JSON1 extension in order to avoid using excess stack space in the recursive descent parser. Fix for ticket [981329adeef51011052667a9]. FossilOrigin-Name: 1f68c184596912d742b50b1ca38252a9e783aacf121619a27b17a7ae9f6df041 --- diff --git a/ext/misc/json1.c b/ext/misc/json1.c index 0d1b9a4642..486eaa4285 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -90,6 +90,7 @@ static const char jsonIsSpace[] = { ** but the definitions need to be repeated for separate compilation. */ typedef sqlite3_uint64 u64; typedef unsigned int u32; + typedef unsigned short int u16; typedef unsigned char u8; #endif @@ -169,8 +170,18 @@ struct JsonParse { u32 *aUp; /* Index of parent of each node */ u8 oom; /* Set to true if out of memory */ u8 nErr; /* Number of errors seen */ + u16 iDepth; /* Nesting depth */ }; +/* +** Maximum nesting depth of JSON for this implementation. +** +** This limit is needed to avoid a stack overflow in the recursive +** descent parser. A depth of 2000 is far deeper than any sane JSON +** should go. +*/ +#define JSON_MAX_DEPTH 2000 + /************************************************************************** ** Utility routines for dealing with JsonString objects **************************************************************************/ @@ -735,8 +746,10 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ if( iThis<0 ) return -1; for(j=i+1;;j++){ while( safe_isspace(z[j]) ){ j++; } + if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; x = jsonParseValue(pParse, j); if( x<0 ){ + pParse->iDepth--; if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; return -1; } @@ -749,6 +762,7 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ if( z[j]!=':' ) return -1; j++; x = jsonParseValue(pParse, j); + pParse->iDepth--; if( x<0 ) return -1; j = x; while( safe_isspace(z[j]) ){ j++; } @@ -765,7 +779,9 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ if( iThis<0 ) return -1; for(j=i+1;;j++){ while( safe_isspace(z[j]) ){ j++; } + if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1; x = jsonParseValue(pParse, j); + pParse->iDepth--; if( x<0 ){ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; return -1; @@ -885,6 +901,7 @@ static int jsonParse( i = jsonParseValue(pParse, 0); if( pParse->oom ) i = -1; if( i>0 ){ + assert( pParse->iDepth==0 ); while( safe_isspace(zJson[i]) ) i++; if( zJson[i] ) i = -1; } diff --git a/manifest b/manifest index 24cef3a8e4..e085e3f18c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Smaller\sand\sfaster\simplementation\sof\sexprMightBeIndexed(). -D 2017-04-11T18:06:48.387 +C Limit\sthe\sdepth\sof\srecursion\sfor\svalid\sJSON\sin\sthe\sJSON1\sextension\sin\sorder\nto\savoid\susing\sexcess\sstack\sspace\sin\sthe\srecursive\sdescent\sparser.\nFix\sfor\sticket\s[981329adeef51011052667a9]. +D 2017-04-11T18:55:05.542 F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc a4c0613a18663bda56d8cf76079ab6590a7c3602e54befb4bbdef76bcaa38b6a @@ -218,7 +218,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2 F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25 F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c -F ext/misc/json1.c 70d49f69ce61e54a83a29e425e704ca3e7e42e6bd9a7cf3c112d0ad995f6560b +F ext/misc/json1.c 18d80526c34e3eab8adf6a86f7e45b873c19b33d341e76993590a3fca9aefa14 F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33 F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342 F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e @@ -911,7 +911,7 @@ F test/journal3.test ff8af941f9e06161d3db1b46bb9f965ff0e7f307 F test/jrnlmode.test 7864d59cf7f6e552b9b99ba0f38acd167edc10fa F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa -F test/json101.test c0897616f32d95431f37fd291cb78742181980ac +F test/json101.test 9e68ac5c7cb3fabe22677d919ca025f80f27dde37f4e760b43f9720179ee466c F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1 F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0 F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa @@ -1571,7 +1571,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 4143650c4ce32289d2301cdfc69bb10877246420f656bed122886f6803fc956a -R 1aa45dcbe6873a793fc57d44af855002 +P 76cd611d41465fcec61c21520d55172cb236530f38386b7d4a5544ba87de2353 +R 4121191f9cbabfb85c1e92872e6e98a5 U drh -Z c24847878c6bf2e9fe8bedbea41e582e +Z 8a8f0ee4e24e0270c8727f53d830c8c6 diff --git a/manifest.uuid b/manifest.uuid index a6b9476e65..fa40f168fa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -76cd611d41465fcec61c21520d55172cb236530f38386b7d4a5544ba87de2353 \ No newline at end of file +1f68c184596912d742b50b1ca38252a9e783aacf121619a27b17a7ae9f6df041 \ No newline at end of file diff --git a/test/json101.test b/test/json101.test index 37123eef1d..e7dc8888c8 100644 --- a/test/json101.test +++ b/test/json101.test @@ -688,5 +688,29 @@ do_execsql_test json-10.95 { SELECT json_valid('" \~ "'); } {0} +#-------------------------------------------------------------------------- +# 2017-04-11. https://www.sqlite.org/src/info/981329adeef51011 +# Stack overflow on deeply nested JSON. +# +# The following tests confirm that deeply nested JSON is considered invalid. +# +do_execsql_test json-11.0 { + /* Shallow enough to be parsed */ + SELECT json_valid(printf('%.2000c0%.2000c','[',']')); +} {1} +do_execsql_test json-11.1 { + /* Too deep by one */ + SELECT json_valid(printf('%.2001c0%.2001c','[',']')); +} {0} +do_execsql_test json-11.2 { + /* Shallow enough to be parsed { */ + SELECT json_valid(replace(printf('%.2000c0%.2000c','[','}'),'[','{"a":')); + /* } */ +} {1} +do_execsql_test json-11.3 { + /* Too deep by one { */ + SELECT json_valid(replace(printf('%.2001c0%.2001c','[','}'),'[','{"a":')); + /* } */ +} {0} finish_test