CVE-2019-19923: NULL Pointer Dereference (CWE-476)
value: flattenSubquery in select.c in SQLite 3.30.1 mishandles certain uses of SELECT DISTINCT involving a LEFT JOIN in which the right-hand side is a view. This can cause a NULL pointer dereference (or incorrect results).
CWE description: The product dereferences a pointer that it expects to be valid but is NULL.
CVSS v3 base score: 7.5
Published: 2019-12-24T16:15Z
Repository: https://github.com/sqlite/sqlite
Language: Other
Files changed: manifest, manifest.uuid, src/select.c, test/join.test
Commit date: 2019-12-18 20:51:58 +0000
Commit message: Continue to back away from the LEFT JOIN optimization of check-in [41c27bc0ff1d3135]
by disallowing query flattening if the outer query is DISTINCT.  Without this fix,
if an index scan is run on the table within the view on the right-hand side of the
LEFT JOIN, stale result registers might be accessed yielding incorrect results,
and/or an OP_IfNullRow opcode might be invoked on the un-opened table, resulting
in a NULL-pointer dereference.  This problem was found by the Yongheng and Rui fuzzer.

FossilOrigin-Name: 862974312edf00e9d1068115d1a39b7235b7db68b6d86b81d38a12f025a4748e
Diff: diff --git a/manifest b/manifest
index a202a22b061..f2fcc703905 100644
--- a/manifest
+++ b/manifest
@@ -1,7 +1,7 @@
-C Add\sthe\s--vdbe-debug\soption\sto\sfuzzcheck.
-D 2019-12-18T13:42:04.200
+C Continue\sto\sback\saway\sfrom\sthe\sLEFT\sJOIN\soptimization\sof\scheck-in\s[41c27bc0ff1d3135]\nby\sdisallowing\squery\sflattening\sif\sthe\souter\squery\sis\sDISTINCT.\s\sWithout\sthis\sfix,\nif\san\sindex\sscan\sis\srun\son\sthe\stable\swithin\sthe\sview\son\sthe\sright-hand\sside\sof\sthe\nLEFT\sJOIN,\sstale\sresult\sregisters\smight\sbe\saccessed\syielding\sincorrect\sresults,\nand/or\san\sOP_IfNullRow\sopcode\smight\sbe\sinvoked\son\sthe\sun-opened\stable,\sresulting\nin\sa\sNULL-pointer\sdereference.\s\sThis\sproblem\swas\sfound\sby\sthe\sYongheng\sand\sRui\sfuzzer.
+D 2019-12-18T20:51:58.702
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
 F Makefile.in d3a862c9742f5a08230a3b295c0a47fd3067f19356dc39935280135f90474b04
 F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
@@ -525,11 +525,11 @@ F src/pragma.h ec3b31eac9b1df040f1cc8cb3d89bc06605c3b4cb3d76f833de8d6d6c3f77f04
 F src/prepare.c 6049beb71385f017af6fc320d2c75a4e50b75e280c54232442b785fbb83df057
 F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4
 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
 F src/resolve.c 86a7773d2892227ba9ad1721c41bb03c501830f1bf6de5f78dd0062b82e10c9d
 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
-F src/select.c 0fe10579de20eb8dc04ec9ed29659fa782bee2bcc85a35734637f3e2cabc2762
+F src/select.c dd7e40967760b28efe274ade35043d5bf5d72774208bb75d2cb4dd59cbd59ad1
 F src/shell.c.in 4a3a9e1c11847b1904f2b01d087af1c052f660902755abab457cab1756817ded
 F src/sqlite.h.in 2a23e8161775253d9cf383c2c6aa559005dc787d350dcb0be67a6c4cc3bd1d19
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 72af51aa4e912e14cd495fb6e7fac65f0940db80ed950d90911aff292cc47ce2
 F src/sqliteInt.h 60d92fad64da7c3e77bbc35ee306340814cdaa5df32892b0ec58d306d99b5733
