Blame SOURCES/sqlite-3.26.0-CVE-2019-5018.patch

7d97b9
Subject: [PATCH] Prevent aliases of window functions expressions from being
7d97b9
 used as arguments to aggregate or other window functions.
7d97b9
7d97b9
---
7d97b9
 src/resolve.c       |  21 ++++++---
7d97b9
 src/sqliteInt.h     |   2 +
7d97b9
 test/windowerr.tcl  |  59 ++++++++++++++++++++++++++
7d97b9
 test/windowerr.test | 99 ++++++++++++++++++++++++++++++++++++++++++
7d97b9
 4 files changed, 176 insertions(+), 5 deletions(-)
7d97b9
 create mode 100644 test/windowerr.tcl
7d97b9
 create mode 100644 test/windowerr.test
7d97b9
7d97b9
diff --git a/src/resolve.c b/src/resolve.c
7d97b9
index 0c7dfc0..cdcf4d9 100644
7d97b9
--- a/src/resolve.c
7d97b9
+++ b/src/resolve.c
7d97b9
@@ -436,6 +436,10 @@ static int lookupName(
7d97b9
             sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
7d97b9
             return WRC_Abort;
7d97b9
           }
7d97b9
+          if( (pNC->ncFlags&NC_AllowWin)==0 && ExprHasProperty(pOrig, EP_Win) ){
7d97b9
+            sqlite3ErrorMsg(pParse, "misuse of aliased window function %s",zAs);
7d97b9
+            return WRC_Abort;
7d97b9
+          }
7d97b9
           if( sqlite3ExprVectorSize(pOrig)!=1 ){
7d97b9
             sqlite3ErrorMsg(pParse, "row value misused");
7d97b9
             return WRC_Abort;
7d97b9
@@ -707,6 +711,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
7d97b9
       const char *zId;            /* The function name. */
7d97b9
       FuncDef *pDef;              /* Information about the function */
7d97b9
       u8 enc = ENC(pParse->db);   /* The database encoding */
7d97b9
+      int savedAllowFlags = (pNC->ncFlags & (NC_AllowAgg | NC_AllowWin));
7d97b9
 
7d97b9
       assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
7d97b9
       zId = pExpr->u.zToken;
7d97b9
@@ -828,8 +833,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
7d97b9
           pNC->nErr++;
7d97b9
         }
7d97b9
         if( is_agg ){
7d97b9
+          /* Window functions may not be arguments of aggregate functions.
7d97b9
+          ** Or arguments of other window functions. But aggregate functions
7d97b9
+          ** may be arguments for window functions.  */
7d97b9
 #ifndef SQLITE_OMIT_WINDOWFUNC
7d97b9
-          pNC->ncFlags &= ~(pExpr->y.pWin ? NC_AllowWin : NC_AllowAgg);
7d97b9
+          pNC->ncFlags &= ~(NC_AllowWin | (!pExpr->y.pWin ? NC_AllowAgg : 0));
7d97b9
 #else
7d97b9
           pNC->ncFlags &= ~NC_AllowAgg;
7d97b9
 #endif
7d97b9
@@ -850,7 +858,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
7d97b9
             pExpr->y.pWin->pNextWin = pSel->pWin;
7d97b9
             pSel->pWin = pExpr->y.pWin;
7d97b9
           }
7d97b9
-          pNC->ncFlags |= NC_AllowWin;
7d97b9
+          pNC->ncFlags |= NC_HasWin;
7d97b9
         }else
7d97b9
 #endif /* SQLITE_OMIT_WINDOWFUNC */
7d97b9
         {
7d97b9
@@ -868,8 +876,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
7d97b9
             pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);
7d97b9
 
7d97b9
           }
7d97b9
-          pNC->ncFlags |= NC_AllowAgg;
7d97b9
         }
7d97b9
+        pNC->ncFlags |= savedAllowFlags;
7d97b9
       }
