diff --git a/CHANGELOG.md b/CHANGELOG.md index ab1fb828..d0e8d8b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,15 +5,44 @@ This project adheres to [Semantic Versioning](http://semver.org/). + +# [1.1.0 / 5.56.0] - 2022-01-?? + +### Added +- added support for NtRenameKey (this requires UseRegDeleteV2=y) [#205](https://github.com/sandboxie-plus/Sandboxie/issues/205) +- added options menu command to reset the GUI [#1589](https://github.com/sandboxie-plus/Sandboxie/issues/1589) + +### Changed +- reworked the mechanism sandboxie uses to mark host files as deleted +-- the new behavioure creates a data file in the box root FilePaths.dat instead of creating dummy files +-- it can be enabled with UseFileDeleteV2=y sane for the registry UseRegDeleteV2=y using RegPaths.dat +- disabled a couple driver based workarounds for boxes in compartment mode as then thay should not be required + + +### Fixed +- fixed folder rename issues (this requires UseFileDeleteV2=y) [#71](https://github.com/sandboxie-plus/Sandboxie/issues/71) + + + + # [1.0.10 / 5.55.10] - 2022-01-?? ### Added -- added option to show only boxes in hray with runnign processes [#1186](https://github.com/sandboxie-plus/Sandboxie/issues/1186) -todo:- add reset ui ooption +- added option to show only boxes in tray with runnign processes [#1186](https://github.com/sandboxie-plus/Sandboxie/issues/1186) +-- additional option show only pinned bixes, in box options a bix can be set to be always shown in theay list (Pinned) +- add reset ui option +- added 'Run Un-Sandboxed' context menu option +- added new trigger "OnBoxDelete" that allows to specify a command that is run UNBOXED just before the box content gets deleted +-- note: this can be used as a replacemetn to the DeleteCommand [#591](https://github.com/sandboxie-plus/Sandboxie/issues/591) +- sellected box operations (deletion) no longer show the progress dialog [1061](https://github.com/sandboxie-plus/Sandboxie/issues/1061) +-- instead a box with a running operation show a blinking hour glass icon, the context menu can be used to cancel the operation ### Changed - HideHostProcess=program.exe can now be used to hide sandboxie services [#1336](https://github.com/sandboxie-plus/Sandboxie/issues/1336) -- updater blocking is now done using a template with BlockSoftwareUpdaters +- updater blocking is now done using a template called BlockSoftwareUpdaters +- enchanced "StartProgram=..." making "StartCommand=..." obsolete +-- for same functionality as "StartCommand=..." use "StartProgram=%SbieHome%\Start.exe ..." +- merged "Auto Start" General tab with the "Auto Exec" Advanced tab into a universal"Triggers" Advanced tab ### Fixed - fixed a couple issues with the new breakout process feature and improved security (thanks Diversenok) @@ -22,8 +51,8 @@ todo:- add reset ui ooption - fixed issue handling commandline invokation [#1133](https://github.com/sandboxie-plus/Sandboxie/issues/1133) - fixed ui issue with main window state when switching always on top attribute [#1169](https://github.com/sandboxie-plus/Sandboxie/issues/1169) - fixed issue with box context menu in tray list [1106](https://github.com/sandboxie-plus/Sandboxie/issues/1106) - - +- fixed issue with "AutoExec=..." +- fixed issues canceling box deletion operations didn't working [1061](https://github.com/sandboxie-plus/Sandboxie/issues/1061) diff --git a/Sandboxie/common/my_version.h b/Sandboxie/common/my_version.h index 1d86d4ef..ade0b98b 100644 --- a/Sandboxie/common/my_version.h +++ b/Sandboxie/common/my_version.h @@ -21,8 +21,8 @@ #ifndef _MY_VERSION_H #define _MY_VERSION_H -#define MY_VERSION_BINARY 5,55,10 -#define MY_VERSION_STRING "5.55.10" +#define MY_VERSION_BINARY 5,56,0 +#define MY_VERSION_STRING "5.56.0" #define MY_VERSION_COMPAT "5.55.0" // this refers to the driver ABI compatibility // These #defines are used by either Resource Compiler or NSIS installer diff --git a/Sandboxie/core/dll/SboxDll.vcxproj b/Sandboxie/core/dll/SboxDll.vcxproj index 7a73dd19..f0470d0c 100644 --- a/Sandboxie/core/dll/SboxDll.vcxproj +++ b/Sandboxie/core/dll/SboxDll.vcxproj @@ -96,6 +96,7 @@ true false + WITH_DEBUG;%(PreprocessorDefinitions) ntdll.lib;uuid.lib;kernel32.lib @@ -117,6 +118,7 @@ Default true false + WITH_DEBUG;%(PreprocessorDefinitions) ntdll.lib;uuid.lib;kernel32.lib @@ -243,6 +245,12 @@ + + true + true + true + true + true true @@ -279,6 +287,18 @@ true true + + true + true + true + true + + + true + true + true + true + @@ -291,6 +311,7 @@ + @@ -305,6 +326,12 @@ + + true + true + true + true + true true @@ -427,6 +454,7 @@ + diff --git a/Sandboxie/core/dll/SboxDll.vcxproj.filters b/Sandboxie/core/dll/SboxDll.vcxproj.filters index 0e744e64..048cd5b6 100644 --- a/Sandboxie/core/dll/SboxDll.vcxproj.filters +++ b/Sandboxie/core/dll/SboxDll.vcxproj.filters @@ -6,11 +6,9 @@ - - @@ -218,6 +216,25 @@ debug + + file + + + key + + + obj + + + obj + + + + file + + + file + @@ -255,9 +272,6 @@ api - - com - common @@ -312,6 +326,12 @@ debug + + obj + + + obj + @@ -373,6 +393,9 @@ {db0f9820-8908-4325-96f9-69c82fa9e268} + + {05955a21-494a-4624-854e-d7c9b1e33401} + diff --git a/Sandboxie/core/dll/debug.c b/Sandboxie/core/dll/debug.c index f64a3fd6..2c0ed036 100644 --- a/Sandboxie/core/dll/debug.c +++ b/Sandboxie/core/dll/debug.c @@ -420,6 +420,33 @@ void DbgPrint(const char* format, ...) } + +//--------------------------------------------------------------------------- +// DbgPrint +//--------------------------------------------------------------------------- + + +void DbgTrace(const char* format, ...) +{ + va_list va_args; + va_start(va_args, format); + + char *tmp1 = Dll_AllocTemp(510); + + extern int(*P_vsnprintf)(char *_Buffer, size_t Count, const char * const, va_list Args); + P_vsnprintf(tmp1, 510, format, va_args); + + WCHAR *tmp2 = Dll_AllocTemp(510*sizeof(WCHAR)); + Sbie_snwprintf((WCHAR *)tmp2, 510, L"%S", tmp1); + + SbieApi_MonitorPut2(MONITOR_OTHER | MONITOR_TRACE, tmp2, FALSE); + + Dll_Free(tmp1); + + va_end(va_args); +} + + //--------------------------------------------------------------------------- diff --git a/Sandboxie/core/dll/debug.h b/Sandboxie/core/dll/debug.h index 0a0a02e0..b07afaaf 100644 --- a/Sandboxie/core/dll/debug.h +++ b/Sandboxie/core/dll/debug.h @@ -43,6 +43,7 @@ int Debug_Init(void); void DbgPrint(const char* format, ...); +void DbgTrace(const char* format, ...); #endif WITH_DEBUG diff --git a/Sandboxie/core/dll/dll.h b/Sandboxie/core/dll/dll.h index 0775a846..21471802 100644 --- a/Sandboxie/core/dll/dll.h +++ b/Sandboxie/core/dll/dll.h @@ -48,7 +48,8 @@ extern __declspec(dllexport) int __CRTDECL Sbie_snprintf(char *_Buffer, size_t C #define TRUE_NAME_BUFFER 0 #define COPY_NAME_BUFFER 1 #define TMPL_NAME_BUFFER 2 -#define NAME_BUFFER_COUNT 3 +#define MOVE_NAME_BUFFER 3 +#define NAME_BUFFER_COUNT 4 #define NAME_BUFFER_DEPTH 24 @@ -280,6 +281,7 @@ extern BOOLEAN Dll_RestrictedToken; extern BOOLEAN Dll_ChromeSandbox; extern BOOLEAN Dll_FirstProcessInBox; extern BOOLEAN Dll_CompartmentMode; +//extern BOOLEAN Dll_AlernateIpcNaming; extern ULONG Dll_ImageType; @@ -348,6 +350,11 @@ void Dll_FreeTlsData(void); WCHAR *Dll_GetTlsNameBuffer(THREAD_DATA *data, ULONG which, ULONG size); void Dll_PushTlsNameBuffer(THREAD_DATA *data); void Dll_PopTlsNameBuffer(THREAD_DATA *data); +//void Dll_PushTlsNameBuffer_(THREAD_DATA *data, char* func); +//void Dll_PopTlsNameBuffer_(THREAD_DATA *data, char* func); +//#define Dll_PushTlsNameBuffer(x) Dll_PushTlsNameBuffer_(x, __FUNCTION__) +//#define Dll_PopTlsNameBuffer(x) Dll_PopTlsNameBuffer_(x, __FUNCTION__) + //--------------------------------------------------------------------------- @@ -444,7 +451,7 @@ NTSTATUS Pipe_NtCreateFile( void *EaBuffer, ULONG EaLength); -void File_DuplicateRecover(HANDLE OldFileHandle, HANDLE NewFileHandle); +void Handle_SetupDuplicate(HANDLE OldFileHandle, HANDLE NewFileHandle); void File_DoAutoRecover(BOOLEAN force); @@ -477,9 +484,7 @@ BOOLEAN File_IsBlockedNetParam(const WCHAR *BoxName); void File_GetSetDeviceMap(WCHAR *DeviceMap96); -typedef void(*P_CloseHandler)(HANDLE handle); -BOOLEAN File_RegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler); -BOOLEAN File_UnRegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler); +void File_NotifyRecover(HANDLE FileHandle); //--------------------------------------------------------------------------- // Functions (key) @@ -612,7 +617,7 @@ BOOLEAN Win32_Init(HMODULE hmodule); // Functions (init for DllMain) //--------------------------------------------------------------------------- -BOOLEAN File_InitHandles(void); +BOOLEAN Handle_Init(void); BOOLEAN Key_Init(void); diff --git a/Sandboxie/core/dll/dllmain.c b/Sandboxie/core/dll/dllmain.c index 6d3af3b3..9728b6d3 100644 --- a/Sandboxie/core/dll/dllmain.c +++ b/Sandboxie/core/dll/dllmain.c @@ -87,6 +87,7 @@ BOOLEAN Dll_RestrictedToken = FALSE; BOOLEAN Dll_ChromeSandbox = FALSE; BOOLEAN Dll_FirstProcessInBox = FALSE; BOOLEAN Dll_CompartmentMode = FALSE; +//BOOLEAN Dll_AlernateIpcNaming = FALSE; ULONG Dll_ImageType = DLL_IMAGE_UNSPECIFIED; @@ -326,6 +327,28 @@ _FX void Dll_InitInjected(void) Dll_BoxKeyPathLen = wcslen(Dll_BoxKeyPath); Dll_BoxIpcPathLen = wcslen(Dll_BoxIpcPath); + // Dll_AlernateIpcNaming = SbieApi_QueryConfBool(NULL, L"UseAlernateIpcNaming", FALSE); + // if (Dll_AlernateIpcNaming) { + // + // // + // // instead of using a separate namespace + // // just replace all \ with _ and use it as a sufix rather then an actual path + // // similarly a its done for named pipes already + // // this approche can help to reduce teh footprint when running in portable mode + // // alternatively we could create volatile entries under AppContainerNamedObjects + // // + // + // WCHAR* ptr = (WCHAR*)Dll_BoxIpcPath; + // while (*ptr) { + // WCHAR *ptr2 = wcschr(ptr, L'\\'); + // if (ptr2) { + // ptr = ptr2; + // *ptr = L'_'; + // } else + // ptr += wcslen(ptr); + // } + // } + // // check if process SID is LocalSystem // @@ -348,7 +371,7 @@ _FX void Dll_InitInjected(void) Dll_FixWow64Syscall(); if (ok) - ok = File_InitHandles(); + ok = Handle_Init(); if (ok) ok = Obj_Init(); @@ -418,7 +441,7 @@ _FX void Dll_InitInjected(void) if (ok) ok = Gui_InitConsole1(); - if (ok) + if (ok) // Note: Ldr_Init may cause rpcss to be started early ok = Ldr_Init(); // last to initialize // diff --git a/Sandboxie/core/dll/dllmem.c b/Sandboxie/core/dll/dllmem.c index d63439aa..36c62c02 100644 --- a/Sandboxie/core/dll/dllmem.c +++ b/Sandboxie/core/dll/dllmem.c @@ -24,6 +24,7 @@ #include "dll.h" #include "common/pool.h" #include +#include "debug.h" //--------------------------------------------------------------------------- @@ -372,8 +373,10 @@ ALIGNED WCHAR *Dll_GetTlsNameBuffer( //--------------------------------------------------------------------------- +//ALIGNED void Dll_PushTlsNameBuffer_(THREAD_DATA *data, char* func) ALIGNED void Dll_PushTlsNameBuffer(THREAD_DATA *data) { + //DbgTrace("Dll_PushTlsNameBuffer, %s, %d\r\n", func, data->depth); ++data->depth; if (data->depth > NAME_BUFFER_DEPTH - 4) SbieApi_Log(2310, L"%d", data->depth); @@ -388,8 +391,11 @@ ALIGNED void Dll_PushTlsNameBuffer(THREAD_DATA *data) //--------------------------------------------------------------------------- +//_FX void Dll_PopTlsNameBuffer_(THREAD_DATA *data, char* func) _FX void Dll_PopTlsNameBuffer(THREAD_DATA *data) { + //DbgTrace("Dll_PopTlsNameBuffer, %s, %d\r\n", func, data->depth-1); + // // debug checks: the name buffer is allocated at least 64 bytes // more than needed. fill these with 0xCC, andd check that later diff --git a/Sandboxie/core/dll/file.c b/Sandboxie/core/dll/file.c index 1f79d8c2..4562d2e7 100644 --- a/Sandboxie/core/dll/file.c +++ b/Sandboxie/core/dll/file.c @@ -23,11 +23,12 @@ #define NOGDI #include "dll.h" #include "obj.h" +#include "handle.h" #include #include #include "core/svc/FileWire.h" #include "core/svc/InteractiveWire.h" - +#include "debug.h" //--------------------------------------------------------------------------- // Defines @@ -97,19 +98,13 @@ typedef struct _FILE_LINK FILE_LINK; typedef struct _FILE_DRIVE FILE_DRIVE; -typedef struct _FILE_SNAPSHOT { - WCHAR ID[17]; - ULONG IDlen; - ULONG ScramKey; - //WCHAR Name[34]; - struct _FILE_SNAPSHOT* Parent; -} FILE_SNAPSHOT, *PFILE_SNAPSHOT; - //--------------------------------------------------------------------------- // Functions //--------------------------------------------------------------------------- +static ULONG File_FindBoxPrefixLength(const WCHAR* CopyPath); + SBIEDLL_EXPORT NTSTATUS File_GetName( HANDLE RootDirectory, UNICODE_STRING *ObjectName, @@ -139,10 +134,6 @@ static NTSTATUS File_GetName_FromFileId( OBJECT_ATTRIBUTES *ObjectAttributes, WCHAR **OutTruePath, WCHAR **OutCopyPath); -static WCHAR* File_MakeSnapshotPath(FILE_SNAPSHOT* Cur_Snapshot, WCHAR* CopyPath); - -static BOOLEAN File_FindSnapshotPath(WCHAR** CopyPath); - static ULONG File_MatchPath(const WCHAR *path, ULONG *FileFlags); static ULONG File_MatchPath2(const WCHAR *path, ULONG *FileFlags, BOOLEAN bCheckObjectExists, BOOLEAN bMonitorLog); @@ -193,17 +184,10 @@ static BOOLEAN File_CheckDeletedParent(WCHAR *CopyPath); static NTSTATUS File_CreatePath(WCHAR *TruePath, WCHAR *CopyPath); -static NTSTATUS File_CreatePath_2( - HANDLE *handle, OBJECT_ATTRIBUTES *objattrs, - IO_STATUS_BLOCK *IoStatusBlock, ULONG FileAttributes); - static NTSTATUS File_MigrateFile( const WCHAR *TruePath, const WCHAR *CopyPath, BOOLEAN IsWritePath, BOOLEAN WithContents); -static const BOOLEAN File_MigrateFile_ManualBypass( - const WCHAR *TruePath, ULONGLONG file_size); - static NTSTATUS File_CopyShortName( const WCHAR *TruePath, const WCHAR *CopyPath); @@ -274,10 +258,6 @@ static BOOLEAN File_RecordRecover(HANDLE FileHandle, const WCHAR *TruePath); static NTSTATUS File_SetReparsePoint( HANDLE FileHandle, PREPARSE_DATA_BUFFER Data, ULONG DataLen); -static void File_ScrambleShortName(WCHAR* ShortName, CCHAR* ShortNameLength, ULONG ScramKey); - -static void File_UnScrambleShortName(WCHAR* ShortName, ULONG ScramKey); - static NTSTATUS File_GetFileName(HANDLE FileHandle, ULONG NameLen, WCHAR *NameBuf); //--------------------------------------------------------------------------- @@ -357,15 +337,15 @@ static ULONG File_PublicUserLen = 0; static BOOLEAN File_DriveAddSN = FALSE; +static BOOLEAN File_Delete_v2 = FALSE; +static BOOLEAN File_NoReparse = FALSE; + static BOOLEAN File_Windows2000 = FALSE; static WCHAR *File_AltBoxPath = NULL; static ULONG File_AltBoxPathLen = 0; -static FILE_SNAPSHOT *File_Snapshot = NULL; -static ULONG File_Snapshot_Count = 0; - //--------------------------------------------------------------------------- // File (other modules) @@ -375,7 +355,10 @@ static ULONG File_Snapshot_Count = 0; #include #include "file_link.c" #include "file_pipe.c" +#include "file_del.c" +#include "file_snapshots.c" #include "file_dir.c" +#include "file_recovery.c" #include "file_misc.c" #include "file_copy.c" #include "file_init.c" @@ -468,7 +451,17 @@ _FX NTSTATUS File_GetName( if (RootDirectory) { - UNICODE_STRING *uni; + UNICODE_STRING *uni = NULL; + + name = Handle_GetRelocationPath(RootDirectory, objname_len + sizeof(UNICODE_STRING)); + if (name) { + + length = (wcslen(name) + 1) * sizeof(WCHAR); + uni = ((UCHAR*)name) + (length + objname_len); + RtlInitUnicodeString(uni, name); + + } + else { length = 256; name = Dll_GetTlsNameBuffer( @@ -507,6 +500,7 @@ _FX NTSTATUS File_GetName( return status; uni = &((OBJECT_NAME_INFORMATION *)name)->Name; + } #ifdef WOW64_FS_REDIR // @@ -1360,6 +1354,7 @@ _FX WCHAR *File_GetName_TranslateSymlinks( if (NT_SUCCESS(status)) break; + if (!Dll_CompartmentMode) // NoDriverAssist if (status == STATUS_ACCESS_DENIED && objname.Length <= 1020 * sizeof(WCHAR)) { @@ -1503,40 +1498,6 @@ copy_suffix: } -//--------------------------------------------------------------------------- -// File_MakeSnapshotPath -//--------------------------------------------------------------------------- - - -_FX WCHAR* File_MakeSnapshotPath(FILE_SNAPSHOT* Cur_Snapshot, WCHAR* CopyPath) -{ - if (!Cur_Snapshot) - return NULL; - - ULONG length = wcslen(CopyPath); - ULONG prefixLen = 0; - if (length >= Dll_BoxFilePathLen && 0 == Dll_NlsStrCmp(CopyPath, Dll_BoxFilePath, Dll_BoxFilePathLen)) - prefixLen = Dll_BoxFilePathLen; - if (File_AltBoxPath && length >= File_AltBoxPathLen && 0 == Dll_NlsStrCmp(CopyPath, File_AltBoxPath, File_AltBoxPathLen)) - prefixLen = File_AltBoxPathLen; - - if (prefixLen == 0) - return NULL; - - - THREAD_DATA *TlsData = Dll_GetTlsData(NULL); - - WCHAR* TmplName = Dll_GetTlsNameBuffer(TlsData, TMPL_NAME_BUFFER, (wcslen(CopyPath) + 9 + 17 + 1) * sizeof(WCHAR)); - - wcsncpy(TmplName, CopyPath, prefixLen + 1); - wcscpy(TmplName + prefixLen + 1, L"snapshot-"); - wcscpy(TmplName + prefixLen + 1 + 9, Cur_Snapshot->ID); - wcscpy(TmplName + prefixLen + 1 + 9 + Cur_Snapshot->IDlen, CopyPath + prefixLen); - - return TmplName; -} - - //--------------------------------------------------------------------------- // File_GetName_ExpandShortNames2 //--------------------------------------------------------------------------- @@ -2308,50 +2269,6 @@ finish: } -//--------------------------------------------------------------------------- -// File_FindSnapshotPath -//--------------------------------------------------------------------------- - - -_FX BOOLEAN File_FindSnapshotPath(WCHAR** CopyPath) -{ - NTSTATUS status; - OBJECT_ATTRIBUTES objattrs; - UNICODE_STRING objname; - ULONG FileType; - - InitializeObjectAttributes(&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); - - // - // When working with snapshots the actual "CopyFile" may be located in a snapshot directory. - // To deal with that when the file is not in the active box directory we look through the snapshots, - // When we find it we update the path to point to the snapshot containing the file. - // - - RtlInitUnicodeString(&objname, *CopyPath); - status = File_GetFileType(&objattrs, FALSE, &FileType, NULL); - if (!(status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND)) - return FALSE; // file is present directly in copy path - - for (FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot; Cur_Snapshot != NULL; Cur_Snapshot = Cur_Snapshot->Parent) - { - WCHAR* TmplName = File_MakeSnapshotPath(Cur_Snapshot, *CopyPath); - if (!TmplName) - break; - - RtlInitUnicodeString(&objname, TmplName); - status = File_GetFileType(&objattrs, FALSE, &FileType, NULL); - if (!(status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND)) - { - *CopyPath = TmplName; - return TRUE; - } - } - - return FALSE; // this file is not sandboxed -} - - //--------------------------------------------------------------------------- // File_NtOpenFile //--------------------------------------------------------------------------- @@ -2408,7 +2325,8 @@ _FX NTSTATUS File_NtCreateFile( // File_NtCreateFileImpl //--------------------------------------------------------------------------- -/* + +#ifdef WITH_DEBUG_ static P_NtCreateFile __sys_NtCreateFile_ = NULL; _FX NTSTATUS File_MyCreateFile( @@ -2430,18 +2348,18 @@ _FX NTSTATUS File_MyCreateFile( CreateOptions, EaBuffer, EaLength); if (ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer - && _wcsicmp(ObjectAttributes->ObjectName->Buffer, L"\\??\\PhysicalDrive0") == 0) + && wcsstr(ObjectAttributes->ObjectName->Buffer, L"ext-ms-win-branding-winbrand-l1-1-0.dll") != 0) { - WCHAR text[1024]; - Sbie_snwprintf(text, 1024, L"%s <%08X>", ObjectAttributes->ObjectName->Buffer, status); - SbieApi_MonitorPut(MONITOR_OTHER, text); + return status; } + //if (NT_SUCCESS(status)) DbgPrint("%p: %p\r\n", _ReturnAddress(), *FileHandle); + status = StopTailCallOptimization(status); return status; -}*/ - +} +#endif _FX NTSTATUS File_NtCreateFileImpl( HANDLE *FileHandle, @@ -2472,7 +2390,10 @@ _FX NTSTATUS File_NtCreateFileImpl( BOOLEAN IsEmptyCopyFile; BOOLEAN AlreadyReparsed; UCHAR HaveTrueFile; - BOOLEAN HaveSnapshotFile, HaveSnapshotParent; + BOOLEAN HaveSnapshotParent; + ULONG TruePathFlags; + WCHAR* OriginalPath; + BOOLEAN TrueOpened; //char *pPtr = NULL; //if (wcsstr(Dll_ImageName, L"chrome.exe") != 0) { @@ -2481,13 +2402,15 @@ _FX NTSTATUS File_NtCreateFileImpl( // // __debugbreak(); //} - /*if (__sys_NtCreateFile_ == NULL) +#ifdef WITH_DEBUG_ + if (__sys_NtCreateFile_ == NULL) { __sys_NtCreateFile_ = __sys_NtCreateFile; __sys_NtCreateFile = File_MyCreateFile; } +#endif - if (ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer + /*if (ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer && _wcsicmp(ObjectAttributes->ObjectName->Buffer, L"\\??\\PhysicalDrive0") == 0) { return __sys_NtCreateFile( @@ -2497,7 +2420,7 @@ _FX NTSTATUS File_NtCreateFileImpl( }*/ /*if (ObjectAttributes && ObjectAttributes->ObjectName && ObjectAttributes->ObjectName->Buffer - && wcsstr(ObjectAttributes->ObjectName->Buffer, L"Game.ini") != NULL ) { + && wcsstr(ObjectAttributes->ObjectName->Buffer, L"socket_") != NULL ) { while (! IsDebuggerPresent()) { OutputDebugString(L"BREAK\n"); Sleep(500); } __debugbreak(); }*/ @@ -2543,7 +2466,8 @@ _FX NTSTATUS File_NtCreateFileImpl( DesiredAccess &= ~ACCESS_SYSTEM_SECURITY; } - + OriginalPath = NULL; + TrueOpened = FALSE; __try { @@ -2781,6 +2705,8 @@ ReparseLoop: if (ReparsedPath) Dll_Free(ReparsedPath); + if (NT_SUCCESS(status)) TrueOpened = TRUE; + // // if we got STATUS_OBJECT_PATH_NOT_FOUND on an open path, meaning // that parent directories are missing outside the sandbox, then @@ -2818,25 +2744,6 @@ ReparseLoop: if (! NT_SUCCESS(status)) __leave; - HaveSnapshotFile = FALSE; - HaveSnapshotParent = FALSE; - - if (File_Snapshot != NULL) { - - WCHAR* TmplPath = CopyPath; - - File_FindSnapshotPath(&TmplPath); - - if (TmplPath != CopyPath) { - - HaveSnapshotFile = TRUE; - - TruePath = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, (wcslen(TmplPath) + 1) * sizeof(WCHAR)); - wcscpy(TruePath, TmplPath); - } - } - - // // if TruePath and CopyPath contain colons that indicate an NTFS // alternate data stream, we remove these for now @@ -2860,6 +2767,7 @@ ReparseLoop: // abort early if the parent of CopyPath exists but marked deleted // + if (!File_Delete_v2) if (File_CheckDeletedParent(CopyPath)) { status = STATUS_OBJECT_PATH_NOT_FOUND; __leave; @@ -2897,6 +2805,20 @@ ReparseLoop: RtlInitUnicodeString(&objname, CopyPath); status = File_GetFileType(&objattrs, FALSE, &FileType, &IsEmptyCopyFile); + + HaveSnapshotParent = FALSE; + + // + // Check true path relocation + // + + WCHAR* OldTruePath = File_ResolveTruePath(TruePath, CopyPath, &TruePathFlags); + if (OldTruePath) { + OriginalPath = TruePath; + TruePath = OldTruePath; + } + + if (NT_SUCCESS(status)) { ULONG TrueFileType; @@ -2957,19 +2879,21 @@ ReparseLoop: if (! HaveCopyParent) { - WCHAR* TargetName = wcsrchr(CopyPath, L'\\'); - *TargetName = L'\0'; + WCHAR* ptr1 = wcsrchr(CopyPath, L'\\'); + *ptr1 = L'\0'; + //WCHAR* ptr2 = wcsrchr(TruePath, L'\\'); + //*ptr2 = L'\0'; - WCHAR* TmplPath = CopyPath; - - File_FindSnapshotPath(&TmplPath); - - if (TmplPath != CopyPath) { + Dll_PushTlsNameBuffer(TlsData); + WCHAR* TmplName = File_FindSnapshotPath(CopyPath); + if (TmplName != NULL) HaveSnapshotParent = TRUE; - } - *TargetName = L'\\'; + Dll_PopTlsNameBuffer(TlsData); + + //*ptr2 = L'\\'; + *ptr1 = L'\\'; } // @@ -3021,7 +2945,19 @@ ReparseLoop: // otherwise not write-only, so do normal File_GetFileType // - status = File_GetFileType(&objattrs, FALSE, &FileType, NULL); + status = STATUS_SUCCESS; + FileType = 0; + + if (TruePathFlags) { + if (FILE_PARENT_DELETED(TruePathFlags)) + status = STATUS_OBJECT_PATH_NOT_FOUND; + else if (FILE_IS_DELETED(TruePathFlags)) + status = STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (NT_SUCCESS(status)) { + status = File_GetFileType(&objattrs, FALSE, &FileType, NULL); + } } // @@ -3029,7 +2965,7 @@ ReparseLoop: // check for this and act acrodingly. // - if (HaveSnapshotFile) { + if (TruePathFlags & FILE_INSNAPSHOT_FLAG) { if (FileType & TYPE_DELETED) { @@ -3066,7 +3002,8 @@ ReparseLoop: HaveTrueFile = 'Y'; else HaveTrueFile = 'N'; - } + } else if (NT_SUCCESS(status)) + HaveTrueFile = 'y'; if (status == STATUS_OBJECT_PATH_NOT_FOUND) HaveTrueParent = FALSE; @@ -3154,6 +3091,8 @@ ReparseLoop: ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); + if (NT_SUCCESS(status)) TrueOpened = TRUE; + //if (status == STATUS_ACCESS_DENIED) //{ // while(!IsDebuggerPresent()) Sleep(50); __debugbreak(); @@ -3207,6 +3146,28 @@ ReparseLoop: } + // + // abort early if the parent of CopyPath exists but marked deleted + // + + if (FILE_PATH_DELETED(TruePathFlags)) { // actual file or its parent + if (!HaveCopyFile && (HaveTrueFile == 'Y' || HaveTrueFile == 'y')) { // if this is set status will be success + + FileType = 0; + status = STATUS_OBJECT_PATH_NOT_FOUND; + + // + // if this is a create operation check if the parent fodler is ok and if so clear the error + // + + if (CreateDisposition != FILE_OPEN && CreateDisposition != FILE_OVERWRITE) { + if (!FILE_PARENT_DELETED(TruePathFlags)) { // parent not deleted + status = STATUS_SUCCESS; + } + } + } + } + if (! NT_SUCCESS(status)) __leave; @@ -3290,6 +3251,8 @@ ReparseLoop: ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); + if (NT_SUCCESS(status)) TrueOpened = TRUE; + __leave; } } @@ -3317,7 +3280,7 @@ ReparseLoop: if (HaveTrueParent || HaveSnapshotParent) { - status = File_CreatePath(TruePath, CopyPath); + status = File_CreatePath(OriginalPath ? OriginalPath : TruePath, CopyPath); } else status = STATUS_OBJECT_PATH_NOT_FOUND; @@ -3420,6 +3383,8 @@ ReparseLoop: FileHandle, DesiredAccess, &objattrs, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); + + if (NT_SUCCESS(status)) TrueOpened = TRUE; } __leave; @@ -3432,33 +3397,36 @@ ReparseLoop: // in this case we physically delete the stale CopyPath. // - DeleteChildren = FALSE; + if (!File_Delete_v2) { - if (HaveCopyFile && (FileType & TYPE_DELETED) && - (CreateDisposition != FILE_OPEN)) { + DeleteChildren = FALSE; - RtlInitUnicodeString(&objname, CopyPath); - status = __sys_NtDeleteFile(&objattrs); + if (HaveCopyFile && (FileType & TYPE_DELETED) && + (CreateDisposition != FILE_OPEN)) { - if (! NT_SUCCESS(status)) - __leave; + RtlInitUnicodeString(&objname, CopyPath); + status = __sys_NtDeleteFile(&objattrs); - FileType = 0; + if (! NT_SUCCESS(status)) + __leave; - if ((CreateOptions & FILE_DIRECTORY_FILE) && (! CopyPathColon)) { + FileType = 0; - // - // if the caller is re-creating a directory that was already - // deleted (and marked so) in the sandbox, then we should mark - // everything in it as deleted, after it has been re-created - // + if ((CreateOptions & FILE_DIRECTORY_FILE) && (! CopyPathColon)) { - DeleteChildren = TRUE; + // + // if the caller is re-creating a directory that was already + // deleted (and marked so) in the sandbox, then we should mark + // everything in it as deleted, after it has been re-created + // + + DeleteChildren = TRUE; + } } } // - // Note: This is disabled in the driver since Win 10 1903 (see comments in file.c in File_Generic_MyParseProc). + // Note: This is disabled in the driver since Win 10 1903 (see my comments in file.c in File_Generic_MyParseProc). // if the caller specifies write attributes, this is only permitted // on non-directory files, so we must be sure to tell the driver // @@ -3489,7 +3457,7 @@ ReparseLoop: *CopyPathColon = L':'; RtlInitUnicodeString(&objname, CopyPath); - if (DeleteOnClose && HaveTrueFile == 'N') { + if (DeleteOnClose && (File_Delete_v2 || HaveTrueFile == 'N')) { CreateOptions |= FILE_DELETE_ON_CLOSE; DesiredAccess |= DELETE; @@ -3500,7 +3468,7 @@ ReparseLoop: &objattrs, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); - if (DeleteOnClose && HaveTrueFile == 'N' && (! NT_SUCCESS(status))) { + if (!NT_SUCCESS(status) && DeleteOnClose && !File_Delete_v2 && HaveTrueFile == 'N') { CreateOptions &= ~FILE_DELETE_ON_CLOSE; DesiredAccess &= ~DELETE; @@ -3531,6 +3499,8 @@ ReparseLoop: if (CopyPathColon) status = STATUS_ACCESS_DENIED; + else if (File_Delete_v2) + status = File_MarkDeleted_v2(OriginalPath ? OriginalPath : TruePath); else status = File_MarkDeleted(*FileHandle, CopyPath); } @@ -3543,8 +3513,8 @@ ReparseLoop: // file was not opened for deletion, but NTFS file systems // may sometimes persist an (out of date) creation time // - - status = File_SetCreateTime(*FileHandle, CopyPath); + if (!File_Delete_v2) + status = File_SetCreateTime(*FileHandle, CopyPath); if (NT_SUCCESS(status)) { @@ -3555,11 +3525,13 @@ ReparseLoop: // directory, then mark all its children deleted // - if (DeleteChildren) { + if (!File_Delete_v2) { + if (DeleteChildren) { - TlsData->file_NtCreateFile_lock = FALSE; + TlsData->file_NtCreateFile_lock = FALSE; - File_MarkChildrenDeleted(TruePath); + File_MarkChildrenDeleted(TruePath); + } } } else { @@ -3639,10 +3611,21 @@ ReparseLoop: AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); + if (NT_SUCCESS(status)) TrueOpened = TRUE; // is that right? + if (! NT_SUCCESS(status)) status = STATUS_ACCESS_DENIED; } + // + // Relocation, if we opened the true file and its relocated set the path info + // + + if (TrueOpened && OriginalPath) { + + Handle_SetRelocationPath(*FileHandle, OriginalPath); + } + // // finish // @@ -3925,8 +3908,10 @@ _FX NTSTATUS File_GetFileType( if (info.FileAttributes & FILE_ATTRIBUTE_SYSTEM) type |= TYPE_SYSTEM; - if (IS_DELETE_MARK(&info.CreationTime)) - type |= TYPE_DELETED; + if (!File_Delete_v2) { + if (IS_DELETE_MARK(&info.CreationTime)) + type |= TYPE_DELETED; + } *FileType = type; @@ -4029,6 +4014,7 @@ _FX NTSTATUS File_CreatePath(WCHAR *TruePath, WCHAR *CopyPath) ULONG TruePath_len, CopyPath_len; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION basic_info; + BOOLEAN IsDeleted = FALSE; // // first we traverse backward along the path, removing the last @@ -4072,6 +4058,10 @@ _FX NTSTATUS File_CreatePath(WCHAR *TruePath, WCHAR *CopyPath) savechar = *sep; *sep = L'\0'; + sep2 = TruePath + TruePath_len - (CopyPath_len - (sep - CopyPath)); + savechar2 = *sep2; + *sep2 = L'\0'; + savelength = objname.Length; savemaximumlength = objname.MaximumLength; objname.Length = (sep - path) * sizeof(WCHAR); @@ -4082,20 +4072,33 @@ _FX NTSTATUS File_CreatePath(WCHAR *TruePath, WCHAR *CopyPath) &IoStatusBlock, NULL, 0, FILE_SHARE_VALID_FLAGS, FILE_OPEN_IF, FILE_DIRECTORY_FILE, NULL, 0); + if (File_Delete_v2) { + if (!NT_SUCCESS(status)) { + IsDeleted = FILE_IS_DELETED(File_IsDeletedEx(TruePath, CopyPath, NULL)); + } + } + objname.Length = savelength; objname.MaximumLength = savemaximumlength; *sep = savechar; + *sep2 = savechar2; if (NT_SUCCESS(status)) { - status = __sys_NtQueryInformationFile( - handle, &IoStatusBlock, &basic_info, - sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); + if (!File_Delete_v2) { + + status = __sys_NtQueryInformationFile( + handle, &IoStatusBlock, &basic_info, + sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); + + if (NT_SUCCESS(status)) { + IsDeleted = IS_DELETE_MARK(&basic_info.CreationTime); + } + } NtClose(handle); - if (NT_SUCCESS(status) && - IS_DELETE_MARK(&basic_info.CreationTime)) { + if (IsDeleted) { return STATUS_OBJECT_PATH_NOT_FOUND; } @@ -4631,13 +4634,33 @@ _FX NTSTATUS File_QueryFullAttributesDirectoryFile( HANDLE FileHandle; NTSTATUS status; - // - // try to use SbieApi_OpenFile which will open the file, bypassing - // ClosedFilePath settings, but only if it a directory file. it - // returns a handle that can only be used to query file attributes - // + if (!Dll_CompartmentMode) { // NoDriverAssist + + // + // try to use SbieApi_OpenFile which will open the file, bypassing + // ClosedFilePath settings, but only if it a directory file. it + // returns a handle that can only be used to query file attributes + // + + status = SbieApi_OpenFile(&FileHandle, TruePath); + + } + else { + + OBJECT_ATTRIBUTES objattrs; + UNICODE_STRING objname; + + InitializeObjectAttributes( + &objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); + + RtlInitUnicodeString(&objname, TruePath); + + status = __sys_NtCreateFile( + &FileHandle, FILE_GENERIC_READ, &objattrs, &MyIoStatusBlock, + NULL, 0, FILE_SHARE_VALID_FLAGS, + FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + } - status = SbieApi_OpenFile(&FileHandle, TruePath); if (NT_SUCCESS(status)) { status = __sys_NtQueryInformationFile( @@ -4807,6 +4830,7 @@ _FX NTSTATUS File_NtQueryFullAttributesFileImpl( WCHAR *TruePath; WCHAR *CopyPath; ULONG FileFlags, FileAttrs, mp_flags; + ULONG TruePathFlags; // // special case: when it starts, the Windows Explorer process looks @@ -4911,14 +4935,12 @@ _FX NTSTATUS File_NtQueryFullAttributesFileImpl( // try NtQueryFullAttributesFile on the CopyPath first // + if (!File_Delete_v2) if (File_CheckDeletedParent(CopyPath)) { status = STATUS_OBJECT_PATH_NOT_FOUND; __leave; } - if (File_Snapshot != NULL) - File_FindSnapshotPath(&CopyPath); - RtlInitUnicodeString(&objname, CopyPath); status = __sys_NtQueryFullAttributesFile(&objattrs, FileInformation); @@ -4927,9 +4949,12 @@ _FX NTSTATUS File_NtQueryFullAttributesFileImpl( status != STATUS_OBJECT_NAME_NOT_FOUND && status != STATUS_OBJECT_PATH_NOT_FOUND)) { - if (NT_SUCCESS(status) && + if (!File_Delete_v2) { + + if (NT_SUCCESS(status) && IS_DELETE_MARK(&FileInformation->CreationTime)) - status = STATUS_OBJECT_NAME_NOT_FOUND; + status = STATUS_OBJECT_NAME_NOT_FOUND; + } if (NT_SUCCESS(status)) FileAttrs = FileInformation->FileAttributes; @@ -4937,6 +4962,14 @@ _FX NTSTATUS File_NtQueryFullAttributesFileImpl( __leave; } + // + // Check true path relocation + // + + WCHAR* OldTruePath = File_ResolveTruePath(TruePath, CopyPath, &TruePathFlags); + if (OldTruePath) + TruePath = OldTruePath; + // // check if this is a write-only path. if the path is not // the highest level match on the write-only setting, we @@ -4990,6 +5023,21 @@ _FX NTSTATUS File_NtQueryFullAttributesFileImpl( status2 = __sys_NtQueryFullAttributesFile(&objattrs, FileInformation); + if (TruePathFlags && NT_SUCCESS(status2)) { + + // + // if we found only the true file check if its listed as deleted + // + + if (FILE_PARENT_DELETED(TruePathFlags)) { // parent deleted + status = STATUS_OBJECT_PATH_NOT_FOUND; + __leave; + } else if (FILE_IS_DELETED(TruePathFlags)) { // path deleted + status = STATUS_OBJECT_NAME_NOT_FOUND; + __leave; + } + } + if (status2 != STATUS_OBJECT_PATH_NOT_FOUND) { status = status2; @@ -6146,16 +6194,7 @@ _FX NTSTATUS File_SetDisposition( status = STATUS_CANNOT_DELETE; } else { - EnterCriticalSection(&File_HandleOnClose_CritSec); - - FILE_ON_CLOSE* on_close = map_get(&File_HandleOnClose, FileHandle); - if (!on_close) { - on_close = map_insert(&File_HandleOnClose, FileHandle, NULL, sizeof(FILE_ON_CLOSE)); - } - - on_close->DeleteOnClose = DeleteOnClose; - - LeaveCriticalSection(&File_HandleOnClose_CritSec); + Handle_SetDeleteOnClose(FileHandle, DeleteOnClose); } /* @@ -6215,6 +6254,145 @@ _FX NTSTATUS File_NtDeleteFileImpl(OBJECT_ATTRIBUTES *ObjectAttributes) } +//--------------------------------------------------------------------------- +// File_RenameOpenFile +//--------------------------------------------------------------------------- + + +_FX LONG File_RenameOpenFile( + HANDLE file_handle, + const WCHAR* user_dir, const WCHAR* user_name, + BOOLEAN replace_if_exists) +{ + // + // in compartment mode we dont need driver assistance we can do things ourselvs + // this code is a port of the same routine in teh driver + // + + NTSTATUS status; + ULONG user_dir_len = (wcslen(user_dir) + 1) * sizeof(WCHAR); + ULONG user_name_len = (wcslen(user_name) + 1) * sizeof(WCHAR); + WCHAR *path, *name; + FILE_RENAME_INFORMATION *info; + ULONG path_len, name_len, info_len; + WCHAR save_char; + HANDLE dir_handle; + OBJECT_ATTRIBUTES objattrs; + UNICODE_STRING objname; + IO_STATUS_BLOCK IoStatusBlock; + ULONG mp_flags; + + // + // copy user parameters into consolidated buffer: dir"\"name + // + + path_len = user_dir_len + user_name_len + sizeof(WCHAR) * 8; + path = Dll_AllocTemp(path_len); + if (! path) + return STATUS_INSUFFICIENT_RESOURCES; + memzero(path, path_len); + + memcpy(path, user_dir, user_dir_len); + name = path + wcslen(path); + *name = L'\\'; + memcpy(&name[1], user_name, user_name_len); + + if (wcschr(&name[1], L'\\')) + return STATUS_INVALID_PARAMETER; + + // + // check if the full target path is an open path, and stop if not + // + + mp_flags = File_MatchPath(path, NULL); + + if (!PATH_IS_OPEN(mp_flags) || PATH_IS_CLOSED(mp_flags)) { + Dll_Free(path); + return STATUS_BAD_INITIAL_PC; + } + + // + // check if the target directory is an open path, and stop if it is + // + + *name = L'\0'; + + mp_flags = File_MatchPath(path, NULL); + + if (PATH_IS_OPEN(mp_flags) || PATH_IS_CLOSED(mp_flags)) { + Dll_Free(path); + return STATUS_BAD_INITIAL_PC; + } + + // + // now we have established that the full target path name is an + // open path, but the parent directory in that path isn't open. + // therefore we will open the parent directory for write access + // from kernel mode, and do the rename here + // + // we put a the trailing backslash on the path, so that we can open + // the parent directory even when the parent is the root directory + // + + save_char = name[1]; + name[0] = L'\\'; + name[1] = L'\0'; + + InitializeObjectAttributes( + &objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); + + RtlInitUnicodeString(&objname, path); + + status = __sys_NtCreateFile( + &dir_handle, FILE_GENERIC_WRITE, &objattrs, + &IoStatusBlock, NULL, 0, FILE_SHARE_VALID_FLAGS, + FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + + if (! NT_SUCCESS(status)) { + Dll_Free(path); + return status; + } + + // + // allocate an information buffer, and issue rename request + // + + ++name; + *name = save_char; + name_len = wcslen(name) * sizeof(WCHAR); + + info_len = sizeof(FILE_RENAME_INFORMATION) + name_len + 8; + info = Dll_AllocTemp(info_len); + if (! info) + status = STATUS_INSUFFICIENT_RESOURCES; + else { + + memzero(info, info_len); + info->ReplaceIfExists = replace_if_exists; + info->RootDirectory = dir_handle; + info->FileNameLength = name_len; + memcpy(info->FileName, name, name_len); + + if (NT_SUCCESS(status)) { + + status = __sys_NtSetInformationFile( + file_handle, &IoStatusBlock, //args->file_handle.val, &IoStatusBlock, + info, info_len, FileRenameInformation); + } + + // FIXME, we may get STATUS_NOT_SAME_DEVICE, however, in most cases, + // this API call is used to rename a file inside a folder, rather + // than move files across folders, so that isn't a problem + + Dll_Free(info); + } + + NtClose(dir_handle); + Dll_Free(path); + return status; +} + + //--------------------------------------------------------------------------- // File_RenameFile //--------------------------------------------------------------------------- @@ -6350,9 +6528,6 @@ _FX NTSTATUS File_RenameFile( SourceTruePath = Dll_AllocTemp(len); memcpy(SourceTruePath, TruePath, len); - if (File_Snapshot != NULL) - File_FindSnapshotPath(&CopyPath); - len = (wcslen(CopyPath) + 1) * sizeof(WCHAR); SourceCopyPath = Dll_AllocTemp(len); memcpy(SourceCopyPath, CopyPath, len); @@ -6418,8 +6593,10 @@ _FX NTSTATUS File_RenameFile( if (! ReparsedPath) ReparsedPath = TargetTruePath; - status = SbieApi_RenameFile( - SourceHandle, ReparsedPath, TargetFileName, info->ReplaceIfExists); + if (!Dll_CompartmentMode) // NoDriverAssist + status = SbieApi_RenameFile(SourceHandle, ReparsedPath, TargetFileName, info->ReplaceIfExists); + else + status = File_RenameOpenFile(SourceHandle, ReparsedPath, TargetFileName, info->ReplaceIfExists); if (ReparsedPath != TargetTruePath) Dll_Free(ReparsedPath); @@ -6545,7 +6722,7 @@ _FX NTSTATUS File_RenameFile( if (NT_SUCCESS(status)) { - if (IS_DELETE_MARK(&open_info.CreationTime)) { + if (IS_DELETE_MARK(&open_info.CreationTime)) { // !File_Delete_v2 && info2->ReplaceIfExists = TRUE; @@ -6555,16 +6732,26 @@ _FX NTSTATUS File_RenameFile( } } else { + WCHAR* TargetTruePath2 = TargetTruePath; - RtlInitUnicodeString(&objname, TargetTruePath); + ULONG TargetTruePathFlags = 0; + WCHAR* OldTruePath = File_ResolveTruePath(TargetTruePath, TargetCopyPath, &TargetTruePathFlags); + if (OldTruePath) + TargetTruePath2 = OldTruePath; - if (!Dll_DigitalGuardian) + RtlInitUnicodeString(&objname, TargetTruePath2); + + if (FILE_PATH_DELETED(TargetTruePathFlags)) // File_Delete_v2 && + { + status = STATUS_OBJECT_NAME_NOT_FOUND; + } + else if (!Dll_DigitalGuardian) { status = __sys_NtQueryFullAttributesFile(&objattrs, &open_info); } else { - ULONG mp_flags = File_MatchPath(TargetTruePath, &TargetFlags); + ULONG mp_flags = File_MatchPath(TargetTruePath2, &TargetFlags); if (PATH_IS_OPEN(mp_flags) || !mp_flags) { @@ -6640,22 +6827,26 @@ issue_rename: // is an open path // - RtlInitUnicodeString(&objname, TargetCopyPath); + if (!File_Delete_v2) { - status = __sys_NtCreateFile( - &TargetHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, - &objattrs, &IoStatusBlock, NULL, 0, FILE_SHARE_VALID_FLAGS, - FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + RtlInitUnicodeString(&objname, TargetCopyPath); - if (NT_SUCCESS(status)) { + status = __sys_NtCreateFile( + &TargetHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &objattrs, &IoStatusBlock, NULL, 0, FILE_SHARE_VALID_FLAGS, + FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); - File_SetCreateTime(TargetHandle, TargetCopyPath); + if (NT_SUCCESS(status)) { - NtClose(TargetHandle); - TargetHandle = NULL; + File_SetCreateTime(TargetHandle, TargetCopyPath); - } else - status = STATUS_SUCCESS; + NtClose(TargetHandle); + TargetHandle = NULL; + + } + else + status = STATUS_SUCCESS; + } // // record for recovery @@ -6673,13 +6864,64 @@ after_rename: if (SourceFlags & FGN_IS_BOXED_PATH) { NTSTATUS status2; - HANDLE handle2; - FILE_NETWORK_OPEN_INFORMATION open_info; + WCHAR* SourceTruePath2 = SourceTruePath; - RtlInitUnicodeString(&objname, SourceTruePath); + WCHAR* OldTruePath = File_ResolveTruePath(SourceTruePath, SourceCopyPath, NULL); + if (OldTruePath) + SourceTruePath2 = OldTruePath; + + RtlInitUnicodeString(&objname, SourceTruePath2); status2 = __sys_NtQueryFullAttributesFile(&objattrs, &open_info); + + if (File_Delete_v2) { + + BOOLEAN TrueExists = FALSE; + BOOLEAN IsDirectroy; + + if (NT_SUCCESS(status2)) { + + // + // if this file exist in the true path mark it as deleted, + // directories are handled by File_SetRelocation + // + + TrueExists = TRUE; + IsDirectroy = (open_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + + if (!IsDirectroy) + File_MarkDeleted_v2(SourceTruePath); + } + else { + + // + // if it does nto exist check if it was a directory, it may be a boxed directroy + // which is a relocation target in which case we will need to update the relocation data + // + + IO_STATUS_BLOCK IoStatusBlock; + FILE_BASIC_INFORMATION info3; + + status2 = __sys_NtQueryInformationFile( + FileHandle, &IoStatusBlock, &info3, + sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); + + IsDirectroy = (info3.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + } + + // + // if this is a directory and if so update/create the appropriate remapping + // + + if (IsDirectroy) { + + File_SetRelocation(SourceTruePath, TargetTruePath, TrueExists); + } + } + else if (NT_SUCCESS(status2)) { + HANDLE handle2; + // // mark deleted only if there is a corresponding file // outside the sandbox @@ -6840,8 +7082,10 @@ _FX ULONG SbieDll_GetHandlePath( if (Dll_BoxName && // sandboxed process IsBoxedPath && *IsBoxedPath) { - if (File_Snapshot != NULL) - File_FindSnapshotPath(&CopyPath); + if (File_Snapshot != NULL) { + WCHAR* TmplName = File_FindSnapshotPath(CopyPath); + if (TmplName) CopyPath = TmplName; + } src = CopyPath; } diff --git a/Sandboxie/core/dll/file_copy.c b/Sandboxie/core/dll/file_copy.c index c6173790..7102baef 100644 --- a/Sandboxie/core/dll/file_copy.c +++ b/Sandboxie/core/dll/file_copy.c @@ -278,6 +278,7 @@ _FX NTSTATUS File_MigrateFile( if (status == STATUS_SHARING_VIOLATION) { + if (!Dll_CompartmentMode) // NoDriverAssist status = SbieApi_OpenFile(&TrueHandle, TruePath); if (!NT_SUCCESS(status)) { diff --git a/Sandboxie/core/dll/file_del.c b/Sandboxie/core/dll/file_del.c new file mode 100644 index 00000000..1feaa362 --- /dev/null +++ b/Sandboxie/core/dll/file_del.c @@ -0,0 +1,763 @@ +/* + * Copyright 2022 David Xanatos, xanasoft.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//--------------------------------------------------------------------------- +// File (Delete) +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// Defines +//--------------------------------------------------------------------------- + +#define FILE_PATH_FILE_NAME L"FilePaths.dat" + +// path flages, saved to file +#define FILE_DELETED_FLAG 0x0001 +#define FILE_RELOCATION_FLAG 0x0002 + +// internal volatile status flags +#define FILE_PATH_DELETED_FLAG 0x00010000 +#define FILE_PATH_RELOCATED_FLAG 0x00020000 +#define FILE_CHILDREN_DELETED_FLAG 0x00040000 + +#define FILE_DELETED_MASK (FILE_DELETED_FLAG | FILE_PATH_DELETED_FLAG) +#define FILE_RELOCATED_MASK (FILE_RELOCATION_FLAG | FILE_PATH_RELOCATED_FLAG) + +#define FILE_IS_DELETED(x) ((x & FILE_DELETED_FLAG) != 0) +#define FILE_PATH_DELETED(x) ((x & FILE_DELETED_MASK) != 0) +#define FILE_PARENT_DELETED(x) ((x & FILE_PATH_DELETED_FLAG) != 0) +#define FILE_PATH_RELOCATED(x) ((x & FILE_RELOCATED_MASK) != 0) + +//--------------------------------------------------------------------------- +// Structures and Types +//--------------------------------------------------------------------------- + +typedef struct _PATH_NODE { + LIST_ELEM list_elem; + LIST items; + ULONG flags; + WCHAR* relocation; + ULONG name_len; + WCHAR name[1]; +} PATH_NODE; + + +//--------------------------------------------------------------------------- +// Variables +//--------------------------------------------------------------------------- + + +static LIST File_PathRoot; +static CRITICAL_SECTION *File_PathRoot_CritSec = NULL; + +static HANDLE File_BoxRootWatcher = NULL; + +//--------------------------------------------------------------------------- +// Functions +//--------------------------------------------------------------------------- + +static ULONG File_GetPathFlags(const WCHAR* Path, WCHAR** pRelocation); +static BOOLEAN File_SavePathTree(); +static BOOLEAN File_LoadPathTree(); +static VOID File_RefreshPathTree(); +static BOOLEAN File_InitDelete_v2(); + +static NTSTATUS File_MarkDeleted_v2(const WCHAR *TruePath); +static ULONG File_IsDeleted_v2(const WCHAR* TruePath); +static BOOLEAN File_HasDeleted_v2(const WCHAR* TruePath); +static WCHAR* File_GetRelocation(const WCHAR* TruePath); +static NTSTATUS File_SetRelocation(const WCHAR *OldTruePath, const WCHAR *NewTruePath, BOOLEAN TrueExists); + +//--------------------------------------------------------------------------- +// File_ClearPathBranche +//--------------------------------------------------------------------------- + + +_FX VOID File_ClearPathBranche_internal(LIST* parent) +{ + PATH_NODE* child = List_Head(parent); + while (child) { + + PATH_NODE* next_child = List_Next(child); + + File_ClearPathBranche_internal(&child->items); + + List_Remove(parent, child); + if(child->relocation) Dll_Free(child->relocation); + Dll_Free(child); + + child = next_child; + } +} + + +//--------------------------------------------------------------------------- +// File_GetPathNode_internal +//--------------------------------------------------------------------------- + + +_FX PATH_NODE* File_GetPathNode_internal(LIST* parent, const WCHAR* name, ULONG name_len, BOOLEAN can_add) +{ + PATH_NODE* child; + + child = List_Head(parent); + while (child) { + + if (child->name_len == name_len && _wcsnicmp(child->name, name, name_len) == 0) + break; + + child = List_Next(child); + } + + if (!child && can_add) { + + child = Dll_Alloc(sizeof(PATH_NODE) + name_len*sizeof(WCHAR)); + memzero(child, sizeof(PATH_NODE)); + //List_Init(child->items); // done by memzero + child->name_len = name_len; + wmemcpy(child->name, name, name_len); + child->name[name_len] = L'\0'; + + List_Insert_After(parent, NULL, child); + } + + return child; +} + + +//--------------------------------------------------------------------------- +// File_FindPathBranche_internal +//--------------------------------------------------------------------------- + + +_FX PATH_NODE* File_FindPathBranche_internal(LIST* Root, const WCHAR* Path, LIST** pParent, BOOLEAN can_add) +{ + LIST* Parent = Root; + PATH_NODE* Node; + const WCHAR* next; + for (const WCHAR* ptr = Path; *ptr; ptr = next + 1) { + next = wcschr(ptr, L'\\'); + if (ptr == next) // handle initial \ as well as \\ or \\\ etc cases + continue; + if(!next) next = wcschr(ptr, L'\0'); // last + + Node = File_GetPathNode_internal(Parent, ptr, (ULONG)(next - ptr), can_add); + if (!Node) + return NULL; + + if (*next == L'\0') { + if (pParent) *pParent = Parent; + return Node; + } + Parent = &Node->items; + } + + return NULL; +} + + +//--------------------------------------------------------------------------- +// File_SetPathFlags_internal +//--------------------------------------------------------------------------- + + +_FX VOID File_SetPathFlags_internal(LIST* Root, const WCHAR* Path, ULONG setFlags, ULONG clrFlags, const WCHAR* Relocation) +{ + PATH_NODE* Parent = Root; + PATH_NODE* Node; + const WCHAR* next; + for (const WCHAR* ptr = Path; *ptr; ptr = next + 1) { + next = wcschr(ptr, L'\\'); + if (ptr == next) // handle initial \ as well as \\ or \\\ etc cases + continue; + if(!next) next = wcschr(ptr, L'\0'); // last + + Node = File_GetPathNode_internal(Parent, ptr, (ULONG)(next - ptr), TRUE); + + if (*next == L'\0') { // set flag always on the last element only + + Node->flags |= setFlags; + Node->flags &= ~clrFlags; + + if ((clrFlags & FILE_RELOCATION_FLAG) != 0 || (setFlags & FILE_RELOCATION_FLAG) != 0) { + if (Node->relocation) { + Dll_Free(Node->relocation); + Node->relocation = NULL; + } + } + if ((setFlags & FILE_RELOCATION_FLAG) != 0 && Relocation != NULL) { + if (Relocation && wcslen(Relocation) > 0) { + Node->relocation = Dll_Alloc((wcslen(Relocation) + 1) * sizeof(WCHAR)); + wcscpy(Node->relocation, Relocation); + } + } + + break; + } + Parent = &Node->items; + } +} + + +//--------------------------------------------------------------------------- +// File_GetPathFlags_internal +//--------------------------------------------------------------------------- + + +_FX ULONG File_GetPathFlags_internal(LIST* Root, const WCHAR* Path, WCHAR** pRelocation, BOOLEAN CheckChildren) +{ + ULONG Flags = 0; + const WCHAR* Relocation = NULL; + const WCHAR* SubPath = NULL; + + LIST* Parent = Root; + PATH_NODE* Node; + PATH_NODE* child; + const WCHAR* next; + for (const WCHAR* ptr = Path; *ptr; ptr = next + 1) { + next = wcschr(ptr, L'\\'); + if (ptr == next) // handle initial \ as well as \\ or \\\ etc cases + continue; + if(!next) next = wcschr(ptr, L'\0'); // last + + Node = File_GetPathNode_internal(Parent, ptr, (ULONG)(next - ptr), FALSE); + if (!Node) + break; + + // + // we return the last relocation target + // + + if ((Node->flags & FILE_RELOCATION_FLAG) != 0) { + Relocation = Node->relocation; + SubPath = next; + } + + + if (*next == L'\0') { // last path segment + + if ((Node->flags & FILE_RELOCATION_FLAG) != 0) + Flags |= FILE_RELOCATION_FLAG; + if ((Node->flags & FILE_DELETED_FLAG) != 0) + Flags |= FILE_DELETED_FLAG; // flag set for the path + + if (CheckChildren) { + child = List_Head(&Node->items); + while (child) { + if ((child->flags & Flags) == Flags) { + Flags |= FILE_CHILDREN_DELETED_FLAG; // path set for children + break; + } + child = List_Next(child); + } + } + + break; + } + + // + // if we encounter a relocation previosue deletions on the path will be reset + // relocations are only allowed to exist for not deleted paths + // + + if ((Node->flags & FILE_RELOCATION_FLAG) != 0) { + Flags = 0; // reset + Flags |= FILE_PATH_RELOCATED_FLAG; + } + else if ((Node->flags & FILE_DELETED_FLAG) != 0) + Flags |= FILE_PATH_DELETED_FLAG; // flag set for ancestor + + Parent = &Node->items; + } + + if (Relocation && pRelocation) { + + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + *pRelocation = Dll_GetTlsNameBuffer(TlsData, MOVE_NAME_BUFFER, (wcslen(Relocation) + wcslen(SubPath) + 16) * sizeof(WCHAR)); // +16 some room for changes + wcscpy(*pRelocation, Relocation); + wcscat(*pRelocation, SubPath); + } + + return Flags; +} + + +//--------------------------------------------------------------------------- +// File_GetPathFlags +//--------------------------------------------------------------------------- + + +_FX ULONG File_GetPathFlags(const WCHAR* Path, WCHAR** pRelocation) +{ + ULONG Flags; + + File_RefreshPathTree(); + + EnterCriticalSection(File_PathRoot_CritSec); + + Flags = File_GetPathFlags_internal(&File_PathRoot, Path, pRelocation, TRUE); + + LeaveCriticalSection(File_PathRoot_CritSec); + + return Flags; +} + + +//--------------------------------------------------------------------------- +// File_SavePathNode_internal +//--------------------------------------------------------------------------- + + +_FX VOID File_SavePathNode_internal(HANDLE hPathsFile, LIST* parent, WCHAR* Path, ULONG Length, ULONG SetFlags) +{ + const WCHAR CrLf[] = L"\r\n"; + WCHAR FlagStr[16] = L"|"; + + // append L"\\" + Path[Length++] = L'\\'; //Path[Length] = L'0'; + WCHAR* PathBase = Path + Length; + + PATH_NODE* child; + child = List_Head(parent); + while (child) { + + wmemcpy(PathBase, child->name, child->name_len + 1); + ULONG Path_Len = Length + child->name_len; + + // + // don't write down flags that were already set for the parent, + // unless we have a relocation, that resets everything + // + + if ((child->flags & FILE_RELOCATION_FLAG) != 0) + SetFlags = 0; + + if ((child->flags & ~SetFlags) != 0 || child->relocation != NULL) { + + // write the path + WriteFile(hPathsFile, Path, Path_Len * sizeof(WCHAR), NULL, NULL); + + // write the flags + _ultow(child->flags, FlagStr + 1, 16); + WriteFile(hPathsFile, FlagStr, wcslen(FlagStr) * sizeof(WCHAR), NULL, NULL); + + // write the relocation + if (child->relocation != NULL) { + WriteFile(hPathsFile, FlagStr, sizeof(WCHAR), NULL, NULL); // write | + WriteFile(hPathsFile, child->relocation, wcslen(child->relocation) * sizeof(WCHAR), NULL, NULL); + } + + // write line ending + WriteFile(hPathsFile, CrLf, sizeof(CrLf) - sizeof(WCHAR), NULL, NULL); + } + + File_SavePathNode_internal(hPathsFile, &child->items, Path, Path_Len, SetFlags | child->flags); + + child = List_Next(child); + } +} + + +//--------------------------------------------------------------------------- +// File_SavePathTree_internal +//--------------------------------------------------------------------------- + + +_FX VOID File_SavePathTree_internal(LIST* Root, const WCHAR* name) +{ + WCHAR PathsFile[MAX_PATH] = { 0 }; + wcscpy(PathsFile, Dll_BoxFilePath); + wcscat(PathsFile, L"\\"); + wcscat(PathsFile, name); + SbieDll_TranslateNtToDosPath(PathsFile); + + HANDLE hPathsFile; + hPathsFile = CreateFile(PathsFile, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hPathsFile == INVALID_HANDLE_VALUE) + return; + + WCHAR* Path = (WCHAR *)Dll_Alloc((0x7FFF + 1)*sizeof(WCHAR)); // max nt path + + File_SavePathNode_internal(hPathsFile, Root, Path, 0, 0); + + Dll_Free(Path); + + CloseHandle(hPathsFile); +} + + +//--------------------------------------------------------------------------- +// File_SavePathTree +//--------------------------------------------------------------------------- + + +_FX BOOLEAN File_SavePathTree() +{ + EnterCriticalSection(File_PathRoot_CritSec); + + File_SavePathTree_internal(&File_PathRoot, FILE_PATH_FILE_NAME); + + LeaveCriticalSection(File_PathRoot_CritSec); + + return TRUE; +} + + +//--------------------------------------------------------------------------- +// File_LoadPathTree_internal +//--------------------------------------------------------------------------- + + +_FX VOID File_LoadPathTree_internal(LIST* Root, const WCHAR* name) +{ + WCHAR PathsFile[MAX_PATH] = { 0 }; + wcscpy(PathsFile, Dll_BoxFilePath); + wcscat(PathsFile, L"\\"); + wcscat(PathsFile, name); + SbieDll_TranslateNtToDosPath(PathsFile); + + HANDLE hPathsFile; + hPathsFile = CreateFile(PathsFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hPathsFile == INVALID_HANDLE_VALUE) + return; + + File_ClearPathBranche_internal(Root); + + LARGE_INTEGER fileSize; + GetFileSizeEx(hPathsFile, &fileSize); + + WCHAR* Buffer = (WCHAR *)Dll_Alloc((ULONG)fileSize.QuadPart + 128); + DWORD bytesRead; + ReadFile(hPathsFile, Buffer, (DWORD)fileSize.QuadPart, &bytesRead, NULL); + Buffer[bytesRead/sizeof(WCHAR)] = L'\0'; + + WCHAR* Next = Buffer; + while (*Next) { + WCHAR* Line = Next; + WCHAR* End = wcschr(Line, L'\n'); + if (End == NULL) { + End = wcschr(Line, L'\0'); + Next = End; + } else + Next = End + 1; + LONG LineLen = (LONG)(End - Line); + if (LineLen > 1 && Line[LineLen - 1] == L'\r') + LineLen -= 1; + + WCHAR savechar = Line[LineLen]; + Line[LineLen] = L'\0'; + + WCHAR* Sep = wcschr(Line, L'|'); + if (!Sep || Sep > Next) continue; // invalid line, flags field missing + *Sep = L'\0'; + + WCHAR* endptr; + ULONG Flags = wcstoul(Sep + 1, &endptr, 16); + if (endptr && *endptr == L'|') endptr++; + else endptr = NULL; + + File_SetPathFlags_internal(Root, Line, Flags, 0, endptr); + + *Sep = L'|'; + Line[LineLen] = savechar; + } + + Dll_Free(Buffer); + + CloseHandle(hPathsFile); +} + + +//--------------------------------------------------------------------------- +// File_LoadPathTree +//--------------------------------------------------------------------------- + + +_FX BOOLEAN File_LoadPathTree() +{ + EnterCriticalSection(File_PathRoot_CritSec); + + File_LoadPathTree_internal(&File_PathRoot, FILE_PATH_FILE_NAME); + + LeaveCriticalSection(File_PathRoot_CritSec); + + return TRUE; +} + + +//--------------------------------------------------------------------------- +// File_RefreshPathTree +//--------------------------------------------------------------------------- + + +_FX VOID File_RefreshPathTree() +{ + if (!File_BoxRootWatcher) + return; + + if (WaitForSingleObject(File_BoxRootWatcher, 0) == WAIT_OBJECT_0) { + + // + // somethign changed, reload the path tree + // + + File_LoadPathTree(); + } + + FindNextChangeNotification(File_BoxRootWatcher); // rearm the watcher +} + + +//--------------------------------------------------------------------------- +// File_InitDelete_v2 +//--------------------------------------------------------------------------- + + +_FX BOOLEAN File_InitDelete_v2() +{ + List_Init(&File_PathRoot); + + File_PathRoot_CritSec = Dll_Alloc(sizeof(CRITICAL_SECTION)); + InitializeCriticalSectionAndSpinCount(File_PathRoot_CritSec, 1000); + + File_LoadPathTree(); + +//#ifdef WITH_DEBUG +// File_SavePathTree(); +//#endif + + WCHAR BoxFilePath[MAX_PATH] = { 0 }; + wcscpy(BoxFilePath, Dll_BoxFilePath); + SbieDll_TranslateNtToDosPath(BoxFilePath); + + File_BoxRootWatcher = FindFirstChangeNotification(BoxFilePath, FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); + + return TRUE; +} + + +//--------------------------------------------------------------------------- +// File_MarkDeleted_internal +//--------------------------------------------------------------------------- + + +_FX VOID File_MarkDeleted_internal(LIST* Root, const WCHAR* Path) +{ + EnterCriticalSection(File_PathRoot_CritSec); + + // 1. remove deleted branche + + LIST* Parent = NULL; + PATH_NODE* Node = File_FindPathBranche_internal(Root, Path, &Parent, FALSE); + if (Node) { + List_Remove(Parent, Node); + + File_ClearPathBranche_internal(&Node->items); + if (Node->relocation) Dll_Free(Node->relocation); + Dll_Free(Node); + } + + // 2. set deleted flag + + File_SetPathFlags_internal(Root, Path, FILE_DELETED_FLAG, 0, NULL); + + // done + + LeaveCriticalSection(File_PathRoot_CritSec); + + File_SavePathTree(); +} + + +//--------------------------------------------------------------------------- +// File_MarkDeleted_v2 +//--------------------------------------------------------------------------- + + +_FX NTSTATUS File_MarkDeleted_v2(const WCHAR* TruePath) +{ + // + // add a file or directory to the deleted list + // + + EnterCriticalSection(File_PathRoot_CritSec); + + File_MarkDeleted_internal(&File_PathRoot, TruePath); + + LeaveCriticalSection(File_PathRoot_CritSec); + + File_SavePathTree(); + + return STATUS_SUCCESS; +} + + +//--------------------------------------------------------------------------- +// File_IsDeleted_v2 +//--------------------------------------------------------------------------- + + +_FX ULONG File_IsDeleted_v2(const WCHAR* TruePath) +{ + // + // check if the file or one of its parent directories is listed as deleted + // use the dedicated test method to properly take into account relocations + // + + ULONG Flags = File_GetPathFlags(TruePath, NULL); + + return (Flags & FILE_DELETED_MASK); +} + + +//--------------------------------------------------------------------------- +// File_HasDeleted_v2 +//--------------------------------------------------------------------------- + + +_FX BOOLEAN File_HasDeleted_v2(const WCHAR* TruePath) +{ + // + // Check if this folder has deleted children + // + + ULONG Flags = File_GetPathFlags(TruePath, NULL); + + return (Flags & FILE_CHILDREN_DELETED_FLAG) != 0; +} + + +//--------------------------------------------------------------------------- +// File_SetRelocation_internal +//--------------------------------------------------------------------------- + + +_FX VOID File_SetRelocation_internal(LIST* Root, const WCHAR *OldTruePath, const WCHAR *NewTruePath, BOOLEAN TrueExists) +{ + // 1. separate branche from OldTruePath + + LIST* Parent = NULL; + PATH_NODE* Node = File_FindPathBranche_internal(Root, OldTruePath, &Parent, FALSE); + //if(Node) + // List_Remove(Parent, Node); // leave node in it may have a delete flag + + // 2. check if old path has a relocation + + BOOLEAN HasRelocation = FALSE; + if (Node && (Node->flags & FILE_RELOCATION_FLAG) != 0) { + Node->flags &= ~FILE_RELOCATION_FLAG; + if (Node->relocation) { + HasRelocation = TRUE; + OldTruePath = Node->relocation; // update relocation to oritinal true target + } + } + + // 3. add true delete entry OldTruePath + + File_SetPathFlags_internal(Root, OldTruePath, FILE_DELETED_FLAG, 0, NULL); + + // 4. set redirection NewTruePath -> OldTruePath + + if (TrueExists || HasRelocation || (Node && Node->items.count > 0)) { + + PATH_NODE* NewNode = File_FindPathBranche_internal(Root, NewTruePath, NULL, TRUE); + + // OldTruePath may have a relocated parent, if so unwrap it + if (!HasRelocation) { + WCHAR* OldOldTruePath = NULL; + File_GetPathFlags_internal(&File_PathRoot, OldTruePath, &OldOldTruePath, TRUE); + if (OldOldTruePath) OldTruePath = OldOldTruePath; + } + + if (TrueExists || HasRelocation) { + NewNode->flags |= FILE_RELOCATION_FLAG; + NewNode->relocation = Dll_Alloc((wcslen(OldTruePath) + 1) * sizeof(WCHAR)); + wcscpy(NewNode->relocation, OldTruePath); + } + + // 5. reatach branche to NewTruePath + + if (Node) { + PATH_NODE* child = List_Head(&Node->items); + while (child) { + + PATH_NODE* next_child = List_Next(child); + + List_Remove(&Node->items, child); + + List_Insert_After(&NewNode->items, NULL, child); + + child = next_child; + } + } + } + + // 6. clean up + + //if (Node) { + if (HasRelocation) { + //if (Node->relocation) + Dll_Free(Node->relocation); + Node->relocation = NULL; + //Dll_Free(Node); + } +} + + +//--------------------------------------------------------------------------- +// File_SetRelocation +//--------------------------------------------------------------------------- + + +_FX NTSTATUS File_SetRelocation(const WCHAR* OldTruePath, const WCHAR* NewTruePath, BOOLEAN TrueExists) +{ + // + // List a mapping for the new location + // + + EnterCriticalSection(File_PathRoot_CritSec); + + File_SetRelocation_internal(&File_PathRoot, OldTruePath, NewTruePath, TrueExists); + + LeaveCriticalSection(File_PathRoot_CritSec); + + File_SavePathTree(); + + return STATUS_SUCCESS; +} + + +//--------------------------------------------------------------------------- +// File_GetRelocation +//--------------------------------------------------------------------------- + + +_FX WCHAR* File_GetRelocation(const WCHAR *TruePath) +{ + // + // Get redirection location, only if its the actual path and not a parent + // + + WCHAR* OldTruePath = NULL; + ULONG Flags = File_GetPathFlags(TruePath, &OldTruePath); + if (FILE_PATH_RELOCATED(Flags)) + return OldTruePath; + + return NULL; +} + diff --git a/Sandboxie/core/dll/file_dir.c b/Sandboxie/core/dll/file_dir.c index 4897f79f..30e98793 100644 --- a/Sandboxie/core/dll/file_dir.c +++ b/Sandboxie/core/dll/file_dir.c @@ -44,6 +44,7 @@ typedef struct _FILE_MERGE_CACHE_FILE { typedef struct _FILE_MERGE_FILE { HANDLE handle; + FILE_SNAPSHOT* shapshot; FILE_ID_BOTH_DIR_INFORMATION *info; ULONG info_len; WCHAR *name; @@ -94,14 +95,6 @@ typedef struct _FILE_FS_DEVICE_INFORMATION { ULONG Characteristics; } FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; -#define MAX_CLOSE_HANDLERS 4 - -typedef struct _FILE_ON_CLOSE { - - BOOLEAN DeleteOnClose; - P_CloseHandler CloseHandlers[MAX_CLOSE_HANDLERS]; - -} FILE_ON_CLOSE; //--------------------------------------------------------------------------- // Functions @@ -157,7 +150,7 @@ static NTSTATUS File_MergeDummy( static void File_MergeFree(FILE_MERGE *merge); static NTSTATUS File_GetMergedInformation( - FILE_MERGE *merge, + FILE_MERGE *merge, WCHAR *TruePath, WCHAR *CopyPath, IO_STATUS_BLOCK *IoStatusBlock, void *FileInformation, ULONG Length, @@ -178,14 +171,6 @@ static NTSTATUS File_DeleteDirectory( static NTSTATUS File_MarkChildrenDeleted(const WCHAR *ParentTruePath); -static void File_InitRecoverList( - const WCHAR *setting, LIST *list, BOOLEAN MustBeValidPath, - WCHAR *buf, ULONG buf_len); - -static void File_NotifyRecover(HANDLE FileHandle); - -static BOOLEAN File_IsRecoverable(const WCHAR *TruePath); - static ULONG File_RtlGetCurrentDirectory_U(ULONG buf_len, WCHAR *buf_ptr); static NTSTATUS File_RtlSetCurrentDirectory_U(UNICODE_STRING *PathName); @@ -207,17 +192,6 @@ static NTSTATUS File_NtQueryVolumeInformationFile( ULONG Length, ULONG FsInformationClass); -static void File_DoAutoRecover_2(BOOLEAN force, ULONG ticks); - -static ULONG File_DoAutoRecover_3( - const WCHAR *PathToFind, WCHAR *PathBuf1024, - SYSTEM_HANDLE_INFORMATION *info, FILE_GET_ALL_HANDLES_RPL *rpl, - UCHAR *FileObjectTypeNumber); - -static ULONG File_DoAutoRecover_4( - const WCHAR *PathToFind, WCHAR *PathBuf1024, - HANDLE FileHandle, UCHAR ObjectTypeNumber, UCHAR *FileObjectTypeNumber); - NTSTATUS File_NtCloseImpl(HANDLE FileHandle); VOID File_NtCloseDir(HANDLE FileHandle); @@ -227,12 +201,6 @@ VOID File_NtCloseDir(HANDLE FileHandle); //--------------------------------------------------------------------------- -static LIST File_RecoverFolders; -static LIST File_RecoverIgnores; - -static LIST File_RecPaths; -static CRITICAL_SECTION File_RecHandles_CritSec; - static CRITICAL_SECTION File_CurDir_CritSec; static WCHAR *File_CurDir_LastInput = NULL; static WCHAR *File_CurDir_LastOutput = NULL; @@ -240,10 +208,7 @@ static WCHAR *File_CurDir_LastOutput = NULL; static LIST File_DirHandles; static CRITICAL_SECTION File_DirHandles_CritSec; -static HASH_MAP File_HandleOnClose; -static CRITICAL_SECTION File_HandleOnClose_CritSec; -static BOOLEAN File_MsoDllLoaded = FALSE; //--------------------------------------------------------------------------- @@ -418,7 +383,7 @@ _FX NTSTATUS File_NtQueryDirectoryFile( merge_lock = TRUE; status = File_GetMergedInformation( - merge, IoStatusBlock, + merge, TruePath, CopyPath, IoStatusBlock, FileInformation, Length, FileInformationClass, ReturnSingleEntry); if (merge->first_request) { @@ -519,7 +484,7 @@ _FX NTSTATUS File_Merge( } else { - File_UnRegisterCloseHandler(merge->handle, File_NtCloseDir); + Handle_UnRegisterCloseHandler(merge->handle, File_NtCloseDir); List_Remove(&File_DirHandles, merge); File_MergeFree(merge); } @@ -573,7 +538,7 @@ _FX NTSTATUS File_Merge( } List_Insert_After(&File_DirHandles, NULL, merge); - File_RegisterCloseHandler(merge->handle, File_NtCloseDir); + Handle_RegisterCloseHandler(merge->handle, File_NtCloseDir); } // @@ -637,8 +602,14 @@ _FX NTSTATUS File_OpenForMerge( WCHAR *ptr; // BOOLEAN TruePathIsRoot; BOOLEAN TruePathDeleted = FALSE; // indicates that one of the parent snapshots deleted the true directory + WCHAR* OriginalPath = NULL; + ULONG TruePathFlags = 0; BOOLEAN NoCopyPath = FALSE; + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + Dll_PushTlsNameBuffer(TlsData); + InitializeObjectAttributes( &objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); @@ -646,8 +617,27 @@ _FX NTSTATUS File_OpenForMerge( // open the copy file // - if (File_CheckDeletedParent(CopyPath)) - return STATUS_OBJECT_PATH_NOT_FOUND; + if (File_Delete_v2) { + + // + // test if the path is deleted and find the oldest snapshot with a relocation, + // or + // + + WCHAR* OldTruePath = File_ResolveTruePath(TruePath, NULL, &TruePathFlags); + if (FILE_PATH_DELETED(TruePathFlags)) + TruePathDeleted = TRUE; + else if (OldTruePath) { + OriginalPath = TruePath; + TruePath = OldTruePath; + } + } + else { + if (File_CheckDeletedParent(CopyPath)) { + status = STATUS_OBJECT_PATH_NOT_FOUND; + goto finish; + } + } RtlInitUnicodeString(&objname, CopyPath); @@ -678,6 +668,7 @@ _FX NTSTATUS File_OpenForMerge( if (NT_SUCCESS(status)) { + // if (!File_Delete_v2 && if (IS_DELETE_MARK(&info.basic.CreationTime)) { status = STATUS_OBJECT_NAME_NOT_FOUND; @@ -694,10 +685,10 @@ _FX NTSTATUS File_OpenForMerge( __sys_NtClose(merge->files[0].handle); merge->files[0].handle = NULL; - return status; + goto finish; } - // + // // copy file passed all checks; indicate it is ready for use // @@ -719,7 +710,7 @@ _FX NTSTATUS File_OpenForMerge( NoCopyPath = TRUE; } else - return status; + goto finish; } // @@ -728,6 +719,8 @@ _FX NTSTATUS File_OpenForMerge( if (File_Snapshot != NULL) { + WCHAR* TempPath = TruePath; + for (FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot; Cur_Snapshot != NULL; Cur_Snapshot = Cur_Snapshot->Parent) { WCHAR* TmplName = File_MakeSnapshotPath(Cur_Snapshot, CopyPath); @@ -757,14 +750,13 @@ _FX NTSTATUS File_OpenForMerge( // make sure it is a directory file // - // todo reduce redundant code, combine with the code for the copy_file - status = __sys_NtQueryInformationFile( merge->files[merge->files_count].handle, &IoStatusBlock, &info, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (NT_SUCCESS(status)) { + // if (!File_Delete_v2 && if (IS_DELETE_MARK(&info.basic.CreationTime)) { status = STATUS_OBJECT_NAME_NOT_FOUND; @@ -786,7 +778,9 @@ _FX NTSTATUS File_OpenForMerge( break; // dont look any further } - // + merge->files[merge->files_count].shapshot = Cur_Snapshot; + + // // copy file passed all checks; indicate it is ready for use // @@ -796,13 +790,46 @@ _FX NTSTATUS File_OpenForMerge( merge->files_count++; } - else { + // else: ignore the error, proceed to next snapshot - // - // Ignroe errors here for now // todo - // + // + // check if we have a relocation and update CopyPath for the next snapshot accordingly + // since we dont need opypath anyware anymore we can alter it + // - } + if (File_Delete_v2) { + + WCHAR* Relocation; + ULONG Flags = File_GetPathFlags_internal(&Cur_Snapshot->PathRoot, TempPath, &Relocation, TRUE); + if (FILE_PATH_DELETED(Flags)) + break; + + if (Relocation) { + + if (!Cur_Snapshot->Parent) + break; // take a shortcut + + TempPath = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, (wcslen(Relocation) + 1) * sizeof(WCHAR)); + wcscpy(TempPath, Relocation); + + // + // update the copy file name + // + + Dll_PushTlsNameBuffer(TlsData); + + WCHAR* TruePath2, *CopyPath2; + RtlInitUnicodeString(&objname, Relocation); + File_GetName(NULL, &objname, &TruePath2, &CopyPath2, NULL); + + Dll_PopTlsNameBuffer(TlsData); + + // note: pop leaves TruePath2 valid we can still use it + + CopyPath = Dll_GetTlsNameBuffer(TlsData, COPY_NAME_BUFFER, (wcslen(CopyPath2) + 1) * sizeof(WCHAR)); + wcscpy(CopyPath, CopyPath2); + } + } } } @@ -811,11 +838,12 @@ _FX NTSTATUS File_OpenForMerge( // and can let the system work directly on the true file // - if (merge->files_count == 0) { + if ((TruePathFlags & FILE_CHILDREN_DELETED_FLAG) == 0) // we ned to do full merge if children ar marked deleted + if (merge->files_count == 0) { status = STATUS_BAD_INITIAL_PC; - return status; + goto finish; } if (TruePathDeleted) @@ -915,7 +943,7 @@ _FX NTSTATUS File_OpenForMerge( if (status == STATUS_ACCESS_DENIED) status = STATUS_BAD_INITIAL_PC; - return status; + goto finish; } status = STATUS_SUCCESS; @@ -1003,6 +1031,9 @@ skip_true_file: } } +finish: + Dll_PopTlsNameBuffer(TlsData); + return status; } @@ -1517,7 +1548,7 @@ _FX void File_MergeFree(FILE_MERGE *merge) _FX NTSTATUS File_GetMergedInformation( - FILE_MERGE *merge, + FILE_MERGE *merge, WCHAR *TruePath, WCHAR *CopyPath, IO_STATUS_BLOCK *IoStatusBlock, void *FileInformation, ULONG Length, @@ -1531,6 +1562,8 @@ _FX NTSTATUS File_GetMergedInformation( PVOID next_entry; WCHAR *name_ptr; ULONG len; + ULONG TruePathLen = wcslen(TruePath); + ULONG CopyPathLen = wcslen(CopyPath); info_entry_length = 0; if (FileInformationClass == FileDirectoryInformation) @@ -1551,6 +1584,10 @@ _FX NTSTATUS File_GetMergedInformation( if (info_entry_length > Length) return STATUS_INFO_LENGTH_MISMATCH; + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + Dll_PushTlsNameBuffer(TlsData); + prev_entry = FileInformation; next_entry = FileInformation; @@ -1628,15 +1665,6 @@ _FX NTSTATUS File_GetMergedInformation( best->have_entry = FALSE; } - // if the entry found was in the copy directory, then the file - // may be marked deleted (see Filesys_Mark_File_Deleted for - // details). if it is marked so, we pretend this entry does - // not exist by fetching the following one - - if (ptr_info && (!merge->true_ptr || ptr_info != merge->true_ptr->info) && - IS_DELETE_MARK(&ptr_info->CreationTime)) - continue; - // if both directories are exhausted, reset the // NextEntryOffset field of FILE_*_INFORMATION to // indicate no more entries, and return status @@ -1650,6 +1678,51 @@ _FX NTSTATUS File_GetMergedInformation( break; } + if (File_Delete_v2) { + + if ((merge->true_ptr && ptr_info == merge->true_ptr->info) // is in true path + || ptr_info != merge->files[0].info) { // is in template + + WCHAR* TruePath2 = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, ((TruePathLen + 1) * sizeof(WCHAR) + ptr_info->FileNameLength + sizeof(WCHAR))); + WCHAR* ptr = TruePath2; + wmemcpy(ptr, TruePath, TruePathLen); + ptr += TruePathLen; + if (ptr[-1] != L'\\') *ptr++ = L'\\'; + wmemcpy(ptr, ptr_info->FileName, ptr_info->FileNameLength / sizeof(WCHAR)); + ptr += ptr_info->FileNameLength / sizeof(WCHAR); + *ptr = L'\0'; + + WCHAR* CopyPath2 = Dll_GetTlsNameBuffer(TlsData, COPY_NAME_BUFFER, ((CopyPathLen + 1) * sizeof(WCHAR) + ptr_info->FileNameLength + sizeof(WCHAR))); + ptr = CopyPath2; + wmemcpy(ptr, CopyPath, CopyPathLen); + ptr += CopyPathLen; + if (ptr[-1] != L'\\') *ptr++ = L'\\'; + wmemcpy(ptr, ptr_info->FileName, ptr_info->FileNameLength / sizeof(WCHAR)); + ptr += ptr_info->FileNameLength / sizeof(WCHAR); + *ptr = L'\0'; + + // + // chekc if the file is listed as deleted + // + + if (File_IsDeletedEx(TruePath2, CopyPath2, best->shapshot)) + continue; + + } //else // is in copy path - nothing to do + } + else { + + // if the entry found was in the copy directory, then the file + // may be marked deleted (see Filesys_Mark_File_Deleted for + // details). if it is marked so, we pretend this entry does + // not exist by fetching the following one + + if ((!merge->true_ptr || ptr_info != merge->true_ptr->info) && + IS_DELETE_MARK(&ptr_info->CreationTime)) + continue; + } + + // // make sure caller has enough room in output buffer for the // entry. for the first entry in the buffer, it is ok to have @@ -1675,9 +1748,8 @@ _FX NTSTATUS File_GetMergedInformation( *(ULONG *)prev_entry = 0; // reset NextEntryOffset if (next_entry == FileInformation) - return STATUS_BUFFER_OVERFLOW; - else - break; + status = STATUS_BUFFER_OVERFLOW; + break; } // @@ -1743,6 +1815,8 @@ _FX NTSTATUS File_GetMergedInformation( IoStatusBlock->Information = // number of bytes written (UCHAR *)next_entry - (UCHAR *)FileInformation; + Dll_PopTlsNameBuffer(TlsData); + return status; } @@ -2123,73 +2197,6 @@ _FX NTSTATUS File_NtClose(HANDLE FileHandle) } -//--------------------------------------------------------------------------- -// File_RegisterCloseHandler -//--------------------------------------------------------------------------- - - -_FX BOOLEAN File_RegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler) -{ - if (!FileHandle || FileHandle == (HANDLE)-1) - return FALSE; - - ULONG i; - - EnterCriticalSection(&File_HandleOnClose_CritSec); - - FILE_ON_CLOSE* on_close = map_get(&File_HandleOnClose, FileHandle); - if (!on_close) { - on_close = map_insert(&File_HandleOnClose, FileHandle, NULL, sizeof(FILE_ON_CLOSE)); - } - - for (i = 0; i < MAX_CLOSE_HANDLERS; i++) { - if (on_close->CloseHandlers[i] == CloseHandler) - break; // already registered - if (on_close->CloseHandlers[i] == NULL) { - on_close->CloseHandlers[i] = CloseHandler; // set to empty slot - break; - } - } - - LeaveCriticalSection(&File_HandleOnClose_CritSec); - - if (i == MAX_CLOSE_HANDLERS) { - SbieApi_Log(2301, L"No free CloseHandlers slot available"); - return FALSE; - } - - return TRUE; -} - - -//--------------------------------------------------------------------------- -// File_UnRegisterCloseHandler -//--------------------------------------------------------------------------- - - -_FX BOOLEAN File_UnRegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler) -{ - ULONG i = MAX_CLOSE_HANDLERS; - - EnterCriticalSection(&File_HandleOnClose_CritSec); - - FILE_ON_CLOSE* on_close = map_get(&File_HandleOnClose, FileHandle); - if (on_close) { - - for (i = 0; i < MAX_CLOSE_HANDLERS; i++) { - if (on_close->CloseHandlers[i] == CloseHandler) { - on_close->CloseHandlers[i] = NULL; // clear slot - break; - } - } - } - - LeaveCriticalSection(&File_HandleOnClose_CritSec); - - return i != MAX_CLOSE_HANDLERS; -} - - //--------------------------------------------------------------------------- // File_NtCloseImpl //--------------------------------------------------------------------------- @@ -2202,7 +2209,6 @@ _FX NTSTATUS File_NtCloseImpl(HANDLE FileHandle) NTSTATUS status; ULONG i; - BOOLEAN HasCloseHandlers = FALSE; P_CloseHandler CloseHandlers[MAX_CLOSE_HANDLERS]; BOOLEAN DeleteOnClose = FALSE; UNICODE_STRING uni; @@ -2243,25 +2249,7 @@ _FX NTSTATUS File_NtCloseImpl(HANDLE FileHandle) // and prepare the DeleteOnClose if its set // - EnterCriticalSection(&File_HandleOnClose_CritSec); - - FILE_ON_CLOSE* on_close = (FILE_ON_CLOSE*)map_get(&File_HandleOnClose, FileHandle); - if (on_close) { - - HasCloseHandlers = TRUE; - memcpy(CloseHandlers, on_close->CloseHandlers, sizeof(CloseHandlers)); - DeleteOnClose = on_close->DeleteOnClose; - } - - map_remove(&File_HandleOnClose, FileHandle); - - LeaveCriticalSection(&File_HandleOnClose_CritSec); - - // - // execute close handlers - // - - if (HasCloseHandlers) { + if (Handle_FreeCloseHandler(FileHandle, &CloseHandlers[0], &DeleteOnClose)) { for (i = 0; i < MAX_CLOSE_HANDLERS; i++) { if(CloseHandlers[i] != NULL) @@ -2360,7 +2348,7 @@ _FX VOID File_NtCloseDir(HANDLE FileHandle) while (merge) { FILE_MERGE *next = List_Next(merge); if (merge->handle == FileHandle) { - File_UnRegisterCloseHandler(merge->handle, File_NtCloseDir); + Handle_UnRegisterCloseHandler(merge->handle, File_NtCloseDir); List_Remove(&File_DirHandles, merge); File_MergeFree(merge); } @@ -2666,439 +2654,6 @@ _FX NTSTATUS File_MarkChildrenDeleted(const WCHAR *ParentTruePath) } -//--------------------------------------------------------------------------- -// -// Immediate Recovery for Files -// -//--------------------------------------------------------------------------- - - -//--------------------------------------------------------------------------- -// Structures and Types -//--------------------------------------------------------------------------- - - -typedef struct _FILE_RECOVER_FOLDER { - - LIST_ELEM list_elem; - ULONG ticks; // for File_RecPaths - ULONG path_len; - WCHAR path[1]; - -} FILE_RECOVER_FOLDER; - - -//--------------------------------------------------------------------------- -// File_InitRecoverFolders -//--------------------------------------------------------------------------- - - -_FX void File_InitRecoverFolders(void) -{ - // - // init list of recoverable file handles - // - - List_Init(&File_RecoverFolders); - List_Init(&File_RecoverIgnores); - - InitializeCriticalSectionAndSpinCount(&File_RecHandles_CritSec, 1000); - - List_Init(&File_RecPaths); - - // - // init list of recover folders - // - - if (SbieApi_QueryConfBool(NULL, L"AutoRecover", FALSE)) { - - ULONG buf_len = 4096 * sizeof(WCHAR); - WCHAR *buf = Dll_AllocTemp(buf_len); - - File_InitRecoverList( - L"RecoverFolder", &File_RecoverFolders, TRUE, buf, buf_len); - - File_InitRecoverList( - L"AutoRecoverIgnore", &File_RecoverIgnores, FALSE, buf, buf_len); - - Dll_Free(buf); - } -} - - -//--------------------------------------------------------------------------- -// File_InitRecoverList -//--------------------------------------------------------------------------- - - -_FX void File_InitRecoverList( - const WCHAR *setting, LIST *list, BOOLEAN MustBeValidPath, - WCHAR *buf, ULONG buf_len) -{ - UNICODE_STRING uni; - WCHAR *TruePath, *CopyPath, *ReparsedPath; - FILE_RECOVER_FOLDER *fold; - - ULONG index = 0; - while (1) { - - NTSTATUS status = SbieApi_QueryConf( - NULL, setting, index, buf, buf_len - 16 * sizeof(WCHAR)); - if (! NT_SUCCESS(status)) - break; - ++index; - - RtlInitUnicodeString(&uni, buf); - status = File_GetName(NULL, &uni, &TruePath, &CopyPath, NULL); - - ReparsedPath = NULL; - - if (NT_SUCCESS(status) && MustBeValidPath) { - - ReparsedPath = File_TranslateTempLinks(TruePath, FALSE); - if (ReparsedPath) - TruePath = ReparsedPath; - - } else if ((! NT_SUCCESS(status)) && (! MustBeValidPath)) { - - TruePath = buf; - status = STATUS_SUCCESS; - } - - if (NT_SUCCESS(status)) { - - ULONG len = wcslen(TruePath); - if (len && TruePath[len - 1] == L'\\') { - TruePath[len - 1] = L'\0'; - --len; - } - len = sizeof(FILE_RECOVER_FOLDER) - + (len + 1) * sizeof(WCHAR); - fold = Dll_Alloc(len); - - fold->ticks = 0; // not used - - wcscpy(fold->path, TruePath); - fold->path_len = wcslen(fold->path); - - List_Insert_After(list, NULL, fold); - } - - if (ReparsedPath) - Dll_Free(ReparsedPath); - } -} - - -//--------------------------------------------------------------------------- -// File_IsRecoverable -//--------------------------------------------------------------------------- - - -_FX BOOLEAN File_IsRecoverable( - const WCHAR *TruePath) -{ - const WCHAR *save_TruePath; - FILE_RECOVER_FOLDER *fold; - const WCHAR *ptr; - ULONG TruePath_len; - ULONG PrefixLen; - BOOLEAN ok; - - // - // if we have a path that looks like - // \Device\LanmanRedirector\;Q:000000000000b09f\server\share\f1.txt - // \Device\Mup\;LanmanRedirector\;Q:000000000000b09f\server\share\f1.txt - // then translate to - // \Device\Mup\server\share\f1.txt - // and test again. We do this because the SbieDrv records paths - // in the \Device\Mup format. See SbieDrv::File_TranslateShares. - // - - save_TruePath = TruePath; - - if (_wcsnicmp(TruePath, File_Redirector, File_RedirectorLen) == 0) - PrefixLen = File_RedirectorLen; - else if (_wcsnicmp(TruePath, File_DfsClientRedir, File_DfsClientRedirLen) == 0) - PrefixLen = File_DfsClientRedirLen; - else if (_wcsnicmp(TruePath, File_HgfsRedir, File_HgfsRedirLen) == 0) - PrefixLen = File_HgfsRedirLen; - else if (_wcsnicmp(TruePath, File_MupRedir, File_MupRedirLen) == 0) - PrefixLen = File_MupRedirLen; - else - PrefixLen = 0; - - if (PrefixLen && TruePath[PrefixLen] == L';') { - - WCHAR *ptr = wcschr(TruePath + PrefixLen, L'\\'); - if (ptr && ptr[0] && ptr[1]) { - - ULONG len1 = wcslen(ptr + 1); - ULONG len2 = (File_MupLen + len1 + 8) * sizeof(WCHAR); - WCHAR *path2 = Dll_Alloc(len2); - wmemcpy(path2, File_Mup, File_MupLen); - wmemcpy(path2 + File_MupLen, ptr + 1, len1 + 1); - - TruePath = (const WCHAR *)path2; - } - } - - // - // look for the TruePath in the list of RecoverFolder settings - // - - ok = FALSE; - - fold = List_Head(&File_RecoverFolders); - while (fold) { - - if (_wcsnicmp(fold->path, TruePath, fold->path_len) == 0) { - ptr = TruePath + fold->path_len; - if (*ptr == L'\\' || *ptr == L'\0') { - ok = TRUE; - break; - } - } - - fold = List_Next(fold); - } - - if (! ok) - goto finish; - - // - // ignore files that begin with ~$ (Microsoft Office temp files) - // or that don't have a file type extension (probably temp files) - // - - if (File_MsoDllLoaded) { - - ptr = wcsrchr(TruePath, L'\\'); - if (ptr) { - if (ptr[1] == L'~' && ptr[2] == L'$') - ok = FALSE; - else { - ptr = wcschr(ptr, L'.'); - if (! ptr) - ok = FALSE; - } - if (! ok) - goto finish; - } - } - - // - // look for TruePath in the list of AutoRecoverIgnore settings - // - - TruePath_len = wcslen(TruePath); - - fold = List_Head(&File_RecoverIgnores); - while (fold) { - - if (_wcsnicmp(fold->path, TruePath, fold->path_len) == 0) { - ptr = TruePath + fold->path_len; - if (*ptr == L'\\' || *ptr == L'\0') { - ok = FALSE; - break; - } - } - - if (TruePath_len >= fold->path_len) { - ptr = TruePath + TruePath_len - fold->path_len; - if (_wcsicmp(fold->path, ptr) == 0) { - ok = FALSE; - break; - } - } - - fold = List_Next(fold); - } - - // - // finish - // - -finish: - - if (TruePath != save_TruePath) - Dll_Free((WCHAR *)TruePath); - return ok; -} - - -//--------------------------------------------------------------------------- -// File_RecordRecover -//--------------------------------------------------------------------------- - - -_FX BOOLEAN File_RecordRecover(HANDLE FileHandle, const WCHAR *TruePath) -{ - BOOLEAN IsRecoverable; - - IsRecoverable = File_IsRecoverable(TruePath); - - // - // in a Chrome sandbox process, handles are opened by the broker, - // so skip checking against the list of recorded file handles - // - - // Note: this does not seam to be required anymore - - //if ((! IsRecoverable) && Dll_ChromeSandbox) { - // - // FILE_ACCESS_INFORMATION info; - // - // status = __sys_NtQueryInformationFile( - // FileHandle, &IoStatusBlock, &info, - // sizeof(FILE_ACCESS_INFORMATION), FileAccessInformation); - // - // if (NT_SUCCESS(status) && (info.AccessFlags & FILE_WRITE_DATA)) - // IsRecoverable = 2; //TRUE; // we still want to return false when called from File_NtCreateFileImpl - // else - // IsRecoverable = FALSE; - //} - - if (IsRecoverable != FALSE) - File_RegisterCloseHandler(FileHandle, File_NotifyRecover); - - return IsRecoverable == TRUE; -} - - -//--------------------------------------------------------------------------- -// File_DuplicateRecover -//--------------------------------------------------------------------------- - - -_FX void File_DuplicateRecover( - HANDLE OldFileHandle, HANDLE NewFileHandle) -{ - ULONG i; - BOOLEAN dup; - - // - // called from NtDuplicateObject to duplicate the "recoverability" - // of the old handle to the new handle. needed in particular for - // SHFileOperation to recover correctly on Windows Vista - // - - dup = FALSE; - - EnterCriticalSection(&File_HandleOnClose_CritSec); - - FILE_ON_CLOSE* on_close = map_get(&File_HandleOnClose, OldFileHandle); - if (on_close) { - for (i = 0; i < MAX_CLOSE_HANDLERS; i++) { - if(on_close->CloseHandlers[i] == File_NotifyRecover) - dup = TRUE; - } - } - - LeaveCriticalSection(&File_HandleOnClose_CritSec); - - if (dup && NewFileHandle) - File_RegisterCloseHandler(NewFileHandle, File_NotifyRecover); -} - - -//--------------------------------------------------------------------------- -// File_NotifyRecover -//--------------------------------------------------------------------------- - - -_FX void File_NotifyRecover(HANDLE FileHandle) -{ - THREAD_DATA *TlsData = Dll_GetTlsData(NULL); - - NTSTATUS status; - union { - FILE_NETWORK_OPEN_INFORMATION open; - ULONG space[16]; - } info; - ULONG length; - ULONG FileFlags; - UNICODE_STRING uni; - WCHAR *TruePath, *CopyPath; - IO_STATUS_BLOCK IoStatusBlock; - - // - // send request to SbieCtrl (if recoverable file) - // - - Dll_PushTlsNameBuffer(TlsData); - - do { - - RtlInitUnicodeString(&uni, L""); - status = File_GetName( - FileHandle, &uni, &TruePath, &CopyPath, &FileFlags); - if (! NT_SUCCESS(status)) - break; - - if (! (FileFlags & FGN_IS_BOXED_PATH)) - break; - - // - // Immediate Recovery - // - - if (!File_IsRecoverable(TruePath)) - break; - - status = __sys_NtQueryInformationFile( - FileHandle, &IoStatusBlock, &info, - sizeof(FILE_NETWORK_OPEN_INFORMATION), - FileNetworkOpenInformation); - - if (! NT_SUCCESS(status)) - break; - if (info.open.EndOfFile.QuadPart == 0) - break; - - // - // queue immediate recovery elements for later processing - // - - FILE_RECOVER_FOLDER *rec; - ULONG TruePath_len; - - EnterCriticalSection(&File_RecHandles_CritSec); - - TruePath_len = wcslen(TruePath); - - rec = List_Head(&File_RecPaths); - while (rec) { - if (rec->path_len == TruePath_len) - if (_wcsicmp(rec->path, TruePath) == 0) - break; - rec = List_Next(rec); - } - - if (! rec) { - - length = sizeof(FILE_RECOVER_FOLDER) - + (TruePath_len + 1) * sizeof(WCHAR); - rec = Dll_Alloc(length); - - rec->ticks = GetTickCount(); - - wcscpy(rec->path, TruePath); - rec->path_len = TruePath_len; - - List_Insert_After(&File_RecPaths, NULL, rec); - } - - LeaveCriticalSection(&File_RecHandles_CritSec); - if (rec) - File_DoAutoRecover(TRUE); - - } while (0); - - Dll_PopTlsNameBuffer(TlsData); -} - - //--------------------------------------------------------------------------- // File_RtlGetCurrentDirectory_U //--------------------------------------------------------------------------- @@ -3633,9 +3188,11 @@ _FX NTSTATUS File_SetReparsePoint( __leave; } - //if (File_Snapshot != NULL) - // File_FindSnapshotPath(&CopyPath); - + //if (File_Snapshot != NULL){ + // WCHAR* TmplName = File_FindSnapshotPath(CopyPath); + // if (TmplName) CopyPath = TmplName; + //} + //SourcePath = Dll_Alloc((wcslen(CopyPath) + 4) * sizeof(WCHAR)); //wcscpy(SourcePath, CopyPath); @@ -3764,265 +3321,6 @@ _FX NTSTATUS File_SetReparsePoint( } -//--------------------------------------------------------------------------- -// File_DoAutoRecover -//--------------------------------------------------------------------------- - - -_FX void File_DoAutoRecover(BOOLEAN force) -{ - static ULONG last_ticks = 0; - - ULONG LastError; - THREAD_DATA *TlsData = Dll_GetTlsData(&LastError); - - ULONG ticks = GetTickCount(); - if (force || (ticks - last_ticks > 400)) { - - last_ticks = ticks; - - if (TryEnterCriticalSection(&File_RecHandles_CritSec)) { - - if (List_Head(&File_RecPaths)) { - - Dll_PushTlsNameBuffer(TlsData); - - File_DoAutoRecover_2(force, ticks); - - Dll_PopTlsNameBuffer(TlsData); - } - - LeaveCriticalSection(&File_RecHandles_CritSec); - } - } - - SetLastError(LastError); -} - - -//--------------------------------------------------------------------------- -// File_DoAutoRecover_2 -//--------------------------------------------------------------------------- - - -_FX void File_DoAutoRecover_2(BOOLEAN force, ULONG ticks) -{ - NTSTATUS status; - SYSTEM_HANDLE_INFORMATION *info = NULL; - FILE_GET_ALL_HANDLES_RPL *rpl = NULL; - ULONG info_len = 64, len, i; - WCHAR *pathbuf; - ULONG UseCount = 0; - FILE_RECOVER_FOLDER *rec; - UCHAR FileObjectTypeNumber = 0; - - // - // get list of open handles in the system - // - - for (i = 0; i < 5; ++i) { - - info = Dll_AllocTemp(info_len); - - status = NtQuerySystemInformation( - SystemHandleInformation, info, info_len, &len); - - if (NT_SUCCESS(status)) - break; - - Dll_Free(info); - info_len = len + 64; - - if (status == STATUS_BUFFER_OVERFLOW || - status == STATUS_INFO_LENGTH_MISMATCH || - status == STATUS_BUFFER_TOO_SMALL) { - - continue; - } - - break; - } - - if ((Dll_ProcessFlags & SBIE_FLAG_APP_COMPARTMENT) == 0) // don't try that in app mode, we had a proepr token - if (status == STATUS_ACCESS_DENIED) { - - // - // on Windows 8.1, NtQuerySystemInformation fails, probably because - // we are running without any privileges, so go through SbieSvc - // - - MSG_HEADER req; - req.length = sizeof(req); - req.msgid = MSGID_FILE_GET_ALL_HANDLES; - rpl = (FILE_GET_ALL_HANDLES_RPL *)SbieDll_CallServer(&req); - - if (rpl) { - info = NULL; - status = STATUS_SUCCESS; - } - } - - if (! NT_SUCCESS(status)) - return; - - pathbuf = Dll_AllocTemp(1024); - - // - // scan list of queued recovery files - // - - rec = List_Head(&File_RecPaths); - while (rec) { - - FILE_RECOVER_FOLDER *rec_next = List_Next(rec); - BOOLEAN send2199 = FALSE; - - if (force) - send2199 = TRUE; - else { - if (ticks - rec->ticks >= 1000) { - ULONG UseCount = File_DoAutoRecover_3( - rec->path, pathbuf, info, rpl, &FileObjectTypeNumber); - if (UseCount == 0) - send2199 = TRUE; - } - } - - if (send2199) { - WCHAR *colon = wcschr(rec->path, L':'); - if (!colon) { - - UNICODE_STRING uni; - WCHAR *TruePath, *CopyPath; - RtlInitUnicodeString(&uni, rec->path); - status = File_GetName(NULL, &uni, &TruePath, &CopyPath, NULL); - - const WCHAR* strings[] = { Dll_BoxName, rec->path, CopyPath, NULL }; - SbieApi_LogMsgExt(2199, strings); - } - List_Remove(&File_RecPaths, rec); - } - - rec = rec_next; - } - - // - // finish - // - - Dll_Free(pathbuf); - if (info) - Dll_Free(info); - if (rpl) - Dll_Free(rpl); -} - - -//--------------------------------------------------------------------------- -// File_DoAutoRecover_3 -//--------------------------------------------------------------------------- - - -_FX ULONG File_DoAutoRecover_3( - const WCHAR *PathToFind, WCHAR *PathBuf1024, - SYSTEM_HANDLE_INFORMATION *info, FILE_GET_ALL_HANDLES_RPL *rpl, - UCHAR *FileObjectTypeNumber) -{ - HANDLE FileHandle; - ULONG UseCount, i; - - // - // scan handles for current process - // - - UseCount = 0; - - if (info) { - - for (i = 0; i < info->Count; ++i) { - - HANDLE_INFO *hi = &info->HandleInfo[i]; - - if (hi->ProcessId != Dll_ProcessId) - continue; - - FileHandle = (HANDLE)(ULONG_PTR)hi->Handle; - - UseCount += File_DoAutoRecover_4( - PathToFind, PathBuf1024, - FileHandle, hi->ObjectTypeNumber, FileObjectTypeNumber); - } - - } else if (rpl) { - - for (i = 0; i < rpl->num_handles; ++i) { - - UCHAR objtype = (UCHAR)(rpl->handles[i] >> 24); - - FileHandle = (HANDLE)(ULONG_PTR)(rpl->handles[i] & 0x00FFFFFFU); - - UseCount += File_DoAutoRecover_4( - PathToFind, PathBuf1024, - FileHandle, objtype, FileObjectTypeNumber); - } - } - - return UseCount; -} - - -//--------------------------------------------------------------------------- -// File_DoAutoRecover_4 -//--------------------------------------------------------------------------- - - -_FX ULONG File_DoAutoRecover_4( - const WCHAR *PathToFind, WCHAR *PathBuf1024, - HANDLE FileHandle, UCHAR ObjectTypeNumber, UCHAR *FileObjectTypeNumber) -{ - UNICODE_STRING uni; - WCHAR *TruePath, *CopyPath; - NTSTATUS status; - - // - // make sure the handle is to a file - // - - if (*FileObjectTypeNumber) { - - if (ObjectTypeNumber != *FileObjectTypeNumber) - return 0; - - } else { - - if (Obj_GetObjectType(FileHandle) == OBJ_TYPE_FILE) { - - *FileObjectTypeNumber = ObjectTypeNumber; - - } else - return 0; - } - - // - // get file name - // - - status = File_GetFileName(FileHandle, 1000, PathBuf1024); - if (! NT_SUCCESS(status)) - return 0; - - RtlInitUnicodeString(&uni, PathBuf1024); - status = File_GetName(NULL, &uni, &TruePath, &CopyPath, NULL); - if (! NT_SUCCESS(status)) - return 0; - - if (_wcsicmp(PathToFind, TruePath) == 0) - return 1; - - return 0; -} - - //--------------------------------------------------------------------------- // File_MyQueryDirectoryFile //--------------------------------------------------------------------------- @@ -4049,134 +3347,6 @@ _FX NTSTATUS File_MyQueryDirectoryFile( } -//--------------------------------------------------------------------------- -// File_MsoDll -//--------------------------------------------------------------------------- - - -_FX BOOLEAN File_MsoDll(HMODULE module) -{ - // - // hack for File_IsRecoverable - // - - File_MsoDllLoaded = TRUE; - return TRUE; -} - - -//--------------------------------------------------------------------------- -// File_Scramble_Char -//--------------------------------------------------------------------------- - - -_FX WCHAR File_Scramble_Char(WCHAR wValue, int Key, BOOLEAN scram) -{ - // - // This function allows to scramble file name charakters properly, - // i.e. no invalid cahacters can result fron this operation. - // It does not scramble invalid charakters like: " * / : < > ? \ | - // And it does not scramble ~ - // The entropy of the scrambler is 25,5bit (i.e. 52 million values) - // - - char reserved_ch[] = { '\"', '*', '/', ':', '<', '>', '?', '\\', '|' }; - const int reserved_count = 9; - const int max_ch = 0x7E - reserved_count - 0x20; - - int uValue = (wValue & 0x7F); - if (uValue < 0x20 || uValue >= 0x7E) // < space || >= ~ - return wValue; - for (int i = 0; i < reserved_count; i++) - if (uValue == reserved_ch[i]) return wValue; - - Key &= 0x7f; - while (Key >= max_ch) - Key -= max_ch; - if (!scram) - Key = -Key; - - for (int i = 1; i <= reserved_count; i++) - if (uValue > reserved_ch[reserved_count - i]) uValue -= 1; - uValue -= 0x20; - - uValue += Key; - - if (uValue >= max_ch) - uValue -= max_ch; - else if (uValue < 0) - uValue += max_ch; - - uValue += 0x20; - for (int i = 0; i < reserved_count; i++) - if (uValue >= reserved_ch[i]) uValue += 1; - - return uValue; -} - - -//--------------------------------------------------------------------------- -// File_ScrambleShortName -//--------------------------------------------------------------------------- - - -_FX void File_ScrambleShortName(WCHAR* ShortName, CCHAR* ShortNameBytes, ULONG ScramKey) -{ - CCHAR ShortNameLength = *ShortNameBytes / sizeof(WCHAR); - - CCHAR dot_pos; - WCHAR *dot = wcsrchr(ShortName, L'.'); - if (dot == NULL) { - dot_pos = ShortNameLength; - if (ShortNameLength >= 12) - return; // this should never not happen! - ShortName[ShortNameLength++] = L'.'; - } - else - dot_pos = (CCHAR)(dot - ShortName); - - while (ShortNameLength - dot_pos < 4) - { - if (ShortNameLength >= 12) - return; // this should never not happen! - ShortName[ShortNameLength++] = L' '; - } - - *ShortNameBytes = ShortNameLength * sizeof(WCHAR); - - if (dot_pos > 0) - ShortName[dot_pos - 1] = File_Scramble_Char(ShortName[dot_pos - 1], ((char*)&ScramKey)[0], TRUE); - for (int i = 1; i <= 3; i++) - ShortName[dot_pos + i] = File_Scramble_Char(ShortName[dot_pos + i], ((char*)&ScramKey)[i], TRUE); -} - - -//--------------------------------------------------------------------------- -// File_UnScrambleShortName -//--------------------------------------------------------------------------- - - -_FX void File_UnScrambleShortName(WCHAR* ShortName, ULONG ScramKey) -{ - CCHAR ShortNameLength = (CCHAR)wcslen(ShortName); - - WCHAR *dot = wcsrchr(ShortName, L'.'); - if (dot == NULL) - return; // not a scrambled short name. - CCHAR dot_pos = (CCHAR)(dot - ShortName); - - if (dot_pos > 0) - ShortName[dot_pos - 1] = File_Scramble_Char(ShortName[dot_pos - 1], ((char*)&ScramKey)[0], FALSE); - for (int i = 1; i <= 3; i++) - ShortName[dot_pos + i] = File_Scramble_Char(ShortName[dot_pos + i], ((char*)&ScramKey)[i], FALSE); - - while (ShortName[ShortNameLength - 1] == L' ') - ShortName[ShortNameLength-- - 1] = 0; - if (ShortName[ShortNameLength - 1] == L'.') - ShortName[ShortNameLength-- - 1] = 0; -} - - //--------------------------------------------------------------------------- // Key_CreateBaseFolders //--------------------------------------------------------------------------- diff --git a/Sandboxie/core/dll/file_init.c b/Sandboxie/core/dll/file_init.c index 71462449..584ab5ce 100644 --- a/Sandboxie/core/dll/file_init.c +++ b/Sandboxie/core/dll/file_init.c @@ -106,8 +106,6 @@ static WCHAR *File_AllocAndInitEnvironment_2( static void File_AdjustDrives( ULONG path_drive_index, BOOLEAN subst, const WCHAR *path); -static void File_InitSnapshots(void); - //--------------------------------------------------------------------------- // Variables @@ -122,20 +120,6 @@ static const WCHAR *File_DeviceMap_EnvVar = ENV_VAR_PFX L"DEVICE_MAP"; #undef ENV_VAR_PFX -//--------------------------------------------------------------------------- -// File_InitHandles -//--------------------------------------------------------------------------- - - -_FX BOOLEAN File_InitHandles(void) -{ - InitializeCriticalSection(&File_HandleOnClose_CritSec); - map_init(&File_HandleOnClose, Dll_Pool); - - return TRUE; -} - - //--------------------------------------------------------------------------- // File_Init //--------------------------------------------------------------------------- @@ -158,6 +142,10 @@ _FX BOOLEAN File_Init(void) File_DriveAddSN = SbieApi_QueryConfBool(NULL, L"UseVolumeSerialNumbers", FALSE); + File_Delete_v2 = SbieApi_QueryConfBool(NULL, L"UseFileDeleteV2", FALSE); + + File_NoReparse = SbieApi_QueryConfBool(NULL, L"NoPathReparse", FALSE); + if (! File_InitDrives(0xFFFFFFFF)) return FALSE; @@ -166,6 +154,16 @@ _FX BOOLEAN File_Init(void) return FALSE; } + if (Dll_OsBuild >= 6000) { // needed for File_GetFileName used indirectly by File_InitRecoverFolders + + void *GetFinalPathNameByHandleW = + GetProcAddress(Dll_KernelBase ? Dll_KernelBase : Dll_Kernel32, + "GetFinalPathNameByHandleW"); + if (GetFinalPathNameByHandleW) { + SBIEDLL_HOOK(File_,GetFinalPathNameByHandleW); + } + } + File_InitSnapshots(); File_InitRecoverFolders(); @@ -230,16 +228,6 @@ _FX BOOLEAN File_Init(void) } } - if (Dll_OsBuild >= 6000) { - - void *GetFinalPathNameByHandleW = - GetProcAddress(Dll_KernelBase ? Dll_KernelBase : Dll_Kernel32, - "GetFinalPathNameByHandleW"); - if (GetFinalPathNameByHandleW) { - SBIEDLL_HOOK(File_,GetFinalPathNameByHandleW); - } - } - if (Dll_OsBuild >= 8400 && Dll_IsSystemSid) { // see File_GetTempPathW in file file_misc.c GetTempPathW = GetProcAddress(Dll_KernelBase, "GetTempPathW"); @@ -248,6 +236,16 @@ _FX BOOLEAN File_Init(void) } } + + if (File_Delete_v2) + File_InitDelete_v2(); + + // Note: loading the file tha way its done now only works once file hooks are installed so this must eb here + extern BOOLEAN Key_Delete_v2; + extern BOOLEAN Key_InitDelete_v2(); + if (Key_Delete_v2) + Key_InitDelete_v2(); + // // support for Google Chrome flash plugin process // @@ -517,6 +515,7 @@ _FX BOOLEAN File_InitDrives(ULONG DriveMask) status = NtOpenSymbolicLinkObject( &handle, SYMBOLIC_LINK_QUERY, &objattrs); + if (!Dll_CompartmentMode) // NoDriverAssist if (status == STATUS_ACCESS_DENIED) { // @@ -1747,6 +1746,7 @@ _FX void File_GetSetDeviceMap(WCHAR *DeviceMap96) status = NtOpenDirectoryObject(&handle, DIRECTORY_QUERY, &objattrs); + if (!Dll_CompartmentMode) // NoDriverAssist if (status == STATUS_ACCESS_DENIED) { // @@ -1787,58 +1787,4 @@ _FX void File_GetSetDeviceMap(WCHAR *DeviceMap96) } } } -} - - -//--------------------------------------------------------------------------- -// File_InitSnapshots -//--------------------------------------------------------------------------- - -// CRC -#define CRC_WITH_ADLERTZUK64 -#include "common/crc.c" - -_FX void File_InitSnapshots(void) -{ - WCHAR ShapshotsIni[MAX_PATH] = { 0 }; - wcscpy(ShapshotsIni, Dll_BoxFilePath); - wcscat(ShapshotsIni, L"\\Snapshots.ini"); - SbieDll_TranslateNtToDosPath(ShapshotsIni); - - WCHAR Shapshot[16] = { 0 }; - GetPrivateProfileStringW(L"Current", L"Snapshot", L"", Shapshot, 16, ShapshotsIni); - - if (*Shapshot == 0) - return; // not using snapshots - - File_Snapshot = Dll_Alloc(sizeof(FILE_SNAPSHOT)); - memzero(File_Snapshot, sizeof(FILE_SNAPSHOT)); - wcscpy(File_Snapshot->ID, Shapshot); - File_Snapshot->IDlen = wcslen(Shapshot); - FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot; - File_Snapshot_Count = 1; - - for (;;) - { - Cur_Snapshot->ScramKey = CRC32(Cur_Snapshot->ID, Cur_Snapshot->IDlen * sizeof(WCHAR)); - - WCHAR ShapshotId[26] = L"Snapshot_"; - wcscat(ShapshotId, Shapshot); - - //WCHAR ShapshotName[34] = { 0 }; - //GetPrivateProfileStringW(ShapshotId, L"Name", L"", ShapshotName, 34, ShapshotsIni); - //wcscpy(Cur_Snapshot->Name, ShapshotName); - - GetPrivateProfileStringW(ShapshotId, L"Parent", L"", Shapshot, 16, ShapshotsIni); - - if (*Shapshot == 0) - break; // no more snapshots - - Cur_Snapshot->Parent = Dll_Alloc(sizeof(FILE_SNAPSHOT)); - memzero(Cur_Snapshot->Parent, sizeof(FILE_SNAPSHOT)); - wcscpy(Cur_Snapshot->Parent->ID, Shapshot); - Cur_Snapshot->Parent->IDlen = wcslen(Shapshot); - Cur_Snapshot = Cur_Snapshot->Parent; - File_Snapshot_Count++; - } -} +} \ No newline at end of file diff --git a/Sandboxie/core/dll/file_link.c b/Sandboxie/core/dll/file_link.c index 406f6c06..3e2b33ad 100644 --- a/Sandboxie/core/dll/file_link.c +++ b/Sandboxie/core/dll/file_link.c @@ -1,5 +1,6 @@ /* * Copyright 2004-2020 Sandboxie Holdings, LLC + * Copyright 2020-2022 David Xanatos, xanasoft.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -470,6 +471,9 @@ _FX WCHAR *File_TranslateTempLinks( WCHAR *ret; ULONG TruePath_len, ret_len; + if (File_NoReparse) + return NULL; + // // entry // @@ -794,12 +798,13 @@ _FX WCHAR *File_TranslateTempLinks_2(WCHAR *input_str, ULONG input_len) _FX NTSTATUS File_GetFileName(HANDLE FileHandle, ULONG NameLen, WCHAR* NameBuf) { - //extern P_GetFinalPathNameByHandle __sys_GetFinalPathNameByHandleW; - //if (__sys_GetFinalPathNameByHandleW(FileHandle, NameBuf, NameLen, VOLUME_NAME_NT) > 0) - // return STATUS_SUCCESS; - //return STATUS_UNSUCCESSFUL; + if (!Dll_CompartmentMode || !__sys_GetFinalPathNameByHandleW) // NoDriverAssist + return SbieApi_GetFileName(FileHandle, NameLen, NameBuf); - return SbieApi_GetFileName(FileHandle, NameLen, NameBuf); + // available in vista and later + if (__sys_GetFinalPathNameByHandleW(FileHandle, NameBuf, NameLen, VOLUME_NAME_NT) > 0) + return STATUS_SUCCESS; + return STATUS_UNSUCCESSFUL; } diff --git a/Sandboxie/core/dll/file_misc.c b/Sandboxie/core/dll/file_misc.c index c83f61e6..a960432d 100644 --- a/Sandboxie/core/dll/file_misc.c +++ b/Sandboxie/core/dll/file_misc.c @@ -1,6 +1,6 @@ /* * Copyright 2004-2020 Sandboxie Holdings, LLC - * Copyright 2020 David Xanatos, xanasoft.com + * Copyright 2020-2022 David Xanatos, xanasoft.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -329,8 +329,10 @@ _FX void File_ReplaceFileW_3( (*FileFlags) &= FGN_IS_BOXED_PATH; if (*FileFlags) { - if (File_Snapshot != NULL) - File_FindSnapshotPath(&CopyPath); + if (File_Snapshot != NULL) { + WCHAR* TmplName = File_FindSnapshotPath(CopyPath); + if (TmplName) CopyPath = TmplName; + } len = (wcslen(CopyPath) + 1) * sizeof(WCHAR); path = Dll_AllocTemp(len); diff --git a/Sandboxie/core/dll/file_pipe.c b/Sandboxie/core/dll/file_pipe.c index 3e8edad2..6d1268bc 100644 --- a/Sandboxie/core/dll/file_pipe.c +++ b/Sandboxie/core/dll/file_pipe.c @@ -1164,7 +1164,7 @@ _FX NTSTATUS File_NtFsControlFile( InputBuffer, InputBufferLength); SetLastError(LastError); - } else if (IoControlCode == FSCTL_PIPE_IMPERSONATE) { + } else if (IoControlCode == FSCTL_PIPE_IMPERSONATE && !Dll_CompartmentMode) { SbieApi_Log(2205, L"ImpersonateNamedPipe"); if (Proc_ImpersonateSelf(TRUE)) diff --git a/Sandboxie/core/dll/file_recovery.c b/Sandboxie/core/dll/file_recovery.c new file mode 100644 index 00000000..be97b1ea --- /dev/null +++ b/Sandboxie/core/dll/file_recovery.c @@ -0,0 +1,726 @@ +/* + * Copyright 2004-2020 Sandboxie Holdings, LLC + * Copyright 2020-2022 David Xanatos, xanasoft.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//--------------------------------------------------------------------------- +// +// Immediate Recovery for Files +// +//--------------------------------------------------------------------------- + + +//--------------------------------------------------------------------------- +// Functions +//--------------------------------------------------------------------------- + + +static void File_InitRecoverFolders(void); + +static void File_InitRecoverList( + const WCHAR *setting, LIST *list, BOOLEAN MustBeValidPath, + WCHAR *buf, ULONG buf_len); + +static BOOLEAN File_IsRecoverable(const WCHAR *TruePath); + +static void File_DoAutoRecover_2(BOOLEAN force, ULONG ticks); + +static ULONG File_DoAutoRecover_3( + const WCHAR *PathToFind, WCHAR *PathBuf1024, + SYSTEM_HANDLE_INFORMATION *info, FILE_GET_ALL_HANDLES_RPL *rpl, + UCHAR *FileObjectTypeNumber); + +static ULONG File_DoAutoRecover_4( + const WCHAR *PathToFind, WCHAR *PathBuf1024, + HANDLE FileHandle, UCHAR ObjectTypeNumber, UCHAR *FileObjectTypeNumber); + + +//--------------------------------------------------------------------------- +// Variables +//--------------------------------------------------------------------------- + + +static LIST File_RecoverFolders; +static LIST File_RecoverIgnores; + +static LIST File_RecPaths; +static CRITICAL_SECTION File_RecHandles_CritSec; + +static BOOLEAN File_MsoDllLoaded = FALSE; + +//--------------------------------------------------------------------------- +// Structures and Types +//--------------------------------------------------------------------------- + + +typedef struct _FILE_RECOVER_FOLDER { + + LIST_ELEM list_elem; + ULONG ticks; // for File_RecPaths + ULONG path_len; + WCHAR path[1]; + +} FILE_RECOVER_FOLDER; + + +//--------------------------------------------------------------------------- +// File_InitRecoverFolders +//--------------------------------------------------------------------------- + + +_FX void File_InitRecoverFolders(void) +{ + // + // init list of recoverable file handles + // + + List_Init(&File_RecoverFolders); + List_Init(&File_RecoverIgnores); + + InitializeCriticalSectionAndSpinCount(&File_RecHandles_CritSec, 1000); + + List_Init(&File_RecPaths); + + // + // init list of recover folders + // + + if (SbieApi_QueryConfBool(NULL, L"AutoRecover", FALSE)) { + + ULONG buf_len = 4096 * sizeof(WCHAR); + WCHAR *buf = Dll_AllocTemp(buf_len); + + File_InitRecoverList( + L"RecoverFolder", &File_RecoverFolders, TRUE, buf, buf_len); + + File_InitRecoverList( + L"AutoRecoverIgnore", &File_RecoverIgnores, FALSE, buf, buf_len); + + Dll_Free(buf); + } +} + + +//--------------------------------------------------------------------------- +// File_InitRecoverList +//--------------------------------------------------------------------------- + + +_FX void File_InitRecoverList( + const WCHAR *setting, LIST *list, BOOLEAN MustBeValidPath, + WCHAR *buf, ULONG buf_len) +{ + UNICODE_STRING uni; + WCHAR *TruePath, *CopyPath, *ReparsedPath; + FILE_RECOVER_FOLDER *fold; + + ULONG index = 0; + while (1) { + + NTSTATUS status = SbieApi_QueryConf( + NULL, setting, index, buf, buf_len - 16 * sizeof(WCHAR)); + if (! NT_SUCCESS(status)) + break; + ++index; + + RtlInitUnicodeString(&uni, buf); + status = File_GetName(NULL, &uni, &TruePath, &CopyPath, NULL); + + ReparsedPath = NULL; + + if (NT_SUCCESS(status) && MustBeValidPath) { + + ReparsedPath = File_TranslateTempLinks(TruePath, FALSE); + if (ReparsedPath) + TruePath = ReparsedPath; + + } else if ((! NT_SUCCESS(status)) && (! MustBeValidPath)) { + + TruePath = buf; + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) { + + ULONG len = wcslen(TruePath); + if (len && TruePath[len - 1] == L'\\') { + TruePath[len - 1] = L'\0'; + --len; + } + len = sizeof(FILE_RECOVER_FOLDER) + + (len + 1) * sizeof(WCHAR); + fold = Dll_Alloc(len); + + fold->ticks = 0; // not used + + wcscpy(fold->path, TruePath); + fold->path_len = wcslen(fold->path); + + List_Insert_After(list, NULL, fold); + } + + if (ReparsedPath) + Dll_Free(ReparsedPath); + } +} + + +//--------------------------------------------------------------------------- +// File_IsRecoverable +//--------------------------------------------------------------------------- + + +_FX BOOLEAN File_IsRecoverable( + const WCHAR *TruePath) +{ + const WCHAR *save_TruePath; + FILE_RECOVER_FOLDER *fold; + const WCHAR *ptr; + ULONG TruePath_len; + ULONG PrefixLen; + BOOLEAN ok; + + // + // if we have a path that looks like + // \Device\LanmanRedirector\;Q:000000000000b09f\server\share\f1.txt + // \Device\Mup\;LanmanRedirector\;Q:000000000000b09f\server\share\f1.txt + // then translate to + // \Device\Mup\server\share\f1.txt + // and test again. We do this because the SbieDrv records paths + // in the \Device\Mup format. See SbieDrv::File_TranslateShares. + // + + save_TruePath = TruePath; + + if (_wcsnicmp(TruePath, File_Redirector, File_RedirectorLen) == 0) + PrefixLen = File_RedirectorLen; + else if (_wcsnicmp(TruePath, File_DfsClientRedir, File_DfsClientRedirLen) == 0) + PrefixLen = File_DfsClientRedirLen; + else if (_wcsnicmp(TruePath, File_HgfsRedir, File_HgfsRedirLen) == 0) + PrefixLen = File_HgfsRedirLen; + else if (_wcsnicmp(TruePath, File_MupRedir, File_MupRedirLen) == 0) + PrefixLen = File_MupRedirLen; + else + PrefixLen = 0; + + if (PrefixLen && TruePath[PrefixLen] == L';') { + + WCHAR *ptr = wcschr(TruePath + PrefixLen, L'\\'); + if (ptr && ptr[0] && ptr[1]) { + + ULONG len1 = wcslen(ptr + 1); + ULONG len2 = (File_MupLen + len1 + 8) * sizeof(WCHAR); + WCHAR *path2 = Dll_Alloc(len2); + wmemcpy(path2, File_Mup, File_MupLen); + wmemcpy(path2 + File_MupLen, ptr + 1, len1 + 1); + + TruePath = (const WCHAR *)path2; + } + } + + // + // look for the TruePath in the list of RecoverFolder settings + // + + ok = FALSE; + + fold = List_Head(&File_RecoverFolders); + while (fold) { + + if (_wcsnicmp(fold->path, TruePath, fold->path_len) == 0) { + ptr = TruePath + fold->path_len; + if (*ptr == L'\\' || *ptr == L'\0') { + ok = TRUE; + break; + } + } + + fold = List_Next(fold); + } + + if (! ok) + goto finish; + + // + // ignore files that begin with ~$ (Microsoft Office temp files) + // or that don't have a file type extension (probably temp files) + // + + if (File_MsoDllLoaded) { + + ptr = wcsrchr(TruePath, L'\\'); + if (ptr) { + if (ptr[1] == L'~' && ptr[2] == L'$') + ok = FALSE; + else { + ptr = wcschr(ptr, L'.'); + if (! ptr) + ok = FALSE; + } + if (! ok) + goto finish; + } + } + + // + // look for TruePath in the list of AutoRecoverIgnore settings + // + + TruePath_len = wcslen(TruePath); + + fold = List_Head(&File_RecoverIgnores); + while (fold) { + + if (_wcsnicmp(fold->path, TruePath, fold->path_len) == 0) { + ptr = TruePath + fold->path_len; + if (*ptr == L'\\' || *ptr == L'\0') { + ok = FALSE; + break; + } + } + + if (TruePath_len >= fold->path_len) { + ptr = TruePath + TruePath_len - fold->path_len; + if (_wcsicmp(fold->path, ptr) == 0) { + ok = FALSE; + break; + } + } + + fold = List_Next(fold); + } + + // + // finish + // + +finish: + + if (TruePath != save_TruePath) + Dll_Free((WCHAR *)TruePath); + return ok; +} + + +//--------------------------------------------------------------------------- +// File_RecordRecover +//--------------------------------------------------------------------------- + + +_FX BOOLEAN File_RecordRecover(HANDLE FileHandle, const WCHAR *TruePath) +{ + BOOLEAN IsRecoverable; + + IsRecoverable = File_IsRecoverable(TruePath); + + // + // in a Chrome sandbox process, handles are opened by the broker, + // so skip checking against the list of recorded file handles + // + + // Note: this does not seam to be required anymore + + //if ((! IsRecoverable) && Dll_ChromeSandbox) { + // + // FILE_ACCESS_INFORMATION info; + // + // status = __sys_NtQueryInformationFile( + // FileHandle, &IoStatusBlock, &info, + // sizeof(FILE_ACCESS_INFORMATION), FileAccessInformation); + // + // if (NT_SUCCESS(status) && (info.AccessFlags & FILE_WRITE_DATA)) + // IsRecoverable = 2; //TRUE; // we still want to return false when called from File_NtCreateFileImpl + // else + // IsRecoverable = FALSE; + //} + + if (IsRecoverable != FALSE) + Handle_RegisterCloseHandler(FileHandle, File_NotifyRecover); + + return IsRecoverable == TRUE; +} + + +//--------------------------------------------------------------------------- +// File_NotifyRecover +//--------------------------------------------------------------------------- + + +_FX void File_NotifyRecover(HANDLE FileHandle) +{ + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + NTSTATUS status; + union { + FILE_NETWORK_OPEN_INFORMATION open; + ULONG space[16]; + } info; + ULONG length; + ULONG FileFlags; + UNICODE_STRING uni; + WCHAR *TruePath, *CopyPath; + IO_STATUS_BLOCK IoStatusBlock; + + // + // send request to SbieCtrl (if recoverable file) + // + + Dll_PushTlsNameBuffer(TlsData); + + do { + + RtlInitUnicodeString(&uni, L""); + status = File_GetName( + FileHandle, &uni, &TruePath, &CopyPath, &FileFlags); + if (! NT_SUCCESS(status)) + break; + + if (! (FileFlags & FGN_IS_BOXED_PATH)) + break; + + // + // Immediate Recovery + // + + if (!File_IsRecoverable(TruePath)) + break; + + status = __sys_NtQueryInformationFile( + FileHandle, &IoStatusBlock, &info, + sizeof(FILE_NETWORK_OPEN_INFORMATION), + FileNetworkOpenInformation); + + if (! NT_SUCCESS(status)) + break; + if (info.open.EndOfFile.QuadPart == 0) + break; + + // + // queue immediate recovery elements for later processing + // + + FILE_RECOVER_FOLDER *rec; + ULONG TruePath_len; + + EnterCriticalSection(&File_RecHandles_CritSec); + + TruePath_len = wcslen(TruePath); + + rec = List_Head(&File_RecPaths); + while (rec) { + if (rec->path_len == TruePath_len) + if (_wcsicmp(rec->path, TruePath) == 0) + break; + rec = List_Next(rec); + } + + if (! rec) { + + length = sizeof(FILE_RECOVER_FOLDER) + + (TruePath_len + 1) * sizeof(WCHAR); + rec = Dll_Alloc(length); + + rec->ticks = GetTickCount(); + + wcscpy(rec->path, TruePath); + rec->path_len = TruePath_len; + + List_Insert_After(&File_RecPaths, NULL, rec); + } + + LeaveCriticalSection(&File_RecHandles_CritSec); + if (rec) + File_DoAutoRecover(TRUE); + + } while (0); + + Dll_PopTlsNameBuffer(TlsData); +} + + +//--------------------------------------------------------------------------- +// File_DoAutoRecover +//--------------------------------------------------------------------------- + + +_FX void File_DoAutoRecover(BOOLEAN force) +{ + static ULONG last_ticks = 0; + + ULONG LastError; + THREAD_DATA *TlsData = Dll_GetTlsData(&LastError); + + ULONG ticks = GetTickCount(); + if (force || (ticks - last_ticks > 400)) { + + last_ticks = ticks; + + if (TryEnterCriticalSection(&File_RecHandles_CritSec)) { + + if (List_Head(&File_RecPaths)) { + + Dll_PushTlsNameBuffer(TlsData); + + File_DoAutoRecover_2(force, ticks); + + Dll_PopTlsNameBuffer(TlsData); + } + + LeaveCriticalSection(&File_RecHandles_CritSec); + } + } + + SetLastError(LastError); +} + + +//--------------------------------------------------------------------------- +// File_DoAutoRecover_2 +//--------------------------------------------------------------------------- + + +_FX void File_DoAutoRecover_2(BOOLEAN force, ULONG ticks) +{ + NTSTATUS status; + SYSTEM_HANDLE_INFORMATION *info = NULL; + FILE_GET_ALL_HANDLES_RPL *rpl = NULL; + ULONG info_len = 64, len, i; + WCHAR *pathbuf; + ULONG UseCount = 0; + FILE_RECOVER_FOLDER *rec; + UCHAR FileObjectTypeNumber = 0; + + // + // get list of open handles in the system + // + + for (i = 0; i < 5; ++i) { + + info = Dll_AllocTemp(info_len); + + status = NtQuerySystemInformation( + SystemHandleInformation, info, info_len, &len); + + if (NT_SUCCESS(status)) + break; + + Dll_Free(info); + info_len = len + 64; + + if (status == STATUS_BUFFER_OVERFLOW || + status == STATUS_INFO_LENGTH_MISMATCH || + status == STATUS_BUFFER_TOO_SMALL) { + + continue; + } + + break; + } + + if (!Dll_CompartmentMode) // NoServiceAssist // don't try that in app mode, we had a proepr token + if (status == STATUS_ACCESS_DENIED) { + + // + // on Windows 8.1, NtQuerySystemInformation fails, probably because + // we are running without any privileges, so go through SbieSvc + // + + MSG_HEADER req; + req.length = sizeof(req); + req.msgid = MSGID_FILE_GET_ALL_HANDLES; + rpl = (FILE_GET_ALL_HANDLES_RPL *)SbieDll_CallServer(&req); + + if (rpl) { + info = NULL; + status = STATUS_SUCCESS; + } + } + + if (! NT_SUCCESS(status)) + return; + + pathbuf = Dll_AllocTemp(1024); + + // + // scan list of queued recovery files + // + + rec = List_Head(&File_RecPaths); + while (rec) { + + FILE_RECOVER_FOLDER *rec_next = List_Next(rec); + BOOLEAN send2199 = FALSE; + + if (force) + send2199 = TRUE; + else { + if (ticks - rec->ticks >= 1000) { + ULONG UseCount = File_DoAutoRecover_3( + rec->path, pathbuf, info, rpl, &FileObjectTypeNumber); + if (UseCount == 0) + send2199 = TRUE; + } + } + + if (send2199) { + WCHAR *colon = wcschr(rec->path, L':'); + if (!colon) { + + UNICODE_STRING uni; + WCHAR *TruePath, *CopyPath; + RtlInitUnicodeString(&uni, rec->path); + status = File_GetName(NULL, &uni, &TruePath, &CopyPath, NULL); + + const WCHAR* strings[] = { Dll_BoxName, rec->path, CopyPath, NULL }; + SbieApi_LogMsgExt(2199, strings); + } + List_Remove(&File_RecPaths, rec); + } + + rec = rec_next; + } + + // + // finish + // + + Dll_Free(pathbuf); + if (info) + Dll_Free(info); + if (rpl) + Dll_Free(rpl); +} + + +//--------------------------------------------------------------------------- +// File_DoAutoRecover_3 +//--------------------------------------------------------------------------- + + +_FX ULONG File_DoAutoRecover_3( + const WCHAR *PathToFind, WCHAR *PathBuf1024, + SYSTEM_HANDLE_INFORMATION *info, FILE_GET_ALL_HANDLES_RPL *rpl, + UCHAR *FileObjectTypeNumber) +{ + HANDLE FileHandle; + ULONG UseCount, i; + + // + // scan handles for current process + // + + UseCount = 0; + + if (info) { + + for (i = 0; i < info->Count; ++i) { + + HANDLE_INFO *hi = &info->HandleInfo[i]; + + if (hi->ProcessId != Dll_ProcessId) + continue; + + FileHandle = (HANDLE)(ULONG_PTR)hi->Handle; + + UseCount += File_DoAutoRecover_4( + PathToFind, PathBuf1024, + FileHandle, hi->ObjectTypeNumber, FileObjectTypeNumber); + } + + } else if (rpl) { + + for (i = 0; i < rpl->num_handles; ++i) { + + UCHAR objtype = (UCHAR)(rpl->handles[i] >> 24); + + FileHandle = (HANDLE)(ULONG_PTR)(rpl->handles[i] & 0x00FFFFFFU); + + UseCount += File_DoAutoRecover_4( + PathToFind, PathBuf1024, + FileHandle, objtype, FileObjectTypeNumber); + } + } + + return UseCount; +} + + +//--------------------------------------------------------------------------- +// File_DoAutoRecover_4 +//--------------------------------------------------------------------------- + + +_FX ULONG File_DoAutoRecover_4( + const WCHAR *PathToFind, WCHAR *PathBuf1024, + HANDLE FileHandle, UCHAR ObjectTypeNumber, UCHAR *FileObjectTypeNumber) +{ + UNICODE_STRING uni; + WCHAR *TruePath, *CopyPath; + NTSTATUS status; + + // + // make sure the handle is to a file + // + + if (*FileObjectTypeNumber) { + + if (ObjectTypeNumber != *FileObjectTypeNumber) + return 0; + + } else { + + if (Obj_GetObjectType(FileHandle) == OBJ_TYPE_FILE) { + + *FileObjectTypeNumber = ObjectTypeNumber; + + } else + return 0; + } + + // + // get file name + // + + status = File_GetFileName(FileHandle, 1000, PathBuf1024); + if (! NT_SUCCESS(status)) + return 0; + + RtlInitUnicodeString(&uni, PathBuf1024); + status = File_GetName(NULL, &uni, &TruePath, &CopyPath, NULL); + if (! NT_SUCCESS(status)) + return 0; + + if (_wcsicmp(PathToFind, TruePath) == 0) + return 1; + + return 0; +} + + +//--------------------------------------------------------------------------- +// File_MsoDll +//--------------------------------------------------------------------------- + + +_FX BOOLEAN File_MsoDll(HMODULE module) +{ + // + // hack for File_IsRecoverable + // + + File_MsoDllLoaded = TRUE; + return TRUE; +} \ No newline at end of file diff --git a/Sandboxie/core/dll/file_snapshots.c b/Sandboxie/core/dll/file_snapshots.c new file mode 100644 index 00000000..237942ff --- /dev/null +++ b/Sandboxie/core/dll/file_snapshots.c @@ -0,0 +1,463 @@ +/* + * Copyright 2020-2022 David Xanatos, xanasoft.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//--------------------------------------------------------------------------- +// File (Snapshot) +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// Defines +//--------------------------------------------------------------------------- + +#define FILE_MAX_SNAPSHOT_ID 17 + +#define FILE_INSNAPSHOT_FLAG 0x0004 + +//--------------------------------------------------------------------------- +// Structures and Types +//--------------------------------------------------------------------------- + + +typedef struct _FILE_SNAPSHOT { + WCHAR ID[FILE_MAX_SNAPSHOT_ID]; + ULONG IDlen; + ULONG ScramKey; + //WCHAR Name[34]; + struct _FILE_SNAPSHOT* Parent; + LIST PathRoot; +} FILE_SNAPSHOT, *PFILE_SNAPSHOT; + + +//--------------------------------------------------------------------------- +// Variables +//--------------------------------------------------------------------------- + + +static const WCHAR* File_Snapshot_Prefix = L"snapshot-"; +static const ULONG File_Snapshot_PrefixLen = 9; // wcslen(File_Snapshot_Prefix); + + +static FILE_SNAPSHOT *File_Snapshot = NULL; +static ULONG File_Snapshot_Count = 0; + + + +//--------------------------------------------------------------------------- +// Functions +//--------------------------------------------------------------------------- + +static void File_ScrambleShortName(WCHAR* ShortName, CCHAR* ShortNameLength, ULONG ScramKey); +static void File_UnScrambleShortName(WCHAR* ShortName, ULONG ScramKey); + +static WCHAR* File_MakeSnapshotPath(FILE_SNAPSHOT* Cur_Snapshot, const WCHAR* CopyPath); +static WCHAR* File_FindSnapshotPath(WCHAR* CopyPath); +static WCHAR* File_ResolveTruePath(WCHAR* TruePath, WCHAR* CopyPath, ULONG* pFlags); +static ULONG File_IsDeletedEx(const WCHAR* TruePath, const WCHAR* CopyPath, FILE_SNAPSHOT* snapshot); + + +static void File_InitSnapshots(void); + +//--------------------------------------------------------------------------- +// File_Scramble_Char +//--------------------------------------------------------------------------- + + +_FX WCHAR File_Scramble_Char(WCHAR wValue, int Key, BOOLEAN scram) +{ + // + // This function allows to scramble file name charakters properly, + // i.e. no invalid cahacters can result fron this operation. + // It does not scramble invalid charakters like: " * / : < > ? \ | + // And it does not scramble ~ + // The entropy of the scrambler is 25,5bit (i.e. 52 million values) + // + + char reserved_ch[] = { '\"', '*', '/', ':', '<', '>', '?', '\\', '|' }; + const int reserved_count = 9; + const int max_ch = 0x7E - reserved_count - 0x20; + + int uValue = (wValue & 0x7F); + if (uValue < 0x20 || uValue >= 0x7E) // < space || >= ~ + return wValue; + for (int i = 0; i < reserved_count; i++) + if (uValue == reserved_ch[i]) return wValue; + + Key &= 0x7f; + while (Key >= max_ch) + Key -= max_ch; + if (!scram) + Key = -Key; + + for (int i = 1; i <= reserved_count; i++) + if (uValue > reserved_ch[reserved_count - i]) uValue -= 1; + uValue -= 0x20; + + uValue += Key; + + if (uValue >= max_ch) + uValue -= max_ch; + else if (uValue < 0) + uValue += max_ch; + + uValue += 0x20; + for (int i = 0; i < reserved_count; i++) + if (uValue >= reserved_ch[i]) uValue += 1; + + return uValue; +} + + +//--------------------------------------------------------------------------- +// File_ScrambleShortName +//--------------------------------------------------------------------------- + + +_FX void File_ScrambleShortName(WCHAR* ShortName, CCHAR* ShortNameBytes, ULONG ScramKey) +{ + CCHAR ShortNameLength = *ShortNameBytes / sizeof(WCHAR); + + CCHAR dot_pos; + WCHAR *dot = wcsrchr(ShortName, L'.'); + if (dot == NULL) { + dot_pos = ShortNameLength; + if (ShortNameLength >= 12) + return; // this should never not happen! + ShortName[ShortNameLength++] = L'.'; + } + else + dot_pos = (CCHAR)(dot - ShortName); + + while (ShortNameLength - dot_pos < 4) + { + if (ShortNameLength >= 12) + return; // this should never not happen! + ShortName[ShortNameLength++] = L' '; + } + + *ShortNameBytes = ShortNameLength * sizeof(WCHAR); + + if (dot_pos > 0) + ShortName[dot_pos - 1] = File_Scramble_Char(ShortName[dot_pos - 1], ((char*)&ScramKey)[0], TRUE); + for (int i = 1; i <= 3; i++) + ShortName[dot_pos + i] = File_Scramble_Char(ShortName[dot_pos + i], ((char*)&ScramKey)[i], TRUE); +} + + +//--------------------------------------------------------------------------- +// File_UnScrambleShortName +//--------------------------------------------------------------------------- + + +_FX void File_UnScrambleShortName(WCHAR* ShortName, ULONG ScramKey) +{ + CCHAR ShortNameLength = (CCHAR)wcslen(ShortName); + + WCHAR *dot = wcsrchr(ShortName, L'.'); + if (dot == NULL) + return; // not a scrambled short name. + CCHAR dot_pos = (CCHAR)(dot - ShortName); + + if (dot_pos > 0) + ShortName[dot_pos - 1] = File_Scramble_Char(ShortName[dot_pos - 1], ((char*)&ScramKey)[0], FALSE); + for (int i = 1; i <= 3; i++) + ShortName[dot_pos + i] = File_Scramble_Char(ShortName[dot_pos + i], ((char*)&ScramKey)[i], FALSE); + + while (ShortName[ShortNameLength - 1] == L' ') + ShortName[ShortNameLength-- - 1] = 0; + if (ShortName[ShortNameLength - 1] == L'.') + ShortName[ShortNameLength-- - 1] = 0; +} + + +//--------------------------------------------------------------------------- +// File_MakeSnapshotPath +//--------------------------------------------------------------------------- + + +_FX WCHAR* File_MakeSnapshotPath(FILE_SNAPSHOT* Cur_Snapshot, const WCHAR* CopyPath) +{ + if (!Cur_Snapshot) + return NULL; + + ULONG prefixLen = File_FindBoxPrefixLength(CopyPath); + if (prefixLen == 0) + return NULL; + + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + WCHAR* TmplName = Dll_GetTlsNameBuffer(TlsData, TMPL_NAME_BUFFER, (wcslen(CopyPath) + File_Snapshot_PrefixLen + FILE_MAX_SNAPSHOT_ID + 1) * sizeof(WCHAR)); + + wcsncpy(TmplName, CopyPath, prefixLen + 1); + wcscpy(TmplName + prefixLen + 1, File_Snapshot_Prefix); + wcscpy(TmplName + prefixLen + 1 + File_Snapshot_PrefixLen, Cur_Snapshot->ID); + wcscpy(TmplName + prefixLen + 1 + File_Snapshot_PrefixLen + Cur_Snapshot->IDlen, CopyPath + prefixLen); + + return TmplName; +} + + +//--------------------------------------------------------------------------- +// File_FindSnapshotPath +//--------------------------------------------------------------------------- + + +_FX WCHAR* File_FindSnapshotPath(WCHAR* CopyPath) +{ + NTSTATUS status; + OBJECT_ATTRIBUTES objattrs; + UNICODE_STRING objname; + ULONG FileType; + + InitializeObjectAttributes(&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); + + // + // When working with snapshots the actual "CopyFile" may be located in a snapshot directory. + // To deal with that when the file is not in the active box directory we look through the snapshots, + // When we find it we update the path to point to the snapshot containing the file. + // + + RtlInitUnicodeString(&objname, CopyPath); + status = File_GetFileType(&objattrs, FALSE, &FileType, NULL); + if (!(status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND)) + return NULL; // file is present directly in copy path + + for (FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot; Cur_Snapshot != NULL; Cur_Snapshot = Cur_Snapshot->Parent) + { + WCHAR* TmplName = File_MakeSnapshotPath(Cur_Snapshot, CopyPath); + if (!TmplName) + break; + + RtlInitUnicodeString(&objname, TmplName); + status = File_GetFileType(&objattrs, FALSE, &FileType, NULL); + if (!(status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND)) + { + return TmplName; + } + } + + return NULL; // this file is not in any snapshot +} + + +//--------------------------------------------------------------------------- +// File_GetPathFlagsEx +//--------------------------------------------------------------------------- + + +_FX ULONG File_GetPathFlagsEx(const WCHAR *TruePath, const WCHAR *CopyPath, WCHAR** pRelocation, FILE_SNAPSHOT* lastSnapshot) +{ + ULONG Flags = 0; + WCHAR* Relocation = NULL; + + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + // + // this function handles the Delete V2 as well as with snapshots + // + + if (File_Delete_v2) { + + // + // check true path relocation and deleteion for the active state + // + + Relocation = NULL; + Flags = File_GetPathFlags(TruePath, &Relocation); + if (FILE_PATH_DELETED(Flags)) + goto finish; + + if (Relocation) { + + if (!File_Snapshot) + goto finish; // take a shortcut + + TruePath = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, wcslen(Relocation)); + wcscpy((WCHAR*)TruePath, Relocation); + } + } + + if (File_Snapshot != NULL) { + + NTSTATUS status; + OBJECT_ATTRIBUTES objattrs; + UNICODE_STRING objname; + ULONG FileType; + + InitializeObjectAttributes(&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); + + for (FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot; Cur_Snapshot != lastSnapshot; Cur_Snapshot = Cur_Snapshot->Parent) + { + if (CopyPath) { + + // + // check if the specified file is present in the current snapshot + // + + WCHAR* TmplName = File_MakeSnapshotPath(Cur_Snapshot, CopyPath); + if (!TmplName) + break; // something went wrong + + RtlInitUnicodeString(&objname, TmplName); + status = File_GetFileType(&objattrs, FALSE, &FileType, NULL); + if (!(status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND)) { + + Flags |= FILE_INSNAPSHOT_FLAG; + Relocation = TmplName; + goto finish; + } + } + + if (File_Delete_v2) { + + // + // check true path relocation and deleteion for the current snapshot + // + + Flags = File_GetPathFlags_internal(&Cur_Snapshot->PathRoot, TruePath, &Relocation, TRUE); + if (FILE_PATH_DELETED(Flags)) + goto finish; + + if (Relocation) { + + if (!Cur_Snapshot->Parent) + break; // take a shortcut + + TruePath = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, (wcslen(Relocation) + 1) * sizeof(WCHAR)); + wcscpy((WCHAR*)TruePath, Relocation); + + if (!CopyPath) + continue; + + // + // update the copy file name + // + + Dll_PushTlsNameBuffer(TlsData); + + WCHAR* TruePath2, *CopyPath2; + RtlInitUnicodeString(&objname, Relocation); + File_GetName(NULL, &objname, &TruePath2, &CopyPath2, NULL); + + Dll_PopTlsNameBuffer(TlsData); + + // note: pop leaves TruePath2 valid we can still use it + + CopyPath = Dll_GetTlsNameBuffer(TlsData, COPY_NAME_BUFFER, (wcslen(CopyPath2) + 1) * sizeof(WCHAR)); + wcscpy((WCHAR*)CopyPath, CopyPath2); + } + } + } + } + +finish: + + if (pRelocation) *pRelocation = Relocation; // can be template buffer or move buffer + return Flags; +} + + +//--------------------------------------------------------------------------- +// File_ResolveTruePath +//--------------------------------------------------------------------------- + + +_FX WCHAR* File_ResolveTruePath(WCHAR *TruePath, WCHAR *CopyPath, ULONG* pFlags) +{ + WCHAR* Relocation = NULL; + ULONG Flags = File_GetPathFlagsEx(TruePath, CopyPath, &Relocation, NULL); + + if (pFlags) *pFlags = Flags; + return Relocation; +} + + +//--------------------------------------------------------------------------- +// File_IsDeletedEx +//--------------------------------------------------------------------------- + + +_FX ULONG File_IsDeletedEx(const WCHAR* TruePath, const WCHAR* CopyPath, FILE_SNAPSHOT* snapshot) +{ + ULONG Flags = File_GetPathFlagsEx(TruePath, CopyPath, NULL, snapshot); + + return (Flags & FILE_DELETED_MASK); +} + + +//--------------------------------------------------------------------------- +// File_InitSnapshots +//--------------------------------------------------------------------------- + +// CRC +#define CRC_WITH_ADLERTZUK64 +#include "common/crc.c" + +_FX void File_InitSnapshots(void) +{ + WCHAR ShapshotsIni[MAX_PATH] = { 0 }; + wcscpy(ShapshotsIni, Dll_BoxFilePath); + wcscat(ShapshotsIni, L"\\Snapshots.ini"); + SbieDll_TranslateNtToDosPath(ShapshotsIni); + + WCHAR Shapshot[FILE_MAX_SNAPSHOT_ID] = { 0 }; + GetPrivateProfileStringW(L"Current", L"Snapshot", L"", Shapshot, FILE_MAX_SNAPSHOT_ID, ShapshotsIni); + + if (*Shapshot == 0) + return; // not using snapshots + + File_Snapshot = Dll_Alloc(sizeof(FILE_SNAPSHOT)); + memzero(File_Snapshot, sizeof(FILE_SNAPSHOT)); + wcscpy(File_Snapshot->ID, Shapshot); + File_Snapshot->IDlen = wcslen(Shapshot); + FILE_SNAPSHOT* Cur_Snapshot = File_Snapshot; + File_Snapshot_Count = 1; + + for (;;) + { + Cur_Snapshot->ScramKey = CRC32(Cur_Snapshot->ID, Cur_Snapshot->IDlen * sizeof(WCHAR)); + + WCHAR ShapshotId[26] = L"Snapshot_"; + wcscat(ShapshotId, Shapshot); + + if (File_Delete_v2) { + + WCHAR PathFile[MAX_PATH]; + wcscpy(PathFile, File_Snapshot_Prefix); + wcscat(PathFile, Cur_Snapshot->ID); + wcscat(PathFile, L"\\"); + wcscat(PathFile, FILE_PATH_FILE_NAME); + + File_LoadPathTree_internal(&Cur_Snapshot->PathRoot, PathFile); + } + + //WCHAR ShapshotName[34] = { 0 }; + //GetPrivateProfileStringW(ShapshotId, L"Name", L"", ShapshotName, 34, ShapshotsIni); + //wcscpy(Cur_Snapshot->Name, ShapshotName); + + GetPrivateProfileStringW(ShapshotId, L"Parent", L"", Shapshot, 16, ShapshotsIni); + + if (*Shapshot == 0) + break; // no more snapshots + + Cur_Snapshot->Parent = Dll_Alloc(sizeof(FILE_SNAPSHOT)); + memzero(Cur_Snapshot->Parent, sizeof(FILE_SNAPSHOT)); + wcscpy(Cur_Snapshot->Parent->ID, Shapshot); + Cur_Snapshot->Parent->IDlen = wcslen(Shapshot); + Cur_Snapshot = Cur_Snapshot->Parent; + File_Snapshot_Count++; + } +} diff --git a/Sandboxie/core/dll/handle.c b/Sandboxie/core/dll/handle.c new file mode 100644 index 00000000..a81d4d16 --- /dev/null +++ b/Sandboxie/core/dll/handle.c @@ -0,0 +1,271 @@ +/* + * Copyright 2021-2022 David Xanatos, xanasoft.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//--------------------------------------------------------------------------- +// Handle +//--------------------------------------------------------------------------- + +#define NOGDI +#include "dll.h" +#include "handle.h" +#include +#include "debug.h" + +#include "common/pool.h" +#include "common/map.h" + + +//--------------------------------------------------------------------------- +// Structures and Types +//--------------------------------------------------------------------------- + +typedef struct _HANDLE_STATE { + + BOOLEAN DeleteOnClose; + P_CloseHandler CloseHandlers[MAX_CLOSE_HANDLERS]; + WCHAR* RelocationPath; + +} HANDLE_STATE; + + +//--------------------------------------------------------------------------- +// Variables +//--------------------------------------------------------------------------- + +extern POOL* Dll_Pool; + +static HASH_MAP Handle_StatusData; +static CRITICAL_SECTION Handle_StatusData_CritSec; + + +//--------------------------------------------------------------------------- +// Functions +//--------------------------------------------------------------------------- + + + +//--------------------------------------------------------------------------- +// Handle_Init +//--------------------------------------------------------------------------- + + +_FX BOOLEAN Handle_Init(void) +{ + InitializeCriticalSection(&Handle_StatusData_CritSec); + map_init(&Handle_StatusData, Dll_Pool); + + return TRUE; +} + + +//--------------------------------------------------------------------------- +// Handle_SetDeleteOnClose +//--------------------------------------------------------------------------- + + +_FX VOID Handle_SetDeleteOnClose(HANDLE FileHandle, BOOLEAN DeleteOnClose) +{ + EnterCriticalSection(&Handle_StatusData_CritSec); + + HANDLE_STATE* state = map_get(&Handle_StatusData, FileHandle); + if (!state) { + state = map_insert(&Handle_StatusData, FileHandle, NULL, sizeof(HANDLE_STATE)); + } + + state->DeleteOnClose = DeleteOnClose; + + LeaveCriticalSection(&Handle_StatusData_CritSec); +} + + +//--------------------------------------------------------------------------- +// Handle_SetRelocationPath +//--------------------------------------------------------------------------- + + +_FX VOID Handle_SetRelocationPath(HANDLE FileHandle, WCHAR* RelocationPath) +{ + EnterCriticalSection(&Handle_StatusData_CritSec); + + HANDLE_STATE* state = map_get(&Handle_StatusData, FileHandle); + if (!state) { // this shoudl always be the case, as we only use Handle_SetRelocationPath when the handle is first created + state = map_insert(&Handle_StatusData, FileHandle, NULL, sizeof(HANDLE_STATE)); + } else if (state->RelocationPath) Dll_Free(state->RelocationPath); // should not happen but in case + + state->RelocationPath = Dll_Alloc((wcslen(RelocationPath) + 1) * sizeof(WCHAR)); + wcscpy(state->RelocationPath, RelocationPath); + + LeaveCriticalSection(&Handle_StatusData_CritSec); +} + + +//--------------------------------------------------------------------------- +// Handle_GetRelocationPath +//--------------------------------------------------------------------------- + + +_FX WCHAR* Handle_GetRelocationPath(HANDLE FileHandle, ULONG ExtraLength) +{ + WCHAR* name = NULL; + + EnterCriticalSection(&Handle_StatusData_CritSec); + + HANDLE_STATE* state = map_get(&Handle_StatusData, FileHandle); + if (state && state->RelocationPath) { + + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + ULONG length = (wcslen(state->RelocationPath) + 1) * sizeof(WCHAR); + name = Dll_GetTlsNameBuffer(TlsData, TRUE_NAME_BUFFER, length + ExtraLength); + wcscpy(name, state->RelocationPath); + } + + LeaveCriticalSection(&Handle_StatusData_CritSec); + + return name; +} + + +//--------------------------------------------------------------------------- +// Handle_FreeCloseHandler +//--------------------------------------------------------------------------- + + +_FX BOOLEAN Handle_FreeCloseHandler(HANDLE FileHandle, P_CloseHandler* CloseHandlers, BOOLEAN* DeleteOnClose) +{ + BOOLEAN HasCloseHandlers = FALSE; + + EnterCriticalSection(&Handle_StatusData_CritSec); + + HANDLE_STATE* state = (HANDLE_STATE*)map_get(&Handle_StatusData, FileHandle); + if (state) { + + HasCloseHandlers = TRUE; + + if(CloseHandlers) + memcpy(CloseHandlers, state->CloseHandlers, MAX_CLOSE_HANDLERS * sizeof(P_CloseHandler)); + if(DeleteOnClose) *DeleteOnClose = state->DeleteOnClose; + + if (state->RelocationPath) Dll_Free(state->RelocationPath); + } + + map_remove(&Handle_StatusData, FileHandle); + + LeaveCriticalSection(&Handle_StatusData_CritSec); + + return HasCloseHandlers; +} + + +//--------------------------------------------------------------------------- +// Handle_RegisterCloseHandler +//--------------------------------------------------------------------------- + + +_FX BOOLEAN Handle_RegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler) +{ + if (!FileHandle || FileHandle == (HANDLE)-1) + return FALSE; + + ULONG i; + + EnterCriticalSection(&Handle_StatusData_CritSec); + + HANDLE_STATE* state = map_get(&Handle_StatusData, FileHandle); + if (!state) { + state = map_insert(&Handle_StatusData, FileHandle, NULL, sizeof(HANDLE_STATE)); + } + + for (i = 0; i < MAX_CLOSE_HANDLERS; i++) { + if (state->CloseHandlers[i] == CloseHandler) + break; // already registered + if (state->CloseHandlers[i] == NULL) { + state->CloseHandlers[i] = CloseHandler; // set to empty slot + break; + } + } + + LeaveCriticalSection(&Handle_StatusData_CritSec); + + if (i == MAX_CLOSE_HANDLERS) { + SbieApi_Log(2301, L"No free CloseHandlers slot available"); + return FALSE; + } + + return TRUE; +} + + +//--------------------------------------------------------------------------- +// Handle_UnRegisterCloseHandler +//--------------------------------------------------------------------------- + + +_FX BOOLEAN Handle_UnRegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler) +{ + ULONG i = MAX_CLOSE_HANDLERS; + + EnterCriticalSection(&Handle_StatusData_CritSec); + + HANDLE_STATE* state = map_get(&Handle_StatusData, FileHandle); + if (state) { + + for (i = 0; i < MAX_CLOSE_HANDLERS; i++) { + if (state->CloseHandlers[i] == CloseHandler) { + state->CloseHandlers[i] = NULL; // clear slot + break; + } + } + } + + LeaveCriticalSection(&Handle_StatusData_CritSec); + + return i != MAX_CLOSE_HANDLERS; +} + + +//--------------------------------------------------------------------------- +// Handle_SetupDuplicate +//--------------------------------------------------------------------------- + + +_FX void Handle_SetupDuplicate(HANDLE OldFileHandle, HANDLE NewFileHandle) +{ + ULONG i; + + EnterCriticalSection(&Handle_StatusData_CritSec); + + HANDLE_STATE* state = map_get(&Handle_StatusData, OldFileHandle); + if (state) { + + if(state->RelocationPath) + Handle_SetRelocationPath(NewFileHandle, state->RelocationPath); + + // todo: add a flag to each CloseHandlers entry to indicate if it should be propagated or not + BOOLEAN found = FALSE; + for (i = 0; i < MAX_CLOSE_HANDLERS; i++) { + if (state->CloseHandlers[i] == File_NotifyRecover) { + found = TRUE; + break; + } + } + if(found) + Handle_RegisterCloseHandler(NewFileHandle, File_NotifyRecover); + } + + LeaveCriticalSection(&Handle_StatusData_CritSec); +} diff --git a/Sandboxie/core/dll/handle.h b/Sandboxie/core/dll/handle.h new file mode 100644 index 00000000..261aafbf --- /dev/null +++ b/Sandboxie/core/dll/handle.h @@ -0,0 +1,53 @@ +/* + * Copyright 2021-2022 David Xanatos, xanasoft.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#ifndef _MY_HANDLE_H +#define _MY_HANDLE_H + + +//--------------------------------------------------------------------------- +// Defines +//--------------------------------------------------------------------------- + +#define MAX_CLOSE_HANDLERS 4 + + +//--------------------------------------------------------------------------- +// Functions +//--------------------------------------------------------------------------- + + +typedef void(*P_CloseHandler)(HANDLE handle); + +VOID Handle_SetDeleteOnClose(HANDLE FileHandle, BOOLEAN DeleteOnClose); + +BOOLEAN Handle_RegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler); + +BOOLEAN Handle_UnRegisterCloseHandler(HANDLE FileHandle, P_CloseHandler CloseHandler); + +VOID Handle_SetRelocationPath(HANDLE FileHandle, WCHAR* RelocationPath); + +WCHAR* Handle_GetRelocationPath(HANDLE FileHandle, ULONG ExtraLength); + +BOOLEAN Handle_FreeCloseHandler(HANDLE FileHandle, P_CloseHandler* CloseHandlers, BOOLEAN* DeleteOnClose); + + +//--------------------------------------------------------------------------- + + +#endif /* _MY_HANDLE_H */ diff --git a/Sandboxie/core/dll/ipc.c b/Sandboxie/core/dll/ipc.c index 42723ac9..7f895e53 100644 --- a/Sandboxie/core/dll/ipc.c +++ b/Sandboxie/core/dll/ipc.c @@ -379,6 +379,7 @@ _FX BOOLEAN Ipc_Init(void) SBIEDLL_HOOK(Ipc_, NtImpersonateThread); } + //if (!Dll_AlernateIpcNaming) // alternate naming does not need an own namespace Ipc_CreateObjects(); List_Init(&Ipc_DynamicPortNames); @@ -525,6 +526,21 @@ _FX NTSTATUS Ipc_GetName( if (ObjectName) { objname_len = ObjectName->Length & ~1; objname_buf = ObjectName->Buffer; + + //if (Dll_AlernateIpcNaming) { + // + // // + // // Since in this mode we don't call Ipc_CreateObjects we dont have a boxed namespace + // // and are using existing namespaces only with a name suffix + // // hence we can't use Global without system provileges, so we strip it + // // + // + // if (_wcsnicmp(objname_buf, L"Global\\", 7) == 0) { + // objname_len -= 7; + // objname_buf += 7; + // } + //} + } else { objname_len = 0; objname_buf = NULL; @@ -665,6 +681,21 @@ _FX NTSTATUS Ipc_GetName( check_sandbox_prefix: + //if (Dll_AlernateIpcNaming) + //{ + // if (length >= Dll_BoxIpcPathLen && + // 0 == Dll_NlsStrCmp( + // &(*OutTruePath)[length - Dll_BoxIpcPathLen], Dll_BoxIpcPath, Dll_BoxIpcPathLen)) + // { + // (*OutTruePath)[length - Dll_BoxIpcPathLen] = L'\0'; + // length -= Dll_BoxIpcPathLen; + // if (OutIsBoxedPath) + // *OutIsBoxedPath = TRUE; + // + // goto check_sandbox_prefix; + // } + //} + //else if (length >= Dll_BoxIpcPathLen && 0 == Dll_NlsStrCmp( *OutTruePath, Dll_BoxIpcPath, Dll_BoxIpcPathLen)) @@ -688,11 +719,23 @@ check_sandbox_prefix: *OutCopyPath = name; - wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen); - name += Dll_BoxIpcPathLen; + //if (Dll_AlernateIpcNaming) + //{ + // wmemcpy(name, *OutTruePath, length); + // name += length; + // + // wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen); + // name += Dll_BoxIpcPathLen; + //} + //else + { + wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen); + name += Dll_BoxIpcPathLen; + + wmemcpy(name, *OutTruePath, length); + name += length; + } - wmemcpy(name, *OutTruePath, length); - name += length; *name = L'\0'; // @@ -883,6 +926,9 @@ _FX NTSTATUS Ipc_CreatePath(WCHAR *TruePath, WCHAR *CopyPath) UNICODE_STRING objname; WCHAR *backslash; + //if (Dll_AlernateIpcNaming) + // return STATUS_OBJECT_PATH_NOT_FOUND; + // // open the TruePath object directory containing the object // for which we got STATUS_OBJECT_PATH_NOT_FOUND @@ -3730,6 +3776,20 @@ _FX ULONG Ipc_NtQueryObjectName(UNICODE_STRING *ObjectName, ULONG MaxLen) ULONG Len = ObjectName->Length; WCHAR *Buf = ObjectName->Buffer; + //if (Dll_AlernateIpcNaming) + //{ + // if (Len >= Dll_BoxIpcPathLen * sizeof(WCHAR) && + // 0 == Dll_NlsStrCmp(&Buf[Len - Dll_BoxIpcPathLen], Dll_BoxIpcPath, Dll_BoxIpcPathLen)) { + // + // Buf[Len - Dll_BoxIpcPathLen] = L'\0'; + // + // ObjectName->Length -= (USHORT)Dll_BoxIpcPathLen; + // ObjectName->MaximumLength = ObjectName->Length + sizeof(WCHAR); + // + // return ObjectName->MaximumLength; + // } + //} + //else if (Len >= Dll_BoxIpcPathLen * sizeof(WCHAR) && 0 == Dll_NlsStrCmp(Buf, Dll_BoxIpcPath, Dll_BoxIpcPathLen)) { diff --git a/Sandboxie/core/dll/key.c b/Sandboxie/core/dll/key.c index d735fb2f..cef0bc83 100644 --- a/Sandboxie/core/dll/key.c +++ b/Sandboxie/core/dll/key.c @@ -23,10 +23,11 @@ #include "dll.h" #include "obj.h" +#include "handle.h" #include "core/svc/FileWire.h" #include "core/drv/api_defs.h" #include - +#include "debug.h" //--------------------------------------------------------------------------- // Defines @@ -305,6 +306,8 @@ static const WCHAR *Key_Wow6432Node = L"\\Wow6432Node\\"; static BOOLEAN Key_UseObjectNames = FALSE; +BOOLEAN Key_Delete_v2 = FALSE; + //--------------------------------------------------------------------------- // Debug Prints //--------------------------------------------------------------------------- @@ -337,6 +340,7 @@ static BOOLEAN Key_UseObjectNames = FALSE; //--------------------------------------------------------------------------- +#include "key_del.c" #include "key_merge.c" #include "key_util.c" @@ -357,6 +361,8 @@ _FX BOOLEAN Key_Init(void) Key_UseObjectNames = SbieApi_QueryConfBool(NULL, L"UseObjectNameForKeys", FALSE); + Key_Delete_v2 = SbieApi_QueryConfBool(NULL, L"UseRegDeleteV2", FALSE); + List_Init(&Key_Handles); List_Init(&Key_MergeCacheList); @@ -450,6 +456,16 @@ _FX NTSTATUS Key_GetName( if (RootDirectory) { + name = Handle_GetRelocationPath(RootDirectory, objname_len); + if (name) { + + *OutTruePath = name; + + name = (*OutTruePath) + wcslen(*OutTruePath); + + } + else { + length = 256; name = Dll_GetTlsNameBuffer( TlsData, TRUE_NAME_BUFFER, length + objname_len); @@ -504,6 +520,8 @@ _FX NTSTATUS Key_GetName( + ((KEY_NAME_INFORMATION *)name)->NameLength / sizeof(WCHAR); } + } + if (objname_len) { *name = L'\\'; @@ -1095,6 +1113,41 @@ _FX NTSTATUS Key_NtCreateKey( //--------------------------------------------------------------------------- +#ifdef WITH_DEBUG_ +static P_NtCreateKey __sys_NtCreateKey_ = NULL; + +_FX NTSTATUS Key_MyCreateKey( + HANDLE *KeyHandle, + ACCESS_MASK DesiredAccess, + OBJECT_ATTRIBUTES *ObjectAttributes, + ULONG TitleIndex, + UNICODE_STRING *Class, + ULONG CreateOptions, + ULONG *Disposition) +{ + ULONG Disposition_ = 0; + + if (!Disposition) + Disposition = &Disposition_; + + NTSTATUS status = __sys_NtCreateKey_( + KeyHandle, DesiredAccess, ObjectAttributes, TitleIndex, + Class, CreateOptions, Disposition); + + if (*Disposition == REG_CREATED_NEW_KEY) { + while (! IsDebuggerPresent()) { OutputDebugString(L"BREAK\n"); Sleep(500); } + __debugbreak(); + } + + //if (NT_SUCCESS(status)) DbgPrint("%p: %p\r\n", _ReturnAddress(), *KeyHandle); + + status = StopTailCallOptimization(status); + + return status; +} +#endif + + _FX NTSTATUS Key_NtCreateKeyImpl( HANDLE *KeyHandle, ACCESS_MASK DesiredAccess, @@ -1119,6 +1172,17 @@ _FX NTSTATUS Key_NtCreateKeyImpl( BOOLEAN CopyPathCreated; BOOLEAN TruePathExists; PSECURITY_DESCRIPTOR *OverrideSecurityDescriptor; + ULONG TruePathFlags; + WCHAR* OriginalPath; + BOOLEAN TrueOpened; + +#ifdef WITH_DEBUG_ + if (__sys_NtCreateKey_ == NULL) + { + __sys_NtCreateKey_ = __sys_NtCreateKey; + __sys_NtCreateKey = Key_MyCreateKey; + } +#endif // // if this is a recursive invocation of NtCreateKey, @@ -1146,6 +1210,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl( CopyPathCreated = FALSE; TruePathExists = FALSE; + OriginalPath = NULL; + TrueOpened = FALSE; TlsData->key_NtCreateKey_lock = TRUE; @@ -1225,6 +1291,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl( } } + if (NT_SUCCESS(status)) TrueOpened = TRUE; + __leave; #undef KEY_READ_WOW64 @@ -1256,6 +1324,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl( Wow64KeyReadAccess = Key_GetWow64Flag(TruePath, KEY_READ); + RtlInitUnicodeString(&objname, CopyPath); + // // first we try to create or open CopyPath with whatever DesiredAccess // the caller specified. if this succeeds, then CopyPath must exist @@ -1263,8 +1333,7 @@ _FX NTSTATUS Key_NtCreateKeyImpl( // we also check that the parent of the key is not marked deleted. // - RtlInitUnicodeString(&objname, CopyPath); - + if (!Key_Delete_v2) if (Key_CheckDeletedParent(CopyPath)) { // @@ -1310,6 +1379,7 @@ _FX NTSTATUS Key_NtCreateKeyImpl( // requested copy key so that we can open it // + if (!Dll_CompartmentMode) // NoDriverAssist if (status == STATUS_ACCESS_DENIED && Secure_IsRestrictedToken(TRUE)) { NTSTATUS status2 = SbieApi_SetLowLabelKey(CopyPath); @@ -1350,9 +1420,12 @@ _FX NTSTATUS Key_NtCreateKeyImpl( if (NT_SUCCESS(status)) { - BOOLEAN KeyDeleted = Key_CheckDeletedKey(*KeyHandle); + BOOLEAN KeyDeleted = FALSE; - if (KeyDeleted) { + if (!Key_Delete_v2) + if (Key_CheckDeletedKey(*KeyHandle)) { + + KeyDeleted = TRUE; if (CreateOptions == tzuk) { @@ -1417,6 +1490,28 @@ _FX NTSTATUS Key_NtCreateKeyImpl( __leave; } + // + // Check true path relocation + // + + TruePathFlags = 0; + + if (Key_Delete_v2) { + + WCHAR* OldTruePath = Key_ResolveTruePath(TruePath, &TruePathFlags); + if (OldTruePath) { + OriginalPath = TruePath; + TruePath = OldTruePath; + } + + // if key marked as deleted dont even try opening true path + if (KEY_PATH_DELETED(TruePathFlags) && CreateOptions == tzuk) { + status = STATUS_OBJECT_NAME_NOT_FOUND; + __leave; + } + } + + // // if we're successful, or we got any of the three status codes // that we don't handle, then stop here @@ -1447,7 +1542,10 @@ _FX NTSTATUS Key_NtCreateKeyImpl( int depth = Key_CheckDepthForIsWritePath(TruePath); if (depth == 0) { - status = SbieApi_OpenKey(KeyHandle, TruePath); + if (Dll_CompartmentMode) { // NoDriverAssist + status = __sys_NtOpenKey(KeyHandle, Wow64KeyReadAccess, &objattrs); + } else + status = SbieApi_OpenKey(KeyHandle, TruePath); if (NT_SUCCESS(status)) goto SkipReadOnlyCheck; } else @@ -1464,6 +1562,8 @@ _FX NTSTATUS Key_NtCreateKeyImpl( if (NT_SUCCESS(status)) { + TrueOpened = TRUE; + // // if the TruePath key exists, and caller is asking for // read-only (*) access to this key, then return the handle @@ -1614,6 +1714,8 @@ SkipReadOnlyCheck: status = __sys_NtOpenKey( KeyHandle, DesiredAccess, ObjectAttributes); + if (NT_SUCCESS(status)) TrueOpened = TRUE; // is that right? + if (NT_SUCCESS(status) && Disposition) *Disposition = REG_OPENED_EXISTING_KEY; } @@ -1627,6 +1729,19 @@ SkipReadOnlyCheck: if (CopyPathCreated) Key_DiscardMergeByPath(TruePath, TRUE); + // + // Relocation, if we opened the true key and its relocated set the path info + // + + if (TrueOpened && OriginalPath) { + + Handle_SetRelocationPath(*KeyHandle, OriginalPath); + } + + // + // finish + // + Dll_PopTlsNameBuffer(TlsData); TlsData->key_NtCreateKey_lock = FALSE; @@ -1654,6 +1769,34 @@ _FX NTSTATUS Key_CreatePath( USHORT savemaximumlength; ULONG disp; + if (Key_Delete_v2) { + + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + BOOLEAN ParentDeleted = FALSE; + WCHAR *TruePath; + WCHAR *CopyPath; + + Dll_PushTlsNameBuffer(TlsData); + + __try { + + status = Key_GetName(NULL, objattrs->ObjectName, &TruePath, &CopyPath, NULL); + + } __except (EXCEPTION_EXECUTE_HANDLER) { + status = GetExceptionCode(); + } + + if (NT_SUCCESS(status)) { + ParentDeleted = KEY_PARENT_DELETED(Key_IsDeleted_v2(TruePath)); + } + + Dll_PopTlsNameBuffer(TlsData); + + if(ParentDeleted) + return STATUS_OBJECT_NAME_NOT_FOUND; + } + // // first we traverse backward along the path, removing the last // path component each time, and trying to create the path that @@ -1702,6 +1845,7 @@ _FX NTSTATUS Key_CreatePath( if (NT_SUCCESS(status)) { + if (!Key_Delete_v2) if (disp == REG_OPENED_EXISTING_KEY) { if (Key_CheckDeletedKey(handle)) { @@ -1746,6 +1890,7 @@ _FX NTSTATUS Key_CreatePath( status = Key_CreatePath_Key(&handle, objattrs, &disp); + if (!Dll_CompartmentMode) // NoDriverAssist if (status == STATUS_ACCESS_DENIED && Dll_RestrictedToken) { // @@ -2043,7 +2188,7 @@ _FX NTSTATUS Key_NtDeleteKeyTreeImpl(HANDLE KeyHandle, BOOLEAN DeleteTree) // open the key. this will create a copy key, if necessary // - status = Key_NtOpenKeyImpl(&handle, GENERIC_WRITE | KEY_READ, &objattrs); + status = Key_NtOpenKeyImpl(&handle, GENERIC_WRITE | KEY_READ | DELETE, &objattrs); if (! NT_SUCCESS(status)) __leave; @@ -2182,17 +2327,51 @@ _FX NTSTATUS Key_MarkDeletedAndClose(HANDLE KeyHandle) // mark key deleted by setting its last write time information // - kwti.LastWriteTime.HighPart = DELETE_MARK_HIGH; - kwti.LastWriteTime.LowPart = DELETE_MARK_LOW; - status = NtSetInformationKey( - KeyHandle, KeyWriteTimeInformation, - &kwti, sizeof(KEY_WRITE_TIME_INFORMATION)); + if (Key_Delete_v2) { - // - // refresh all merges - // + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); - Key_DiscardMergeByHandle(TlsData, KeyHandle, TRUE); + UNICODE_STRING objname; + WCHAR *TruePath; + WCHAR *CopyPath; + + Dll_PushTlsNameBuffer(TlsData); + + RtlInitUnicodeString(&objname, L""); + + __try { + + status = Key_GetName(KeyHandle, &objname, &TruePath, &CopyPath, NULL); + + } __except (EXCEPTION_EXECUTE_HANDLER) { + status = GetExceptionCode(); + } + + if (NT_SUCCESS(status)) { + Key_MarkDeletedEx_v2(TruePath, NULL); + + Key_DiscardMergeByPath(TruePath, TRUE); + } + + Dll_PopTlsNameBuffer(TlsData); + + __sys_NtDeleteKey(KeyHandle); + + } + else { + + kwti.LastWriteTime.HighPart = DELETE_MARK_HIGH; + kwti.LastWriteTime.LowPart = DELETE_MARK_LOW; + status = NtSetInformationKey( + KeyHandle, KeyWriteTimeInformation, + &kwti, sizeof(KEY_WRITE_TIME_INFORMATION)); + + // + // refresh all merges + // + + Key_DiscardMergeByHandle(TlsData, KeyHandle, TRUE); + } // // close key handle @@ -2307,14 +2486,18 @@ _FX NTSTATUS Key_NtDeleteValueKey( status = GetExceptionCode(); } - Dll_PopTlsNameBuffer(TlsData); - if (NT_SUCCESS(status)) { if (PATH_IS_OPEN(mp_flags)) { status = __sys_NtDeleteValueKey(KeyHandle, ValueName); + } if (Key_Delete_v2){ + + Key_MarkDeletedEx_v2(TruePath, ValueName->Buffer); + + __sys_NtDeleteValueKey(KeyHandle, ValueName); + } else { // @@ -2341,6 +2524,8 @@ _FX NTSTATUS Key_NtDeleteValueKey( } } + Dll_PopTlsNameBuffer(TlsData); + SetLastError(LastError); return status; } @@ -2495,6 +2680,16 @@ _FX NTSTATUS Key_NtQueryKeyImpl( __try { + // + // get the full paths for the true and copy keys + // + + RtlInitUnicodeString(&objname, L""); + + status = Key_GetName(KeyHandle, &objname, &TruePath, &CopyPath, NULL); + if (! NT_SUCCESS(status)) + __leave; + // // for KeyBasicInformation, KeyNodeInformation, KeyFlagsInformation, // we let the system handle the call, then check for the delete mark. @@ -2509,26 +2704,21 @@ _FX NTSTATUS Key_NtQueryKeyImpl( KeyHandle, KeyInformationClass, KeyInformation, Length, ResultLength); - if (KeyInformationClass != KeyFlagsInformation && - (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && - IS_DELETE_MARK((LARGE_INTEGER *)KeyInformation)) + if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { - status = STATUS_KEY_DELETED; + if (Key_Delete_v2) { + if (Key_IsDeleted_v2(TruePath)) + status = STATUS_KEY_DELETED; + } + else if(KeyInformationClass != KeyFlagsInformation) { + if (IS_DELETE_MARK((LARGE_INTEGER*)KeyInformation)) + status = STATUS_KEY_DELETED; + } } __leave; } - // - // get the full paths for the true and copy keys - // - - RtlInitUnicodeString(&objname, L""); - - status = Key_GetName(KeyHandle, &objname, &TruePath, &CopyPath, NULL); - if (! NT_SUCCESS(status)) - __leave; - // // for KeyNameInformation, we want to place TruePath in the // output buffer, even if KeyHandle is a boxed key. this is @@ -2601,10 +2791,16 @@ _FX NTSTATUS Key_NtQueryKeyImpl( KeyHandle, KeyInformationClass, KeyInformation, Length, ResultLength); - if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && - IS_DELETE_MARK((LARGE_INTEGER *)KeyInformation)) + if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { - status = STATUS_KEY_DELETED; + if (Key_Delete_v2) { + if (Key_IsDeleted_v2(TruePath)) + status = STATUS_KEY_DELETED; + } + else { + if (IS_DELETE_MARK((LARGE_INTEGER*)KeyInformation)) + status = STATUS_KEY_DELETED; + } } } @@ -2789,10 +2985,16 @@ _FX NTSTATUS Key_NtEnumerateKey( KeyHandle, Index, KeyInformationClass, KeyInformation, Length, ResultLength); - if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && - IS_DELETE_MARK((LARGE_INTEGER *)KeyInformation)) + if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { - status = STATUS_KEY_DELETED; + if (Key_Delete_v2) { + if (Key_IsDeleted_v2(TruePath)) + status = STATUS_KEY_DELETED; + } + else { + if (IS_DELETE_MARK((LARGE_INTEGER*)KeyInformation)) + status = STATUS_KEY_DELETED; + } } } @@ -3188,11 +3390,16 @@ _FX NTSTATUS Key_NtQueryValueKey( KeyValueInformationClass, KeyValueInformation, Length, ResultLength); - if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && - Key_CheckDeletedValue( - KeyValueInformationClass, KeyValueInformation)) + if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { - status = STATUS_OBJECT_NAME_NOT_FOUND; + if (Key_Delete_v2) { + if(Key_IsDeletedEx_v2(TruePath, ValueNameBuf, TRUE)) + status = STATUS_OBJECT_NAME_NOT_FOUND; + } + else { + if (Key_CheckDeletedValue(KeyValueInformationClass, KeyValueInformation)) + status = STATUS_OBJECT_NAME_NOT_FOUND; + } } } @@ -3544,11 +3751,26 @@ _FX NTSTATUS Key_NtEnumerateValueKey( KeyValueInformationClass, KeyValueInformation, Length, ResultLength); - if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && - Key_CheckDeletedValue( - KeyValueInformationClass, KeyValueInformation)) + if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { - status = STATUS_OBJECT_NAME_NOT_FOUND; + if (Key_Delete_v2) { + + WCHAR* ValueName; + + if (KeyValueInformationClass == KeyValueBasicInformation) + ValueName = ((KEY_VALUE_BASIC_INFORMATION *)KeyValueInformation)->Name; + else if (KeyValueInformationClass == KeyValueFullInformation) + ValueName = ((KEY_VALUE_FULL_INFORMATION *)KeyValueInformation)->Name; + else + ValueName = 0; + + if(ValueName && Key_IsDeletedEx_v2(TruePath, ValueName, TRUE)) + status = STATUS_OBJECT_NAME_NOT_FOUND; + } + else { + if (Key_CheckDeletedValue(KeyValueInformationClass, KeyValueInformation)) + status = STATUS_OBJECT_NAME_NOT_FOUND; + } } } @@ -4068,8 +4290,153 @@ _FX HANDLE Key_GetTrueHandle(HANDLE KeyHandle, BOOLEAN *pIsOpenPath) _FX NTSTATUS Key_NtRenameKey( HANDLE KeyHandle, UNICODE_STRING *ReplacementName) { - SbieApi_Log(2205, L"NtRenameKey"); - return __sys_NtRenameKey(KeyHandle, ReplacementName); + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + if (!Key_Delete_v2) { + SbieApi_Log(2205, L"NtRenameKey"); + return __sys_NtRenameKey(KeyHandle, ReplacementName); + } + + NTSTATUS status; + OBJECT_ATTRIBUTES objattrs; + UNICODE_STRING objname; + HANDLE handle; + WCHAR* TruePath; + WCHAR* CopyPath; + WCHAR* NewTruePath; + + Dll_PushTlsNameBuffer(TlsData); + + // + // get the full new name of the key to be renamed + // + + __try { + + status = Key_GetName(KeyHandle, NULL, &TruePath, &CopyPath, NULL); + + WCHAR* TruePathSlash = wcsrchr(TruePath, L'\\'); + if (!TruePathSlash) { + status = STATUS_INVALID_PARAMETER; + __leave; + } + ULONG len = (ULONG)(TruePathSlash - TruePath + 1); + + NewTruePath = Dll_GetTlsNameBuffer(TlsData, MOVE_NAME_BUFFER, + len * sizeof(WCHAR) + ReplacementName->Length + sizeof(WCHAR)); + + wmemcpy(NewTruePath, TruePath, len); + wmemcpy(NewTruePath + len, ReplacementName->Buffer, ReplacementName->Length / sizeof(WCHAR)); + NewTruePath[len + ReplacementName->Length / sizeof(WCHAR)] = L'\0'; + + } + __except (EXCEPTION_EXECUTE_HANDLER) { + status = GetExceptionCode(); + } + + // + // rename the key ensuring we wil have a boxed copy + // + + if (NT_SUCCESS(status)) { + + // + // check if the target key already exists in the true path + // + + RtlInitUnicodeString(&objname, NewTruePath); + InitializeObjectAttributes( + &objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); + + status = __sys_NtOpenKey(&handle, KEY_READ, &objattrs); + + if (NT_SUCCESS(status)) { + + if(!Key_IsDeleted_v2(NewTruePath)) + status = STATUS_OBJECT_NAME_COLLISION; + + File_NtCloseImpl(handle); + } + + // + // try renaming if it fails with access denided try again with a new handle + // + + if (NT_SUCCESS(status)) + status = __sys_NtRenameKey(KeyHandle, ReplacementName); + + if (status == STATUS_ACCESS_DENIED) { + + // + // if we get STATUS_ACCESS_DENIED, the caller may be using a + // TruePath handle that was opened with MAXIMUM_ALLOWED, but + // reduced to read-only access in our NtCreateKey + // + + OBJECT_ATTRIBUTES objattrs; + UNICODE_STRING objname; + HANDLE handle; + + RtlInitUnicodeString(&objname, L""); + InitializeObjectAttributes( + &objattrs, &objname, OBJ_CASE_INSENSITIVE, KeyHandle, NULL); + + status = NtOpenKey(&handle, KEY_WRITE, &objattrs); + + if (NT_SUCCESS(status)) { + + status = __sys_NtRenameKey(handle, ReplacementName); + + NtClose(handle); + } + } + } + + // + // set the redirection information + // + + if (NT_SUCCESS(status)) { + + //*TruePathSlash = L'\0'; + //Key_DiscardMergeByPath(TruePath, TRUE); // fix-me: act on Key_MergeCacheList + //*TruePathSlash = L'\\'; + + // + // check if the true path exists and if so mark path deleted + // + + BOOLEAN TrueExists = FALSE; + + RtlInitUnicodeString(&objname, TruePath); + InitializeObjectAttributes( + &objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL); + + status = __sys_NtOpenKey(&handle, KEY_READ, &objattrs); + + if (NT_SUCCESS(status)) { + + // + // if the true key exists mark it deleted + // + + TrueExists = TRUE; + + File_NtCloseImpl(handle); + } + + // + // setup/update the key relocation + // + + Key_SetRelocation(TruePath, NewTruePath, TrueExists); + + status = STATUS_SUCCESS; + } + + Dll_PopTlsNameBuffer(TlsData); + + return status; } @@ -4081,7 +4448,7 @@ _FX NTSTATUS Key_NtRenameKey( _FX NTSTATUS Key_NtSaveKey( HANDLE KeyHandle, HANDLE FileHandle) { - //SbieApi_Log(2205, L"NtSaveKey"); + SbieApi_Log(2205, L"NtSaveKey"); return STATUS_SUCCESS; } @@ -4106,6 +4473,10 @@ _FX NTSTATUS Key_NtLoadKey( FILE_LOAD_KEY_REQ *req; status = __sys_NtLoadKey(TargetObjectAttributes, SourceObjectAttributes); + + if (Dll_CompartmentMode) // NoDriverAssist + return status; + if (status != STATUS_PRIVILEGE_NOT_HELD) return status; diff --git a/Sandboxie/core/dll/key_del.c b/Sandboxie/core/dll/key_del.c new file mode 100644 index 00000000..1f887753 --- /dev/null +++ b/Sandboxie/core/dll/key_del.c @@ -0,0 +1,352 @@ +/* + * Copyright 2022 David Xanatos, xanasoft.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//--------------------------------------------------------------------------- +// Key (Delete) +//--------------------------------------------------------------------------- + +//--------------------------------------------------------------------------- +// Defines +//--------------------------------------------------------------------------- + +#define KEY_PATH_FILE_NAME L"RegPaths.dat" + +// Keep in sync with the FILE_..._FLAG's in file_del.c +// +// path flages, saved to file +#define KEY_DELETED_FLAG 0x0001 +#define KEY_RELOCATION_FLAG 0x0002 + +// internal volatile status flags +#define KEY_PATH_DELETED_FLAG 0x00010000 +#define KEY_PATH_RELOCATED_FLAG 0x00020000 +#define KEY_CHILDREN_DELETED_FLAG 0x00040000 + +#define KEY_DELETED_MASK (KEY_DELETED_FLAG | KEY_PATH_DELETED_FLAG) +#define KEY_RELOCATED_MASK (KEY_RELOCATION_FLAG | KEY_PATH_RELOCATED_FLAG) + +#define KEY_IS_DELETED(x) ((x & KEY_DELETED_FLAG) != 0) +#define KEY_PATH_DELETED(x) ((x & KEY_DELETED_MASK) != 0) +#define KEY_PARENT_DELETED(x) ((x & KEY_PATH_DELETED_FLAG) != 0) +#define KEY_PATH_RELOCATED(x) ((x & KEY_RELOCATED_MASK) != 0) + + +//--------------------------------------------------------------------------- +// Variables +//--------------------------------------------------------------------------- + + +static LIST Key_PathRoot; +static CRITICAL_SECTION *Key_PathRoot_CritSec = NULL; + +static HANDLE Key_BoxRootWatcher = NULL; +static volatile ULONGLONG Key_PathsVersion = 0; // count reloads + + +//--------------------------------------------------------------------------- +// Functions +//--------------------------------------------------------------------------- + +static ULONG Key_GetPathFlags(const WCHAR* Path, WCHAR** pRelocation); +static BOOLEAN Key_SavePathTree(); +static BOOLEAN Key_LoadPathTree(); +static VOID Key_RefreshPathTree(); +BOOLEAN Key_InitDelete_v2(); +static NTSTATUS Key_MarkDeletedEx_v2(const WCHAR* TruePath, const WCHAR* ValueName); +static ULONG Key_IsDeleted_v2(const WCHAR* TruePath); +static ULONG Key_IsDeletedEx_v2(const WCHAR* TruePath, const WCHAR* ValueName, BOOLEAN IsValue); + +// +// we re use the _internal functions of the file implementation as thay all are generic enough +// + +VOID File_ClearPathBranche_internal(LIST* parent); +VOID File_SavePathTree_internal(LIST* Root, const WCHAR* name); +VOID File_LoadPathTree_internal(LIST* Root, const WCHAR* name); +VOID File_SetPathFlags_internal(LIST* Root, const WCHAR* Path, ULONG setFlags, ULONG clrFlags, const WCHAR* Relocation); +ULONG File_GetPathFlags_internal(LIST* Root, const WCHAR* Path, WCHAR** pRelocation, BOOLEAN CheckChildren); +VOID File_SavePathNode_internal(HANDLE hPathsFile, LIST* parent, WCHAR* Path, ULONG Length, ULONG SetFlags); +VOID File_MarkDeleted_internal(LIST* Root, const WCHAR* Path); +VOID File_SetRelocation_internal(LIST* Root, const WCHAR* OldTruePath, const WCHAR* NewTruePath, BOOLEAN TrueExists); + + + +//--------------------------------------------------------------------------- +// Key_GetPathFlags +//--------------------------------------------------------------------------- + + +_FX ULONG Key_GetPathFlags(const WCHAR* Path, WCHAR** pRelocation) +{ + ULONG Flags; + + Key_RefreshPathTree(); + + EnterCriticalSection(Key_PathRoot_CritSec); + + Flags = File_GetPathFlags_internal(&Key_PathRoot, Path, pRelocation, TRUE); + + LeaveCriticalSection(Key_PathRoot_CritSec); + + return Flags; +} + + +//--------------------------------------------------------------------------- +// Key_SavePathTree +//--------------------------------------------------------------------------- + + +_FX BOOLEAN Key_SavePathTree() +{ + EnterCriticalSection(Key_PathRoot_CritSec); + + File_SavePathTree_internal(&Key_PathRoot, KEY_PATH_FILE_NAME); + + LeaveCriticalSection(Key_PathRoot_CritSec); + + Key_PathsVersion++; + + return TRUE; +} + + +//--------------------------------------------------------------------------- +// Key_LoadPathTree +//--------------------------------------------------------------------------- + + +_FX BOOLEAN Key_LoadPathTree() +{ + EnterCriticalSection(Key_PathRoot_CritSec); + + File_LoadPathTree_internal(&Key_PathRoot, KEY_PATH_FILE_NAME); + + LeaveCriticalSection(Key_PathRoot_CritSec); + + Key_PathsVersion++; + + return TRUE; +} + + +//--------------------------------------------------------------------------- +// Key_RefreshPathTree +//--------------------------------------------------------------------------- + + +_FX VOID Key_RefreshPathTree() +{ + if (!Key_BoxRootWatcher) + return; + + if (WaitForSingleObject(Key_BoxRootWatcher, 0) == WAIT_OBJECT_0) { + + // + // somethign changed, reload the path tree + // + + Key_LoadPathTree(); + } + + FindNextChangeNotification(Key_BoxRootWatcher); // rearm the watcher +} + + +//--------------------------------------------------------------------------- +// Key_InitDelete_v2 +//--------------------------------------------------------------------------- + + +_FX BOOLEAN Key_InitDelete_v2() +{ + List_Init(&Key_PathRoot); + + Key_PathRoot_CritSec = Dll_Alloc(sizeof(CRITICAL_SECTION)); + InitializeCriticalSectionAndSpinCount(Key_PathRoot_CritSec, 1000); + + Key_LoadPathTree(); + +//#ifdef WITH_DEBUG +// Key_SavePathTree(); +//#endif + + WCHAR BoxFilePath[MAX_PATH] = { 0 }; + wcscpy(BoxFilePath, Dll_BoxFilePath); + SbieDll_TranslateNtToDosPath(BoxFilePath); + + Key_BoxRootWatcher = FindFirstChangeNotification(BoxFilePath, FALSE, FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); + + return TRUE; +} + + +//--------------------------------------------------------------------------- +// Key_MarkDeletedEx_v2 +//--------------------------------------------------------------------------- + + +_FX NTSTATUS Key_MarkDeletedEx_v2(const WCHAR* TruePath, const WCHAR* ValueName) +{ + // + // add a key/value or directory to the deleted list + // + + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + WCHAR* FullPath = Dll_GetTlsNameBuffer(TlsData, TMPL_NAME_BUFFER, + (wcslen(TruePath) + (ValueName ? wcslen(ValueName) : 0) + 16) * sizeof(WCHAR)); // template buffer is not used for reg reputpose it here + + wcscpy(FullPath, TruePath); + if (ValueName) { + wcscat(FullPath, L"\\$"); + wcscat(FullPath, ValueName); + } + + EnterCriticalSection(Key_PathRoot_CritSec); + + File_MarkDeleted_internal(&Key_PathRoot, FullPath); + + LeaveCriticalSection(Key_PathRoot_CritSec); + + Key_SavePathTree(); + + return STATUS_SUCCESS; +} + + +//--------------------------------------------------------------------------- +// Key_IsDeleted_v2 +//--------------------------------------------------------------------------- + + +_FX ULONG Key_IsDeleted_v2(const WCHAR* TruePath) +{ + // + // check if the key/value or one of its parent directories is listed as deleted + // + + ULONG Flags = Key_GetPathFlags(TruePath, NULL); + + return (Flags & KEY_DELETED_MASK); +} + + +//--------------------------------------------------------------------------- +// Key_IsDeletedEx_v2 +//--------------------------------------------------------------------------- + + +_FX ULONG Key_IsDeletedEx_v2(const WCHAR* TruePath, const WCHAR* ValueName, BOOLEAN IsValue) +{ + // + // check if the key/value or one of its parent directories is listed as deleted + // + + THREAD_DATA *TlsData = Dll_GetTlsData(NULL); + + WCHAR* FullPath = Dll_GetTlsNameBuffer(TlsData, TMPL_NAME_BUFFER, + (wcslen(TruePath) + (ValueName ? wcslen(ValueName) : 0) + 16) * sizeof(WCHAR)); // template buffer is not used for reg reputpose it here + + wcscpy(FullPath, TruePath); + if (ValueName) { + wcscat(FullPath, IsValue ? L"\\$" : L"\\"); + wcscat(FullPath, ValueName); + } + + return Key_IsDeleted_v2(FullPath); +} + + +//--------------------------------------------------------------------------- +// Key_HasDeleted_v2 +//--------------------------------------------------------------------------- + + +_FX BOOLEAN Key_HasDeleted_v2(const WCHAR* TruePath) +{ + // + // Check if this folder has deleted children + // + + ULONG Flags = Key_GetPathFlags(TruePath, NULL); + + return (Flags & KEY_CHILDREN_DELETED_FLAG) != 0; +} + + +//--------------------------------------------------------------------------- +// Key_SetRelocation +//--------------------------------------------------------------------------- + + +_FX NTSTATUS Key_SetRelocation(const WCHAR *OldTruePath, const WCHAR *NewTruePath, BOOLEAN TrueExists) +{ + // + // List a mapping for the new location + // + + EnterCriticalSection(Key_PathRoot_CritSec); + + File_SetRelocation_internal(&Key_PathRoot, OldTruePath, NewTruePath, TrueExists); + + LeaveCriticalSection(Key_PathRoot_CritSec); + + Key_SavePathTree(); + + return STATUS_SUCCESS; +} + + +//--------------------------------------------------------------------------- +// Key_GetRelocation +//--------------------------------------------------------------------------- + + +_FX WCHAR* Key_GetRelocation(const WCHAR *TruePath) +{ + // + // Get redirection location, only if its the actual path and not a parent + // + + WCHAR* OldTruePath = NULL; + ULONG Flags = Key_GetPathFlags(TruePath, &OldTruePath); + if (KEY_PATH_RELOCATED(Flags)) + return OldTruePath; + + return NULL; +} + + +//--------------------------------------------------------------------------- +// Key_ResolveTruePath +//--------------------------------------------------------------------------- + + +_FX WCHAR* Key_ResolveTruePath(const WCHAR *TruePath, ULONG* PathFlags) +{ + // + // Resolve the true path, taking into account redirection locations of parent folder + // + + WCHAR* OldTruePath = NULL; + ULONG Flags = Key_GetPathFlags(TruePath, &OldTruePath); + if (PathFlags) *PathFlags = Flags; + + return OldTruePath; +} + diff --git a/Sandboxie/core/dll/key_merge.c b/Sandboxie/core/dll/key_merge.c index a4488fed..f8bf90c8 100644 --- a/Sandboxie/core/dll/key_merge.c +++ b/Sandboxie/core/dll/key_merge.c @@ -1,5 +1,6 @@ /* * Copyright 2004-2020 Sandboxie Holdings, LLC + * Copyright 2021-2022 David Xanatos, xanasoft.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,6 +36,7 @@ typedef struct _KEY_MERGE { BOOLEAN subkeys_merged; LARGE_INTEGER last_write_time; + ULONGLONG last_paths_version; LIST subkeys; ULONG last_index; @@ -200,7 +202,7 @@ _FX NTSTATUS Key_Merge( // if we got here, we need to discard the stale entry // - File_UnRegisterCloseHandler(merge->handle, Key_NtClose); + Handle_UnRegisterCloseHandler(merge->handle, Key_NtClose); List_Remove(&Key_Handles, merge); Key_MergeFree(merge, TRUE); @@ -226,7 +228,7 @@ _FX NTSTATUS Key_Merge( memcpy(merge->name, TruePath, TruePath_len + sizeof(WCHAR)); List_Insert_Before(&Key_Handles, NULL, merge); - File_RegisterCloseHandler(merge->handle, Key_NtClose); + Handle_RegisterCloseHandler(merge->handle, Key_NtClose); } // @@ -234,6 +236,7 @@ _FX NTSTATUS Key_Merge( // or CopyPath exist, but not both, so return special status // + if(!Key_Delete_v2 || !Key_HasDeleted_v2(TruePath)) if (merge->cant_merge) { LeaveCriticalSection(&Key_Handles_CritSec); @@ -316,6 +319,7 @@ _FX NTSTATUS Key_OpenForMerge( ULONG len; HANDLE TrueHandle; ULONG mp_flags; + const WCHAR* OriginalPath = NULL; *out_TrueMerge = NULL; *out_CopyHandle = NULL; @@ -362,6 +366,7 @@ _FX NTSTATUS Key_OpenForMerge( &info, sizeof(KEY_BASIC_INFORMATION), &len); if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { + // if (!Key_Delete_v2 && if (IS_DELETE_MARK(&info.LastWriteTime)) status = STATUS_KEY_DELETED; else @@ -379,7 +384,10 @@ _FX NTSTATUS Key_OpenForMerge( // if we couldn't find a copy key, indicate there is nothing to merge // - status = STATUS_BAD_INITIAL_PC; + if (Key_Delete_v2 && Key_HasDeleted_v2(TruePath)) + status = STATUS_SUCCESS; + else + status = STATUS_BAD_INITIAL_PC; } if (! NT_SUCCESS(status)) { @@ -387,6 +395,18 @@ _FX NTSTATUS Key_OpenForMerge( return status; } + // + // get the redirection location for this key if there is one + // + + if (Key_Delete_v2) { + WCHAR* OldTruePath = Key_GetRelocation(TruePath); + if (OldTruePath) { + OriginalPath = TruePath; + TruePath = OldTruePath; + } + } + // // open TruePath for KEY_READ access. we use __sys_NtOpenKey // because we really want the TruePath key, even if there is @@ -415,7 +435,7 @@ _FX NTSTATUS Key_OpenForMerge( if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { status = Key_MergeCache( - TrueHandle, &info.LastWriteTime, TruePath, out_TrueMerge); + TrueHandle, &info.LastWriteTime, OriginalPath ? OriginalPath : TruePath, out_TrueMerge); } File_NtCloseImpl(TrueHandle); @@ -623,7 +643,7 @@ _FX NTSTATUS Key_MergeCache( if (merge) { - if (LastWriteTime->QuadPart == merge->last_write_time.QuadPart) { + if (LastWriteTime->QuadPart == merge->last_write_time.QuadPart && Key_PathsVersion == merge->last_paths_version) { *out_TrueMerge = merge; return STATUS_SUCCESS; } @@ -646,6 +666,7 @@ _FX NTSTATUS Key_MergeCache( } merge->last_write_time.QuadPart = LastWriteTime->QuadPart; + merge->last_paths_version = Key_PathsVersion; // // build the subkeys and values in the true merge @@ -730,6 +751,12 @@ _FX NTSTATUS Key_MergeCacheSubkeys(KEY_MERGE *merge, HANDLE TrueHandle) info->ClassOffset != -1 || info->ClassLength); + if (Key_Delete_v2 && Key_IsDeletedEx_v2(merge->name, subkey->name, FALSE)) { + Dll_Free(subkey); + ++index; + continue; + } + // // find where to insert it. if the new key is already larger than // our last key in the sorted list, instead directly at the end @@ -828,6 +855,12 @@ _FX NTSTATUS Key_MergeCacheValues(KEY_MERGE *merge, HANDLE TrueHandle) memcpy(value->data_ptr, (UCHAR *)info + info->DataOffset, info->DataLength); + if (Key_Delete_v2 && Key_IsDeletedEx_v2(merge->name, value->name, TRUE)) { + Dll_Free(value); + ++index; + continue; + } + // // find where to insert it // @@ -864,7 +897,7 @@ _FX NTSTATUS Key_MergeSubkeys( KEY_NODE_INFORMATION *info; ULONG index; KEY_MERGE_SUBKEY *subkey, *subkey2; - BOOLEAN subkey_deleted; + BOOLEAN subkey_deleted = FALSE; // // get the latest of the two LastWriteTime fields @@ -882,6 +915,7 @@ _FX NTSTATUS Key_MergeSubkeys( } merge->last_write_time.QuadPart = info->LastWriteTime.QuadPart; + merge->last_paths_version = Key_PathsVersion; if (! TrueMerge) goto TrueHandleFinish; @@ -962,6 +996,7 @@ TrueHandleFinish: info->ClassOffset != -1 || info->ClassLength); + if (!Key_Delete_v2) if (IS_DELETE_MARK(&info->LastWriteTime)) subkey_deleted = TRUE; else @@ -988,7 +1023,8 @@ TrueHandleFinish: if (subkey->TitleOrClass) subkey2->TitleOrClass = subkey->TitleOrClass; } - subkey_deleted = TRUE; + Dll_Free(subkey); + subkey = NULL; break; } @@ -1033,7 +1069,7 @@ _FX NTSTATUS Key_MergeValues( KEY_VALUE_FULL_INFORMATION *info; ULONG index; KEY_MERGE_VALUE *value, *value2; - BOOLEAN value_deleted; + BOOLEAN value_deleted = FALSE; info_len = 128; // at least sizeof(KEY_VALUE_FULL_INFORMATION) info = Dll_Alloc(info_len); @@ -1125,6 +1161,7 @@ TrueHandleFinish: memcpy(value->data_ptr, (UCHAR *)info + info->DataOffset, value->data_len); + if (!Key_Delete_v2) if (info->Type == tzuk) value_deleted = TRUE; else @@ -1379,7 +1416,7 @@ _FX void Key_DiscardMergeByPath(const WCHAR *TruePath, BOOLEAN Recurse) } } - File_UnRegisterCloseHandler(merge->handle, Key_NtClose); + Handle_UnRegisterCloseHandler(merge->handle, Key_NtClose); List_Remove(&Key_Handles, merge); Key_MergeFree(merge, TRUE); } diff --git a/Sandboxie/core/dll/proc.c b/Sandboxie/core/dll/proc.c index 9bc5eef5..ac4b93da 100644 --- a/Sandboxie/core/dll/proc.c +++ b/Sandboxie/core/dll/proc.c @@ -1323,7 +1323,7 @@ _FX BOOL Proc_AlternateCreateProcess( void *lpCurrentDirectory, LPPROCESS_INFORMATION lpProcessInformation, BOOL *ReturnValue) { - if (SbieApi_QueryConfBool(NULL, L"BlockSoftwareUpdaters", FALSE)) + //if (SbieApi_QueryConfBool(NULL, L"BlockSoftwareUpdaters", TRUE)) if (Proc_IsSoftwareUpdateW(lpApplicationName ? lpApplicationName : lpCommandLine)) { SetLastError(ERROR_ACCESS_DENIED); diff --git a/Sandboxie/core/dll/scm_msi.c b/Sandboxie/core/dll/scm_msi.c index e8abab88..b8109afe 100644 --- a/Sandboxie/core/dll/scm_msi.c +++ b/Sandboxie/core/dll/scm_msi.c @@ -16,10 +16,13 @@ * along with this program. If not, see . */ +#include "handle.h" + //--------------------------------------------------------------------------- // Service Control Manager //--------------------------------------------------------------------------- + //#define ErrorMessageBox(txt) // //#define HOOK_WIN32(func) { \ @@ -237,7 +240,7 @@ _FX BOOL Scm_OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE if (NT_SUCCESS(status) && ProcessHandle == GetCurrentProcess()) { - File_RegisterCloseHandler(*phTokenOut, Scm_TokenCloseHandler); + Handle_RegisterCloseHandler(*phTokenOut, Scm_TokenCloseHandler); TlsData->scm_last_own_token = *phTokenOut; } @@ -258,7 +261,7 @@ _FX BOOL Scm_OpenThreadToken(HANDLE ThreadHandle, DWORD DesiredAccess, BOOL Open if (NT_SUCCESS(status) && ThreadHandle == GetCurrentThread()) { - File_RegisterCloseHandler(*phTokenOut, Scm_TokenCloseHandler); + Handle_RegisterCloseHandler(*phTokenOut, Scm_TokenCloseHandler); TlsData->scm_last_own_token = *phTokenOut; } diff --git a/Sandboxie/core/dll/secure.c b/Sandboxie/core/dll/secure.c index da6a7ea4..9a5519bd 100644 --- a/Sandboxie/core/dll/secure.c +++ b/Sandboxie/core/dll/secure.c @@ -722,8 +722,17 @@ _FX NTSTATUS Secure_NtDuplicateObject( if (SourceProcessHandle == NtCurrentProcess()) { - if (TargetProcessHandle == NtCurrentProcess() && TargetHandle) - File_DuplicateRecover(SourceHandle, *TargetHandle); + if (TargetProcessHandle == NtCurrentProcess() && TargetHandle) { + + // + // this also duplicates the "recoverability" + // of the old handle to the new handle. needed in particular for + // SHFileOperation to recover correctly on Windows Vista + // + + if(SourceHandle && *TargetHandle) + Handle_SetupDuplicate(SourceHandle, *TargetHandle); + } if (SourceHandle) Key_NtClose(SourceHandle); diff --git a/Sandboxie/core/dll/sysinfo.c b/Sandboxie/core/dll/sysinfo.c index b7a70746..5b4babe8 100644 --- a/Sandboxie/core/dll/sysinfo.c +++ b/Sandboxie/core/dll/sysinfo.c @@ -422,14 +422,26 @@ _FX NTSTATUS SysInfo_GetJobName(OBJECT_ATTRIBUTES* ObjectAttributes, WCHAR** Out *OutCopyPath = name; - wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen); - name += Dll_BoxIpcPathLen; + //if (Dll_AlernateIpcNaming) + //{ + // wmemcpy(name, objname_buf, objname_len); + // name += objname_len; + // + // wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen); + // name += Dll_BoxIpcPathLen; + //} + //else + { + wmemcpy(name, Dll_BoxIpcPath, Dll_BoxIpcPathLen); + name += Dll_BoxIpcPathLen; - *name = L'\\'; - name++; + *name = L'\\'; + name++; + + wmemcpy(name, objname_buf, objname_len); + name += objname_len; + } - wmemcpy(name, objname_buf, objname_len); - name += objname_len; *name = L'\0'; return STATUS_SUCCESS; diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp index 7d9d87db..31b47bd2 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp @@ -323,6 +323,8 @@ struct SBoxDataFile QList CSandBox__BoxDataFiles = QList() << SBoxDataFile("RegHive", true, false) + << SBoxDataFile("RegPaths.dat", false, false) + << SBoxDataFile("FilePaths.dat", false, true) ; bool CSandBox::IsInitialized() const diff --git a/SandboxiePlus/version.h b/SandboxiePlus/version.h index 24fbad8d..8eabf5ee 100644 --- a/SandboxiePlus/version.h +++ b/SandboxiePlus/version.h @@ -1,8 +1,8 @@ #pragma once #define VERSION_MJR 1 -#define VERSION_MIN 0 -#define VERSION_REV 10 +#define VERSION_MIN 1 +#define VERSION_REV 0 #define VERSION_UPD 0 #ifndef STR