@@ -1082,11 +1082,11 @@ F test/ioerr2.test 2593563599e2cc6b6b4fcf5878b177bdd5d8df26
 F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
 F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
 F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
 F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
 F test/istrue.test 75327829744e65cc8700e69340b8e6c192e10e39dfae7ccb0e970d3c4f49090a
-F test/join.test f787ee2716efe5beeb9888d10630f917b112c32b6b3e612e48a17ea8aed3a8eb
+F test/join.test 99e1d82fada7a1df9002a7b1160bd231c91077b9372492d5e18bfa1d1694d43c
 F test/join2.test 10f7047e723ebd68b2f47189be8eed20451a6f665d8bf46f1774c640d1062417
 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
 F test/join5.test 3a96dc62f0b45402d7207e22d1993fe0c2fce1c57644a11439891dd62b990eb7
 F test/join6.test cfe6503791ceb0cbb509966740286ec423cbf10b
@@ -1850,9 +1850,9 @@ F vsixtest/pch.h 9cab7980f2ac4baa40807d8b5e52af32a21cf78c
 F vsixtest/vsixtest.sln 77cadbe4e96c1fe1bf51cd77de9e9b0a12ada547
 F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P ae7cbb246bff3717c283869ccf27ce83611422f3801176819465a8d96f6481bf
-R 698a2a75d4b0cd7521db241025664bfa
+P 289158aa24b066c453d2bce4bc2dead1c56fb0b23c3f7c4810b34b13627cef34
+R 9f20156b75204a3ebfd831615fb6a91c
 U drh
