aboutsummaryrefslogtreecommitdiff
path: root/src/zenmaster/sandboxwin.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-09-27 22:41:09 +0200
committerStefan Boberg <[email protected]>2025-09-27 22:41:09 +0200
commit6c036989c9b74affc98c5f29e574375c59cbb0d2 (patch)
treeefa4fc9c7b02b34330bd281058c6ca2b98b29c01 /src/zenmaster/sandboxwin.cpp
parentadd zen master cmd (diff)
downloadzen-6c036989c9b74affc98c5f29e574375c59cbb0d2.tar.xz
zen-6c036989c9b74affc98c5f29e574375c59cbb0d2.zip
minor additions
Diffstat (limited to 'src/zenmaster/sandboxwin.cpp')
-rw-r--r--src/zenmaster/sandboxwin.cpp163
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;
+}