This commit is contained in:
DavidXanatos 2022-02-05 15:17:33 +01:00
parent 46904667b0
commit 1d29ff173e
31 changed files with 4023 additions and 1391 deletions

View File

@ -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)

View File

@ -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

View File

@ -96,6 +96,7 @@
<OmitFramePointers />
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>false</TreatWarningAsError>
<PreprocessorDefinitions>WITH_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies>ntdll.lib;uuid.lib;kernel32.lib</AdditionalDependencies>
@ -117,6 +118,7 @@
<CompileAs>Default</CompileAs>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<TreatWarningAsError>false</TreatWarningAsError>
<PreprocessorDefinitions>WITH_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalDependencies>ntdll.lib;uuid.lib;kernel32.lib</AdditionalDependencies>
@ -243,6 +245,12 @@
<ClCompile Include="dump.c" />
<ClCompile Include="event.c" />
<ClCompile Include="file.c" />
<ClCompile Include="file_del.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="file_dir.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
@ -279,6 +287,18 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="file_recovery.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="file_snapshots.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="gdi.c" />
<ClCompile Include="gui.c" />
<ClCompile Include="guiclass.c" />
@ -291,6 +311,7 @@
<ClCompile Include="guimsg.c" />
<ClCompile Include="guiprop.c" />
<ClCompile Include="guititle.c" />
<ClCompile Include="handle.c" />
<ClCompile Include="hook_inst.c" />
<ClCompile Include="hook_tramp.c" />
<ClCompile Include="includes.c" />
@ -305,6 +326,12 @@
<ClCompile Include="ipstore_enum.cpp" />
<ClCompile Include="ipstore_impl.cpp" />
<ClCompile Include="key.c" />
<ClCompile Include="key_del.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="key_merge.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
@ -427,6 +454,7 @@
<ClInclude Include="dump.h" />
<ClInclude Include="guidlg.h" />
<ClInclude Include="gui_p.h" />
<ClInclude Include="handle.h" />
<ClInclude Include="hook.h" />
<ClInclude Include="ipstore_enum.h" />
<ClInclude Include="ipstore_impl.h" />

View File

@ -6,11 +6,9 @@
<ClCompile Include="custom.c" />
<ClCompile Include="dllmem.c" />
<ClCompile Include="dllpath.c" />
<ClCompile Include="event.c" />
<ClCompile Include="includes.c" />
<ClCompile Include="lsa.c" />
<ClCompile Include="mscoree.c" />
<ClCompile Include="obj.c" />
<ClCompile Include="pdh.c" />
<ClCompile Include="proc.c" />
<ClCompile Include="secure.c" />
@ -218,6 +216,25 @@
<ClCompile Include="dump.c">
<Filter>debug</Filter>
</ClCompile>
<ClCompile Include="file_del.c">
<Filter>file</Filter>
</ClCompile>
<ClCompile Include="key_del.c">
<Filter>key</Filter>
</ClCompile>
<ClCompile Include="obj.c">
<Filter>obj</Filter>
</ClCompile>
<ClCompile Include="handle.c">
<Filter>obj</Filter>
</ClCompile>
<ClCompile Include="event.c" />
<ClCompile Include="file_recovery.c">
<Filter>file</Filter>
</ClCompile>
<ClCompile Include="file_snapshots.c">
<Filter>file</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="advapi.h" />
@ -255,9 +272,6 @@
<ClInclude Include="sbiedll.h">
<Filter>api</Filter>
</ClInclude>
<ClInclude Include="obj.h">
<Filter>com</Filter>
</ClInclude>
<ClInclude Include="..\..\common\stream.h">
<Filter>common</Filter>
</ClInclude>
@ -312,6 +326,12 @@
<ClInclude Include="dump.h">
<Filter>debug</Filter>
</ClInclude>
<ClInclude Include="obj.h">
<Filter>obj</Filter>
</ClInclude>
<ClInclude Include="handle.h">
<Filter>obj</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="resource.rc" />
@ -373,6 +393,9 @@
<Filter Include="debug">
<UniqueIdentifier>{db0f9820-8908-4325-96f9-69c82fa9e268}</UniqueIdentifier>
</Filter>
<Filter Include="obj">
<UniqueIdentifier>{05955a21-494a-4624-854e-d7c9b1e33401}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Midl Include="pstore.idl">

View File

@ -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);
}
//---------------------------------------------------------------------------

View File

@ -43,6 +43,7 @@
int Debug_Init(void);
void DbgPrint(const char* format, ...);
void DbgTrace(const char* format, ...);
#endif WITH_DEBUG

View File

@ -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);

View File

@ -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
//

View File

@ -24,6 +24,7 @@
#include "dll.h"
#include "common/pool.h"
#include <stdio.h>
#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

File diff suppressed because it is too large Load Diff

View File

@ -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)) {

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// 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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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++;
}
}
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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))

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//
// 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;
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// 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++;
}
}

271
Sandboxie/core/dll/handle.c Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// Handle
//---------------------------------------------------------------------------
#define NOGDI
#include "dll.h"
#include "handle.h"
#include <stdio.h>
#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);
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#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 */

View File

@ -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)) {

View File

@ -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 <stdio.h>
#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;

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// 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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -16,10 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#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;
}

View File

@ -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);

View File

@ -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;

View File

@ -323,6 +323,8 @@ struct SBoxDataFile
QList<SBoxDataFile> CSandBox__BoxDataFiles = QList<SBoxDataFile>()
<< SBoxDataFile("RegHive", true, false)
<< SBoxDataFile("RegPaths.dat", false, false)
<< SBoxDataFile("FilePaths.dat", false, true)
;
bool CSandBox::IsInitialized() const

View File

@ -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