7d97b9
       /* FIX ME:  Compute pExpr->affinity based on the expected return
7d97b9
       ** type of the function 
7d97b9
@@ -1573,8 +1581,8 @@ int sqlite3ResolveExprNames(
7d97b9
   Walker w;
7d97b9
 
7d97b9
   if( pExpr==0 ) return SQLITE_OK;
7d97b9
-  savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg);
7d97b9
-  pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg);
7d97b9
+  savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
7d97b9
+  pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
7d97b9
   w.pParse = pNC->pParse;
7d97b9
   w.xExprCallback = resolveExprStep;
7d97b9
   w.xSelectCallback = resolveSelectStep;
7d97b9
@@ -1593,6 +1601,9 @@ int sqlite3ResolveExprNames(
7d97b9
   if( pNC->ncFlags & NC_HasAgg ){
7d97b9
     ExprSetProperty(pExpr, EP_Agg);
7d97b9
   }
7d97b9
+  if( pNC->ncFlags & NC_HasWin ){
7d97b9
+    ExprSetProperty(pExpr, EP_Win);
7d97b9
+  }
7d97b9
   pNC->ncFlags |= savedHasAgg;
7d97b9
   return pNC->nErr>0 || w.pParse->nErr>0;
7d97b9
 }
7d97b9
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
7d97b9
index 5f5f3cc..b7d3571 100644
7d97b9
--- a/src/sqliteInt.h
7d97b9
+++ b/src/sqliteInt.h
7d97b9
@@ -2517,6 +2517,7 @@ struct Expr {
7d97b9
 #define EP_Alias     0x400000 /* Is an alias for a result set column */
7d97b9
 #define EP_Leaf      0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
7d97b9
 #define EP_WinFunc  0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
7d97b9
+#define EP_Win      0x8000000 /* Contains window functions */
7d97b9
 
7d97b9
 /*
7d97b9
 ** The EP_Propagate mask is a set of properties that automatically propagate
7d97b9
@@ -2773,6 +2774,7 @@ struct NameContext {
7d97b9
 #define NC_MinMaxAgg 0x1000  /* min/max aggregates seen.  See note above */
7d97b9
 #define NC_Complex   0x2000  /* True if a function or subquery seen */
7d97b9
 #define NC_AllowWin  0x4000  /* Window functions are allowed here */
7d97b9
+#define NC_HasWin    0x8000  /* One or more window functions seen */
7d97b9
 
