@holoscript/holosystem 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -3
- package/bin/holosystem.mjs +21 -0
- package/docs/vm-launch-threat-model.md +91 -23
- package/native/windows-sandbox/Canary.c +107 -0
- package/native/windows-sandbox/Program.cs +1117 -0
- package/native/windows-sandbox/README.md +30 -0
- package/native/windows-sandbox/build.ps1 +48 -0
- package/native/windows-x64/holosystem-appcontainer-canary.exe +0 -0
- package/native/windows-x64/holosystem-sandbox-launcher.exe +0 -0
- package/package.json +2 -1
- package/src/index.mjs +20 -0
- package/src/vm-launch.mjs +684 -28
|
@@ -0,0 +1,1117 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Diagnostics;
|
|
4
|
+
using System.IO;
|
|
5
|
+
using System.Net;
|
|
6
|
+
using System.Net.Sockets;
|
|
7
|
+
using System.Runtime.InteropServices;
|
|
8
|
+
using System.Security.AccessControl;
|
|
9
|
+
using System.Security.Principal;
|
|
10
|
+
using System.Text;
|
|
11
|
+
using System.Threading.Tasks;
|
|
12
|
+
|
|
13
|
+
internal static class Program
|
|
14
|
+
{
|
|
15
|
+
private const string Protocol = "holoscript.holosystem.windows-sandbox-launch.v1";
|
|
16
|
+
private const string AppContainerProtocol = "holoscript.holosystem.windows-appcontainer-launch.v1";
|
|
17
|
+
private const string LowIntegritySid = "S-1-16-4096";
|
|
18
|
+
private const int OutputLimit = 1024 * 1024;
|
|
19
|
+
|
|
20
|
+
private const uint TokenAssignPrimary = 0x0001;
|
|
21
|
+
private const uint TokenDuplicate = 0x0002;
|
|
22
|
+
private const uint TokenQuery = 0x0008;
|
|
23
|
+
private const uint TokenAdjustDefault = 0x0080;
|
|
24
|
+
private const uint TokenAdjustSessionId = 0x0100;
|
|
25
|
+
private const uint DisableMaxPrivilege = 0x1;
|
|
26
|
+
private const uint SeGroupIntegrity = 0x20;
|
|
27
|
+
private const uint SePrivilegeEnabled = 0x2;
|
|
28
|
+
private const int TokenPrivileges = 3;
|
|
29
|
+
private const int TokenIntegrityLevel = 25;
|
|
30
|
+
private const int TokenIsAppContainer = 29;
|
|
31
|
+
private const int TokenCapabilities = 30;
|
|
32
|
+
private const int TokenAppContainerSid = 31;
|
|
33
|
+
|
|
34
|
+
private const uint CreateSuspended = 0x00000004;
|
|
35
|
+
private const uint CreateNoWindow = 0x08000000;
|
|
36
|
+
private const uint CreateUnicodeEnvironment = 0x00000400;
|
|
37
|
+
private const uint ExtendedStartupInfoPresent = 0x00080000;
|
|
38
|
+
private const uint StartfUseStdHandles = 0x00000100;
|
|
39
|
+
private const uint HandleFlagInherit = 0x00000001;
|
|
40
|
+
private const uint GenericRead = 0x80000000;
|
|
41
|
+
private const uint FileShareRead = 0x00000001;
|
|
42
|
+
private const uint FileShareWrite = 0x00000002;
|
|
43
|
+
private const uint OpenExisting = 3;
|
|
44
|
+
private const uint FileAttributeNormal = 0x00000080;
|
|
45
|
+
private const uint WaitObject0 = 0;
|
|
46
|
+
private const uint WaitTimeout = 258;
|
|
47
|
+
|
|
48
|
+
private const uint JobObjectLimitActiveProcess = 0x00000008;
|
|
49
|
+
private const uint JobObjectLimitProcessMemory = 0x00000100;
|
|
50
|
+
private const uint JobObjectLimitKillOnJobClose = 0x00002000;
|
|
51
|
+
private const uint JobObjectUiLimitHandles = 0x00000001;
|
|
52
|
+
private const uint JobObjectUiLimitReadClipboard = 0x00000002;
|
|
53
|
+
private const uint JobObjectUiLimitWriteClipboard = 0x00000004;
|
|
54
|
+
private const uint JobObjectUiLimitSystemParameters = 0x00000008;
|
|
55
|
+
private const uint JobObjectUiLimitDisplaySettings = 0x00000010;
|
|
56
|
+
private const uint JobObjectUiLimitGlobalAtoms = 0x00000020;
|
|
57
|
+
private const uint JobObjectUiLimitDesktop = 0x00000040;
|
|
58
|
+
private const uint JobObjectUiLimitExitWindows = 0x00000080;
|
|
59
|
+
private const int JobObjectBasicUiRestrictions = 4;
|
|
60
|
+
private const int JobObjectExtendedLimitInformation = 9;
|
|
61
|
+
private const int ErrorAccessDenied = 5;
|
|
62
|
+
private const int WsaAccessDenied = 10013;
|
|
63
|
+
private const int WsaTimedOut = 10060;
|
|
64
|
+
private static readonly IntPtr ProcThreadAttributeHandleList = new IntPtr(0x00020002);
|
|
65
|
+
private static readonly IntPtr ProcThreadAttributeSecurityCapabilities = new IntPtr(0x00020009);
|
|
66
|
+
|
|
67
|
+
private sealed class Arguments
|
|
68
|
+
{
|
|
69
|
+
public string Executable;
|
|
70
|
+
public string WorkingDirectory;
|
|
71
|
+
public string SandboxRoot;
|
|
72
|
+
public string WritableTemp;
|
|
73
|
+
public int TimeoutMilliseconds;
|
|
74
|
+
public UIntPtr ProcessMemoryBytes;
|
|
75
|
+
public string[] ChildArguments;
|
|
76
|
+
public bool AppContainerDeny;
|
|
77
|
+
public string ProtectedSentinel;
|
|
78
|
+
public string CanaryExecutable;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private sealed class LaunchResult
|
|
82
|
+
{
|
|
83
|
+
public bool Launched;
|
|
84
|
+
public bool TimedOut;
|
|
85
|
+
public int? ExitCode;
|
|
86
|
+
public bool FilteredToken;
|
|
87
|
+
public bool DisableMaxPrivilege;
|
|
88
|
+
public int EnabledPrivilegeCount;
|
|
89
|
+
public bool PrivilegesBounded;
|
|
90
|
+
public bool LowIntegrity;
|
|
91
|
+
public bool AssignedBeforeResume;
|
|
92
|
+
public bool HandleAllowlist;
|
|
93
|
+
public bool KillOnClose;
|
|
94
|
+
public bool ActiveProcessLimit;
|
|
95
|
+
public bool ProcessMemoryLimit;
|
|
96
|
+
public bool UiRestrictions;
|
|
97
|
+
public bool WritableTempLowIntegrity;
|
|
98
|
+
public bool AppContainer;
|
|
99
|
+
public bool AppContainerSidMatched;
|
|
100
|
+
public int CapabilityCount;
|
|
101
|
+
public bool SnapshotReadExecuteGrant;
|
|
102
|
+
public bool WritableTempModifyGrant;
|
|
103
|
+
public bool FilesystemCanaryDenied;
|
|
104
|
+
public int FilesystemCanaryError;
|
|
105
|
+
public bool NetworkCanaryDenied;
|
|
106
|
+
public int NetworkCanaryError;
|
|
107
|
+
public bool LoopbackAccepted;
|
|
108
|
+
public bool ProfileDeleted;
|
|
109
|
+
public bool AppContainerMode;
|
|
110
|
+
public byte[] StandardOutput = new byte[0];
|
|
111
|
+
public byte[] StandardError = new byte[0];
|
|
112
|
+
public string ErrorStage;
|
|
113
|
+
public int ErrorCode;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public static int Main(string[] args)
|
|
117
|
+
{
|
|
118
|
+
LaunchResult result = new LaunchResult();
|
|
119
|
+
try
|
|
120
|
+
{
|
|
121
|
+
Arguments parsed = ParseArguments(args);
|
|
122
|
+
result = Launch(parsed);
|
|
123
|
+
}
|
|
124
|
+
catch (Exception error)
|
|
125
|
+
{
|
|
126
|
+
result.ErrorStage = "launcher-exception";
|
|
127
|
+
result.ErrorCode = Marshal.GetLastWin32Error();
|
|
128
|
+
result.StandardError = Encoding.UTF8.GetBytes(error.GetType().Name + ": " + error.Message);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
Console.OutputEncoding = new UTF8Encoding(false);
|
|
132
|
+
Console.WriteLine(ToJson(result));
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private static Arguments ParseArguments(string[] args)
|
|
137
|
+
{
|
|
138
|
+
Dictionary<string, string> values = new Dictionary<string, string>(StringComparer.Ordinal);
|
|
139
|
+
int separator = Array.IndexOf(args, "--");
|
|
140
|
+
if (separator < 0 || separator % 2 != 0)
|
|
141
|
+
{
|
|
142
|
+
throw new ArgumentException("A closed key/value launcher prefix followed by -- is required.");
|
|
143
|
+
}
|
|
144
|
+
for (int index = 0; index < separator; index += 2)
|
|
145
|
+
{
|
|
146
|
+
string key = args[index];
|
|
147
|
+
if (!key.StartsWith("--", StringComparison.Ordinal) || values.ContainsKey(key))
|
|
148
|
+
{
|
|
149
|
+
throw new ArgumentException("Launcher fields must be unique closed-vocabulary names.");
|
|
150
|
+
}
|
|
151
|
+
values.Add(key, args[index + 1]);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
string[] required = {
|
|
155
|
+
"--executable", "--working-directory", "--sandbox-root", "--writable-temp",
|
|
156
|
+
"--timeout-ms", "--process-memory-bytes"
|
|
157
|
+
};
|
|
158
|
+
bool appContainerDeny = values.ContainsKey("--appcontainer-deny") ||
|
|
159
|
+
values.ContainsKey("--protected-sentinel") ||
|
|
160
|
+
values.ContainsKey("--canary-executable");
|
|
161
|
+
int expectedCount = required.Length + (appContainerDeny ? 3 : 0);
|
|
162
|
+
if (values.Count != expectedCount)
|
|
163
|
+
{
|
|
164
|
+
throw new ArgumentException("Unknown or missing launcher field.");
|
|
165
|
+
}
|
|
166
|
+
foreach (string key in required)
|
|
167
|
+
{
|
|
168
|
+
if (!values.ContainsKey(key)) throw new ArgumentException("Missing launcher field " + key + ".");
|
|
169
|
+
}
|
|
170
|
+
if (appContainerDeny &&
|
|
171
|
+
(!values.ContainsKey("--appcontainer-deny") ||
|
|
172
|
+
!values.ContainsKey("--protected-sentinel") ||
|
|
173
|
+
!values.ContainsKey("--canary-executable") ||
|
|
174
|
+
values["--appcontainer-deny"] != "v1"))
|
|
175
|
+
{
|
|
176
|
+
throw new ArgumentException("AppContainer deny mode requires its exact closed fields.");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
int timeout;
|
|
180
|
+
ulong memory;
|
|
181
|
+
if (!Int32.TryParse(values["--timeout-ms"], out timeout) || timeout < 1000 || timeout > 120000)
|
|
182
|
+
{
|
|
183
|
+
throw new ArgumentException("timeout-ms is outside the fixed launcher bound.");
|
|
184
|
+
}
|
|
185
|
+
if (!UInt64.TryParse(values["--process-memory-bytes"], out memory) || memory < 134217728 || memory > 1073741824)
|
|
186
|
+
{
|
|
187
|
+
throw new ArgumentException("process-memory-bytes is outside the fixed launcher bound.");
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
string executable = Path.GetFullPath(values["--executable"]);
|
|
191
|
+
string working = Path.GetFullPath(values["--working-directory"]);
|
|
192
|
+
string root = Path.GetFullPath(values["--sandbox-root"]);
|
|
193
|
+
string writableTemp = Path.GetFullPath(values["--writable-temp"]);
|
|
194
|
+
string rootPrefix = root.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)
|
|
195
|
+
? root : root + Path.DirectorySeparatorChar;
|
|
196
|
+
if (!IsInsideRoot(executable, root, rootPrefix) ||
|
|
197
|
+
!IsInsideRoot(working, root, rootPrefix) ||
|
|
198
|
+
!IsInsideRoot(writableTemp, root, rootPrefix))
|
|
199
|
+
{
|
|
200
|
+
throw new ArgumentException("Executable, working directory, and writable temp must stay inside sandbox-root.");
|
|
201
|
+
}
|
|
202
|
+
string protectedSentinel = appContainerDeny
|
|
203
|
+
? Path.GetFullPath(values["--protected-sentinel"])
|
|
204
|
+
: null;
|
|
205
|
+
if (appContainerDeny &&
|
|
206
|
+
(IsInsideRoot(protectedSentinel, root, rootPrefix) || !File.Exists(protectedSentinel)))
|
|
207
|
+
{
|
|
208
|
+
throw new ArgumentException("Protected sentinel must be an existing caller-readable file outside sandbox-root.");
|
|
209
|
+
}
|
|
210
|
+
string canaryExecutable = appContainerDeny
|
|
211
|
+
? Path.GetFullPath(values["--canary-executable"])
|
|
212
|
+
: null;
|
|
213
|
+
if (appContainerDeny &&
|
|
214
|
+
(!IsInsideRoot(canaryExecutable, root, rootPrefix) || !File.Exists(canaryExecutable)))
|
|
215
|
+
{
|
|
216
|
+
throw new ArgumentException("AppContainer canary must be an existing file inside sandbox-root.");
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
string[] child = new string[args.Length - separator - 1];
|
|
220
|
+
Array.Copy(args, separator + 1, child, 0, child.Length);
|
|
221
|
+
return new Arguments {
|
|
222
|
+
Executable = executable,
|
|
223
|
+
WorkingDirectory = working,
|
|
224
|
+
SandboxRoot = root,
|
|
225
|
+
WritableTemp = writableTemp,
|
|
226
|
+
TimeoutMilliseconds = timeout,
|
|
227
|
+
ProcessMemoryBytes = new UIntPtr(memory),
|
|
228
|
+
ChildArguments = child,
|
|
229
|
+
AppContainerDeny = appContainerDeny,
|
|
230
|
+
ProtectedSentinel = protectedSentinel,
|
|
231
|
+
CanaryExecutable = canaryExecutable,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private static bool IsInsideRoot(string value, string root, string rootPrefix)
|
|
236
|
+
{
|
|
237
|
+
return value.Equals(root, StringComparison.OrdinalIgnoreCase) ||
|
|
238
|
+
value.StartsWith(rootPrefix, StringComparison.OrdinalIgnoreCase);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private static LaunchResult Launch(Arguments args)
|
|
242
|
+
{
|
|
243
|
+
LaunchResult result = new LaunchResult();
|
|
244
|
+
IntPtr processToken = IntPtr.Zero;
|
|
245
|
+
IntPtr restrictedToken = IntPtr.Zero;
|
|
246
|
+
IntPtr lowSid = IntPtr.Zero;
|
|
247
|
+
IntPtr appContainerSid = IntPtr.Zero;
|
|
248
|
+
IntPtr childToken = IntPtr.Zero;
|
|
249
|
+
IntPtr job = IntPtr.Zero;
|
|
250
|
+
IntPtr stdoutRead = IntPtr.Zero;
|
|
251
|
+
IntPtr stdoutWrite = IntPtr.Zero;
|
|
252
|
+
IntPtr stderrRead = IntPtr.Zero;
|
|
253
|
+
IntPtr stderrWrite = IntPtr.Zero;
|
|
254
|
+
IntPtr nullInput = IntPtr.Zero;
|
|
255
|
+
IntPtr attributeList = IntPtr.Zero;
|
|
256
|
+
IntPtr handleList = IntPtr.Zero;
|
|
257
|
+
IntPtr securityCapabilitiesPointer = IntPtr.Zero;
|
|
258
|
+
string appContainerIdentity = null;
|
|
259
|
+
bool appContainerProfileCreated = false;
|
|
260
|
+
PROCESS_INFORMATION process = new PROCESS_INFORMATION();
|
|
261
|
+
|
|
262
|
+
try
|
|
263
|
+
{
|
|
264
|
+
ApplyLowIntegrityLabel(args.WritableTemp);
|
|
265
|
+
result.WritableTempLowIntegrity = true;
|
|
266
|
+
result.AppContainerMode = args.AppContainerDeny;
|
|
267
|
+
|
|
268
|
+
uint tokenAccess = TokenAssignPrimary | TokenDuplicate | TokenQuery | TokenAdjustDefault | TokenAdjustSessionId;
|
|
269
|
+
Check(OpenProcessToken(GetCurrentProcess(), tokenAccess, out processToken), "open-process-token");
|
|
270
|
+
Check(CreateRestrictedToken(processToken, DisableMaxPrivilege, 0, null, 0, IntPtr.Zero, 0, null, out restrictedToken), "create-restricted-token");
|
|
271
|
+
result.FilteredToken = true;
|
|
272
|
+
result.DisableMaxPrivilege = true;
|
|
273
|
+
|
|
274
|
+
Check(ConvertStringSidToSid(LowIntegritySid, out lowSid), "create-low-integrity-sid");
|
|
275
|
+
SetTokenIntegrity(restrictedToken, lowSid);
|
|
276
|
+
result.LowIntegrity = HasLowIntegrity(restrictedToken);
|
|
277
|
+
result.EnabledPrivilegeCount = EnabledPrivilegeCount(restrictedToken);
|
|
278
|
+
result.PrivilegesBounded = result.EnabledPrivilegeCount <= 1;
|
|
279
|
+
if (!result.LowIntegrity || !result.PrivilegesBounded)
|
|
280
|
+
{
|
|
281
|
+
throw new InvalidOperationException("Restricted-token evidence did not verify before launch.");
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
job = CreateJobObject(IntPtr.Zero, null);
|
|
285
|
+
Check(job != IntPtr.Zero, "create-job-object");
|
|
286
|
+
ConfigureJob(job, args.ProcessMemoryBytes);
|
|
287
|
+
result.KillOnClose = true;
|
|
288
|
+
result.ActiveProcessLimit = true;
|
|
289
|
+
result.ProcessMemoryLimit = true;
|
|
290
|
+
result.UiRestrictions = true;
|
|
291
|
+
|
|
292
|
+
if (args.AppContainerDeny)
|
|
293
|
+
{
|
|
294
|
+
appContainerIdentity = "HoloScript.HoloSystem.WHPX_" + Guid.NewGuid().ToString("N");
|
|
295
|
+
int profileResult = CreateAppContainerProfile(
|
|
296
|
+
appContainerIdentity,
|
|
297
|
+
"HoloSystem WHPX isolation",
|
|
298
|
+
"Ephemeral zero-capability HoloSystem VM host boundary",
|
|
299
|
+
IntPtr.Zero,
|
|
300
|
+
0,
|
|
301
|
+
out appContainerSid
|
|
302
|
+
);
|
|
303
|
+
if (profileResult != 0)
|
|
304
|
+
{
|
|
305
|
+
throw new LauncherException("create-appcontainer-profile", profileResult);
|
|
306
|
+
}
|
|
307
|
+
appContainerProfileCreated = true;
|
|
308
|
+
SecurityIdentifier appSid = new SecurityIdentifier(appContainerSid);
|
|
309
|
+
GrantDirectoryAccess(args.SandboxRoot, appSid, FileSystemRights.ReadAndExecute | FileSystemRights.ListDirectory);
|
|
310
|
+
result.SnapshotReadExecuteGrant = true;
|
|
311
|
+
GrantDirectoryAccess(args.WritableTemp, appSid, FileSystemRights.Modify);
|
|
312
|
+
result.WritableTempModifyGrant = true;
|
|
313
|
+
HardenProtectedSentinel(args.ProtectedSentinel);
|
|
314
|
+
RunAppContainerCanaries(args, restrictedToken, appContainerSid, job, result);
|
|
315
|
+
if (!result.FilesystemCanaryDenied || !result.NetworkCanaryDenied)
|
|
316
|
+
{
|
|
317
|
+
throw new LauncherException("appcontainer-canary-denial", 0);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
SECURITY_ATTRIBUTES pipeSecurity = new SECURITY_ATTRIBUTES();
|
|
322
|
+
pipeSecurity.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES));
|
|
323
|
+
pipeSecurity.bInheritHandle = true;
|
|
324
|
+
Check(CreatePipe(out stdoutRead, out stdoutWrite, ref pipeSecurity, 0), "create-stdout-pipe");
|
|
325
|
+
Check(SetHandleInformation(stdoutRead, HandleFlagInherit, 0), "protect-stdout-reader");
|
|
326
|
+
Check(CreatePipe(out stderrRead, out stderrWrite, ref pipeSecurity, 0), "create-stderr-pipe");
|
|
327
|
+
Check(SetHandleInformation(stderrRead, HandleFlagInherit, 0), "protect-stderr-reader");
|
|
328
|
+
|
|
329
|
+
nullInput = CreateFile("NUL", GenericRead, FileShareRead | FileShareWrite, ref pipeSecurity, OpenExisting, FileAttributeNormal, IntPtr.Zero);
|
|
330
|
+
Check(nullInput != new IntPtr(-1), "open-null-input");
|
|
331
|
+
|
|
332
|
+
UIntPtr attributeBytes = UIntPtr.Zero;
|
|
333
|
+
int attributeCount = args.AppContainerDeny ? 2 : 1;
|
|
334
|
+
InitializeProcThreadAttributeList(IntPtr.Zero, attributeCount, 0, ref attributeBytes);
|
|
335
|
+
attributeList = Marshal.AllocHGlobal((int)attributeBytes.ToUInt64());
|
|
336
|
+
Check(InitializeProcThreadAttributeList(attributeList, attributeCount, 0, ref attributeBytes), "initialize-handle-allowlist");
|
|
337
|
+
handleList = Marshal.AllocHGlobal(IntPtr.Size * 3);
|
|
338
|
+
Marshal.WriteIntPtr(handleList, 0, nullInput);
|
|
339
|
+
Marshal.WriteIntPtr(handleList, IntPtr.Size, stdoutWrite);
|
|
340
|
+
Marshal.WriteIntPtr(handleList, IntPtr.Size * 2, stderrWrite);
|
|
341
|
+
Check(UpdateProcThreadAttribute(
|
|
342
|
+
attributeList,
|
|
343
|
+
0,
|
|
344
|
+
ProcThreadAttributeHandleList,
|
|
345
|
+
handleList,
|
|
346
|
+
new UIntPtr((uint)(IntPtr.Size * 3)),
|
|
347
|
+
IntPtr.Zero,
|
|
348
|
+
IntPtr.Zero
|
|
349
|
+
), "set-handle-allowlist");
|
|
350
|
+
result.HandleAllowlist = true;
|
|
351
|
+
|
|
352
|
+
if (args.AppContainerDeny)
|
|
353
|
+
{
|
|
354
|
+
SECURITY_CAPABILITIES securityCapabilities = new SECURITY_CAPABILITIES();
|
|
355
|
+
securityCapabilities.AppContainerSid = appContainerSid;
|
|
356
|
+
securityCapabilities.Capabilities = IntPtr.Zero;
|
|
357
|
+
securityCapabilities.CapabilityCount = 0;
|
|
358
|
+
securityCapabilities.Reserved = 0;
|
|
359
|
+
int securityCapabilitiesSize = Marshal.SizeOf(typeof(SECURITY_CAPABILITIES));
|
|
360
|
+
securityCapabilitiesPointer = Marshal.AllocHGlobal(securityCapabilitiesSize);
|
|
361
|
+
Marshal.StructureToPtr(securityCapabilities, securityCapabilitiesPointer, false);
|
|
362
|
+
Check(UpdateProcThreadAttribute(
|
|
363
|
+
attributeList,
|
|
364
|
+
0,
|
|
365
|
+
ProcThreadAttributeSecurityCapabilities,
|
|
366
|
+
securityCapabilitiesPointer,
|
|
367
|
+
new UIntPtr((uint)securityCapabilitiesSize),
|
|
368
|
+
IntPtr.Zero,
|
|
369
|
+
IntPtr.Zero
|
|
370
|
+
), "set-appcontainer-security-capabilities");
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
STARTUPINFOEX startup = new STARTUPINFOEX();
|
|
374
|
+
startup.StartupInfo.cb = Marshal.SizeOf(typeof(STARTUPINFOEX));
|
|
375
|
+
startup.StartupInfo.dwFlags = StartfUseStdHandles;
|
|
376
|
+
startup.StartupInfo.hStdInput = nullInput;
|
|
377
|
+
startup.StartupInfo.hStdOutput = stdoutWrite;
|
|
378
|
+
startup.StartupInfo.hStdError = stderrWrite;
|
|
379
|
+
startup.lpAttributeList = attributeList;
|
|
380
|
+
|
|
381
|
+
StringBuilder commandLine = new StringBuilder(BuildCommandLine(args.Executable, args.ChildArguments));
|
|
382
|
+
uint flags = CreateSuspended | CreateNoWindow | CreateUnicodeEnvironment | ExtendedStartupInfoPresent;
|
|
383
|
+
bool created = CreateProcessAsUser(
|
|
384
|
+
restrictedToken,
|
|
385
|
+
args.Executable,
|
|
386
|
+
commandLine,
|
|
387
|
+
IntPtr.Zero,
|
|
388
|
+
IntPtr.Zero,
|
|
389
|
+
true,
|
|
390
|
+
flags,
|
|
391
|
+
IntPtr.Zero,
|
|
392
|
+
args.WorkingDirectory,
|
|
393
|
+
ref startup,
|
|
394
|
+
out process
|
|
395
|
+
);
|
|
396
|
+
Check(created, "create-restricted-process");
|
|
397
|
+
result.Launched = true;
|
|
398
|
+
|
|
399
|
+
if (args.AppContainerDeny)
|
|
400
|
+
{
|
|
401
|
+
Check(OpenProcessToken(process.hProcess, TokenQuery, out childToken), "open-appcontainer-process-token");
|
|
402
|
+
result.AppContainer = IsAppContainer(childToken);
|
|
403
|
+
result.AppContainerSidMatched = AppContainerSidMatches(childToken, appContainerSid);
|
|
404
|
+
result.CapabilityCount = TokenGroupCount(childToken, TokenCapabilities);
|
|
405
|
+
result.LowIntegrity = HasLowIntegrity(childToken);
|
|
406
|
+
result.EnabledPrivilegeCount = EnabledPrivilegeCount(childToken);
|
|
407
|
+
result.PrivilegesBounded = result.EnabledPrivilegeCount <= 1;
|
|
408
|
+
if (!result.AppContainer || !result.AppContainerSidMatched || result.CapabilityCount != 0 ||
|
|
409
|
+
!result.LowIntegrity || !result.PrivilegesBounded)
|
|
410
|
+
{
|
|
411
|
+
throw new LauncherException("appcontainer-token-evidence", 0);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
CloseHandle(stdoutWrite);
|
|
416
|
+
stdoutWrite = IntPtr.Zero;
|
|
417
|
+
CloseHandle(stderrWrite);
|
|
418
|
+
stderrWrite = IntPtr.Zero;
|
|
419
|
+
|
|
420
|
+
Check(AssignProcessToJobObject(job, process.hProcess), "assign-process-to-job");
|
|
421
|
+
result.AssignedBeforeResume = true;
|
|
422
|
+
|
|
423
|
+
Task<byte[]> stdoutTask = ReadBoundedAsync(stdoutRead);
|
|
424
|
+
Task<byte[]> stderrTask = ReadBoundedAsync(stderrRead);
|
|
425
|
+
uint resumed = ResumeThread(process.hThread);
|
|
426
|
+
if (resumed == UInt32.MaxValue) ThrowWin32("resume-restricted-process");
|
|
427
|
+
|
|
428
|
+
uint wait = WaitForSingleObject(process.hProcess, (uint)args.TimeoutMilliseconds);
|
|
429
|
+
if (wait == WaitTimeout)
|
|
430
|
+
{
|
|
431
|
+
result.TimedOut = true;
|
|
432
|
+
TerminateJobObject(job, 0x7f);
|
|
433
|
+
WaitForSingleObject(process.hProcess, 5000);
|
|
434
|
+
}
|
|
435
|
+
else if (wait != WaitObject0)
|
|
436
|
+
{
|
|
437
|
+
ThrowWin32("wait-restricted-process");
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
uint exitCode;
|
|
441
|
+
Check(GetExitCodeProcess(process.hProcess, out exitCode), "read-process-exit");
|
|
442
|
+
result.ExitCode = unchecked((int)exitCode);
|
|
443
|
+
Task.WaitAll(new Task[] { stdoutTask, stderrTask }, 5000);
|
|
444
|
+
result.StandardOutput = stdoutTask.IsCompleted ? stdoutTask.Result : new byte[0];
|
|
445
|
+
result.StandardError = stderrTask.IsCompleted ? stderrTask.Result : new byte[0];
|
|
446
|
+
}
|
|
447
|
+
catch (LauncherException error)
|
|
448
|
+
{
|
|
449
|
+
result.ErrorStage = error.Stage;
|
|
450
|
+
result.ErrorCode = error.NativeError;
|
|
451
|
+
if (process.hProcess != IntPtr.Zero) TerminateJobObject(job, 0x7e);
|
|
452
|
+
}
|
|
453
|
+
finally
|
|
454
|
+
{
|
|
455
|
+
CloseIfValid(process.hThread);
|
|
456
|
+
CloseIfValid(process.hProcess);
|
|
457
|
+
CloseIfValid(stdoutRead);
|
|
458
|
+
CloseIfValid(stdoutWrite);
|
|
459
|
+
CloseIfValid(stderrRead);
|
|
460
|
+
CloseIfValid(stderrWrite);
|
|
461
|
+
CloseIfValid(nullInput);
|
|
462
|
+
if (attributeList != IntPtr.Zero) DeleteProcThreadAttributeList(attributeList);
|
|
463
|
+
if (handleList != IntPtr.Zero) Marshal.FreeHGlobal(handleList);
|
|
464
|
+
if (securityCapabilitiesPointer != IntPtr.Zero) Marshal.FreeHGlobal(securityCapabilitiesPointer);
|
|
465
|
+
if (attributeList != IntPtr.Zero) Marshal.FreeHGlobal(attributeList);
|
|
466
|
+
CloseIfValid(job);
|
|
467
|
+
CloseIfValid(childToken);
|
|
468
|
+
CloseIfValid(restrictedToken);
|
|
469
|
+
CloseIfValid(processToken);
|
|
470
|
+
if (lowSid != IntPtr.Zero) LocalFree(lowSid);
|
|
471
|
+
if (appContainerProfileCreated)
|
|
472
|
+
{
|
|
473
|
+
int deleteResult = DeleteAppContainerProfile(appContainerIdentity);
|
|
474
|
+
result.ProfileDeleted = deleteResult == 0;
|
|
475
|
+
if (deleteResult != 0 && result.ErrorStage == null)
|
|
476
|
+
{
|
|
477
|
+
result.ErrorStage = "delete-appcontainer-profile";
|
|
478
|
+
result.ErrorCode = deleteResult;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (appContainerSid != IntPtr.Zero) FreeSid(appContainerSid);
|
|
482
|
+
}
|
|
483
|
+
return result;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
private static void ApplyLowIntegrityLabel(string path)
|
|
487
|
+
{
|
|
488
|
+
IntPtr descriptor;
|
|
489
|
+
uint size;
|
|
490
|
+
Check(ConvertStringSecurityDescriptorToSecurityDescriptor("S:(ML;OICI;NW;;;LW)", 1, out descriptor, out size), "create-low-integrity-acl");
|
|
491
|
+
try
|
|
492
|
+
{
|
|
493
|
+
Check(SetFileSecurity(path, 0x00000010, descriptor), "apply-low-integrity-acl");
|
|
494
|
+
}
|
|
495
|
+
finally
|
|
496
|
+
{
|
|
497
|
+
LocalFree(descriptor);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
private static void GrantDirectoryAccess(string path, SecurityIdentifier sid, FileSystemRights rights)
|
|
502
|
+
{
|
|
503
|
+
DirectoryInfo directory = new DirectoryInfo(path);
|
|
504
|
+
DirectorySecurity security = directory.GetAccessControl(AccessControlSections.Access);
|
|
505
|
+
security.AddAccessRule(new FileSystemAccessRule(
|
|
506
|
+
sid,
|
|
507
|
+
rights | FileSystemRights.Synchronize,
|
|
508
|
+
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
|
|
509
|
+
PropagationFlags.None,
|
|
510
|
+
AccessControlType.Allow
|
|
511
|
+
));
|
|
512
|
+
directory.SetAccessControl(security);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
private static void HardenProtectedSentinel(string path)
|
|
516
|
+
{
|
|
517
|
+
SecurityIdentifier user = WindowsIdentity.GetCurrent().User;
|
|
518
|
+
if (user == null) throw new InvalidOperationException("Current user SID is unavailable.");
|
|
519
|
+
FileSecurity security = new FileSecurity();
|
|
520
|
+
security.SetOwner(user);
|
|
521
|
+
security.SetAccessRuleProtection(true, false);
|
|
522
|
+
security.AddAccessRule(new FileSystemAccessRule(user, FileSystemRights.FullControl, AccessControlType.Allow));
|
|
523
|
+
File.SetAccessControl(path, security);
|
|
524
|
+
using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
|
|
525
|
+
{
|
|
526
|
+
if (stream.Length == 0) throw new InvalidOperationException("Protected sentinel is empty.");
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
private static void RunAppContainerCanaries(
|
|
531
|
+
Arguments args,
|
|
532
|
+
IntPtr restrictedToken,
|
|
533
|
+
IntPtr appContainerSid,
|
|
534
|
+
IntPtr job,
|
|
535
|
+
LaunchResult result)
|
|
536
|
+
{
|
|
537
|
+
TcpListener listener = new TcpListener(IPAddress.Loopback, 0);
|
|
538
|
+
listener.Start(1);
|
|
539
|
+
try
|
|
540
|
+
{
|
|
541
|
+
int port = ((IPEndPoint)listener.LocalEndpoint).Port;
|
|
542
|
+
Dictionary<string, int> evidence = RunAppContainerCanaryChild(
|
|
543
|
+
args,
|
|
544
|
+
restrictedToken,
|
|
545
|
+
appContainerSid,
|
|
546
|
+
job,
|
|
547
|
+
port
|
|
548
|
+
);
|
|
549
|
+
result.FilesystemCanaryError = evidence["filesystemError"];
|
|
550
|
+
result.NetworkCanaryError = evidence["networkError"];
|
|
551
|
+
result.LoopbackAccepted = listener.Pending();
|
|
552
|
+
result.FilesystemCanaryDenied = evidence["appContainer"] == 1 &&
|
|
553
|
+
evidence["capabilityCount"] == 0 &&
|
|
554
|
+
result.FilesystemCanaryError == ErrorAccessDenied;
|
|
555
|
+
result.NetworkCanaryDenied = evidence["appContainer"] == 1 &&
|
|
556
|
+
evidence["capabilityCount"] == 0 &&
|
|
557
|
+
(result.NetworkCanaryError == WsaAccessDenied ||
|
|
558
|
+
result.NetworkCanaryError == WsaTimedOut) &&
|
|
559
|
+
!result.LoopbackAccepted;
|
|
560
|
+
}
|
|
561
|
+
finally
|
|
562
|
+
{
|
|
563
|
+
listener.Stop();
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
private static Dictionary<string, int> RunAppContainerCanaryChild(
|
|
568
|
+
Arguments args,
|
|
569
|
+
IntPtr restrictedToken,
|
|
570
|
+
IntPtr appContainerSid,
|
|
571
|
+
IntPtr job,
|
|
572
|
+
int port)
|
|
573
|
+
{
|
|
574
|
+
IntPtr stdoutRead = IntPtr.Zero;
|
|
575
|
+
IntPtr stdoutWrite = IntPtr.Zero;
|
|
576
|
+
IntPtr stderrRead = IntPtr.Zero;
|
|
577
|
+
IntPtr stderrWrite = IntPtr.Zero;
|
|
578
|
+
IntPtr nullInput = IntPtr.Zero;
|
|
579
|
+
IntPtr attributeList = IntPtr.Zero;
|
|
580
|
+
IntPtr handleList = IntPtr.Zero;
|
|
581
|
+
IntPtr securityCapabilitiesPointer = IntPtr.Zero;
|
|
582
|
+
PROCESS_INFORMATION process = new PROCESS_INFORMATION();
|
|
583
|
+
try
|
|
584
|
+
{
|
|
585
|
+
SECURITY_ATTRIBUTES pipeSecurity = new SECURITY_ATTRIBUTES();
|
|
586
|
+
pipeSecurity.nLength = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES));
|
|
587
|
+
pipeSecurity.bInheritHandle = true;
|
|
588
|
+
Check(CreatePipe(out stdoutRead, out stdoutWrite, ref pipeSecurity, 0), "create-canary-stdout-pipe");
|
|
589
|
+
Check(SetHandleInformation(stdoutRead, HandleFlagInherit, 0), "protect-canary-stdout-reader");
|
|
590
|
+
Check(CreatePipe(out stderrRead, out stderrWrite, ref pipeSecurity, 0), "create-canary-stderr-pipe");
|
|
591
|
+
Check(SetHandleInformation(stderrRead, HandleFlagInherit, 0), "protect-canary-stderr-reader");
|
|
592
|
+
nullInput = CreateFile("NUL", GenericRead, FileShareRead | FileShareWrite, ref pipeSecurity, OpenExisting, FileAttributeNormal, IntPtr.Zero);
|
|
593
|
+
Check(nullInput != new IntPtr(-1), "open-canary-null-input");
|
|
594
|
+
|
|
595
|
+
UIntPtr attributeBytes = UIntPtr.Zero;
|
|
596
|
+
InitializeProcThreadAttributeList(IntPtr.Zero, 2, 0, ref attributeBytes);
|
|
597
|
+
attributeList = Marshal.AllocHGlobal((int)attributeBytes.ToUInt64());
|
|
598
|
+
Check(InitializeProcThreadAttributeList(attributeList, 2, 0, ref attributeBytes), "initialize-canary-attributes");
|
|
599
|
+
handleList = Marshal.AllocHGlobal(IntPtr.Size * 3);
|
|
600
|
+
Marshal.WriteIntPtr(handleList, 0, nullInput);
|
|
601
|
+
Marshal.WriteIntPtr(handleList, IntPtr.Size, stdoutWrite);
|
|
602
|
+
Marshal.WriteIntPtr(handleList, IntPtr.Size * 2, stderrWrite);
|
|
603
|
+
Check(UpdateProcThreadAttribute(
|
|
604
|
+
attributeList,
|
|
605
|
+
0,
|
|
606
|
+
ProcThreadAttributeHandleList,
|
|
607
|
+
handleList,
|
|
608
|
+
new UIntPtr((uint)(IntPtr.Size * 3)),
|
|
609
|
+
IntPtr.Zero,
|
|
610
|
+
IntPtr.Zero
|
|
611
|
+
), "set-canary-handle-allowlist");
|
|
612
|
+
|
|
613
|
+
SECURITY_CAPABILITIES securityCapabilities = new SECURITY_CAPABILITIES();
|
|
614
|
+
securityCapabilities.AppContainerSid = appContainerSid;
|
|
615
|
+
int securityCapabilitiesSize = Marshal.SizeOf(typeof(SECURITY_CAPABILITIES));
|
|
616
|
+
securityCapabilitiesPointer = Marshal.AllocHGlobal(securityCapabilitiesSize);
|
|
617
|
+
Marshal.StructureToPtr(securityCapabilities, securityCapabilitiesPointer, false);
|
|
618
|
+
Check(UpdateProcThreadAttribute(
|
|
619
|
+
attributeList,
|
|
620
|
+
0,
|
|
621
|
+
ProcThreadAttributeSecurityCapabilities,
|
|
622
|
+
securityCapabilitiesPointer,
|
|
623
|
+
new UIntPtr((uint)securityCapabilitiesSize),
|
|
624
|
+
IntPtr.Zero,
|
|
625
|
+
IntPtr.Zero
|
|
626
|
+
), "set-canary-appcontainer");
|
|
627
|
+
|
|
628
|
+
string executable = args.CanaryExecutable;
|
|
629
|
+
string[] canaryArguments = {
|
|
630
|
+
"--protected-sentinel",
|
|
631
|
+
args.ProtectedSentinel,
|
|
632
|
+
"--loopback-port",
|
|
633
|
+
port.ToString()
|
|
634
|
+
};
|
|
635
|
+
STARTUPINFOEX startup = new STARTUPINFOEX();
|
|
636
|
+
startup.StartupInfo.cb = Marshal.SizeOf(typeof(STARTUPINFOEX));
|
|
637
|
+
startup.StartupInfo.dwFlags = StartfUseStdHandles;
|
|
638
|
+
startup.StartupInfo.hStdInput = nullInput;
|
|
639
|
+
startup.StartupInfo.hStdOutput = stdoutWrite;
|
|
640
|
+
startup.StartupInfo.hStdError = stderrWrite;
|
|
641
|
+
startup.lpAttributeList = attributeList;
|
|
642
|
+
StringBuilder commandLine = new StringBuilder(BuildCommandLine(executable, canaryArguments));
|
|
643
|
+
uint flags = CreateSuspended | CreateNoWindow | CreateUnicodeEnvironment | ExtendedStartupInfoPresent;
|
|
644
|
+
Check(CreateProcessAsUser(
|
|
645
|
+
restrictedToken,
|
|
646
|
+
executable,
|
|
647
|
+
commandLine,
|
|
648
|
+
IntPtr.Zero,
|
|
649
|
+
IntPtr.Zero,
|
|
650
|
+
true,
|
|
651
|
+
flags,
|
|
652
|
+
IntPtr.Zero,
|
|
653
|
+
args.SandboxRoot,
|
|
654
|
+
ref startup,
|
|
655
|
+
out process
|
|
656
|
+
), "create-appcontainer-canary");
|
|
657
|
+
CloseHandle(stdoutWrite);
|
|
658
|
+
stdoutWrite = IntPtr.Zero;
|
|
659
|
+
CloseHandle(stderrWrite);
|
|
660
|
+
stderrWrite = IntPtr.Zero;
|
|
661
|
+
Check(AssignProcessToJobObject(job, process.hProcess), "assign-canary-to-job");
|
|
662
|
+
Task<byte[]> stdoutTask = ReadBoundedAsync(stdoutRead);
|
|
663
|
+
Task<byte[]> stderrTask = ReadBoundedAsync(stderrRead);
|
|
664
|
+
uint resumed = ResumeThread(process.hThread);
|
|
665
|
+
if (resumed == UInt32.MaxValue) ThrowWin32("resume-appcontainer-canary");
|
|
666
|
+
uint wait = WaitForSingleObject(process.hProcess, 10000);
|
|
667
|
+
if (wait != WaitObject0)
|
|
668
|
+
{
|
|
669
|
+
TerminateProcess(process.hProcess, 0x7d);
|
|
670
|
+
WaitForSingleObject(process.hProcess, 5000);
|
|
671
|
+
throw new LauncherException("wait-appcontainer-canary", unchecked((int)wait));
|
|
672
|
+
}
|
|
673
|
+
uint exitCode;
|
|
674
|
+
Check(GetExitCodeProcess(process.hProcess, out exitCode), "read-canary-exit");
|
|
675
|
+
Task.WaitAll(new Task[] { stdoutTask, stderrTask }, 5000);
|
|
676
|
+
byte[] stdout = stdoutTask.IsCompleted ? stdoutTask.Result : new byte[0];
|
|
677
|
+
byte[] stderr = stderrTask.IsCompleted ? stderrTask.Result : new byte[0];
|
|
678
|
+
if (exitCode != 0 || stderr.Length != 0) throw new InvalidOperationException("AppContainer canary failed closed.");
|
|
679
|
+
return ParseCanaryEvidence(Encoding.UTF8.GetString(stdout).Trim());
|
|
680
|
+
}
|
|
681
|
+
finally
|
|
682
|
+
{
|
|
683
|
+
CloseIfValid(process.hThread);
|
|
684
|
+
CloseIfValid(process.hProcess);
|
|
685
|
+
CloseIfValid(stdoutRead);
|
|
686
|
+
CloseIfValid(stdoutWrite);
|
|
687
|
+
CloseIfValid(stderrRead);
|
|
688
|
+
CloseIfValid(stderrWrite);
|
|
689
|
+
CloseIfValid(nullInput);
|
|
690
|
+
if (attributeList != IntPtr.Zero) DeleteProcThreadAttributeList(attributeList);
|
|
691
|
+
if (handleList != IntPtr.Zero) Marshal.FreeHGlobal(handleList);
|
|
692
|
+
if (securityCapabilitiesPointer != IntPtr.Zero) Marshal.FreeHGlobal(securityCapabilitiesPointer);
|
|
693
|
+
if (attributeList != IntPtr.Zero) Marshal.FreeHGlobal(attributeList);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
private static Dictionary<string, int> ParseCanaryEvidence(string value)
|
|
698
|
+
{
|
|
699
|
+
Dictionary<string, int> parsed = new Dictionary<string, int>(StringComparer.Ordinal);
|
|
700
|
+
foreach (string field in value.Split(';'))
|
|
701
|
+
{
|
|
702
|
+
string[] pair = field.Split(new char[] { '=' }, 2);
|
|
703
|
+
int number;
|
|
704
|
+
if (pair.Length != 2 || parsed.ContainsKey(pair[0]) || !Int32.TryParse(pair[1], out number))
|
|
705
|
+
{
|
|
706
|
+
throw new InvalidOperationException("AppContainer canary protocol is invalid.");
|
|
707
|
+
}
|
|
708
|
+
parsed.Add(pair[0], number);
|
|
709
|
+
}
|
|
710
|
+
string[] keys = { "appContainer", "capabilityCount", "filesystemError", "networkError" };
|
|
711
|
+
if (parsed.Count != keys.Length) throw new InvalidOperationException("AppContainer canary protocol is incomplete.");
|
|
712
|
+
foreach (string key in keys)
|
|
713
|
+
{
|
|
714
|
+
if (!parsed.ContainsKey(key)) throw new InvalidOperationException("AppContainer canary field is missing.");
|
|
715
|
+
}
|
|
716
|
+
return parsed;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
private static void SetTokenIntegrity(IntPtr token, IntPtr sid)
|
|
720
|
+
{
|
|
721
|
+
int sidLength = (int)GetLengthSid(sid);
|
|
722
|
+
int structLength = Marshal.SizeOf(typeof(TOKEN_MANDATORY_LABEL));
|
|
723
|
+
IntPtr buffer = Marshal.AllocHGlobal(structLength + sidLength);
|
|
724
|
+
try
|
|
725
|
+
{
|
|
726
|
+
IntPtr copiedSid = IntPtr.Add(buffer, structLength);
|
|
727
|
+
Check(CopySid((uint)sidLength, copiedSid, sid), "copy-low-integrity-sid");
|
|
728
|
+
TOKEN_MANDATORY_LABEL label = new TOKEN_MANDATORY_LABEL();
|
|
729
|
+
label.Label.Sid = copiedSid;
|
|
730
|
+
label.Label.Attributes = SeGroupIntegrity;
|
|
731
|
+
Marshal.StructureToPtr(label, buffer, false);
|
|
732
|
+
Check(SetTokenInformation(token, TokenIntegrityLevel, buffer, structLength + sidLength), "set-low-integrity-token");
|
|
733
|
+
}
|
|
734
|
+
finally
|
|
735
|
+
{
|
|
736
|
+
Marshal.FreeHGlobal(buffer);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
private static bool HasLowIntegrity(IntPtr token)
|
|
741
|
+
{
|
|
742
|
+
IntPtr buffer = QueryTokenInformation(token, TokenIntegrityLevel);
|
|
743
|
+
try
|
|
744
|
+
{
|
|
745
|
+
TOKEN_MANDATORY_LABEL label = (TOKEN_MANDATORY_LABEL)Marshal.PtrToStructure(buffer, typeof(TOKEN_MANDATORY_LABEL));
|
|
746
|
+
IntPtr countPointer = GetSidSubAuthorityCount(label.Label.Sid);
|
|
747
|
+
byte count = Marshal.ReadByte(countPointer);
|
|
748
|
+
if (count == 0) return false;
|
|
749
|
+
int level = Marshal.ReadInt32(GetSidSubAuthority(label.Label.Sid, (uint)(count - 1)));
|
|
750
|
+
return level <= 4096;
|
|
751
|
+
}
|
|
752
|
+
finally
|
|
753
|
+
{
|
|
754
|
+
Marshal.FreeHGlobal(buffer);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
private static int EnabledPrivilegeCount(IntPtr token)
|
|
759
|
+
{
|
|
760
|
+
IntPtr buffer = QueryTokenInformation(token, TokenPrivileges);
|
|
761
|
+
try
|
|
762
|
+
{
|
|
763
|
+
uint count = unchecked((uint)Marshal.ReadInt32(buffer));
|
|
764
|
+
int offset = 4;
|
|
765
|
+
int size = Marshal.SizeOf(typeof(LUID_AND_ATTRIBUTES));
|
|
766
|
+
int enabled = 0;
|
|
767
|
+
for (uint index = 0; index < count; index++)
|
|
768
|
+
{
|
|
769
|
+
IntPtr entryPointer = IntPtr.Add(buffer, offset + ((int)index * size));
|
|
770
|
+
LUID_AND_ATTRIBUTES entry = (LUID_AND_ATTRIBUTES)Marshal.PtrToStructure(entryPointer, typeof(LUID_AND_ATTRIBUTES));
|
|
771
|
+
if ((entry.Attributes & SePrivilegeEnabled) != 0) enabled++;
|
|
772
|
+
}
|
|
773
|
+
return enabled;
|
|
774
|
+
}
|
|
775
|
+
finally
|
|
776
|
+
{
|
|
777
|
+
Marshal.FreeHGlobal(buffer);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
private static bool IsAppContainer(IntPtr token)
|
|
782
|
+
{
|
|
783
|
+
IntPtr buffer = QueryTokenInformation(token, TokenIsAppContainer);
|
|
784
|
+
try
|
|
785
|
+
{
|
|
786
|
+
return Marshal.ReadInt32(buffer) != 0;
|
|
787
|
+
}
|
|
788
|
+
finally
|
|
789
|
+
{
|
|
790
|
+
Marshal.FreeHGlobal(buffer);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
private static int TokenGroupCount(IntPtr token, int informationClass)
|
|
795
|
+
{
|
|
796
|
+
IntPtr buffer = QueryTokenInformation(token, informationClass);
|
|
797
|
+
try
|
|
798
|
+
{
|
|
799
|
+
return Marshal.ReadInt32(buffer);
|
|
800
|
+
}
|
|
801
|
+
finally
|
|
802
|
+
{
|
|
803
|
+
Marshal.FreeHGlobal(buffer);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
private static bool AppContainerSidMatches(IntPtr token, IntPtr expectedSid)
|
|
808
|
+
{
|
|
809
|
+
IntPtr buffer = QueryTokenInformation(token, TokenAppContainerSid);
|
|
810
|
+
try
|
|
811
|
+
{
|
|
812
|
+
TOKEN_APPCONTAINER_INFORMATION information =
|
|
813
|
+
(TOKEN_APPCONTAINER_INFORMATION)Marshal.PtrToStructure(
|
|
814
|
+
buffer,
|
|
815
|
+
typeof(TOKEN_APPCONTAINER_INFORMATION)
|
|
816
|
+
);
|
|
817
|
+
return information.TokenAppContainer != IntPtr.Zero &&
|
|
818
|
+
EqualSid(information.TokenAppContainer, expectedSid);
|
|
819
|
+
}
|
|
820
|
+
finally
|
|
821
|
+
{
|
|
822
|
+
Marshal.FreeHGlobal(buffer);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
private static IntPtr QueryTokenInformation(IntPtr token, int informationClass)
|
|
827
|
+
{
|
|
828
|
+
int length = 0;
|
|
829
|
+
GetTokenInformation(token, informationClass, IntPtr.Zero, 0, out length);
|
|
830
|
+
if (length <= 0) ThrowWin32("size-token-information");
|
|
831
|
+
IntPtr buffer = Marshal.AllocHGlobal(length);
|
|
832
|
+
if (!GetTokenInformation(token, informationClass, buffer, length, out length))
|
|
833
|
+
{
|
|
834
|
+
int error = Marshal.GetLastWin32Error();
|
|
835
|
+
Marshal.FreeHGlobal(buffer);
|
|
836
|
+
throw new LauncherException("read-token-information", error);
|
|
837
|
+
}
|
|
838
|
+
return buffer;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
private static void ConfigureJob(IntPtr job, UIntPtr processMemory)
|
|
842
|
+
{
|
|
843
|
+
JOBOBJECT_EXTENDED_LIMIT_INFORMATION limits = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
|
|
844
|
+
limits.BasicLimitInformation.LimitFlags = JobObjectLimitKillOnJobClose |
|
|
845
|
+
JobObjectLimitActiveProcess | JobObjectLimitProcessMemory;
|
|
846
|
+
limits.BasicLimitInformation.ActiveProcessLimit = 1;
|
|
847
|
+
limits.ProcessMemoryLimit = processMemory;
|
|
848
|
+
int limitSize = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
|
|
849
|
+
IntPtr limitPointer = Marshal.AllocHGlobal(limitSize);
|
|
850
|
+
try
|
|
851
|
+
{
|
|
852
|
+
Marshal.StructureToPtr(limits, limitPointer, false);
|
|
853
|
+
Check(SetInformationJobObject(job, JobObjectExtendedLimitInformation, limitPointer, (uint)limitSize), "set-job-limits");
|
|
854
|
+
}
|
|
855
|
+
finally
|
|
856
|
+
{
|
|
857
|
+
Marshal.FreeHGlobal(limitPointer);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
JOBOBJECT_BASIC_UI_RESTRICTIONS ui = new JOBOBJECT_BASIC_UI_RESTRICTIONS();
|
|
861
|
+
ui.UIRestrictionsClass = JobObjectUiLimitHandles | JobObjectUiLimitReadClipboard |
|
|
862
|
+
JobObjectUiLimitWriteClipboard | JobObjectUiLimitSystemParameters |
|
|
863
|
+
JobObjectUiLimitDisplaySettings | JobObjectUiLimitGlobalAtoms |
|
|
864
|
+
JobObjectUiLimitDesktop | JobObjectUiLimitExitWindows;
|
|
865
|
+
int uiSize = Marshal.SizeOf(typeof(JOBOBJECT_BASIC_UI_RESTRICTIONS));
|
|
866
|
+
IntPtr uiPointer = Marshal.AllocHGlobal(uiSize);
|
|
867
|
+
try
|
|
868
|
+
{
|
|
869
|
+
Marshal.StructureToPtr(ui, uiPointer, false);
|
|
870
|
+
Check(SetInformationJobObject(job, JobObjectBasicUiRestrictions, uiPointer, (uint)uiSize), "set-job-ui-limits");
|
|
871
|
+
}
|
|
872
|
+
finally
|
|
873
|
+
{
|
|
874
|
+
Marshal.FreeHGlobal(uiPointer);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
private static Task<byte[]> ReadBoundedAsync(IntPtr handle)
|
|
880
|
+
{
|
|
881
|
+
return Task.Factory.StartNew(delegate {
|
|
882
|
+
using (FileStream stream = new FileStream(new Microsoft.Win32.SafeHandles.SafeFileHandle(handle, false), FileAccess.Read, 4096, false))
|
|
883
|
+
using (MemoryStream output = new MemoryStream())
|
|
884
|
+
{
|
|
885
|
+
byte[] buffer = new byte[8192];
|
|
886
|
+
while (true)
|
|
887
|
+
{
|
|
888
|
+
int read = stream.Read(buffer, 0, buffer.Length);
|
|
889
|
+
if (read == 0) break;
|
|
890
|
+
if (output.Length + read > OutputLimit) throw new IOException("Child output exceeded the launcher limit.");
|
|
891
|
+
output.Write(buffer, 0, read);
|
|
892
|
+
}
|
|
893
|
+
return output.ToArray();
|
|
894
|
+
}
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
private static string BuildCommandLine(string executable, string[] args)
|
|
899
|
+
{
|
|
900
|
+
StringBuilder result = new StringBuilder();
|
|
901
|
+
result.Append(QuoteWindowsArgument(executable));
|
|
902
|
+
foreach (string argument in args)
|
|
903
|
+
{
|
|
904
|
+
result.Append(' ');
|
|
905
|
+
result.Append(QuoteWindowsArgument(argument));
|
|
906
|
+
}
|
|
907
|
+
return result.ToString();
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
private static string QuoteWindowsArgument(string value)
|
|
911
|
+
{
|
|
912
|
+
if (value.Length > 0 && value.IndexOfAny(new char[] { ' ', '\t', '\n', '\v', '"' }) < 0) return value;
|
|
913
|
+
StringBuilder result = new StringBuilder("\"");
|
|
914
|
+
int slashes = 0;
|
|
915
|
+
foreach (char character in value)
|
|
916
|
+
{
|
|
917
|
+
if (character == '\\')
|
|
918
|
+
{
|
|
919
|
+
slashes++;
|
|
920
|
+
}
|
|
921
|
+
else if (character == '"')
|
|
922
|
+
{
|
|
923
|
+
result.Append('\\', slashes * 2 + 1);
|
|
924
|
+
result.Append('"');
|
|
925
|
+
slashes = 0;
|
|
926
|
+
}
|
|
927
|
+
else
|
|
928
|
+
{
|
|
929
|
+
result.Append('\\', slashes);
|
|
930
|
+
result.Append(character);
|
|
931
|
+
slashes = 0;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
result.Append('\\', slashes * 2);
|
|
935
|
+
result.Append('"');
|
|
936
|
+
return result.ToString();
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
private static string ToJson(LaunchResult result)
|
|
940
|
+
{
|
|
941
|
+
string isolation = result.AppContainerMode
|
|
942
|
+
?
|
|
943
|
+
"\"filteredToken\":" + Bool(result.FilteredToken) + "," +
|
|
944
|
+
"\"disableMaxPrivilege\":" + Bool(result.DisableMaxPrivilege) + "," +
|
|
945
|
+
"\"enabledPrivilegeCount\":" + result.EnabledPrivilegeCount.ToString() + "," +
|
|
946
|
+
"\"privilegesBounded\":" + Bool(result.PrivilegesBounded) + "," +
|
|
947
|
+
"\"lowIntegrity\":" + Bool(result.LowIntegrity) + "," +
|
|
948
|
+
"\"assignedBeforeResume\":" + Bool(result.AssignedBeforeResume) + "," +
|
|
949
|
+
"\"handleAllowlist\":" + Bool(result.HandleAllowlist) + "," +
|
|
950
|
+
"\"killOnClose\":" + Bool(result.KillOnClose) + "," +
|
|
951
|
+
"\"activeProcessLimit\":" + Bool(result.ActiveProcessLimit) + "," +
|
|
952
|
+
"\"processMemoryLimit\":" + Bool(result.ProcessMemoryLimit) + "," +
|
|
953
|
+
"\"uiRestrictions\":" + Bool(result.UiRestrictions) + "," +
|
|
954
|
+
"\"appContainer\":" + Bool(result.AppContainer) + "," +
|
|
955
|
+
"\"appContainerSidMatched\":" + Bool(result.AppContainerSidMatched) + "," +
|
|
956
|
+
"\"capabilityCount\":" + result.CapabilityCount.ToString() + "," +
|
|
957
|
+
"\"snapshotReadExecuteGrant\":" + Bool(result.SnapshotReadExecuteGrant) + "," +
|
|
958
|
+
"\"writableTempModifyGrant\":" + Bool(result.WritableTempModifyGrant) + "," +
|
|
959
|
+
"\"filesystemCanaryDenied\":" + Bool(result.FilesystemCanaryDenied) + "," +
|
|
960
|
+
"\"filesystemCanaryError\":" + result.FilesystemCanaryError.ToString() + "," +
|
|
961
|
+
"\"networkCanaryDenied\":" + Bool(result.NetworkCanaryDenied) + "," +
|
|
962
|
+
"\"networkCanaryError\":" + result.NetworkCanaryError.ToString() + "," +
|
|
963
|
+
"\"loopbackAccepted\":" + Bool(result.LoopbackAccepted) + "," +
|
|
964
|
+
"\"profileDeleted\":" + Bool(result.ProfileDeleted)
|
|
965
|
+
:
|
|
966
|
+
"\"filteredToken\":" + Bool(result.FilteredToken) + "," +
|
|
967
|
+
"\"disableMaxPrivilege\":" + Bool(result.DisableMaxPrivilege) + "," +
|
|
968
|
+
"\"enabledPrivilegeCount\":" + result.EnabledPrivilegeCount.ToString() + "," +
|
|
969
|
+
"\"privilegesBounded\":" + Bool(result.PrivilegesBounded) + "," +
|
|
970
|
+
"\"lowIntegrity\":" + Bool(result.LowIntegrity) + "," +
|
|
971
|
+
"\"assignedBeforeResume\":" + Bool(result.AssignedBeforeResume) + "," +
|
|
972
|
+
"\"handleAllowlist\":" + Bool(result.HandleAllowlist) + "," +
|
|
973
|
+
"\"killOnClose\":" + Bool(result.KillOnClose) + "," +
|
|
974
|
+
"\"activeProcessLimit\":" + Bool(result.ActiveProcessLimit) + "," +
|
|
975
|
+
"\"processMemoryLimit\":" + Bool(result.ProcessMemoryLimit) + "," +
|
|
976
|
+
"\"uiRestrictions\":" + Bool(result.UiRestrictions) + "," +
|
|
977
|
+
"\"writableTempLowIntegrity\":" + Bool(result.WritableTempLowIntegrity);
|
|
978
|
+
return "{" +
|
|
979
|
+
"\"protocol\":\"" + (result.AppContainerMode ? AppContainerProtocol : Protocol) + "\"," +
|
|
980
|
+
"\"launched\":" + Bool(result.Launched) + "," +
|
|
981
|
+
"\"timedOut\":" + Bool(result.TimedOut) + "," +
|
|
982
|
+
"\"exitCode\":" + (result.ExitCode.HasValue ? result.ExitCode.Value.ToString() : "null") + "," +
|
|
983
|
+
"\"isolation\":{" + isolation + "}," +
|
|
984
|
+
"\"stdoutBase64\":\"" + Convert.ToBase64String(result.StandardOutput) + "\"," +
|
|
985
|
+
"\"stderrBase64\":\"" + Convert.ToBase64String(result.StandardError) + "\"," +
|
|
986
|
+
"\"errorStage\":" + (result.ErrorStage == null ? "null" : "\"" + EscapeJson(result.ErrorStage) + "\"") + "," +
|
|
987
|
+
"\"errorCode\":" + result.ErrorCode.ToString() +
|
|
988
|
+
"}";
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
private static string Bool(bool value) { return value ? "true" : "false"; }
|
|
992
|
+
|
|
993
|
+
private static string EscapeJson(string value)
|
|
994
|
+
{
|
|
995
|
+
return value.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r").Replace("\n", "\\n");
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
private static void Check(bool condition, string stage)
|
|
999
|
+
{
|
|
1000
|
+
if (!condition) ThrowWin32(stage);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
private static void ThrowWin32(string stage)
|
|
1004
|
+
{
|
|
1005
|
+
throw new LauncherException(stage, Marshal.GetLastWin32Error());
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
private static void CloseIfValid(IntPtr handle)
|
|
1009
|
+
{
|
|
1010
|
+
if (handle != IntPtr.Zero && handle != new IntPtr(-1)) CloseHandle(handle);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
private sealed class LauncherException : Exception
|
|
1014
|
+
{
|
|
1015
|
+
public readonly string Stage;
|
|
1016
|
+
public readonly int NativeError;
|
|
1017
|
+
public LauncherException(string stage, int nativeError) : base(stage + " failed with Windows error " + nativeError + ".")
|
|
1018
|
+
{
|
|
1019
|
+
Stage = stage;
|
|
1020
|
+
NativeError = nativeError;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1025
|
+
private struct SID_AND_ATTRIBUTES { public IntPtr Sid; public uint Attributes; }
|
|
1026
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1027
|
+
private struct LUID { public uint LowPart; public int HighPart; }
|
|
1028
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1029
|
+
private struct LUID_AND_ATTRIBUTES { public LUID Luid; public uint Attributes; }
|
|
1030
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1031
|
+
private struct TOKEN_MANDATORY_LABEL { public SID_AND_ATTRIBUTES Label; }
|
|
1032
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1033
|
+
private struct TOKEN_APPCONTAINER_INFORMATION { public IntPtr TokenAppContainer; }
|
|
1034
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1035
|
+
private struct SECURITY_CAPABILITIES
|
|
1036
|
+
{
|
|
1037
|
+
public IntPtr AppContainerSid;
|
|
1038
|
+
public IntPtr Capabilities;
|
|
1039
|
+
public uint CapabilityCount;
|
|
1040
|
+
public uint Reserved;
|
|
1041
|
+
}
|
|
1042
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1043
|
+
private struct SECURITY_ATTRIBUTES { public int nLength; public IntPtr lpSecurityDescriptor; [MarshalAs(UnmanagedType.Bool)] public bool bInheritHandle; }
|
|
1044
|
+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
1045
|
+
private struct STARTUPINFO
|
|
1046
|
+
{
|
|
1047
|
+
public int cb; public string lpReserved; public string lpDesktop; public string lpTitle;
|
|
1048
|
+
public uint dwX; public uint dwY; public uint dwXSize; public uint dwYSize;
|
|
1049
|
+
public uint dwXCountChars; public uint dwYCountChars; public uint dwFillAttribute;
|
|
1050
|
+
public uint dwFlags; public ushort wShowWindow; public ushort cbReserved2;
|
|
1051
|
+
public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError;
|
|
1052
|
+
}
|
|
1053
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1054
|
+
private struct STARTUPINFOEX { public STARTUPINFO StartupInfo; public IntPtr lpAttributeList; }
|
|
1055
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1056
|
+
private struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; }
|
|
1057
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1058
|
+
private struct JOBOBJECT_BASIC_LIMIT_INFORMATION
|
|
1059
|
+
{
|
|
1060
|
+
public long PerProcessUserTimeLimit; public long PerJobUserTimeLimit; public uint LimitFlags;
|
|
1061
|
+
public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public uint ActiveProcessLimit;
|
|
1062
|
+
public long Affinity; public uint PriorityClass; public uint SchedulingClass;
|
|
1063
|
+
}
|
|
1064
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1065
|
+
private struct IO_COUNTERS
|
|
1066
|
+
{
|
|
1067
|
+
public ulong ReadOperationCount; public ulong WriteOperationCount; public ulong OtherOperationCount;
|
|
1068
|
+
public ulong ReadTransferCount; public ulong WriteTransferCount; public ulong OtherTransferCount;
|
|
1069
|
+
}
|
|
1070
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1071
|
+
private struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
|
|
1072
|
+
{
|
|
1073
|
+
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public IO_COUNTERS IoInfo;
|
|
1074
|
+
public UIntPtr ProcessMemoryLimit; public UIntPtr JobMemoryLimit;
|
|
1075
|
+
public UIntPtr PeakProcessMemoryUsed; public UIntPtr PeakJobMemoryUsed;
|
|
1076
|
+
}
|
|
1077
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1078
|
+
private struct JOBOBJECT_BASIC_UI_RESTRICTIONS { public uint UIRestrictionsClass; }
|
|
1079
|
+
|
|
1080
|
+
[DllImport("kernel32.dll")] private static extern IntPtr GetCurrentProcess();
|
|
1081
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool CloseHandle(IntPtr handle);
|
|
1082
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr LocalFree(IntPtr handle);
|
|
1083
|
+
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern IntPtr CreateFile(string fileName, uint access, uint shareMode, ref SECURITY_ATTRIBUTES securityAttributes, uint creationDisposition, uint flagsAndAttributes, IntPtr templateFile);
|
|
1084
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool CreatePipe(out IntPtr read, out IntPtr write, ref SECURITY_ATTRIBUTES attributes, uint size);
|
|
1085
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetHandleInformation(IntPtr handle, uint mask, uint flags);
|
|
1086
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern uint WaitForSingleObject(IntPtr handle, uint milliseconds);
|
|
1087
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern uint ResumeThread(IntPtr thread);
|
|
1088
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetExitCodeProcess(IntPtr process, out uint exitCode);
|
|
1089
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool TerminateProcess(IntPtr process, uint exitCode);
|
|
1090
|
+
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern IntPtr CreateJobObject(IntPtr attributes, string name);
|
|
1091
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetInformationJobObject(IntPtr job, int informationClass, IntPtr information, uint length);
|
|
1092
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
|
|
1093
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool TerminateJobObject(IntPtr job, uint exitCode);
|
|
1094
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool InitializeProcThreadAttributeList(IntPtr attributeList, int attributeCount, int flags, ref UIntPtr size);
|
|
1095
|
+
[DllImport("kernel32.dll", SetLastError = true)] private static extern bool UpdateProcThreadAttribute(IntPtr attributeList, uint flags, IntPtr attribute, IntPtr value, UIntPtr size, IntPtr previousValue, IntPtr returnSize);
|
|
1096
|
+
[DllImport("kernel32.dll")] private static extern void DeleteProcThreadAttributeList(IntPtr attributeList);
|
|
1097
|
+
|
|
1098
|
+
[DllImport("advapi32.dll", SetLastError = true)] private static extern bool OpenProcessToken(IntPtr process, uint access, out IntPtr token);
|
|
1099
|
+
[DllImport("advapi32.dll", SetLastError = true)] private static extern bool CreateRestrictedToken(IntPtr existingToken, uint flags, uint disableSidCount, SID_AND_ATTRIBUTES[] disableSids, uint deletePrivilegeCount, IntPtr deletePrivileges, uint restrictedSidCount, SID_AND_ATTRIBUTES[] restrictedSids, out IntPtr newToken);
|
|
1100
|
+
[DllImport("advapi32.dll", SetLastError = true)] private static extern bool SetTokenInformation(IntPtr token, int informationClass, IntPtr information, int length);
|
|
1101
|
+
[DllImport("advapi32.dll", SetLastError = true)] private static extern bool GetTokenInformation(IntPtr token, int informationClass, IntPtr information, int length, out int returnLength);
|
|
1102
|
+
[DllImport("advapi32.dll", SetLastError = true)] private static extern IntPtr GetSidSubAuthorityCount(IntPtr sid);
|
|
1103
|
+
[DllImport("advapi32.dll", SetLastError = true)] private static extern IntPtr GetSidSubAuthority(IntPtr sid, uint subAuthority);
|
|
1104
|
+
[DllImport("advapi32.dll", SetLastError = true)] private static extern uint GetLengthSid(IntPtr sid);
|
|
1105
|
+
[DllImport("advapi32.dll", SetLastError = true)] private static extern bool EqualSid(IntPtr firstSid, IntPtr secondSid);
|
|
1106
|
+
[DllImport("advapi32.dll", SetLastError = true)] private static extern IntPtr FreeSid(IntPtr sid);
|
|
1107
|
+
[DllImport("advapi32.dll", SetLastError = true)] private static extern bool CopySid(uint destinationLength, IntPtr destination, IntPtr source);
|
|
1108
|
+
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern bool ConvertStringSidToSid(string sid, out IntPtr binarySid);
|
|
1109
|
+
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string descriptor, uint revision, out IntPtr securityDescriptor, out uint size);
|
|
1110
|
+
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern bool SetFileSecurity(string path, uint securityInformation, IntPtr securityDescriptor);
|
|
1111
|
+
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
|
1112
|
+
private static extern bool CreateProcessAsUser(IntPtr token, string applicationName, StringBuilder commandLine, IntPtr processAttributes, IntPtr threadAttributes, bool inheritHandles, uint creationFlags, IntPtr environment, string currentDirectory, ref STARTUPINFOEX startupInfo, out PROCESS_INFORMATION processInformation);
|
|
1113
|
+
[DllImport("userenv.dll", CharSet = CharSet.Unicode)]
|
|
1114
|
+
private static extern int CreateAppContainerProfile(string appContainerName, string displayName, string description, IntPtr capabilities, uint capabilityCount, out IntPtr appContainerSid);
|
|
1115
|
+
[DllImport("userenv.dll", CharSet = CharSet.Unicode)]
|
|
1116
|
+
private static extern int DeleteAppContainerProfile(string appContainerName);
|
|
1117
|
+
}
|