-Z 3b78f03b6dfb23a7688d2381f3d2f680
+Z bb78c6170ca7c38efc6081f3520d1341
diff --git a/manifest.uuid b/manifest.uuid
index f2c7aaca3cd..f41b130af7c 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-289158aa24b066c453d2bce4bc2dead1c56fb0b23c3f7c4810b34b13627cef34
\ No newline at end of file
+862974312edf00e9d1068115d1a39b7235b7db68b6d86b81d38a12f025a4748e
\ No newline at end of file
diff --git a/src/select.c b/src/select.c
index 26c72d6dade..a94c4236e8a 100644
--- a/src/select.c
+++ b/src/select.c
@@ -3598,10 +3598,11 @@ static void substSelect(
 **   (3)  If the subquery is the right operand of a LEFT JOIN then
 **        (3a) the subquery may not be a join and
 **        (3b) the FROM clause of the subquery may not contain a virtual
 **             table and
 **        (3c) the outer query may not be an aggregate.
+**        (3d) the outer query may not be DISTINCT.
 **
 **   (4)  The subquery can not be DISTINCT.
 **
 **  (**)  At one point restrictions (4) and (5) defined a subset of DISTINCT
 **        sub-queries that were excluded from this optimization. Restriction 
@@ -3794,12 +3795,15 @@ static int flattenSubquery(
   **
   ** See also tickets #306, #350, and #3300.
   */
   if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
     isLeftJoin = 1;
-    if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){
-      /*  (3a)             (3c)     (3b) */
+    if( pSubSrc->nSrc>1                   /* (3a) */
+     || isAgg                             /* (3b) */
+     || IsVirtual(pSubSrc->a[0].pTab)     /* (3c) */
+     || (p->selFlags & SF_Distinct)!=0    /* (3d) */
+    ){
       return 0;
     }
   }
 #ifdef SQLITE_EXTRA_IFNULLROW
   else if( iFrom>0 && !isAgg ){
diff --git a/test/join.test b/test/join.test
index 19a061d46ed..3b8936fc0ee 100644
--- a/test/join.test
+++ b/test/join.test
@@ -973,6 +973,19 @@ do_execsql_test join-21.10 {
   SELECT 22, * FROM t1 LEFT JOIN t0 WHERE +aa ISNULL;
   SELECT 23, * FROM t1 LEFT JOIN t0 ON aa ISNULL;
   SELECT 24, * FROM t1 LEFT JOIN t0 ON +aa ISNULL;
 } {13 1 {} 14 1 {} 23 1 {} 24 1 {}}
 
+# 2019-12-18 problem with a LEFT JOIN where the RHS is a view.
+# Detected by Yongheng and Rui.
+# Follows from the optimization attempt of check-in 41c27bc0ff1d3135
+# on 2017-04-18
+#
+reset_db
+do_execsql_test join-22.10 {
+  CREATE TABLE t0(a, b);
+  CREATE INDEX t0a ON t0(a);
+  INSERT INTO t0 VALUES(10,10),(10,11),(10,12);
+  SELECT DISTINCT c FROM t0 LEFT JOIN (SELECT a+1 AS c FROM t0) ORDER BY c ;
+} {11}
+
 finish_test

Vulnerable code: C Add\sthe\s--vdbe-debug\soption\sto\sfuzzcheck.
D 2019-12-18T13:42:04.200
F src/select.c 0fe10579de20eb8dc04ec9ed29659fa782bee2bcc85a35734637f3e2cabc2762
F test/join.test f787ee2716efe5beeb9888d10630f917b112c32b6b3e612e48a17ea8aed3a8eb
P ae7cbb246bff3717c283869ccf27ce83611422f3801176819465a8d96f6481bf
R 698a2a75d4b0cd7521db241025664bfa
Z 3b78f03b6dfb23a7688d2381f3d2f680
289158aa24b066c453d2bce4bc2dead1c56fb0b23c3f7c4810b34b13627cef34
    if( pSubSrc->nSrc>1 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){
      /*  (3a)             (3c)     (3b) */
Fixed code: C Continue\sto\sback\saway\sfrom\sthe\sLEFT\sJOIN\soptimization\sof\scheck-in\s[41c27bc0ff1d3135]\nby\sdisallowing\squery\sflattening\sif\sthe\souter\squery\sis\sDISTINCT.\s\sWithout\sthis\sfix,\nif\san\sindex\sscan\sis\srun\son\sthe\stable\swithin\sthe\sview\son\sthe\sright-hand\sside\sof\sthe\nLEFT\sJOIN,\sstale\sresult\sregisters\smight\sbe\saccessed\syielding\sincorrect\sresults,\nand/or\san\sOP_IfNullRow\sopcode\smight\sbe\sinvoked\son\sthe\sun-opened\stable,\sresulting\nin\sa\sNULL-pointer\sdereference.\s\sThis\sproblem\swas\sfound\sby\sthe\sYongheng\sand\sRui\sfuzzer.
D 2019-12-18T20:51:58.702
F src/select.c dd7e40967760b28efe274ade35043d5bf5d72774208bb75d2cb4dd59cbd59ad1
F test/join.test 99e1d82fada7a1df9002a7b1160bd231c91077b9372492d5e18bfa1d1694d43c
P 289158aa24b066c453d2bce4bc2dead1c56fb0b23c3f7c4810b34b13627cef34
R 9f20156b75204a3ebfd831615fb6a91c
Z bb78c6170ca7c38efc6081f3520d1341
862974312edf00e9d1068115d1a39b7235b7db68b6d86b81d38a12f025a4748e
**        (3d) the outer query may not be DISTINCT.
    if( pSubSrc->nSrc>1                   /* (3a) */
     || isAgg                             /* (3b) */
     || IsVirtual(pSubSrc->a[0].pTab)     /* (3c) */
     || (p->selFlags & SF_Distinct)!=0    /* (3d) */
    ){
# 2019-12-18 problem with a LEFT JOIN where the RHS is a view.
# Detected by Yongheng and Rui.
# Follows from the optimization attempt of check-in 41c27bc0ff1d3135
# on 2017-04-18
#
reset_db
do_execsql_test join-22.10 {
  CREATE TABLE t0(a, b);
  CREATE INDEX t0a ON t0(a);
  INSERT INTO t0 VALUES(10,10),(10,11),(10,12);
  SELECT DISTINCT c FROM t0 LEFT JOIN (SELECT a+1 AS c FROM t0) ORDER BY c ;
} {11}