From 15ee49f88c2159d7ac88599fe32ce2f6b24cb002 Mon Sep 17 00:00:00 2001 From: rramachandra Date: Fri, 7 Nov 2025 23:06:06 -0600 Subject: [PATCH 1/2] Initial commit based --- .../SandboxIPCSample/win32/.gitignore | 57 +++ .../SandboxIPCSample/win32/IPCDemo.sln | 102 +++++ .../SandboxIPCSample/win32/README.md | 127 ++++++ .../SandboxIPCSample/win32/demo_child.cpp | 210 +++++++++ .../SandboxIPCSample/win32/demo_child.vcxproj | 100 +++++ .../SandboxIPCSample/win32/demo_parent.cpp | 400 ++++++++++++++++++ .../win32/demo_parent.vcxproj | 100 +++++ 7 files changed, 1096 insertions(+) create mode 100644 DeveloperLabs/SandboxIPCSample/win32/.gitignore create mode 100644 DeveloperLabs/SandboxIPCSample/win32/IPCDemo.sln create mode 100644 DeveloperLabs/SandboxIPCSample/win32/README.md create mode 100644 DeveloperLabs/SandboxIPCSample/win32/demo_child.cpp create mode 100644 DeveloperLabs/SandboxIPCSample/win32/demo_child.vcxproj create mode 100644 DeveloperLabs/SandboxIPCSample/win32/demo_parent.cpp create mode 100644 DeveloperLabs/SandboxIPCSample/win32/demo_parent.vcxproj diff --git a/DeveloperLabs/SandboxIPCSample/win32/.gitignore b/DeveloperLabs/SandboxIPCSample/win32/.gitignore new file mode 100644 index 0000000..ffde08e --- /dev/null +++ b/DeveloperLabs/SandboxIPCSample/win32/.gitignore @@ -0,0 +1,57 @@ +# Visual Studio +.vs/ +bin/ +obj/ +*.user +*.suo +*.userosscache +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Build results +*.exe +*.dll +*.pdb +*.ilk +*.obj +*.iobj +*.pch +*.ipdb +*.idb +*.lib +*.exp + +# Package files +*.appx +*.appxbundle +*.msix +*.msixbundle +Package/ + +# Test certificates +*.pfx +*.cer diff --git a/DeveloperLabs/SandboxIPCSample/win32/IPCDemo.sln b/DeveloperLabs/SandboxIPCSample/win32/IPCDemo.sln new file mode 100644 index 0000000..26ffd07 --- /dev/null +++ b/DeveloperLabs/SandboxIPCSample/win32/IPCDemo.sln @@ -0,0 +1,102 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo_parent", "demo_parent.vcxproj", "{A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo_child", "demo_child.vcxproj", "{B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}" +EndProject +Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "IPCDemoPkg", "IPCDemoPkg\IPCDemoPkg.wapproj", "{C59347EC-47B1-43FB-BAAB-63E4944FADEF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|Any CPU.ActiveCfg = Debug|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|Any CPU.Build.0 = Debug|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|ARM.ActiveCfg = Debug|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|ARM.Build.0 = Debug|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|ARM64.ActiveCfg = Debug|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|ARM64.Build.0 = Debug|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|x64.ActiveCfg = Debug|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|x64.Build.0 = Debug|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|x86.ActiveCfg = Debug|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Debug|x86.Build.0 = Debug|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|Any CPU.ActiveCfg = Release|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|Any CPU.Build.0 = Release|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|ARM.ActiveCfg = Release|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|ARM.Build.0 = Release|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|ARM64.ActiveCfg = Release|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|ARM64.Build.0 = Release|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|x64.ActiveCfg = Release|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|x64.Build.0 = Release|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|x86.ActiveCfg = Release|x64 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}.Release|x86.Build.0 = Release|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|Any CPU.ActiveCfg = Debug|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|Any CPU.Build.0 = Debug|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|ARM.ActiveCfg = Debug|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|ARM.Build.0 = Debug|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|ARM64.ActiveCfg = Debug|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|ARM64.Build.0 = Debug|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|x64.ActiveCfg = Debug|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|x64.Build.0 = Debug|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|x86.ActiveCfg = Debug|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Debug|x86.Build.0 = Debug|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|Any CPU.ActiveCfg = Release|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|Any CPU.Build.0 = Release|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|ARM.ActiveCfg = Release|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|ARM.Build.0 = Release|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|ARM64.ActiveCfg = Release|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|ARM64.Build.0 = Release|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|x64.ActiveCfg = Release|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|x64.Build.0 = Release|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|x86.ActiveCfg = Release|x64 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}.Release|x86.Build.0 = Release|x64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|ARM.ActiveCfg = Debug|ARM + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|ARM.Build.0 = Debug|ARM + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|ARM.Deploy.0 = Debug|ARM + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|ARM64.Build.0 = Debug|ARM64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|x64.ActiveCfg = Debug|x64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|x64.Build.0 = Debug|x64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|x64.Deploy.0 = Debug|x64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|x86.ActiveCfg = Debug|x86 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|x86.Build.0 = Debug|x86 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Debug|x86.Deploy.0 = Debug|x86 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|Any CPU.Build.0 = Release|Any CPU + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|Any CPU.Deploy.0 = Release|Any CPU + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|ARM.ActiveCfg = Release|ARM + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|ARM.Build.0 = Release|ARM + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|ARM.Deploy.0 = Release|ARM + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|ARM64.ActiveCfg = Release|ARM64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|ARM64.Build.0 = Release|ARM64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|ARM64.Deploy.0 = Release|ARM64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|x64.ActiveCfg = Release|x64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|x64.Build.0 = Release|x64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|x64.Deploy.0 = Release|x64 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|x86.ActiveCfg = Release|x86 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|x86.Build.0 = Release|x86 + {C59347EC-47B1-43FB-BAAB-63E4944FADEF}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {12345678-1234-1234-1234-123456789012} + EndGlobalSection +EndGlobal diff --git a/DeveloperLabs/SandboxIPCSample/win32/README.md b/DeveloperLabs/SandboxIPCSample/win32/README.md new file mode 100644 index 0000000..2663666 --- /dev/null +++ b/DeveloperLabs/SandboxIPCSample/win32/README.md @@ -0,0 +1,127 @@ +# IPC Demo - Parent-Child Process Communication + +This project demonstrates interprocess communication (IPC) between a full trust parent process and a sandboxed (AppContainer) child process using named pipes. + +## Architecture + +- **demo_parent.exe**: Full trust console application that: + - Spawns the child process using the app execution alias (`demo_child_ac.exe`) + - Creates a named pipe with proper security attributes to allow AppContainer access + - Sends messages to the child and receives echoed responses + - Manages the child process lifecycle + +- **demo_child.exe**: Sandboxed (AppContainer) console application that: + - Runs in a restricted security context + - Connects to the named pipe created by the parent + - Receives messages and echoes them back + - Exits gracefully when receiving the EXIT command + +## Key Features + +### Security Attributes for Named Pipe + +The parent process creates the named pipe with a security descriptor that allows AppContainer processes to access it: + +```cpp +// SDDL: Grants Generic All to World Domain and Generic Read/Write to ALL APPLICATION PACKAGES +LPCWSTR sddl = L"D:(A;;GA;;;WD)(A;;GRGW;;;AC)"; +``` + +This is critical for allowing the sandboxed child process to communicate with the full trust parent. + +### App Execution Alias + +The manifest uses the `uap5:AppExecutionAlias` feature to create aliases: +- `demo_parent.exe` - Full trust parent +- `demo_child_ac.exe` - Sandboxed child (alias for `demo_child.exe`) + +The parent spawns the child using `demo_child_ac.exe`, which automatically runs it in the AppContainer sandbox. + +## Building + +1. Open `IPCDemo.sln` in Visual Studio 2022 or later +2. Build the solution (both Debug and Release configurations supported) +3. Executables will be output to `bin\Debug\` or `bin\Release\` + +## Creating the APPX Package + +To deploy this as a packaged application: + +1. Create a folder structure: + ``` + Package\ + ├── demo_parent.exe + ├── demo_child.exe + ├── AppxManifest.xml + └── Images\ + ├── StoreLogo.png + └── AppList.png + ``` + +2. Copy the built executables to the Package folder + +3. Create placeholder images (or use real ones): + - StoreLogo.png (150x150) + - AppList.png (44x44) + +4. Use `MakeAppx.exe` to create the package: + ```powershell + MakeAppx.exe pack /d Package /p IPCDemo.appx + ``` + +5. Sign the package (for testing, use a test certificate): + ```powershell + SignTool.exe sign /fd SHA256 /a /f TestCert.pfx IPCDemo.appx + ``` + +## Running + +### From Visual Studio (Debug) + +Simply run the `demo_parent` project. It will automatically launch the child process. + +### From Command Line (Packaged) + +1. Install the package: `Add-AppxPackage .\IPCDemo.appx` +2. Run: `demo_parent.exe` + +## Communication Flow + +1. Parent starts and creates security descriptor +2. Parent launches child using `demo_child_ac.exe` alias +3. Parent creates named pipe with AppContainer-accessible security +4. Parent waits for child to connect +5. Child waits for pipe availability and connects +6. Parent sends "Hello from parent!" → Child echoes back +7. Parent sends "This is message number 2" → Child echoes back +8. Parent sends "EXIT" command +9. Child closes pipe and exits +10. Parent waits for child exit and closes + +## Important Notes + +- The child process runs in an AppContainer, which has restricted access to system resources +- The named pipe security descriptor must explicitly grant access to AppContainer processes (SID: S-1-15-2-1) +- The app execution alias mechanism ensures the child runs in the correct security context +- Both processes are console applications for easy debugging and demonstration + +## Requirements + +- Windows 10 version 1809 (17763) or later +- Visual Studio 2022 with C++ development tools +- Windows SDK 10.0 or later + +## Troubleshooting + +If the child fails to connect: +- Ensure the security descriptor on the pipe includes AppContainer access (`AC` in SDDL) +- Verify the child is being launched with the `_ac.exe` alias +- Check that the package is properly installed and the manifest is correct +- Look for error codes in the console output + +## References + +- [AppContainer Isolation](https://docs.microsoft.com/en-us/windows/win32/secauthz/appcontainer-isolation) +- [Named Pipes](https://docs.microsoft.com/en-us/windows/win32/ipc/named-pipes) +- [Security Descriptor String Format (SDDL)](https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-string-format) +- [App Execution Alias](https://docs.microsoft.com/en-us/windows/uwp/launch-resume/execute-in-app-context) diff --git a/DeveloperLabs/SandboxIPCSample/win32/demo_child.cpp b/DeveloperLabs/SandboxIPCSample/win32/demo_child.cpp new file mode 100644 index 0000000..5777b09 --- /dev/null +++ b/DeveloperLabs/SandboxIPCSample/win32/demo_child.cpp @@ -0,0 +1,210 @@ +#include +#include +#include +#include + +#define PIPE_NAME L"\\\\.\\pipe\\IPCDemoPipe" +#define BUFFER_SIZE 512 + +// Function to get and display the current process integrity level and AppContainer status +void DisplayProcessSecurityInfo() +{ + HANDLE hToken = nullptr; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) + { + printf("[Child] Failed to open process token. Error: %lu\n", GetLastError()); + return; + } + + // Get integrity level + DWORD dwLengthNeeded = 0; + GetTokenInformation(hToken, TokenIntegrityLevel, nullptr, 0, &dwLengthNeeded); + + TOKEN_MANDATORY_LABEL* pTIL = (TOKEN_MANDATORY_LABEL*)LocalAlloc(0, dwLengthNeeded); + if (pTIL) + { + if (GetTokenInformation(hToken, TokenIntegrityLevel, pTIL, dwLengthNeeded, &dwLengthNeeded)) + { + DWORD dwIntegrityLevel = *GetSidSubAuthority(pTIL->Label.Sid, + (DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1)); + + const char* integrityLevelStr = "Unknown"; + if (dwIntegrityLevel < SECURITY_MANDATORY_LOW_RID) + integrityLevelStr = "Untrusted"; + else if (dwIntegrityLevel < SECURITY_MANDATORY_MEDIUM_RID) + integrityLevelStr = "Low"; + else if (dwIntegrityLevel < SECURITY_MANDATORY_HIGH_RID) + integrityLevelStr = "Medium"; + else if (dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID) + integrityLevelStr = "High/System"; + + printf("[Child] *** Process Integrity Level: %s (0x%X) ***\n", integrityLevelStr, dwIntegrityLevel); + + // Convert SID to string for display + LPWSTR szIntegritySid = nullptr; + if (ConvertSidToStringSidW(pTIL->Label.Sid, &szIntegritySid)) + { + printf("[Child] *** Integrity SID: %ls ***\n", szIntegritySid); + LocalFree(szIntegritySid); + } + } + LocalFree(pTIL); + } + + // Check if running in AppContainer + DWORD dwIsAppContainer = 0; + dwLengthNeeded = sizeof(DWORD); + if (GetTokenInformation(hToken, TokenIsAppContainer, &dwIsAppContainer, sizeof(DWORD), &dwLengthNeeded)) + { + printf("[Child] *** Running in AppContainer: %s ***\n", dwIsAppContainer ? "YES" : "NO"); + } + + // Get AppContainer SID if applicable + if (dwIsAppContainer) + { + dwLengthNeeded = 0; + GetTokenInformation(hToken, TokenAppContainerSid, nullptr, 0, &dwLengthNeeded); + + TOKEN_APPCONTAINER_INFORMATION* pAppContainerInfo = (TOKEN_APPCONTAINER_INFORMATION*)LocalAlloc(0, dwLengthNeeded); + if (pAppContainerInfo) + { + if (GetTokenInformation(hToken, TokenAppContainerSid, pAppContainerInfo, dwLengthNeeded, &dwLengthNeeded)) + { + LPWSTR szAppContainerSid = nullptr; + if (ConvertSidToStringSidW(pAppContainerInfo->TokenAppContainer, &szAppContainerSid)) + { + printf("[Child] *** AppContainer SID: %ls ***\n", szAppContainerSid); + LocalFree(szAppContainerSid); + } + } + LocalFree(pAppContainerInfo); + } + } + + CloseHandle(hToken); +} + +bool SendMessage(HANDLE hPipe, const char* message) +{ + DWORD bytesWritten; + DWORD messageLen = (DWORD)strlen(message) + 1; + + printf("[Child] Sending: %s\n", message); + + if (!WriteFile(hPipe, message, messageLen, &bytesWritten, nullptr)) + { + printf("[Child] Failed to write to pipe. Error: %lu\n", GetLastError()); + return false; + } + + return true; +} + +bool ReceiveMessage(HANDLE hPipe, char* buffer, DWORD bufferSize) +{ + DWORD bytesRead; + + if (!ReadFile(hPipe, buffer, bufferSize, &bytesRead, nullptr)) + { + printf("[Child] Failed to read from pipe. Error: %lu\n", GetLastError()); + return false; + } + + printf("[Child] Received: %s\n", buffer); + return true; +} + +int main() +{ + printf("=== IPC Demo - Child Process (Sandboxed) ===\n"); + printf("[Child] Starting...\n"); + + // Display security information + printf("\n[Child] === Security Context Information ===\n"); + DisplayProcessSecurityInfo(); + printf("[Child] ==========================================\n\n"); + + // Wait for pipe to be available + printf("[Child] Waiting for pipe to become available...\n"); + + int retries = 0; + while (!WaitNamedPipeW(PIPE_NAME, 5000)) + { + printf("[Child] Pipe not available yet, retrying... (attempt %d)\n", ++retries); + if (retries > 10) + { + printf("[Child] Timeout waiting for pipe\n"); + return 1; + } + } + + printf("[Child] Pipe is available, connecting...\n"); + + // Open the named pipe + HANDLE hPipe = CreateFileW( + PIPE_NAME, + GENERIC_READ | GENERIC_WRITE, + 0, + nullptr, + OPEN_EXISTING, + 0, + nullptr); + + if (hPipe == INVALID_HANDLE_VALUE) + { + printf("[Child] Failed to open pipe. Error: %lu\n", GetLastError()); + return 1; + } + + printf("[Child] Connected to pipe\n"); + + // Set pipe to message mode + DWORD mode = PIPE_READMODE_MESSAGE; + if (!SetNamedPipeHandleState(hPipe, &mode, nullptr, nullptr)) + { + printf("[Child] Failed to set pipe mode. Error: %lu\n", GetLastError()); + CloseHandle(hPipe); + return 1; + } + + char buffer[BUFFER_SIZE]; + + // Message loop + while (true) + { + // Receive message from parent + if (!ReceiveMessage(hPipe, buffer, BUFFER_SIZE)) + { + break; + } + + // Check for exit command + if (strcmp(buffer, "EXIT") == 0) + { + printf("[Child] Received exit command\n"); + break; + } + + // Echo the message back + char response[BUFFER_SIZE]; + snprintf(response, BUFFER_SIZE, "Echo: %s", buffer); + + if (!SendMessage(hPipe, response)) + { + break; + } + } + + // Close pipe + printf("[Child] Closing pipe\n"); + CloseHandle(hPipe); + + printf("[Child] Child process exiting\n"); + + // Wait for user input before closing the console + printf("\n[Child] *** Press Enter to close this window... ***\n"); + getchar(); + + return 0; +} diff --git a/DeveloperLabs/SandboxIPCSample/win32/demo_child.vcxproj b/DeveloperLabs/SandboxIPCSample/win32/demo_child.vcxproj new file mode 100644 index 0000000..dceec52 --- /dev/null +++ b/DeveloperLabs/SandboxIPCSample/win32/demo_child.vcxproj @@ -0,0 +1,100 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E} + Win32Proj + demo_child + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + true + $(SolutionDir)bin\$(Configuration)\ + $(SolutionDir)obj\$(ProjectName)\$(Configuration)\ + demo_child + + + false + $(SolutionDir)bin\$(Configuration)\ + $(SolutionDir)obj\$(ProjectName)\$(Configuration)\ + demo_child + + + + NotUsing + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + + + Console + true + kernel32.lib;user32.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + + + Console + true + true + true + kernel32.lib;user32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/DeveloperLabs/SandboxIPCSample/win32/demo_parent.cpp b/DeveloperLabs/SandboxIPCSample/win32/demo_parent.cpp new file mode 100644 index 0000000..0b3b1e9 --- /dev/null +++ b/DeveloperLabs/SandboxIPCSample/win32/demo_parent.cpp @@ -0,0 +1,400 @@ +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "userenv.lib") + +#define PIPE_NAME L"\\\\.\\pipe\\IPCDemoPipe" +#define BUFFER_SIZE 512 +#define APPCONTAINER_NAME L"IPCDemo.ChildContainer" + +// Function to get and display the current process integrity level +void DisplayProcessSecurityInfo() +{ + HANDLE hToken = nullptr; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) + { + printf("[Parent] Failed to open process token. Error: %lu\n", GetLastError()); + return; + } + + // Get integrity level + DWORD dwLengthNeeded = 0; + GetTokenInformation(hToken, TokenIntegrityLevel, nullptr, 0, &dwLengthNeeded); + + TOKEN_MANDATORY_LABEL* pTIL = (TOKEN_MANDATORY_LABEL*)LocalAlloc(0, dwLengthNeeded); + if (pTIL) + { + if (GetTokenInformation(hToken, TokenIntegrityLevel, pTIL, dwLengthNeeded, &dwLengthNeeded)) + { + DWORD dwIntegrityLevel = *GetSidSubAuthority(pTIL->Label.Sid, + (DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1)); + + const char* integrityLevelStr = "Unknown"; + if (dwIntegrityLevel < SECURITY_MANDATORY_LOW_RID) + integrityLevelStr = "Untrusted"; + else if (dwIntegrityLevel < SECURITY_MANDATORY_MEDIUM_RID) + integrityLevelStr = "Low"; + else if (dwIntegrityLevel < SECURITY_MANDATORY_HIGH_RID) + integrityLevelStr = "Medium"; + else if (dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID) + integrityLevelStr = "High/System"; + + printf("[Parent] *** Process Integrity Level: %s (0x%X) ***\n", integrityLevelStr, dwIntegrityLevel); + + // Convert SID to string for display + LPWSTR szIntegritySid = nullptr; + if (ConvertSidToStringSidW(pTIL->Label.Sid, &szIntegritySid)) + { + printf("[Parent] *** Integrity SID: %ls ***\n", szIntegritySid); + LocalFree(szIntegritySid); + } + } + LocalFree(pTIL); + } + + // Check if running in AppContainer + DWORD dwIsAppContainer = 0; + dwLengthNeeded = sizeof(DWORD); + if (GetTokenInformation(hToken, TokenIsAppContainer, &dwIsAppContainer, sizeof(DWORD), &dwLengthNeeded)) + { + printf("[Parent] *** Running in AppContainer: %s ***\n", dwIsAppContainer ? "YES" : "NO"); + } + + CloseHandle(hToken); +} + +// Create a security descriptor that allows AppContainer access +PSECURITY_DESCRIPTOR CreateAppContainerAccessibleSD() +{ + PSECURITY_DESCRIPTOR pSD = nullptr; + + // SDDL string that grants: + // - Generic All access to the current user (GA) + // - Generic Read/Write access to ALL APPLICATION PACKAGES (AC) - AppContainer processes + // S-1-15-2-1 is the well-known SID for ALL APPLICATION PACKAGES + LPCWSTR sddl = L"D:(A;;GA;;;WD)(A;;GRGW;;;AC)"; + + if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( + sddl, + SDDL_REVISION_1, + &pSD, + nullptr)) + { + printf("Failed to create security descriptor. Error: %lu\n", GetLastError()); + return nullptr; + } + + return pSD; +} + +bool SendMessage(HANDLE hPipe, const char* message) +{ + DWORD bytesWritten; + DWORD messageLen = (DWORD)strlen(message) + 1; + + printf("[Parent] Sending: %s\n", message); + + if (!WriteFile(hPipe, message, messageLen, &bytesWritten, nullptr)) + { + printf("[Parent] Failed to write to pipe. Error: %lu\n", GetLastError()); + return false; + } + + return true; +} + +bool ReceiveMessage(HANDLE hPipe, char* buffer, DWORD bufferSize) +{ + DWORD bytesRead; + + if (!ReadFile(hPipe, buffer, bufferSize, &bytesRead, nullptr)) + { + printf("[Parent] Failed to read from pipe. Error: %lu\n", GetLastError()); + return false; + } + + printf("[Parent] Received: %s\n", buffer); + return true; +} + +int main() +{ + printf("=== IPC Demo - Parent Process ===\n"); + printf("[Parent] Starting...\n"); + + // Display security information + printf("\n[Parent] === Security Context Information ===\n"); + DisplayProcessSecurityInfo(); + printf("[Parent] ==========================================\n\n"); + + // Create security attributes for the pipe + SECURITY_ATTRIBUTES sa = { 0 }; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = CreateAppContainerAccessibleSD(); + sa.bInheritHandle = FALSE; + + if (sa.lpSecurityDescriptor == nullptr) + { + printf("[Parent] Failed to create security descriptor\n"); + return 1; + } + + // Create named pipe BEFORE launching child process + printf("[Parent] Creating named pipe: %ls\n", PIPE_NAME); + + HANDLE hPipe = CreateNamedPipeW( + PIPE_NAME, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, + BUFFER_SIZE, + BUFFER_SIZE, + 0, + &sa); + + if (hPipe == INVALID_HANDLE_VALUE) + { + printf("[Parent] Failed to create named pipe. Error: %lu\n", GetLastError()); + LocalFree(sa.lpSecurityDescriptor); + return 1; + } + + printf("[Parent] Named pipe created successfully\n"); + + // Create or get AppContainer profile for the child process + PSID pAppContainerSid = nullptr; + HRESULT hr = CreateAppContainerProfile( + APPCONTAINER_NAME, + L"IPC Demo Child AppContainer", + L"Sandboxed child process for IPC demonstration", + nullptr, // No capabilities for now + 0, + &pAppContainerSid); + + if (FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) + { + printf("[Parent] Failed to create AppContainer profile. HRESULT: 0x%08X\n", hr); + CloseHandle(hPipe); + LocalFree(sa.lpSecurityDescriptor); + return 1; + } + + // If already exists, get the SID + if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) + { + hr = DeriveAppContainerSidFromAppContainerName(APPCONTAINER_NAME, &pAppContainerSid); + if (FAILED(hr)) + { + printf("[Parent] Failed to get AppContainer SID. HRESULT: 0x%08X\n", hr); + CloseHandle(hPipe); + LocalFree(sa.lpSecurityDescriptor); + return 1; + } + } + + printf("[Parent] AppContainer profile created/retrieved successfully\n"); + + // Set up security capabilities for the AppContainer + SECURITY_CAPABILITIES securityCapabilities = { 0 }; + securityCapabilities.AppContainerSid = pAppContainerSid; + securityCapabilities.Capabilities = nullptr; + securityCapabilities.CapabilityCount = 0; + securityCapabilities.Reserved = 0; + + // Set up process attribute list + SIZE_T attributeListSize = 0; + InitializeProcThreadAttributeList(nullptr, 1, 0, &attributeListSize); + + LPPROC_THREAD_ATTRIBUTE_LIST pAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc( + GetProcessHeap(), 0, attributeListSize); + + if (!pAttributeList) + { + printf("[Parent] Failed to allocate attribute list\n"); + FreeSid(pAppContainerSid); + CloseHandle(hPipe); + LocalFree(sa.lpSecurityDescriptor); + return 1; + } + + if (!InitializeProcThreadAttributeList(pAttributeList, 1, 0, &attributeListSize)) + { + printf("[Parent] Failed to initialize attribute list. Error: %lu\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, pAttributeList); + FreeSid(pAppContainerSid); + CloseHandle(hPipe); + LocalFree(sa.lpSecurityDescriptor); + return 1; + } + + if (!UpdateProcThreadAttribute( + pAttributeList, + 0, + PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, + &securityCapabilities, + sizeof(securityCapabilities), + nullptr, + nullptr)) + { + printf("[Parent] Failed to update proc thread attribute. Error: %lu\n", GetLastError()); + DeleteProcThreadAttributeList(pAttributeList); + HeapFree(GetProcessHeap(), 0, pAttributeList); + FreeSid(pAppContainerSid); + CloseHandle(hPipe); + LocalFree(sa.lpSecurityDescriptor); + return 1; + } + + // NOW launch the child process + STARTUPINFOW si = { 0 }; + PROCESS_INFORMATION pi = { 0 }; + si.cb = sizeof(si); + + // Use STARTUPINFOEX to pass the attribute list + STARTUPINFOEXW siex = { 0 }; + siex.StartupInfo.cb = sizeof(STARTUPINFOEXW); + siex.lpAttributeList = pAttributeList; + + // Get the current module path to find the child exe + wchar_t modulePath[MAX_PATH]; + GetModuleFileNameW(nullptr, modulePath, MAX_PATH); + + // Remove the exe name to get just the directory + wchar_t* lastSlash = wcsrchr(modulePath, L'\\'); + if (lastSlash) + { + *(lastSlash + 1) = L'\0'; + } + + // Construct full path to child executable + wchar_t cmdLine[MAX_PATH]; + swprintf_s(cmdLine, MAX_PATH, L"\"%sdemo_child.exe\"", modulePath); + + printf("[Parent] Launching child process: %ls\n", cmdLine); + + if (!CreateProcessW( + nullptr, + cmdLine, + nullptr, + nullptr, + FALSE, + EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE, // Use extended startup info + nullptr, + nullptr, + &siex.StartupInfo, // Use the extended startup info + &pi)) + { + printf("[Parent] Failed to create child process. Error: %lu\n", GetLastError()); + DeleteProcThreadAttributeList(pAttributeList); + HeapFree(GetProcessHeap(), 0, pAttributeList); + FreeSid(pAppContainerSid); + CloseHandle(hPipe); + LocalFree(sa.lpSecurityDescriptor); + return 1; + } + + printf("[Parent] Child process created. PID: %lu\n", pi.dwProcessId); + + // Clean up attribute list and AppContainer SID + DeleteProcThreadAttributeList(pAttributeList); + HeapFree(GetProcessHeap(), 0, pAttributeList); + FreeSid(pAppContainerSid); + // Clean up security descriptor - no longer needed + LocalFree(sa.lpSecurityDescriptor); + + // Wait for child to connect to the pipe + printf("[Parent] Waiting for child to connect...\n"); + + if (!ConnectNamedPipe(hPipe, nullptr)) + { + DWORD error = GetLastError(); + if (error != ERROR_PIPE_CONNECTED) + { + printf("[Parent] Failed to connect to pipe. Error: %lu\n", error); + CloseHandle(hPipe); + TerminateProcess(pi.hProcess, 1); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return 1; + } + } + + printf("[Parent] Child connected to pipe\n"); + + char buffer[BUFFER_SIZE]; + + // Send first message + if (!SendMessage(hPipe, "Hello from parent!")) + { + CloseHandle(hPipe); + TerminateProcess(pi.hProcess, 1); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return 1; + } + + // Receive response + if (!ReceiveMessage(hPipe, buffer, BUFFER_SIZE)) + { + CloseHandle(hPipe); + TerminateProcess(pi.hProcess, 1); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return 1; + } + + // Send second message + if (!SendMessage(hPipe, "This is message number 2")) + { + CloseHandle(hPipe); + TerminateProcess(pi.hProcess, 1); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return 1; + } + + // Receive response + if (!ReceiveMessage(hPipe, buffer, BUFFER_SIZE)) + { + CloseHandle(hPipe); + TerminateProcess(pi.hProcess, 1); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return 1; + } + + // Send exit message + printf("[Parent] Sending exit command\n"); + SendMessage(hPipe, "EXIT"); + + // Close pipe + printf("[Parent] Closing pipe\n"); + FlushFileBuffers(hPipe); + DisconnectNamedPipe(hPipe); + CloseHandle(hPipe); + + // Wait for child to exit (wait indefinitely for user to close child console) + printf("[Parent] Waiting for child process to exit...\n"); + printf("[Parent] (Child console is waiting for user input - press Enter in child window)\n"); + WaitForSingleObject(pi.hProcess, INFINITE); + + DWORD exitCode; + GetExitCodeProcess(pi.hProcess, &exitCode); + printf("[Parent] Child process exited with code: %lu\n", exitCode); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + printf("[Parent] Parent process exiting\n"); + + // Wait for user input before closing the parent console + printf("\n[Parent] *** Press Enter to close this window... ***\n"); + getchar(); + + return 0; +} diff --git a/DeveloperLabs/SandboxIPCSample/win32/demo_parent.vcxproj b/DeveloperLabs/SandboxIPCSample/win32/demo_parent.vcxproj new file mode 100644 index 0000000..f1dc167 --- /dev/null +++ b/DeveloperLabs/SandboxIPCSample/win32/demo_parent.vcxproj @@ -0,0 +1,100 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D} + Win32Proj + demo_parent + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + true + $(SolutionDir)bin\$(Configuration)\ + $(SolutionDir)obj\$(ProjectName)\$(Configuration)\ + demo_parent + + + false + $(SolutionDir)bin\$(Configuration)\ + $(SolutionDir)obj\$(ProjectName)\$(Configuration)\ + demo_parent + + + + NotUsing + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + + + Console + true + kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + + + Console + true + true + true + kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) + + + + + + + + + \ No newline at end of file From 7524a6f0814cb679741a87be9593805fa545ea0e Mon Sep 17 00:00:00 2001 From: rramachandra Date: Sat, 8 Nov 2025 00:32:01 -0600 Subject: [PATCH 2/2] Made the file match the blog naming Parent -> Host --- .../SandboxIPCSample/win32/IPCDemo.sln | 4 +- .../SandboxIPCSample/win32/demo_child.cpp | 2 +- .../SandboxIPCSample/win32/demo_child.vcxproj | 2 +- .../win32/{demo_parent.cpp => demo_host.cpp} | 201 ++++++++++-------- ...{demo_parent.vcxproj => demo_host.vcxproj} | 8 +- 5 files changed, 122 insertions(+), 95 deletions(-) rename DeveloperLabs/SandboxIPCSample/win32/{demo_parent.cpp => demo_host.cpp} (77%) rename DeveloperLabs/SandboxIPCSample/win32/{demo_parent.vcxproj => demo_host.vcxproj} (96%) diff --git a/DeveloperLabs/SandboxIPCSample/win32/IPCDemo.sln b/DeveloperLabs/SandboxIPCSample/win32/IPCDemo.sln index 26ffd07..bbff78b 100644 --- a/DeveloperLabs/SandboxIPCSample/win32/IPCDemo.sln +++ b/DeveloperLabs/SandboxIPCSample/win32/IPCDemo.sln @@ -2,12 +2,10 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo_parent", "demo_parent.vcxproj", "{A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo_host", "demo_host.vcxproj", "{A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo_child", "demo_child.vcxproj", "{B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E}" EndProject -Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "IPCDemoPkg", "IPCDemoPkg\IPCDemoPkg.wapproj", "{C59347EC-47B1-43FB-BAAB-63E4944FADEF}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/DeveloperLabs/SandboxIPCSample/win32/demo_child.cpp b/DeveloperLabs/SandboxIPCSample/win32/demo_child.cpp index 5777b09..c5bcb04 100644 --- a/DeveloperLabs/SandboxIPCSample/win32/demo_child.cpp +++ b/DeveloperLabs/SandboxIPCSample/win32/demo_child.cpp @@ -142,7 +142,7 @@ int main() printf("[Child] Pipe is available, connecting...\n"); // Open the named pipe - HANDLE hPipe = CreateFileW( + HANDLE hPipe = ::CreateFileW( PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, diff --git a/DeveloperLabs/SandboxIPCSample/win32/demo_child.vcxproj b/DeveloperLabs/SandboxIPCSample/win32/demo_child.vcxproj index dceec52..9eeb7c5 100644 --- a/DeveloperLabs/SandboxIPCSample/win32/demo_child.vcxproj +++ b/DeveloperLabs/SandboxIPCSample/win32/demo_child.vcxproj @@ -14,7 +14,7 @@ 16.0 {B2C3D4E5-F6A7-4B5C-9D0E-1F2A3B4C5D6E} Win32Proj - demo_child + DemoChild 10.0 diff --git a/DeveloperLabs/SandboxIPCSample/win32/demo_parent.cpp b/DeveloperLabs/SandboxIPCSample/win32/demo_host.cpp similarity index 77% rename from DeveloperLabs/SandboxIPCSample/win32/demo_parent.cpp rename to DeveloperLabs/SandboxIPCSample/win32/demo_host.cpp index 0b3b1e9..21b2099 100644 --- a/DeveloperLabs/SandboxIPCSample/win32/demo_parent.cpp +++ b/DeveloperLabs/SandboxIPCSample/win32/demo_host.cpp @@ -9,7 +9,7 @@ #define PIPE_NAME L"\\\\.\\pipe\\IPCDemoPipe" #define BUFFER_SIZE 512 -#define APPCONTAINER_NAME L"IPCDemo.ChildContainer" +#define APPCONTAINER_NAME L"SandboxIpcDemoApp" // Function to get and display the current process integrity level void DisplayProcessSecurityInfo() @@ -18,7 +18,7 @@ void DisplayProcessSecurityInfo() if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { - printf("[Parent] Failed to open process token. Error: %lu\n", GetLastError()); + printf("[Host] Failed to open process token. Error: %lu\n", GetLastError()); return; } @@ -68,103 +68,70 @@ void DisplayProcessSecurityInfo() CloseHandle(hToken); } -// Create a security descriptor that allows AppContainer access -PSECURITY_DESCRIPTOR CreateAppContainerAccessibleSD() -{ - PSECURITY_DESCRIPTOR pSD = nullptr; - - // SDDL string that grants: - // - Generic All access to the current user (GA) - // - Generic Read/Write access to ALL APPLICATION PACKAGES (AC) - AppContainer processes - // S-1-15-2-1 is the well-known SID for ALL APPLICATION PACKAGES - LPCWSTR sddl = L"D:(A;;GA;;;WD)(A;;GRGW;;;AC)"; - - if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( - sddl, - SDDL_REVISION_1, - &pSD, - nullptr)) - { - printf("Failed to create security descriptor. Error: %lu\n", GetLastError()); - return nullptr; - } - return pSD; -} - -bool SendMessage(HANDLE hPipe, const char* message) -{ - DWORD bytesWritten; - DWORD messageLen = (DWORD)strlen(message) + 1; +bool GetSecurityAttributes(SECURITY_ATTRIBUTES& sa, + SECURITY_DESCRIPTOR& sd, + const PSID& app_container_sid) { + // Create a new security descriptor + if (0 == ::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { + auto gle = ::GetLastError(); + printf("InitializeSecurityDescriptor failed. Error: %lu\n", gle); + return false; + } - printf("[Parent] Sending: %s\n", message); + LPCSTR everyone_sid_string = "S-1-1-0"; // Also known as world sid. + PSID everyone_sid; - if (!WriteFile(hPipe, message, messageLen, &bytesWritten, nullptr)) - { - printf("[Parent] Failed to write to pipe. Error: %lu\n", GetLastError()); + if (!ConvertStringSidToSidA(everyone_sid_string, &everyone_sid)) { + printf("Failed to convert String to Sid"); return false; } - return true; -} + // Create a new ACL + PACL acl = nullptr; + constexpr unsigned int kMaxExplicitAccessEntries = 2; + EXPLICIT_ACCESSW ea_list[kMaxExplicitAccessEntries] = {}; + for (int i = 0; i < kMaxExplicitAccessEntries; i++) { + ea_list[i].grfAccessPermissions = FILE_ALL_ACCESS; + ea_list[i].grfAccessMode = GRANT_ACCESS; + ea_list[i].grfInheritance = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + ea_list[i].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea_list[i].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ea_list[i].Trustee.pMultipleTrustee = nullptr; + } -bool ReceiveMessage(HANDLE hPipe, char* buffer, DWORD bufferSize) -{ - DWORD bytesRead; + ea_list[0].Trustee.ptstrName = static_cast(everyone_sid); + // here we explicitly give access to the AppContainer SID + ea_list[1].Trustee.ptstrName = static_cast(app_container_sid); - if (!ReadFile(hPipe, buffer, bufferSize, &bytesRead, nullptr)) - { - printf("[Parent] Failed to read from pipe. Error: %lu\n", GetLastError()); + auto result = ::SetEntriesInAclW(kMaxExplicitAccessEntries, ea_list, nullptr, &acl); + if (result != ERROR_SUCCESS) { + printf("SetEntriesInAclW failed. Error: %lu\n", result); return false; } - printf("[Parent] Received: %s\n", buffer); + // Set the DACL in the security descriptor + if (!::SetSecurityDescriptorDacl(&sd, TRUE, acl, FALSE)) { + printf("SetSecurityDescriptorDacl failed. Error: %lu\n", GetLastError()); + return false; + } + sa.lpSecurityDescriptor = &sd; return true; } +bool SendMessage(HANDLE hPipe, const char* message); +bool ReceiveMessage(HANDLE hPipe, char* buffer, DWORD bufferSize); + int main() { - printf("=== IPC Demo - Parent Process ===\n"); - printf("[Parent] Starting...\n"); + printf("=== IPC Demo - Host Process ===\n"); + printf("[Host] Starting...\n"); // Display security information - printf("\n[Parent] === Security Context Information ===\n"); + printf("\n[Host] === Security Context Information ===\n"); DisplayProcessSecurityInfo(); - printf("[Parent] ==========================================\n\n"); + printf("[Host] ==========================================\n\n"); - // Create security attributes for the pipe - SECURITY_ATTRIBUTES sa = { 0 }; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = CreateAppContainerAccessibleSD(); - sa.bInheritHandle = FALSE; - - if (sa.lpSecurityDescriptor == nullptr) - { - printf("[Parent] Failed to create security descriptor\n"); - return 1; - } - - // Create named pipe BEFORE launching child process - printf("[Parent] Creating named pipe: %ls\n", PIPE_NAME); - - HANDLE hPipe = CreateNamedPipeW( - PIPE_NAME, - PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, - 1, - BUFFER_SIZE, - BUFFER_SIZE, - 0, - &sa); - - if (hPipe == INVALID_HANDLE_VALUE) - { - printf("[Parent] Failed to create named pipe. Error: %lu\n", GetLastError()); - LocalFree(sa.lpSecurityDescriptor); - return 1; - } - - printf("[Parent] Named pipe created successfully\n"); // Create or get AppContainer profile for the child process PSID pAppContainerSid = nullptr; @@ -179,25 +146,54 @@ int main() if (FAILED(hr) && hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) { printf("[Parent] Failed to create AppContainer profile. HRESULT: 0x%08X\n", hr); - CloseHandle(hPipe); - LocalFree(sa.lpSecurityDescriptor); return 1; } - // If already exists, get the SID + // If AppContainerProfile already exists, get the SID if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) { hr = DeriveAppContainerSidFromAppContainerName(APPCONTAINER_NAME, &pAppContainerSid); if (FAILED(hr)) { printf("[Parent] Failed to get AppContainer SID. HRESULT: 0x%08X\n", hr); - CloseHandle(hPipe); - LocalFree(sa.lpSecurityDescriptor); return 1; } } - printf("[Parent] AppContainer profile created/retrieved successfully\n"); + + // Use the the AppContainer SID to create a security attributes for the Named Pipe + SECURITY_DESCRIPTOR sd = { 0 }; + SECURITY_ATTRIBUTES sa = { 0 }; + sa.bInheritHandle = FALSE; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + + + if (!GetSecurityAttributes(sa, sd, pAppContainerSid)) { + printf("[Host] Failed to create security attributes\n"); + return 1; + } + + // Create named pipe BEFORE launching child process + printf("[Host] Creating named pipe: %ls\n", PIPE_NAME); + + HANDLE hPipe = ::CreateNamedPipeW( + PIPE_NAME, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, + BUFFER_SIZE, + BUFFER_SIZE, + 0, + &sa); + + if (hPipe == INVALID_HANDLE_VALUE) + { + printf("[Parent] Failed to create named pipe. Error: %lu\n", GetLastError()); + LocalFree(sa.lpSecurityDescriptor); + return 1; + } + + printf("[Parent] Named pipe created successfully\n"); // Set up security capabilities for the AppContainer SECURITY_CAPABILITIES securityCapabilities = { 0 }; @@ -273,7 +269,7 @@ int main() // Construct full path to child executable wchar_t cmdLine[MAX_PATH]; - swprintf_s(cmdLine, MAX_PATH, L"\"%sdemo_child.exe\"", modulePath); + swprintf_s(cmdLine, MAX_PATH, L"\"%schild.exe\"", modulePath); printf("[Parent] Launching child process: %ls\n", cmdLine); @@ -398,3 +394,36 @@ int main() return 0; } + + + + +bool SendMessage(HANDLE hPipe, const char* message) +{ + DWORD bytesWritten; + DWORD messageLen = (DWORD)strlen(message) + 1; + + printf("[Host] Sending: %s\n", message); + + if (!WriteFile(hPipe, message, messageLen, &bytesWritten, nullptr)) + { + printf("[Host] Failed to write to pipe. Error: %lu\n", GetLastError()); + return false; + } + + return true; +} + +bool ReceiveMessage(HANDLE hPipe, char* buffer, DWORD bufferSize) +{ + DWORD bytesRead; + + if (!ReadFile(hPipe, buffer, bufferSize, &bytesRead, nullptr)) + { + printf("[Parent] Failed to read from pipe. Error: %lu\n", GetLastError()); + return false; + } + + printf("[Parent] Received: %s\n", buffer); + return true; +} diff --git a/DeveloperLabs/SandboxIPCSample/win32/demo_parent.vcxproj b/DeveloperLabs/SandboxIPCSample/win32/demo_host.vcxproj similarity index 96% rename from DeveloperLabs/SandboxIPCSample/win32/demo_parent.vcxproj rename to DeveloperLabs/SandboxIPCSample/win32/demo_host.vcxproj index f1dc167..2f792f4 100644 --- a/DeveloperLabs/SandboxIPCSample/win32/demo_parent.vcxproj +++ b/DeveloperLabs/SandboxIPCSample/win32/demo_host.vcxproj @@ -14,7 +14,7 @@ 16.0 {A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D} Win32Proj - demo_parent + DemoHost 10.0 @@ -47,13 +47,13 @@ true $(SolutionDir)bin\$(Configuration)\ $(SolutionDir)obj\$(ProjectName)\$(Configuration)\ - demo_parent + demo_host false $(SolutionDir)bin\$(Configuration)\ $(SolutionDir)obj\$(ProjectName)\$(Configuration)\ - demo_parent + demo_host @@ -92,7 +92,7 @@ - +