aboutsummaryrefslogtreecommitdiff
path: root/zenserver/testing/launch.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-01-24 22:43:18 +0100
committerStefan Boberg <[email protected]>2023-01-24 22:48:03 +0100
commit4eed3f1730c6c018d5970edb90921ba3e44f7d87 (patch)
tree910e61323e45748a3a3560b6f0619ba097e858db /zenserver/testing/launch.cpp
parentremoved HttpLaunchService and related code (diff)
downloadzen-4eed3f1730c6c018d5970edb90921ba3e44f7d87.tar.xz
zen-4eed3f1730c6c018d5970edb90921ba3e44f7d87.zip
removed HttpLaunchService and related code
this was used for testing but is no longer wanted in this form
Diffstat (limited to 'zenserver/testing/launch.cpp')
-rw-r--r--zenserver/testing/launch.cpp565
1 files changed, 0 insertions, 565 deletions
diff --git a/zenserver/testing/launch.cpp b/zenserver/testing/launch.cpp
deleted file mode 100644
index b26f9e437..000000000
--- a/zenserver/testing/launch.cpp
+++ /dev/null
@@ -1,565 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#include "launch.h"
-
-#if ZEN_WITH_EXEC_SERVICES
-
-# include <zencore/compactbinary.h>
-# include <zencore/compactbinarybuilder.h>
-# include <zencore/compress.h>
-# include <zencore/filesystem.h>
-# include <zencore/fmtutils.h>
-# include <zencore/iobuffer.h>
-# include <zencore/iohash.h>
-# include <zencore/logging.h>
-# include <zencore/windows.h>
-# include <zenstore/cidstore.h>
-
-ZEN_THIRD_PARTY_INCLUDES_START
-# include <AccCtrl.h>
-# include <AclAPI.h>
-# include <UserEnv.h>
-# include <atlbase.h>
-# include <sddl.h>
-ZEN_THIRD_PARTY_INCLUDES_END
-# pragma comment(lib, "UserEnv.lib")
-
-# include <filesystem>
-# include <span>
-
-using namespace std::literals;
-
-namespace zen {
-
-struct BasicJob
-{
-public:
- BasicJob() = default;
- ~BasicJob();
-
- void SetWorkingDirectory(const std::filesystem::path& WorkingDirectory) { m_WorkingDirectory = WorkingDirectory; }
- bool SpawnJob(std::filesystem::path ExePath, std::wstring CommandLine);
- bool Wait(uint32_t TimeoutMs = ~0);
- int ExitCode();
-
-private:
- std::filesystem::path m_WorkingDirectory;
- int m_ProcessId = 0;
- CHandle m_ProcessHandle;
-};
-
-BasicJob::~BasicJob()
-{
- Wait();
-}
-
-bool
-BasicJob::SpawnJob(std::filesystem::path ExePath, std::wstring CommandLine)
-{
- STARTUPINFOEX StartupInfo = {sizeof(STARTUPINFOEX)};
- PROCESS_INFORMATION ProcessInfo{};
-
- std::wstring ExePathNative = ExePath.native();
- std::wstring WorkingDirNative = m_WorkingDirectory.native();
-
- BOOL Created = ::CreateProcess(ExePathNative.data() /* ApplicationName */,
- CommandLine.data() /* Command Line */,
- nullptr /* Process Attributes */,
- nullptr /* Security Attributes */,
- FALSE /* InheritHandles */,
- 0 /* Flags */,
- nullptr /* Environment */,
- WorkingDirNative.data() /* Current Directory */,
- (LPSTARTUPINFO)&StartupInfo,
- &ProcessInfo);
-
- if (!Created)
- {
- throw std::system_error(::GetLastError(), std::system_category(), fmt::format("Failed to create process '{}'", ExePath).c_str());
- }
-
- m_ProcessId = ProcessInfo.dwProcessId;
- m_ProcessHandle.Attach(ProcessInfo.hProcess);
- ::CloseHandle(ProcessInfo.hThread);
-
- ZEN_INFO("Created process {}", m_ProcessId);
-
- return true;
-}
-
-bool
-BasicJob::Wait(uint32_t TimeoutMs)
-{
- if (!m_ProcessHandle)
- {
- return true;
- }
-
- DWORD WaitResult = WaitForSingleObject(m_ProcessHandle, TimeoutMs);
-
- if (WaitResult == WAIT_TIMEOUT)
- {
- return false;
- }
-
- if (WaitResult == WAIT_OBJECT_0)
- {
- return true;
- }
-
- throw std::runtime_error("Failed wait on process handle");
-}
-
-int
-BasicJob::ExitCode()
-{
- DWORD Ec = 0;
- BOOL Success = GetExitCodeProcess(m_ProcessHandle, &Ec);
-
- if (!Success)
- {
- ZEN_WARN("failed getting exit code");
- }
-
- if (Ec == STILL_ACTIVE)
- {
- ZEN_WARN("getting exit code but process is STILL_ACTIVE");
- }
-
- return gsl::narrow_cast<int>(Ec);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-struct SandboxedJob
-{
- SandboxedJob() = default;
- ~SandboxedJob() = default;
-
- void SetWorkingDirectory(const std::filesystem::path& WorkingDirectory) { m_WorkingDirectory = WorkingDirectory; }
- void Initialize(std::string_view AppContainerId);
- bool SpawnJob(std::filesystem::path ExePath);
- void AddWhitelistFile(const std::filesystem::path& FilePath) { m_WhitelistFiles.push_back(FilePath); }
-
-private:
- bool GrantNamedObjectAccess(PWSTR Name, SE_OBJECT_TYPE Type, ACCESS_MASK AccessMask, bool Recursive);
-
- std::filesystem::path m_WorkingDirectory;
- std::vector<std::filesystem::path> m_WhitelistFiles;
- std::vector<std::wstring> m_WhitelistRegistryKeys;
- PSID m_AppContainerSid = nullptr;
- bool m_IsInitialized = false;
-};
-
-bool
-SandboxedJob::GrantNamedObjectAccess(PWSTR ObjectName, SE_OBJECT_TYPE ObjectType, ACCESS_MASK AccessMask, bool Recursive)
-{
- DWORD Status;
- PACL NewAcl = nullptr;
-
- DWORD grfInhericance = 0;
-
- if (Recursive)
- {
- grfInhericance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
- }
-
- EXPLICIT_ACCESS Access{.grfAccessPermissions = AccessMask,
- .grfAccessMode = GRANT_ACCESS,
- .grfInheritance = grfInhericance,
- .Trustee = {.pMultipleTrustee = nullptr,
- .MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE,
- .TrusteeForm = TRUSTEE_IS_SID,
- .TrusteeType = TRUSTEE_IS_GROUP,
- .ptstrName = (PWSTR)m_AppContainerSid}};
-
- PACL OldAcl = nullptr;
-
- Status = GetNamedSecurityInfo(ObjectName /* ObjectName */,
- ObjectType /* ObjectType */,
- DACL_SECURITY_INFORMATION /* SecurityInfo */,
- nullptr /* ppsidOwner */,
- nullptr /* ppsidGroup */,
- &OldAcl /* ppDacl */,
- nullptr /* ppSacl */,
- nullptr /* ppSecurityDescriptor */);
- if (Status != ERROR_SUCCESS)
- return false;
-
- Status = SetEntriesInAcl(1 /* CountOfExplicitEntries */, &Access /* pListOfExplicitEntries */, OldAcl, &NewAcl);
- if (Status != ERROR_SUCCESS)
- return false;
-
- Status = SetNamedSecurityInfo(ObjectName /* ObjectName */,
- ObjectType /* ObjectType */,
- DACL_SECURITY_INFORMATION /*SecurityInfo */,
- nullptr /* psidOwner */,
- nullptr /* psidGroup */,
- NewAcl /* pDacl */,
- nullptr /* pSacl */);
- if (NewAcl)
- ::LocalFree(NewAcl);
-
- return Status == ERROR_SUCCESS;
-}
-
-void
-SandboxedJob::Initialize(std::string_view AppContainerId)
-{
- if (m_IsInitialized)
- {
- return;
- }
-
- std::wstring ContainerName = zen::Utf8ToWide(AppContainerId);
-
- HRESULT hRes = ::CreateAppContainerProfile(ContainerName.c_str(),
- ContainerName.c_str() /* Display Name */,
- ContainerName.c_str() /* Description */,
- nullptr /* Capabilities */,
- 0 /* Capability Count */,
- &m_AppContainerSid);
-
- if (FAILED(hRes))
- {
- hRes = ::DeriveAppContainerSidFromAppContainerName(ContainerName.c_str(), &m_AppContainerSid);
-
- if (FAILED(hRes))
- {
- ZEN_ERROR("Failed creating app container SID");
- }
- }
-
- // Debugging context
-
- PWSTR Str = nullptr;
- ::ConvertSidToStringSid(m_AppContainerSid, &Str);
-
- ZEN_INFO("AppContainer SID : '{}'", WideToUtf8(Str));
-
- PWSTR Path = nullptr;
- if (SUCCEEDED(::GetAppContainerFolderPath(Str, &Path)))
- {
- ZEN_INFO("AppContainer folder: '{}'", WideToUtf8(Path));
-
- ::CoTaskMemFree(Path);
- }
- ::LocalFree(Str);
-
- m_IsInitialized = true;
-}
-
-bool
-SandboxedJob::SpawnJob(std::filesystem::path ExePath)
-{
- // Build process attributes
-
- SECURITY_CAPABILITIES Sc = {0};
- Sc.AppContainerSid = m_AppContainerSid;
-
- STARTUPINFOEX StartupInfo = {sizeof(STARTUPINFOEX)};
- PROCESS_INFORMATION ProcessInfo{};
- SIZE_T Size = 0;
-
- ::InitializeProcThreadAttributeList(nullptr, 1, 0, &Size);
-
- auto AttrBuffer = std::make_unique<uint8_t[]>(Size);
- StartupInfo.lpAttributeList = reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(AttrBuffer.get());
-
- if (!::InitializeProcThreadAttributeList(StartupInfo.lpAttributeList, 1, 0, &Size))
- {
- return false;
- }
-
- if (!::UpdateProcThreadAttribute(StartupInfo.lpAttributeList,
- 0,
- PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES,
- &Sc,
- sizeof Sc,
- nullptr,
- nullptr))
- {
- return false;
- }
-
- // Set up security for files/folders/registry
-
- for (const std::filesystem::path& File : m_WhitelistFiles)
- {
- std::wstring NativeFileName = File.native();
- GrantNamedObjectAccess(NativeFileName.data(), SE_FILE_OBJECT, FILE_ALL_ACCESS, true);
- }
-
- for (std::wstring& RegKey : m_WhitelistRegistryKeys)
- {
- GrantNamedObjectAccess(RegKey.data(), SE_REGISTRY_WOW64_32KEY, KEY_ALL_ACCESS, true);
- }
-
- std::wstring ExePathNative = ExePath.native();
- std::wstring WorkingDirNative = m_WorkingDirectory.native();
-
- BOOL Created = ::CreateProcess(nullptr /* ApplicationName */,
- ExePathNative.data() /* Command line */,
- nullptr /* Process Attributes */,
- nullptr /* Security Attributes */,
- FALSE /* InheritHandles */,
- EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE /* Flags */,
- nullptr /* Environment */,
- WorkingDirNative.data() /* Current Directory */,
- (LPSTARTUPINFO)&StartupInfo,
- &ProcessInfo);
-
- DeleteProcThreadAttributeList(StartupInfo.lpAttributeList);
-
- if (!Created)
- {
- return false;
- }
-
- ZEN_INFO("Created process {}", ProcessInfo.dwProcessId);
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-HttpLaunchService::HttpLaunchService(CidStore& Store, const std::filesystem::path& SandboxBaseDir)
-: m_Log(logging::Get("exec"))
-, m_CidStore(Store)
-, m_SandboxPath(SandboxBaseDir)
-{
- m_Router.AddPattern("job", "([[:digit:]]+)");
-
- m_Router.RegisterRoute(
- "jobs/{job}",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
-
- switch (HttpReq.RequestVerb())
- {
- case HttpVerb::kGet:
- break;
-
- case HttpVerb::kPost:
- break;
-
- default:
- break;
- }
- },
- HttpVerb::kGet | HttpVerb::kPost);
-
- // Experimental
-
-# if 0
- m_Router.RegisterRoute(
- "jobs/sandbox",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
-
- switch (HttpReq.RequestVerb())
- {
- case HttpVerb::kGet:
- break;
-
- case HttpVerb::kPost:
- {
- SandboxedJob Job;
- Job.Initialize("zen_test");
- Job.SetWorkingDirectory("c:\\temp\\sandbox1");
- Job.AddWhitelistFile("c:\\temp\\sandbox1");
- Job.SpawnJob("c:\\windows\\system32\\cmd.exe");
- }
- break;
-
- default:
- break;
- }
- },
- HttpVerb::kGet | HttpVerb::kPost);
-# endif
-
- m_Router.RegisterRoute(
- "jobs/prep",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
-
- switch (HttpReq.RequestVerb())
- {
- case HttpVerb::kPost:
- {
- // This operation takes the proposed job spec and identifies which
- // chunks are not present on this server. This list is then returned in
- // the "need" list in the response
-
- IoBuffer Payload = HttpReq.ReadPayload();
- CbObject RequestObject = LoadCompactBinaryObject(Payload);
-
- std::vector<IoHash> NeedList;
-
- for (auto Entry : RequestObject["files"sv])
- {
- CbObjectView Ob = Entry.AsObjectView();
-
- const IoHash FileHash = Ob["hash"sv].AsHash();
-
- if (!m_CidStore.FindChunkByCid(FileHash))
- {
- ZEN_DEBUG("NEED: {} {} {}", FileHash, Ob["file"sv].AsString(), Ob["size"sv].AsUInt64());
-
- NeedList.push_back(FileHash);
- }
- }
-
- CbObjectWriter Cbo;
- Cbo.BeginArray("need");
-
- for (const IoHash& Hash : NeedList)
- {
- Cbo << Hash;
- }
-
- Cbo.EndArray();
- CbObject Response = Cbo.Save();
-
- return HttpReq.WriteResponse(HttpResponseCode::OK, Response);
- }
- break;
-
- default:
- break;
- }
- },
- HttpVerb::kPost);
-
- m_Router.RegisterRoute(
- "jobs",
- [this](HttpRouterRequest& Req) {
- HttpServerRequest& HttpReq = Req.ServerRequest();
-
- switch (HttpReq.RequestVerb())
- {
- case HttpVerb::kGet:
- break;
-
- case HttpVerb::kPost:
- {
- IoBuffer Payload = HttpReq.ReadPayload();
- CbObject RequestObject = LoadCompactBinaryObject(Payload);
-
- bool AllOk = true;
-
- std::vector<IoHash> NeedList;
-
- std::filesystem::path SandboxDir{CreateNewSandbox()};
-
- ZEN_DEBUG("setting up job in sandbox '{}'", SandboxDir);
-
- zen::DeleteDirectories(SandboxDir);
- zen::CreateDirectories(SandboxDir);
-
- for (auto Entry : RequestObject["files"sv])
- {
- CbObjectView Ob = Entry.AsObjectView();
-
- std::string_view FileName = Ob["file"sv].AsString();
- const IoHash FileHash = Ob["hash"sv].AsHash();
- uint64_t FileSize = Ob["size"sv].AsUInt64();
-
- if (IoBuffer Chunk = m_CidStore.FindChunkByCid(FileHash); !Chunk)
- {
- ZEN_DEBUG("MISSING: {} {} {}", FileHash, FileName, FileSize);
- AllOk = false;
-
- NeedList.push_back(FileHash);
- }
- else
- {
- std::filesystem::path FullPath = SandboxDir / FileName;
-
- IoHash RawHash;
- uint64_t RawSize;
- CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Chunk), RawHash, RawSize);
- ZEN_ASSERT(Compressed);
- ZEN_ASSERT(FileHash == RawHash);
- CompositeBuffer CompositeBuffer = Compressed.DecompressToComposite();
- std::span<const SharedBuffer> Segments = CompositeBuffer.GetSegments();
- std::vector<IoBuffer> Chunks(Segments.size());
- std::vector<IoBuffer*> ChunkPtrs(Segments.size());
- for (size_t Index = 0; Index < Segments.size(); ++Index)
- {
- Chunks[Index] = std::move(Segments[Index].AsIoBuffer());
- ChunkPtrs[Index] = &Chunks[Index];
- }
-
- zen::WriteFile(FullPath, ChunkPtrs.data(), ChunkPtrs.size());
- }
- }
-
- if (!AllOk)
- {
- // TODO: Could report all the missing pieces in the response here
- return HttpReq.WriteResponse(HttpResponseCode::NotFound);
- }
-
- std::string Executable8{RequestObject["cmd"].AsString()};
- std::string Args8{RequestObject["args"].AsString()};
-
- std::wstring Executable = Utf8ToWide(Executable8);
- std::wstring Args = Utf8ToWide(Args8);
-
- ZEN_DEBUG("spawning job in sandbox '{}': '{}' '{}'", SandboxDir, Executable8, Args8);
-
- std::filesystem::path ExeName = SandboxDir / Executable;
-
- BasicJob Job;
- Job.SetWorkingDirectory(SandboxDir);
- Job.SpawnJob(ExeName, Args);
- Job.Wait();
-
- CbObjectWriter Response;
-
- Response << "exitcode" << Job.ExitCode();
-
- return HttpReq.WriteResponse(HttpResponseCode::OK, Response.Save());
- }
- break;
-
- default:
- break;
- }
- },
- HttpVerb::kGet | HttpVerb::kPost);
-}
-
-HttpLaunchService::~HttpLaunchService()
-{
-}
-
-const char*
-HttpLaunchService::BaseUri() const
-{
- return "/exec/";
-}
-
-void
-HttpLaunchService::HandleRequest(HttpServerRequest& Request)
-{
- if (m_Router.HandleRequest(Request) == false)
- {
- ZEN_WARN("No route found for {0}", Request.RelativeUri());
- }
-}
-
-std::filesystem::path
-HttpLaunchService::CreateNewSandbox()
-{
- std::string UniqueId = std::to_string(++m_SandboxCount);
- std::filesystem::path Path = m_SandboxPath / UniqueId;
- zen::CreateDirectories(Path);
- return Path;
-}
-
-} // namespace zen
-
-#endif // ZEN_WITH_EXEC_SERVICES