[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#864088: unblock (pre-approval): sqlite3/3.6.12-4



Package: release.debian.org
User: release.debian.org@packages.debian.org
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) <gcs@debian.org>  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

Reply to: