]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
When doing an SQLAR archive extraction in the CLI, postpone creating symlinks until...
authordrh <>
Mon, 23 Feb 2026 01:34:14 +0000 (01:34 +0000)
committerdrh <>
Mon, 23 Feb 2026 01:34:14 +0000 (01:34 +0000)
all files and directories have been created.  This prevents a hostile archive from
creating a symlink through which it can subsequently write content outside of the target
directory.  [forum:forumpost/9e176adfef91c207|Forum post 9e176adfef91c207].

FossilOrigin-Name: 9719034d4d3becda127dc294f7f58ded9c982509c690dd55b56310912957eb51

manifest
manifest.uuid
src/shell.c.in

index f368ebcd138d9e9db188411b130bfda4e5417c8c..0ad630f8bd8c5a907b2ea90fc4f4c000faf0f59e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Improved\simplementation\sof\srealpath()\sin\sthe\sfileio.c\sextension\sthat\sdoes\snot\srequire\nthe\slast\selement\sof\sthe\spath\sto\sactually\sexist.
-D 2026-02-23T00:57:00.749
+C When\sdoing\san\sSQLAR\sarchive\sextraction\sin\sthe\sCLI,\spostpone\screating\ssymlinks\suntil\safter\nall\sfiles\sand\sdirectories\shave\sbeen\screated.\s\sThis\sprevents\sa\shostile\sarchive\sfrom\ncreating\sa\ssymlink\sthrough\swhich\sit\scan\ssubsequently\swrite\scontent\soutside\sof\sthe\starget\ndirectory.\s\s[forum:forumpost/9e176adfef91c207|Forum\spost\s9e176adfef91c207].
+D 2026-02-23T01:34:14.113
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -739,7 +739,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
 F src/resolve.c 928ff887f2a7c64275182060d94d06fdddbe32226c569781cf7e7edc6f58d7fd
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 F src/select.c 615d62112f5c14fb24facf9391492b42403875bfd4288db6ba10d7e6fbc22c4c
-F src/shell.c.in 3e87584890a4e9797865e4771689d8d1aca3b0f824f973192784716ecfa320a2
+F src/shell.c.in 096db72b94687e46d7805e96c2a28fd1525fc6735d8967b9ce37b0b9dbbb9c90
 F src/sqlite.h.in c7582608c8270428b288a529f4a4170298a19548266b55edaa2e70ce8d607f0e
 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
 F src/sqlite3ext.h 1b7a0ee438bb5c2896d0609c537e917d8057b3340f6ad004d2de44f03e3d3cca
@@ -2195,8 +2195,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P 8bb8941930378b436f1353603be194644568b55fe347475be0caddddad40efa3
-R 655393f8c2d5cab161b45421e875ddda
+P 4df4999484d9008d8af3c9c340810e0cf5f57161ba053ed5501276b450577039
+R 536f614f7f299837eaceb0448191c5cb
 U drh
-Z 730476000580ff31324acec73800a8e3
+Z 1a29d5706c125cd77c3ea8fb58018127
 # Remove this line to create a well-formed Fossil manifest.
index dbb7963f697791ffab12a6daba8feed248cb59a2..75b99ad74c88795c01484fb0aff0b1643f4b45d9 100644 (file)
@@ -1 +1 @@
-4df4999484d9008d8af3c9c340810e0cf5f57161ba053ed5501276b450577039
+9719034d4d3becda127dc294f7f58ded9c982509c690dd55b56310912957eb51
index 8eaa060812aeeb9dd728c5b3df7423f019cb0a28..f071e09bbfb0f8f99047f273ba27f6ccde0a5f12 100644 (file)
@@ -6665,11 +6665,14 @@ static int arRemoveCommand(ArCommand *pAr){
 */
 static int arExtractCommand(ArCommand *pAr){
   const char *zSql1 =
-    "SELECT "
-    " ($dir || name),"
-    " writefile(($dir || name), %s, mode, mtime) "
-    "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)"
-    " AND name NOT GLOB '*..[/\\]*'";
+    "SELECT ($dir || name),\n"
+    "       writefile(($dir || name), %s, mode, mtime)\n"
+    "  FROM %s\n"
+    " WHERE (%s)\n"
+    "   AND NOT ((mode&0xf000)==0x8000 AND $pass>0)\n"  /* Files on pass 0 */
+    "   AND NOT (data IS NULL AND $pass==1)\n"          /* Dirs on passes 0,2 */
+    "   AND NOT ((mode&0xf000)==0xa000 AND $pass<>1)\n" /* Symlink on pass 1 */
+    "   AND name NOT GLOB '*..[/\\]*'\n";
 
   const char *azExtraArg[] = {
     "sqlar_uncompress(data, sz)",
@@ -6705,16 +6708,21 @@ static int arExtractCommand(ArCommand *pAr){
     j = sqlite3_bind_parameter_index(pSql, "$dir");
     sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC);
 
-    /* Run the SELECT statement twice. The first time, writefile() is called
-    ** for all archive members that should be extracted. The second time,
-    ** only for the directories. This is because the timestamps for
-    ** extracted directories must be reset after they are populated (as
-    ** populating them changes the timestamp).  */
-    for(i=0; i<2; i++){
-      j = sqlite3_bind_parameter_index(pSql, "$dirOnly");
+    /* Run the SELECT statement thrice:
+    **   (1) writefile() all files and directories, but not symlinks
+    **   (2) writefile() for symlinks
+    **   (3) writefile() for directory again
+    ** Symlinks are created after everything else to prevent writing content
+    ** through a symlink that was created by the extraction.
+    ** The third pass is so that the timestamps for extracted directories
+    ** will be reset to the value in the archive, since populating them
+    ** in the previous passes will have changed the timestamp. */
+    for(i=0; i<3; i++){
+      j = sqlite3_bind_parameter_index(pSql, "$pass");
       sqlite3_bind_int(pSql, j, i);
       if( pAr->bDryRun ){
         cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql));
+        break;
       }else{
         while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
           if( i==0 && pAr->bVerbose ){