From 372cf04a528d0dc69ef55efc7b63e7372bb11ca3 Mon Sep 17 00:00:00 2001 From: DavidXanatos <3890945+DavidXanatos@users.noreply.github.com> Date: Sat, 22 Jul 2023 21:43:39 +0200 Subject: [PATCH] 1.10.1 --- CHANGELOG.md | 1 + Sandboxie/core/dll/file.c | 11 ++- Sandboxie/core/dll/file_copy.c | 109 ++++++++++++++++++++++++ SandboxiePlus/QSbieAPI/Helpers/NtIO.cpp | 55 ++++++++---- 4 files changed, 159 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a7f8460..281e324a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - fixed Remove Sandbox only deletes the contents of the sandbox when an application is running in the sandbox [#3118](https://github.com/sandboxie-plus/Sandboxie/issues/3118) - fixed crash issue with not peroeprly termianted script engine [#3120](https://github.com/sandboxie-plus/Sandboxie/issues/3120) - fixed ImDisk under Sandboxie supervision causes SBIE2337 and sometimes BSoD [#1092)(https://github.com/sandboxie-plus/Sandboxie/issues/1092) +- fixed Snapshots don't merge duplicate directory junctions [#3016](https://github.com/sandboxie-plus/Sandboxie/issues/3016) diff --git a/Sandboxie/core/dll/file.c b/Sandboxie/core/dll/file.c index c87f69cd..4924e6e9 100644 --- a/Sandboxie/core/dll/file.c +++ b/Sandboxie/core/dll/file.c @@ -189,6 +189,10 @@ static NTSTATUS File_MigrateFile( const WCHAR *TruePath, const WCHAR *CopyPath, BOOLEAN IsWritePath, BOOLEAN WithContents); +static NTSTATUS File_MigrateJunction( + const WCHAR *TruePath, const WCHAR *CopyPath, + BOOLEAN IsWritePath); + static NTSTATUS File_CopyShortName( const WCHAR *TruePath, const WCHAR *CopyPath); @@ -3382,7 +3386,12 @@ ReparseLoop: // write access, or else it would have been handled earlier already) // - if (CreateDisposition == FILE_OPEN || + if (FileType & TYPE_REPARSE_POINT) { + + status = File_MigrateJunction( + TruePath, CopyPath, IsWritePath); + + } else if (CreateDisposition == FILE_OPEN || CreateDisposition == FILE_OPEN_IF || TruePathColon) { diff --git a/Sandboxie/core/dll/file_copy.c b/Sandboxie/core/dll/file_copy.c index c726db94..81b38869 100644 --- a/Sandboxie/core/dll/file_copy.c +++ b/Sandboxie/core/dll/file_copy.c @@ -466,3 +466,112 @@ _FX NTSTATUS File_MigrateFile( return status; } + + +//--------------------------------------------------------------------------- +// File_MigrateJunction +//--------------------------------------------------------------------------- + + +_FX NTSTATUS File_MigrateJunction( + const WCHAR* TruePath, const WCHAR* CopyPath, + BOOLEAN IsWritePath) +{ + NTSTATUS status; + HANDLE TrueHandle, CopyHandle; + OBJECT_ATTRIBUTES objattrs; + UNICODE_STRING objname; + IO_STATUS_BLOCK IoStatusBlock; + FILE_NETWORK_OPEN_INFORMATION open_info; + + InitializeObjectAttributes( + &objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, Secure_NormalSD); + + // + // open TruePath. if we get a sharing violation trying to open it, + // try to get the driver to open it bypassing share access. if even + // this fails, then we can't copy the data, but can still create an + // empty file + // + + RtlInitUnicodeString(&objname, TruePath); + + status = __sys_NtCreateFile( + &TrueHandle, FILE_GENERIC_READ, &objattrs, &IoStatusBlock, + NULL, 0, FILE_SHARE_VALID_FLAGS, + FILE_OPEN, FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + + /*if (IsWritePath && status == STATUS_ACCESS_DENIED) + status = STATUS_SHARING_VIOLATION; + + if (status == STATUS_SHARING_VIOLATION) { + + status = SbieApi_OpenFile(&TrueHandle, TruePath); + }*/ + + if (!NT_SUCCESS(status)) + return status; + + // + // query attributes and size of the TruePath file + // + + status = __sys_NtQueryInformationFile( + TrueHandle, &IoStatusBlock, &open_info, + sizeof(FILE_NETWORK_OPEN_INFORMATION), FileNetworkOpenInformation); + + // + // Get the reparse point data from the source + // + + BYTE buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; // We need a large buffer + REPARSE_DATA_BUFFER* reparseDataBuffer = (REPARSE_DATA_BUFFER*)buf; + status = __sys_NtFsControlFile(TrueHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_GET_REPARSE_POINT, NULL, 0, reparseDataBuffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + + if (!NT_SUCCESS(status)) + return status; + + // + // Create the destination file with reparse point data + // + + RtlInitUnicodeString(&objname, CopyPath); + + status = __sys_NtCreateFile( + &CopyHandle, FILE_GENERIC_WRITE, &objattrs, &IoStatusBlock, + NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_VALID_FLAGS, + FILE_CREATE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT, + NULL, 0); + + if (!NT_SUCCESS(status)) + return status; + + // + // Set the reparse point data to the destination + // + + #define REPARSE_MOUNTPOINT_HEADER_SIZE 8 + status = __sys_NtFsControlFile(CopyHandle, NULL, NULL, NULL, &IoStatusBlock, FSCTL_SET_REPARSE_POINT, reparseDataBuffer, REPARSE_MOUNTPOINT_HEADER_SIZE + reparseDataBuffer->ReparseDataLength, NULL, 0); + + // + // set information on the CopyPath file + // + + if (NT_SUCCESS(status)) { + + FILE_BASIC_INFORMATION info; + + info.CreationTime.QuadPart = open_info.CreationTime.QuadPart; + info.LastAccessTime.QuadPart = open_info.LastAccessTime.QuadPart; + info.LastWriteTime.QuadPart = open_info.LastWriteTime.QuadPart; + info.ChangeTime.QuadPart = open_info.ChangeTime.QuadPart; + info.FileAttributes = open_info.FileAttributes; + + status = File_SetAttributes(CopyHandle, CopyPath, &info); + } + + NtClose(TrueHandle); + NtClose(CopyHandle); + + return status; +} diff --git a/SandboxiePlus/QSbieAPI/Helpers/NtIO.cpp b/SandboxiePlus/QSbieAPI/Helpers/NtIO.cpp index af59052c..4eb61bc3 100644 --- a/SandboxiePlus/QSbieAPI/Helpers/NtIO.cpp +++ b/SandboxiePlus/QSbieAPI/Helpers/NtIO.cpp @@ -98,6 +98,34 @@ NTSTATUS NtIo_RemoveJunction(POBJECT_ATTRIBUTES objattrs) return status; } +NTSTATUS NtIo_DeleteFolderRecursivelyImpl(POBJECT_ATTRIBUTES objattrs, bool (*cb)(const WCHAR* info, void* param), void* param); + +NTSTATUS NtIo_DeleteFileImpl(ULONG FileAttributes, OBJECT_ATTRIBUTES* attr, bool (*cb)(const WCHAR* info, void* param), void* param) +{ + NTSTATUS status; + + if (FileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) + NtIo_RemoveProblematicAttributes(attr); + + if (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + status = NtIo_RemoveJunction(attr); + else if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + status = NtIo_DeleteFolderRecursivelyImpl(attr, cb, param); + + if (NT_SUCCESS(status)) + status = NtDeleteFile(attr); + + return status; +} + +NTSTATUS NtIo_DeleteFileImpl(SNtObject& ntObject, bool (*cb)(const WCHAR* info, void* param), void* param) +{ + FILE_BASIC_INFORMATION info = { 0 }; + NtQueryAttributesFile(&ntObject.attr, &info); + + return NtIo_DeleteFileImpl(info.FileAttributes, &ntObject.attr, cb, param); +} + NTSTATUS NtIo_DeleteFolderRecursivelyImpl(POBJECT_ATTRIBUTES objattrs, bool (*cb)(const WCHAR* info, void* param), void* param) { NTSTATUS status = STATUS_SUCCESS; @@ -147,16 +175,7 @@ NTSTATUS NtIo_DeleteFolderRecursivelyImpl(POBJECT_ATTRIBUTES objattrs, bool (*cb SNtObject ntFoundObject(FileName, Handle); - if (FileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) - NtIo_RemoveProblematicAttributes(&ntFoundObject.attr); - - if (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) - status = NtIo_RemoveJunction(&ntFoundObject.attr); - else if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) - status = NtIo_DeleteFolderRecursivelyImpl(&ntFoundObject.attr, cb, param); - - if (NT_SUCCESS(status)) - status = NtDeleteFile(&ntFoundObject.attr); + status = NtIo_DeleteFileImpl(FileAttributes, &ntFoundObject.attr, cb, param); } NtClose(Handle); @@ -255,7 +274,7 @@ BOOLEAN NtIo_FileExists(POBJECT_ATTRIBUTES objattrs) IO_STATUS_BLOCK Iosb; HANDLE handle; - status = NtCreateFile(&handle, SYNCHRONIZE, objattrs, &Iosb, NULL, 0, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + status = NtCreateFile(&handle, SYNCHRONIZE, objattrs, &Iosb, NULL, 0, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT, NULL, 0); if (NT_SUCCESS(status)) { // STATUS_OBJECT_NAME_NOT_FOUND // STATUS_OBJECT_PATH_NOT_FOUND @@ -325,11 +344,15 @@ NTSTATUS NtIo_MergeFolder(POBJECT_ATTRIBUTES src_objattrs, POBJECT_ATTRIBUTES de //if (FileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) // NtIo_RemoveProblematicAttributes(&ntFoundObject.attr); - if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - if (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + if (FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + if (TargetExists) + status = NtIo_DeleteFileImpl(ntDestObject, cb, param); + if (NT_SUCCESS(status)) status = NtIo_RenameJunction(&ntSrcObject.attr, dest_objattrs, FileName.c_str()); - else if (TargetExists) + } + else if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (TargetExists) status = NtIo_MergeFolder(&ntSrcObject.attr, &ntDestObject.attr, cb, param); else status = NtIo_RenameFolder(&ntSrcObject.attr, dest_objattrs, FileName.c_str()); @@ -337,7 +360,7 @@ NTSTATUS NtIo_MergeFolder(POBJECT_ATTRIBUTES src_objattrs, POBJECT_ATTRIBUTES de else { if (TargetExists) - status = NtDeleteFile(&ntDestObject.attr); + status = NtIo_DeleteFileImpl(ntDestObject, cb, param); if (NT_SUCCESS(status)) status = NtIo_RenameFile(&ntSrcObject.attr, dest_objattrs, FileName.c_str()); }