From 97e9560e2156209881ddb125ffb1a2f7fa275e4c Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 16 Oct 2026 13:59:23 +0000 Subject: [PATCH] Do not allow two or more sandbox() calls with the same nonce within the same SQL statement. Report a sandbox violation if a sandbox() contains the wrong number of arguments. FossilOrigin-Name: b3c63e883bb7d8f1504bc3fa863487ae7dfd923771e20a71e41114cd06b962db --- manifest | 17 +++++++---------- manifest.uuid | 2 +- src/expr.c | 42 +++++++++++++++++++++++++++++------------- test/sandbox1.sql | 12 +++++++++--- 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 6ec376b594..5dabd7f65f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Initial\simplementation\sof\sthe\sexperimental\ssandbox(N1,E,N2)\sfunction.\nThe\sfunction\sresolves\s(by\stransforming\sthe\sAST)\sto\sthe\sexpression\sE\sif\nN1\sand\sN2\sare\sthe\ssame\sconstant\sexpression.\s\sRequires\sthe\n-DSQLITE_ENABLE_SANDBOX_FUNCTION\scompile-time\soption. -D 2026-10-14T20:06:21.237 +C Do\snot\sallow\stwo\sor\smore\ssandbox()\scalls\swith\sthe\ssame\snonce\swithin\sthe\nsame\sSQL\sstatement.\s\sReport\sa\ssandbox\sviolation\sif\sa\ssandbox()\scontains\nthe\swrong\snumber\sof\sarguments. +D 2026-10-16T13:59:23.020 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -755,7 +755,7 @@ F src/date.c 080641f59097d14fc7341f8bc0458d273b3a62d8381916db8ccbc89c2aae07b3 F src/dbpage.c ec8590c5e7a564cef28ca3c6156521316a4d26cb572a34841b0bcb26b67b3f97 F src/dbstat.c 34d4e825fbf763640ce3dbc56910ab080495ef4a6efb48b2b1852a43d43763fc F src/delete.c f3f07c1fb6ac87fac2425d48fd40ecb2f24a4495a9966f5a939668d3576916c8 -F src/expr.c 5ba49ab1ace9fff5a551b71c148945e22cffc4de008eef678f3acab688a31028 +F src/expr.c c7c8a1ba8364c62804bfe44d34406cf6b519b020a2233e5686c0a7d83042ffcb F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 26788ae6c785d70f9829c4176e9764447014fc73e6ba31e9f1881720a64ae7f1 F src/func.c 9372b65d0e5e6fc9fff7c4fc20558c5e68babcc7f54f033bba67da39f47acc37 @@ -1654,7 +1654,7 @@ F test/rowvaluevtab.test cd9747bb3f308086944c07968f547ad6b05022e698d80b9ffbdfe09 F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09 F test/safemode.sql 8373efb03c49a9ceae81fa6d9216c69d7e8573351b273b3f82ae2c5ad9305f99 -F test/sandbox1.sql 35ec3792bde234d03b446a0d5551dba210d4a7bdfb3ee64cd4b7d18cdbd2a613 +F test/sandbox1.sql c325073f9cfcfd2ad6d89eec3369e4e934fb9638d3f4dbe84ea75daebb64d506 F test/savepoint.test 6e9804a17767f08432c7a5e738b9a8f4b891d243110b63d3a41d270d3d1378ec F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7 F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 @@ -2290,11 +2290,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 7408f90ecc2dd26aceb52f92de78b8e1521cb5a294d3231fd32a903afe1db41d -R 2f6a7a6115fad7c13aff2db60c940aac -T *branch * sandbox-func -T *sym-sandbox-func * -T -sym-trunk * +P 035fd52d54a6f8f9c8276a48f466d660832d46d05a02b3ee4a41959922a4bc22 +R a668fd077309af45fcbf778efb15e155 U drh -Z f504d7ec1dca2d8a14e6b845203e3501 +Z cbe4b9ecb15f85c27a4bcdae1726205d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 69c6435f32..a14010ea8b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -035fd52d54a6f8f9c8276a48f466d660832d46d05a02b3ee4a41959922a4bc22 +b3c63e883bb7d8f1504bc3fa863487ae7dfd923771e20a71e41114cd06b962db diff --git a/src/expr.c b/src/expr.c index 80aa520d45..f32ed65a7c 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1196,24 +1196,44 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ ** * N1 (and hence N2 also, due to the prior constrant) must both be ** a constant expression. It cannot use variables or table references. ** +** * N1 must be unique for all sandbox() calls within the same SQL +** statement. +** ** * E does not contain any subqueries - either scalar subqueries or ** "EXISTS" expressions or IN operators where the RHS is a subquery. */ static SQLITE_NOINLINE Expr *exprSandbox(Parse *pParse, Expr *pOrig){ - struct ExprList_item *a = pOrig->x.pList->a; - Expr *pMid = a[1].pExpr; - if( sqlite3ExprCompare(pParse, a[0].pExpr, a[2].pExpr, 0)!=0 + struct ExprList_item *a; + Expr *pMid; + ParseCleanup *pX; + assert( pOrig!=0 && pOrig->op==TK_FUNCTION ); + assert( ExprUseXList(pOrig) ); + if( pOrig->x.pList==0 ) goto sandbox_violation; + a = pOrig->x.pList->a; + if( pOrig->x.pList->nExpr!=3 + || sqlite3ExprCompare(pParse, a[0].pExpr, a[2].pExpr, 0)!=0 || sqlite3ExprIsConstant(pParse, a[0].pExpr)==0 || sqlite3ExprIsConstantOrFunction(a[0].pExpr, 0)==0 - || sqlite3ExprContainsSubquery(pMid) + || sqlite3ExprContainsSubquery(pMid = a[1].pExpr) ){ - sqlite3ErrorMsg(pParse, "sandbox violation"); - return pOrig; + goto sandbox_violation; } - a[1] = a[2]; - pOrig->x.pList->nExpr = 2; + for(pX=pParse->pCleanup; pX; pX=pX->pNext){ + if( pX->xCleanup==(void(*)(sqlite3*,void*))sqlite3ExprDelete + && sqlite3ExprCompare(pParse, a[0].pExpr, (Expr*)pX->pPtr, 0)==0 + ){ + goto sandbox_violation; + } + } + sqlite3ParserAddCleanup(pParse, (void(*)(sqlite3*,void*))sqlite3ExprDelete, + a[2].pExpr); + pOrig->x.pList->nExpr = 1; sqlite3ExprDelete(pParse->db, pOrig); return pMid; + +sandbox_violation: + sqlite3ErrorMsg(pParse, "sandbox violation"); + return pOrig; } #endif /* SQLITE_ENABLE_SANDBOX_FUNCTION */ @@ -1249,11 +1269,7 @@ Expr *sqlite3ExprFunction( sqlite3ExprSetHeightAndFlags(pParse, pNew); if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct); #if SQLITE_ENABLE_SANDBOX_FUNCTION+0>0 - if( pToken->n==7 - && pList!=0 - && pList->nExpr==3 - && sqlite3_strnicmp(pToken->z,"SANDBOX",7)==0 - ){ + if( pToken->n==7 && sqlite3_strnicmp(pToken->z,"SANDBOX",7)==0 ){ pNew = exprSandbox(pParse, pNew); } #endif /* SQLITE_ENABLE_SANDBOX_FUNCTION */ diff --git a/test/sandbox1.sql b/test/sandbox1.sql index 3d8604a418..8a3a946366 100644 --- a/test/sandbox1.sql +++ b/test/sandbox1.sql @@ -21,13 +21,19 @@ SELECT * FROM t1, t2 WHERE sandbox($abc, a=x, $abc); .check --glob 'sandbox violation' .testcase 130 SELECT * FROM t1, t2 WHERE sandbox(2, a=x, 2, 4); -.check --glob 'no such function: sandbox' +.check --glob 'sandbox violation' .testcase 140 SELECT * FROM t1, t2 WHERE sandbox(2, a=x) AND a=x; -.check --glob 'no such function: sandbox' +.check --glob 'sandbox violation' .testcase 150 SELECT * FROM t1, t2 WHERE sandbox() AND a=x; -.check --glob 'no such function: sandbox' +.check --glob 'sandbox violation' +.testcase 160 +SELECT * FROM t1, t2 WHERE sandbox(0,a=x,0) AND sandbox(0,b=y,0); +.check --glob 'sandbox violation' +.testcase 170 +SELECT * FROM t1, t2 WHERE sandbox(0,a=x,0) AND sandbox(1,b=y,1); +.check --glob '' .testcase 200 .eqp on