Package: release.debian.org User: [email protected] Usertags: unblock
Hi Release Team, I would like to upload a security related update for sqlite3. It contains: - Prevent a possible NULL pointer dereference in the OP_Found opcode that can follow an OOM error. Problem found by OSS-Fuzz[1], - Stack overflow while parsing deeply nested JSON[2], - JSON allows unescaped control characters in strings[3], - JSON extension accepts invalid numeric values[4]. Upstream tagged these as 'code defect' and severity 'severe'. The changes itself are small and the 3.19.2-1 version in experimental contains these fixes. Debdiff is attached. Thanks for consideration. Regards, Laszlo/GCS [1] http://www.sqlite.org/src/info/c2de178fe7e2e4e0 [2] https://www.sqlite.org/src/info/981329adeef51011052 [3] https://www.sqlite.org/src/info/6c9b5514077fed34551 [4] https://www.sqlite.org/src/info/b93be8729a895a528e2
diff -Nru sqlite3-3.16.2/debian/changelog sqlite3-3.16.2/debian/changelog --- sqlite3-3.16.2/debian/changelog 2017-02-13 17:31:26.000000000 +0000 +++ sqlite3-3.16.2/debian/changelog 2017-06-04 07:58:54.000000000 +0000 @@ -1,3 +1,13 @@ +sqlite3 (3.16.2-4) unstable; urgency=high + + * Backport fix for a possible NULL pointer dereference in the OP_Found + opcode that can follow an OOM error. + * Backport fix for stack overflow while parsing deeply nested JSON. + * Backport fix for JSON allows unescaped control characters in strings. + * Backport fix for JSON extension accepts invalid numeric values. + + -- Laszlo Boszormenyi (GCS) <[email protected]> Sun, 04 Jun 2017 07:58:54 +0000 + sqlite3 (3.16.2-3) unstable; urgency=medium * Backport upstream fix to ensure that sqlite3_blob_reopen() correctly diff -Nru sqlite3-3.16.2/debian/patches/36-OSS-Fuzz.patch sqlite3-3.16.2/debian/patches/36-OSS-Fuzz.patch --- sqlite3-3.16.2/debian/patches/36-OSS-Fuzz.patch 1970-01-01 00:00:00.000000000 +0000 +++ sqlite3-3.16.2/debian/patches/36-OSS-Fuzz.patch 2017-06-04 07:58:54.000000000 +0000 @@ -0,0 +1,24 @@ +Index: sqlite3/src/vdbe.c +================================================================== +--- sqlite3/src/vdbe.c ++++ sqlite3/src/vdbe.c +@@ -4017,14 +4017,16 @@ + } + #endif + pIdxKey = &r; + pFree = 0; + }else{ ++ assert( pIn3->flags & MEM_Blob ); ++ rc = ExpandBlob(pIn3); ++ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); ++ if( rc ) goto no_mem; + pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo); + if( pIdxKey==0 ) goto no_mem; +- assert( pIn3->flags & MEM_Blob ); +- (void)ExpandBlob(pIn3); + sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); + } + pIdxKey->default_rc = 0; + takeJump = 0; + if( pOp->opcode==OP_NoConflict ){ + diff -Nru sqlite3-3.16.2/debian/patches/40-JSON-1.patch sqlite3-3.16.2/debian/patches/40-JSON-1.patch --- sqlite3-3.16.2/debian/patches/40-JSON-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ sqlite3-3.16.2/debian/patches/40-JSON-1.patch 2017-06-04 07:58:54.000000000 +0000 @@ -0,0 +1,205 @@ +Index: sqlite3/ext/misc/json1.c +================================================================== +--- sqlite3/ext/misc/json1.c ++++ sqlite3/ext/misc/json1.c +@@ -726,17 +726,18 @@ + char c; + u32 j; + int iThis; + int x; + JsonNode *pNode; +- while( safe_isspace(pParse->zJson[i]) ){ i++; } +- if( (c = pParse->zJson[i])=='{' ){ ++ const char *z = pParse->zJson; ++ while( safe_isspace(z[i]) ){ i++; } ++ if( (c = z[i])=='{' ){ + /* Parse object */ + iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + if( iThis<0 ) return -1; + for(j=i+1;;j++){ +- while( safe_isspace(pParse->zJson[j]) ){ j++; } ++ while( safe_isspace(z[j]) ){ j++; } + x = jsonParseValue(pParse, j); + if( x<0 ){ + if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; + return -1; + } +@@ -743,18 +744,18 @@ + if( pParse->oom ) return -1; + pNode = &pParse->aNode[pParse->nNode-1]; + if( pNode->eType!=JSON_STRING ) return -1; + pNode->jnFlags |= JNODE_LABEL; + j = x; +- while( safe_isspace(pParse->zJson[j]) ){ j++; } +- if( pParse->zJson[j]!=':' ) return -1; ++ while( safe_isspace(z[j]) ){ j++; } ++ if( z[j]!=':' ) return -1; + j++; + x = jsonParseValue(pParse, j); + if( x<0 ) return -1; + j = x; +- while( safe_isspace(pParse->zJson[j]) ){ j++; } +- c = pParse->zJson[j]; ++ while( safe_isspace(z[j]) ){ j++; } ++ c = z[j]; + if( c==',' ) continue; + if( c!='}' ) return -1; + break; + } + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; +@@ -762,19 +763,19 @@ + }else if( c=='[' ){ + /* Parse array */ + iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + if( iThis<0 ) return -1; + for(j=i+1;;j++){ +- while( safe_isspace(pParse->zJson[j]) ){ j++; } ++ while( safe_isspace(z[j]) ){ j++; } + x = jsonParseValue(pParse, j); + if( x<0 ){ + if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; + return -1; + } + j = x; +- while( safe_isspace(pParse->zJson[j]) ){ j++; } +- c = pParse->zJson[j]; ++ while( safe_isspace(z[j]) ){ j++; } ++ c = z[j]; + if( c==',' ) continue; + if( c!=']' ) return -1; + break; + } + pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; +@@ -782,75 +783,80 @@ + }else if( c=='"' ){ + /* Parse string */ + u8 jnFlags = 0; + j = i+1; + for(;;){ +- c = pParse->zJson[j]; ++ c = z[j]; + if( c==0 ) return -1; + if( c=='\\' ){ +- c = pParse->zJson[++j]; ++ c = z[++j]; + if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' + || c=='n' || c=='r' || c=='t' +- || (c=='u' && jsonIs4Hex(pParse->zJson+j+1)) ){ ++ || (c=='u' && jsonIs4Hex(z+j+1)) ){ + jnFlags = JNODE_ESCAPE; + }else{ + return -1; + } + }else if( c=='"' ){ + break; + } + j++; + } +- jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]); ++ jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]); + if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; + return j+1; + }else if( c=='n' +- && strncmp(pParse->zJson+i,"null",4)==0 +- && !safe_isalnum(pParse->zJson[i+4]) ){ ++ && strncmp(z+i,"null",4)==0 ++ && !safe_isalnum(z[i+4]) ){ + jsonParseAddNode(pParse, JSON_NULL, 0, 0); + return i+4; + }else if( c=='t' +- && strncmp(pParse->zJson+i,"true",4)==0 +- && !safe_isalnum(pParse->zJson[i+4]) ){ ++ && strncmp(z+i,"true",4)==0 ++ && !safe_isalnum(z[i+4]) ){ + jsonParseAddNode(pParse, JSON_TRUE, 0, 0); + return i+4; + }else if( c=='f' +- && strncmp(pParse->zJson+i,"false",5)==0 +- && !safe_isalnum(pParse->zJson[i+5]) ){ ++ && strncmp(z+i,"false",5)==0 ++ && !safe_isalnum(z[i+5]) ){ + jsonParseAddNode(pParse, JSON_FALSE, 0, 0); + return i+5; + }else if( c=='-' || (c>='0' && c<='9') ){ + /* Parse number */ + u8 seenDP = 0; + u8 seenE = 0; ++ assert( '-' < '0' ); ++ if( c<='0' ){ ++ j = c=='-' ? i+1 : i; ++ if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1; ++ } + j = i+1; + for(;; j++){ +- c = pParse->zJson[j]; ++ c = z[j]; + if( c>='0' && c<='9' ) continue; + if( c=='.' ){ +- if( pParse->zJson[j-1]=='-' ) return -1; ++ if( z[j-1]=='-' ) return -1; + if( seenDP ) return -1; + seenDP = 1; + continue; + } + if( c=='e' || c=='E' ){ +- if( pParse->zJson[j-1]<'0' ) return -1; ++ if( z[j-1]<'0' ) return -1; + if( seenE ) return -1; + seenDP = seenE = 1; +- c = pParse->zJson[j+1]; ++ c = z[j+1]; + if( c=='+' || c=='-' ){ + j++; +- c = pParse->zJson[j+1]; ++ c = z[j+1]; + } + if( c<'0' || c>'9' ) return -1; + continue; + } + break; + } +- if( pParse->zJson[j-1]<'0' ) return -1; ++ if( z[j-1]<'0' ) return -1; + jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, +- j - i, &pParse->zJson[i]); ++ j - i, &z[i]); + return j; + }else if( c=='}' ){ + return -2; /* End of {...} */ + }else if( c==']' ){ + return -3; /* End of [...] */ + +Index: sqlite3/test/json102.test +================================================================== +--- sqlite3/test/json102.test ++++ sqlite3/test/json102.test +@@ -295,7 +295,28 @@ + set str abcdef[string repeat \" [expr {$i+50}]]uvwxyz + do_test json102-[format %d [expr {$i+1300}]] { + db eval {SELECT json_extract(json_array($::str),'$[0]')==$::str} + } {1} + } ++ ++#------------------------------------------------------------------------- ++# 2017-04-08 ticket b93be8729a895a528e2849fca99f7 ++# JSON extension accepts invalid numeric values ++# ++# JSON does not allow leading zeros. But the JSON extension was ++# allowing them. The following tests verify that the problem is now ++# fixed. ++# ++do_execsql_test json102-1401 { SELECT json_valid('{"x":01}') } 0 ++do_execsql_test json102-1402 { SELECT json_valid('{"x":-01}') } 0 ++do_execsql_test json102-1403 { SELECT json_valid('{"x":0}') } 1 ++do_execsql_test json102-1404 { SELECT json_valid('{"x":-0}') } 1 ++do_execsql_test json102-1405 { SELECT json_valid('{"x":0.1}') } 1 ++do_execsql_test json102-1406 { SELECT json_valid('{"x":-0.1}') } 1 ++do_execsql_test json102-1407 { SELECT json_valid('{"x":0.0000}') } 1 ++do_execsql_test json102-1408 { SELECT json_valid('{"x":-0.0000}') } 1 ++do_execsql_test json102-1409 { SELECT json_valid('{"x":01.5}') } 0 ++do_execsql_test json102-1410 { SELECT json_valid('{"x":-01.5}') } 0 ++do_execsql_test json102-1411 { SELECT json_valid('{"x":00}') } 0 ++do_execsql_test json102-1412 { SELECT json_valid('{"x":-00}') } 0 + + finish_test + diff -Nru sqlite3-3.16.2/debian/patches/41-JSON-2_1.patch sqlite3-3.16.2/debian/patches/41-JSON-2_1.patch --- sqlite3-3.16.2/debian/patches/41-JSON-2_1.patch 1970-01-01 00:00:00.000000000 +0000 +++ sqlite3-3.16.2/debian/patches/41-JSON-2_1.patch 2017-06-04 07:58:54.000000000 +0000 @@ -0,0 +1,42 @@ +Index: sqlite3/ext/misc/json1.c +================================================================== +--- sqlite3/ext/misc/json1.c ++++ sqlite3/ext/misc/json1.c +@@ -784,11 +784,11 @@ + /* Parse string */ + u8 jnFlags = 0; + j = i+1; + for(;;){ + c = z[j]; +- if( c==0 ) return -1; ++ if( c<=0x1f ) return -1; /* Control characters not allowed in strings */ + if( c=='\\' ){ + c = z[++j]; + if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' + || c=='n' || c=='r' || c=='t' + || (c=='u' && jsonIs4Hex(z+j+1)) ){ + +Index: sqlite3/test/json102.test +================================================================== +--- sqlite3/test/json102.test ++++ sqlite3/test/json102.test +@@ -316,7 +316,18 @@ + do_execsql_test json102-1408 { SELECT json_valid('{"x":-0.0000}') } 1 + do_execsql_test json102-1409 { SELECT json_valid('{"x":01.5}') } 0 + do_execsql_test json102-1410 { SELECT json_valid('{"x":-01.5}') } 0 + do_execsql_test json102-1411 { SELECT json_valid('{"x":00}') } 0 + do_execsql_test json102-1412 { SELECT json_valid('{"x":-00}') } 0 ++ ++#------------------------------------------------------------------------ ++# 2017-04-10 ticket 6c9b5514077fed34551f98e64c09a10dc2fc8e16 ++# JSON extension accepts strings containing control characters. ++# ++# The JSON spec requires that all control characters be escaped. ++# ++do_execsql_test json102-1500 { ++ WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<0x20) ++ SELECT x FROM c WHERE json_valid(printf('{"a":"x%sz"}', char(x))) ORDER BY x; ++} {32} + + finish_test + diff -Nru sqlite3-3.16.2/debian/patches/42-JSON-2_2.patch sqlite3-3.16.2/debian/patches/42-JSON-2_2.patch --- sqlite3-3.16.2/debian/patches/42-JSON-2_2.patch 1970-01-01 00:00:00.000000000 +0000 +++ sqlite3-3.16.2/debian/patches/42-JSON-2_2.patch 2017-06-04 07:58:54.000000000 +0000 @@ -0,0 +1,46 @@ +Index: sqlite3/ext/misc/json1.c +================================================================== +--- sqlite3/ext/misc/json1.c ++++ sqlite3/ext/misc/json1.c +@@ -784,11 +784,14 @@ + /* Parse string */ + u8 jnFlags = 0; + j = i+1; + for(;;){ + c = z[j]; +- if( c<=0x1f ) return -1; /* Control characters not allowed in strings */ ++ if( (c & ~0x1f)==0 ){ ++ /* Control characters are not allowed in strings */ ++ return -1; ++ } + if( c=='\\' ){ + c = z[++j]; + if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' + || c=='n' || c=='r' || c=='t' + || (c=='u' && jsonIs4Hex(z+j+1)) ){ + +Index: sqlite3/test/json101.test +================================================================== +--- sqlite3/test/json101.test ++++ sqlite3/test/json101.test +@@ -353,10 +353,19 @@ + SELECT b FROM t8; + } {{["abc\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#xyz"]}} + do_execsql_test json-8.2 { + SELECT a=json_extract(b,'$[0]') FROM t8; + } {1} ++ ++# 2017-04-12. Regression reported on the mailing list by Rolf Ade ++# ++do_execsql_test json-8.3 { ++ SELECT json_valid(char(0x22,0xe4,0x22)); ++} {1} ++do_execsql_test json-8.4 { ++ SELECT unicode(json_extract(char(0x22,228,0x22),'$')); ++} {228} + + # The json_quote() function transforms an SQL value into a JSON value. + # String values are quoted and interior quotes are escaped. NULL values + # are rendered as the unquoted string "null". + # + diff -Nru sqlite3-3.16.2/debian/patches/43-JSON-3.patch sqlite3-3.16.2/debian/patches/43-JSON-3.patch --- sqlite3-3.16.2/debian/patches/43-JSON-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ sqlite3-3.16.2/debian/patches/43-JSON-3.patch 2017-06-04 07:58:54.000000000 +0000 @@ -0,0 +1,130 @@ +Index: sqlite3/ext/misc/json1.c +================================================================== +--- sqlite3/ext/misc/json1.c ++++ sqlite3/ext/misc/json1.c +@@ -88,10 +88,11 @@ + #ifndef SQLITE_AMALGAMATION + /* Unsigned integer types. These are already defined in the sqliteInt.h, + ** 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 + + /* Objects */ + typedef struct JsonString JsonString; +@@ -165,12 +166,22 @@ + JsonNode *aNode; /* Array of nodes containing the parse */ + const char *zJson; /* Original JSON string */ + 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 + **************************************************************************/ + + /* Set the JsonString object to an empty string +@@ -734,12 +745,14 @@ + /* Parse object */ + iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); + 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; + } + if( pParse->oom ) return -1; + pNode = &pParse->aNode[pParse->nNode-1]; +@@ -748,10 +761,11 @@ + j = x; + while( safe_isspace(z[j]) ){ j++; } + 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++; } + c = z[j]; + if( c==',' ) continue; +@@ -764,11 +778,13 @@ + /* Parse array */ + iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); + 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; + } + j = x; +@@ -887,10 +903,11 @@ + if( zJson==0 ) return 1; + pParse->zJson = zJson; + 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; + } + if( i<=0 ){ + if( pCtx!=0 ){ + +Index: sqlite3/test/json101.test +================================================================== +--- sqlite3/test/json101.test ++++ sqlite3/test/json101.test +@@ -695,7 +695,31 @@ + } {0} + 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 + diff -Nru sqlite3-3.16.2/debian/patches/series sqlite3-3.16.2/debian/patches/series --- sqlite3-3.16.2/debian/patches/series 2017-02-13 17:31:26.000000000 +0000 +++ sqlite3-3.16.2/debian/patches/series 2017-06-04 07:58:54.000000000 +0000 @@ -7,3 +7,8 @@ 02-use-packaged-lempar.c.patch 32-fix_an_uninitialized_variable_in_the_command-line_shell.patch 35-fix-sqlite3_blob_reopen.patch +36-OSS-Fuzz.patch +40-JSON-1.patch +41-JSON-2_1.patch +42-JSON-2_2.patch +43-JSON-3.patch

