diff options
| author | Stefan Boberg <[email protected]> | 2025-09-27 22:41:09 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2025-09-27 22:41:09 +0200 |
| commit | 6c036989c9b74affc98c5f29e574375c59cbb0d2 (patch) | |
| tree | efa4fc9c7b02b34330bd281058c6ca2b98b29c01 /src/zenmaster/sandboxwin.cpp | |
| parent | add zen master cmd (diff) | |
| download | zen-6c036989c9b74affc98c5f29e574375c59cbb0d2.tar.xz zen-6c036989c9b74affc98c5f29e574375c59cbb0d2.zip | |
minor additions
Diffstat (limited to 'src/zenmaster/sandboxwin.cpp')
| -rw-r--r-- | src/zenmaster/sandboxwin.cpp | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/zenmaster/sandboxwin.cpp b/src/zenmaster/sandboxwin.cpp new file mode 100644 index 000000000..6377fda0b --- /dev/null +++ b/src/zenmaster/sandboxwin.cpp @@ -0,0 +1,163 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +// AppContainerLaunch.cpp +#include <Aclapi.h> +#include <sddl.h> +#include <stdio.h> +#include <userenv.h> +#include <windows.h> + +#pragma comment(lib, "userenv.lib") +#pragma comment(lib, "Advapi32.lib") + +// Helper: add (or merge) an ACE for a SID on a directory +DWORD +GrantFolderAccessToSid(LPCWSTR path, PSID sid, DWORD accessMask) +{ + PACL oldDacl = nullptr, newDacl = nullptr; + PSECURITY_DESCRIPTOR sd = nullptr; + + DWORD err = GetNamedSecurityInfoW(path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr, &oldDacl, nullptr, &sd); + if (err != ERROR_SUCCESS) + return err; + + EXPLICIT_ACCESSW ea = {}; + ea.grfAccessMode = GRANT_ACCESS; + ea.grfAccessPermissions = accessMask; + ea.grfInheritance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; // fine for AppContainer SIDs + ea.Trustee.ptstrName = (LPWSTR)sid; + + err = SetEntriesInAclW(1, &ea, oldDacl, &newDacl); + if (err == ERROR_SUCCESS) + { + err = SetNamedSecurityInfoW((LPWSTR)path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr, newDacl, nullptr); + } + + if (newDacl) + LocalFree(newDacl); + + if (sd) + LocalFree(sd); + + return err; +} + +int +zwmain() +{ + // 1) Choose a stable AppContainer name for your app/sandbox + LPCWSTR containerName = L"com.epicgames.zenmaster.sandbox"; + LPCWSTR displayName = L"zenmaster sandbox"; + LPCWSTR description = L"Sandbox for running restricted zenserver processes"; + + // 1a) Create the profile once (ok if it already exists) + // Requires elevation the first time you create it. If it exists, creation will fail with ERROR_ALREADY_EXISTS—which is fine. + HRESULT hr = CreateAppContainerProfile(containerName, displayName, description, nullptr, 0, nullptr); + if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) + { + hr = S_OK; + } + if (FAILED(hr)) + { + wprintf(L"CreateAppContainerProfile failed: 0x%08X\n", hr); + return 1; + } + + // 1b) Get the AppContainer SID + PSID appContainerSid = nullptr; + hr = DeriveAppContainerSidFromAppContainerName(containerName, &appContainerSid); + if (FAILED(hr)) + { + wprintf(L"DeriveAppContainerSidFromAppContainerName failed: 0x%08X\n", hr); + return 1; + } + + // 2) Grant access to specific folders (repeat for each allowed path) + // Example: allow read/write/list/execute on D:\Allowed\WorkDir + LPCWSTR allowedFolder = L"D:\\Allowed\\WorkDir"; + CreateDirectoryW(allowedFolder, nullptr); // ensure it exists (optional) + + DWORD fsAccess = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | READ_CONTROL | SYNCHRONIZE; + + DWORD err = GrantFolderAccessToSid(allowedFolder, appContainerSid, fsAccess); + if (err != ERROR_SUCCESS) + { + wprintf(L"GrantFolderAccessToSid failed: %lu\n", err); + FreeSid(appContainerSid); + return 1; + } + + // 3) Prepare SECURITY_CAPABILITIES with the AppContainer SID (no broad capabilities) + SID_AND_ATTRIBUTES capSidAndAttrs = {}; // none for now + SECURITY_CAPABILITIES secCaps = {}; + secCaps.AppContainerSid = appContainerSid; + secCaps.Capabilities = nullptr; // you can add capability SIDs here if needed + secCaps.CapabilityCount = 0; + secCaps.Reserved = 0; + + // 4) Build attribute list with PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES + SIZE_T attrListSize = 0; + InitializeProcThreadAttributeList(nullptr, 1, 0, &attrListSize); + LPPROC_THREAD_ATTRIBUTE_LIST attrList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, attrListSize); + + if (!attrList) + { + wprintf(L"HeapAlloc failed\n"); + FreeSid(appContainerSid); + return 1; + } + + if (!InitializeProcThreadAttributeList(attrList, 1, 0, &attrListSize)) + { + wprintf(L"InitializeProcThreadAttributeList failed: %lu\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, attrList); + FreeSid(appContainerSid); + return 1; + } + + if (!UpdateProcThreadAttribute(attrList, 0, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, &secCaps, sizeof(secCaps), nullptr, nullptr)) + { + wprintf(L"UpdateProcThreadAttribute failed: %lu\n", GetLastError()); + DeleteProcThreadAttributeList(attrList); + HeapFree(GetProcessHeap(), 0, attrList); + FreeSid(appContainerSid); + return 1; + } + + // 5) Launch the target EXE in the AppContainer + STARTUPINFOEXW si = {}; + si.StartupInfo.cb = sizeof(si); + si.lpAttributeList = attrList; + + PROCESS_INFORMATION pi = {}; + wchar_t cmdline[] = L"C:\\Path\\To\\YourChild.exe"; // child process + BOOL ok = CreateProcessW(nullptr, + cmdline, + nullptr, + nullptr, + FALSE, + EXTENDED_STARTUPINFO_PRESENT, + nullptr, // environment (null = inherit) + allowedFolder, // set working dir to an allowed folder (optional but handy) + (LPSTARTUPINFOW)&si, + &pi); + + if (!ok) + { + wprintf(L"CreateProcessW failed: %lu\n", GetLastError()); + } + else + { + wprintf(L"Launched pid=%lu in AppContainer.\n", pi.dwProcessId); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + + // Cleanup + DeleteProcThreadAttributeList(attrList); + HeapFree(GetProcessHeap(), 0, attrList); + FreeSid(appContainerSid); + return ok ? 0 : 1; +} |