7d97b9
 /*
7d97b9
 ** An instance of the following object describes a single ON CONFLICT
7d97b9
diff --git a/test/windowerr.tcl b/test/windowerr.tcl
7d97b9
new file mode 100644
7d97b9
index 0000000..80f464d
7d97b9
--- /dev/null
7d97b9
+++ b/test/windowerr.tcl
7d97b9
@@ -0,0 +1,59 @@
7d97b9
+# 2018 May 19
7d97b9
+#
7d97b9
+# The author disclaims copyright to this source code.  In place of
7d97b9
+# a legal notice, here is a blessing:
7d97b9
+#
7d97b9
+#    May you do good and not evil.
7d97b9
+#    May you find forgiveness for yourself and forgive others.
7d97b9
+#    May you share freely, never taking more than you give.
7d97b9
+#
7d97b9
+#***********************************************************************
7d97b9
+#
7d97b9
+
7d97b9
+source [file join [file dirname $argv0] pg_common.tcl]
7d97b9
+
7d97b9
+#=========================================================================
7d97b9
+
7d97b9
+start_test windowerr "2019 March 01"
7d97b9
+ifcapable !windowfunc
7d97b9
+
7d97b9
+execsql_test 1.0 {
7d97b9
+  DROP TABLE IF EXISTS t1;
7d97b9
+  CREATE TABLE t1(a INTEGER, b INTEGER);
7d97b9
+  INSERT INTO t1 VALUES(1, 1);
7d97b9
+  INSERT INTO t1 VALUES(2, 2);
7d97b9
+  INSERT INTO t1 VALUES(3, 3);
7d97b9
+  INSERT INTO t1 VALUES(4, 4);
7d97b9
+  INSERT INTO t1 VALUES(5, 5);
7d97b9
+}
7d97b9
+
7d97b9
+foreach {tn frame} {
7d97b9
+  1 "ORDER BY a ROWS BETWEEN -1 PRECEDING AND 1 FOLLOWING"
7d97b9
+  2 "ORDER BY a ROWS BETWEEN  1 PRECEDING AND -1 FOLLOWING"
7d97b9
+
7d97b9
+  3 "ORDER BY a RANGE BETWEEN -1 PRECEDING AND 1 FOLLOWING"
7d97b9
+  4 "ORDER BY a RANGE BETWEEN  1 PRECEDING AND -1 FOLLOWING"
7d97b9
+
7d97b9
+  5 "ORDER BY a GROUPS BETWEEN -1 PRECEDING AND 1 FOLLOWING"
7d97b9
+  6 "ORDER BY a GROUPS BETWEEN  1 PRECEDING AND -1 FOLLOWING"
7d97b9
+
7d97b9
+  7 "ORDER BY a,b RANGE BETWEEN  1 PRECEDING AND 1 FOLLOWING"
7d97b9
+
7d97b9
+  8 "PARTITION BY a RANGE BETWEEN  1 PRECEDING AND 1 FOLLOWING"
7d97b9
+} {
7d97b9
+  errorsql_test 1.$tn "
7d97b9
+  SELECT a, sum(b) OVER (
7d97b9
+    $frame
7d97b9
+  ) FROM t1 ORDER BY 1
7d97b9
+  "
7d97b9
+}
7d97b9
+errorsql_test 2.1 {
7d97b9
+  SELECT sum( sum(a) OVER () ) FROM t1;
7d97b9
+}
7d97b9
+
7d97b9
+errorsql_test 2.2 {
7d97b9
+  SELECT sum(a) OVER () AS xyz FROM t1 ORDER BY sum(xyz);
7d97b9
+}
7d97b9
+
7d97b9
+
7d97b9
+finish_test
7d97b9
diff --git a/test/windowerr.test b/test/windowerr.test
7d97b9
new file mode 100644
7d97b9
index 0000000..97dae64
7d97b9
--- /dev/null
7d97b9
+++ b/test/windowerr.test
7d97b9
@@ -0,0 +1,99 @@
7d97b9
+# 2019 March 01
7d97b9
+#
7d97b9
+# The author disclaims copyright to this source code.  In place of
7d97b9
+# a legal notice, here is a blessing:
7d97b9
+#
7d97b9
+#    May you do good and not evil.
7d97b9
+#    May you find forgiveness for yourself and forgive others.
7d97b9
+#    May you share freely, never taking more than you give.
7d97b9
+#
7d97b9
+#***********************************************************************
7d97b9
+# This file implements regression tests for SQLite library.
7d97b9
+#
7d97b9
+
7d97b9
+####################################################
7d97b9
+# DO NOT EDIT! THIS FILE IS AUTOMATICALLY GENERATED!
7d97b9
+####################################################
7d97b9
+
7d97b9
+set testdir [file dirname $argv0]
7d97b9
+source $testdir/tester.tcl
7d97b9
+set testprefix windowerr
7d97b9
+
7d97b9
+ifcapable !windowfunc { finish_test ; return }
7d97b9
+do_execsql_test 1.0 {
7d97b9
+  DROP TABLE IF EXISTS t1;
7d97b9
+  CREATE TABLE t1(a INTEGER, b INTEGER);
7d97b9
+  INSERT INTO t1 VALUES(1, 1);
7d97b9
+  INSERT INTO t1 VALUES(2, 2);
7d97b9
+  INSERT INTO t1 VALUES(3, 3);
7d97b9
+  INSERT INTO t1 VALUES(4, 4);
7d97b9
+  INSERT INTO t1 VALUES(5, 5);
7d97b9
+} {}
7d97b9
+
7d97b9
+# PG says ERROR:  frame starting offset must not be negative
7d97b9
+do_test 1.1 { catch { execsql {
7d97b9
+  SELECT a, sum(b) OVER (
7d97b9
+    ORDER BY a ROWS BETWEEN -1 PRECEDING AND 1 FOLLOWING
7d97b9
+  ) FROM t1 ORDER BY 1
7d97b9
+} } } 1
7d97b9
+
7d97b9
+# PG says ERROR:  frame ending offset must not be negative
7d97b9
+do_test 1.2 { catch { execsql {
7d97b9
+  SELECT a, sum(b) OVER (
7d97b9
+    ORDER BY a ROWS BETWEEN  1 PRECEDING AND -1 FOLLOWING
7d97b9
+  ) FROM t1 ORDER BY 1
7d97b9
+} } } 1
7d97b9
+
7d97b9
+# PG says ERROR:  invalid preceding or following size in window function
7d97b9
+do_test 1.3 { catch { execsql {
7d97b9
+  SELECT a, sum(b) OVER (
7d97b9
+    ORDER BY a RANGE BETWEEN -1 PRECEDING AND 1 FOLLOWING
7d97b9
+  ) FROM t1 ORDER BY 1
7d97b9
+} } } 1
7d97b9
+
7d97b9
+# PG says ERROR:  invalid preceding or following size in window function
7d97b9
+do_test 1.4 { catch { execsql {
7d97b9
+  SELECT a, sum(b) OVER (
7d97b9
+    ORDER BY a RANGE BETWEEN  1 PRECEDING AND -1 FOLLOWING
7d97b9
+  ) FROM t1 ORDER BY 1
7d97b9
+} } } 1
7d97b9
+
7d97b9
+# PG says ERROR:  frame starting offset must not be negative
7d97b9
+do_test 1.5 { catch { execsql {
7d97b9
+  SELECT a, sum(b) OVER (
7d97b9
+    ORDER BY a GROUPS BETWEEN -1 PRECEDING AND 1 FOLLOWING
7d97b9
+  ) FROM t1 ORDER BY 1
7d97b9
+} } } 1
7d97b9
+
7d97b9
+# PG says ERROR:  frame ending offset must not be negative
7d97b9
+do_test 1.6 { catch { execsql {
7d97b9
+  SELECT a, sum(b) OVER (
7d97b9
+    ORDER BY a GROUPS BETWEEN  1 PRECEDING AND -1 FOLLOWING
7d97b9
+  ) FROM t1 ORDER BY 1
7d97b9
+} } } 1
7d97b9
+
7d97b9
+# PG says ERROR:  RANGE with offset PRECEDING/FOLLOWING requires exactly one ORDER BY column
7d97b9
+do_test 1.7 { catch { execsql {
7d97b9
+  SELECT a, sum(b) OVER (
7d97b9
+    ORDER BY a,b RANGE BETWEEN  1 PRECEDING AND 1 FOLLOWING
7d97b9
+  ) FROM t1 ORDER BY 1
7d97b9
+} } } 1
7d97b9
+
7d97b9
+# PG says ERROR:  RANGE with offset PRECEDING/FOLLOWING requires exactly one ORDER BY column
7d97b9
+do_test 1.8 { catch { execsql {
7d97b9
+  SELECT a, sum(b) OVER (
7d97b9
+    PARTITION BY a RANGE BETWEEN  1 PRECEDING AND 1 FOLLOWING
7d97b9
+  ) FROM t1 ORDER BY 1
7d97b9
+} } } 1
7d97b9
+
7d97b9
+# PG says ERROR:  aggregate function calls cannot contain window function calls
7d97b9
+do_test 2.1 { catch { execsql {
7d97b9
+  SELECT sum( sum(a) OVER () ) FROM t1;
7d97b9
+} } } 1
7d97b9
+
7d97b9
+# PG says ERROR:  column "xyz" does not exist
7d97b9
+do_test 2.2 { catch { execsql {
7d97b9
+  SELECT sum(a) OVER () AS xyz FROM t1 ORDER BY sum(xyz);
7d97b9
+} } } 1
7d97b9
+
7d97b9
+finish_test
7d97b9
-- 
7d97b9
2.24.1
7d97b9