/// <summary> /// Runs a target process inside the sandbox asynchronously /// </summary> /// <param name="instance">A SandboxExecRunner instance</param> /// <param name="exec">The programs full command line including its arguments</param> /// <param name="workingDirectory">Working directory in which to start the process</param> /// <returns>Task that will execute the process and its arguments inside the BuildXL Sandbox</returns> public static Task <ISandboxedProcess> ExecuteAsync(SandboxExecRunner instance, string[] exec, string workingDirectory) { var processFileName = exec[0]; var processInfo = CreateSandboxedProcessInfo(processFileName, instance); processInfo.Timeout = TimeSpan.FromSeconds(instance.m_options.ProcessTimeout); processInfo.Arguments = ExtractAndEscapeCommandLineArguments(exec); processInfo.WorkingDirectory = workingDirectory; processInfo.EnvironmentVariables = BuildParameters.GetFactory(null).PopulateFromEnvironment(); instance.m_pathTable = processInfo.PathTable; return(SandboxedProcessFactory.StartAsync(processInfo, forceSandboxing: true)); }
/// <summary> /// Creates a SandboxedProcessInfo object that can be used to run a target program within the BuildXL Sandbox and /// forces the Sandbox to explicitly report all file accesses observed /// </summary> /// <param name="processFileName">The fully qualifying file name of the process to run inside the sandbox</param> /// <param name="instance">A SandboxExecRunner instance</param> /// <returns>SandboxedProcessInfo object that is configured to explicitly report all observed file accesses</returns> public static SandboxedProcessInfo CreateSandboxedProcessInfo(string processFileName, SandboxExecRunner instance) { var sandboxProcessInfo = new SandboxedProcessInfo( new PathTable(), fileStorage: instance, fileName: processFileName, disableConHostSharing: true, sandboxConnection: instance.m_sandboxConnection, loggingContext: s_loggingContext); sandboxProcessInfo.PipDescription = processFileName; sandboxProcessInfo.StandardOutputEncoding = Encoding.UTF8; sandboxProcessInfo.StandardOutputObserver = PrintToStdout; sandboxProcessInfo.StandardErrorEncoding = Encoding.UTF8; sandboxProcessInfo.StandardErrorObserver = PrintToStderr; // track directory creation sandboxProcessInfo.FileAccessManifest.EnforceAccessPoliciesOnDirectoryCreation = instance.m_options.TrackDirectoryCreation; // Enable explicit file access reporting sandboxProcessInfo.FileAccessManifest.ReportFileAccesses = true; sandboxProcessInfo.FileAccessManifest.FailUnexpectedFileAccesses = false; sandboxProcessInfo.FileAccessManifest.PipId = Interlocked.Increment(ref s_pipIdCounter); return(sandboxProcessInfo); }
private static int RunTool(Options options, string[] procArgs) { if (procArgs.Length < 1) { var macOSUsageDescription = OperatingSystemHelper.IsUnixOS ? $" [/{ArgReportQueueSizeMB}:<1-1024>] [/{ArgEnableReportBatching}[+,-]]" : ""; PrintToStderr($"Usage: SandboxExec [[/{ArgVerbose}[+,-]] [/{ArgLogToStdOut}[+,-]] [/{ArgProcessTimeout}:seconds] [/{ArgTrackDirectoryCreation}] [/{ArgEnableStatistics}[+,-]] [/{ArgUseEndpointSecuritySandbox}[+,-]]{macOSUsageDescription} --] executable [arg1 arg2 ...]"); return(1); } if (!Path.IsPathRooted(procArgs[0])) { PrintToStderr("The path to the executable must be specified as an absolute path. Exiting."); return(1); } Telemetry.TelemetryStartup(options.EnableTelemetry); CleanupOutputs(); var instance = new SandboxExecRunner(options); SandboxedProcessResult result; Stopwatch sandboxingTime; var overallTime = Stopwatch.StartNew(); using (var process = ExecuteAsync(instance, procArgs, workingDirectory: Directory.GetCurrentDirectory()).GetAwaiter().GetResult()) { sandboxingTime = Stopwatch.StartNew(); result = process.GetResultAsync().GetAwaiter().GetResult(); sandboxingTime.Stop(); PrintToStdout($"Process {procArgs[0]}:{process.ProcessId} exited with exit code: {result.ExitCode}"); } var dedupeTime = Stopwatch.StartNew(); var accessReportCount = result.FileAccesses.Count; // Dedupe reported file accesses var distinctAccessReports = instance.DedupeAccessReports( result.FileAccesses, result.ExplicitlyReportedFileAccesses, result.AllUnexpectedFileAccesses); dedupeTime.Stop(); var outputTime = Stopwatch.StartNew(); if (options.LogToStdOut) { foreach (var report in distinctAccessReports) { PrintToStdout(report); } } else { var path = Path.Combine(Directory.GetCurrentDirectory(), AccessOutput); try { File.WriteAllLines(path, distinctAccessReports); } catch (IOException ex) { PrintToStderr($"Could not write file access report file to {path}. Got excecption instead: " + ex.ToString()); } } outputTime.Stop(); var disposeTime = Stopwatch.StartNew(); if (instance.m_sandboxConnection != null) { // Take care of releasing sandbox kernel extension resources on macOS instance.m_sandboxConnection.Dispose(); } disposeTime.Stop(); overallTime.Stop(); if (options.EnableTelemetry) { PrintToStdout("\nTime unit is: ms\n"); PrintToStdout($"Overall execution time: {overallTime.ElapsedMilliseconds}"); PrintToStdout($"Time spent executing process with sandboxing: {sandboxingTime.ElapsedMilliseconds}"); PrintToStdout($"Time spent deduping access reports: {dedupeTime.ElapsedMilliseconds}"); PrintToStdout($"Time spent outputting access reports: {outputTime.ElapsedMilliseconds}"); PrintToStdout($"Time spent disposing kernel connection: {disposeTime.ElapsedMilliseconds}"); PrintToStdout($"Number of access reports before deduping: {accessReportCount}"); PrintToStdout($"Number of access reports after deduping: {distinctAccessReports.Count}"); PrintToStdout(""); PrintToStdout("Statistics ::"); foreach (KeyValuePair <string, long> kvp in SandboxedProcessFactory.Counters.AsStatistics()) { PrintToStdout($"{kvp.Key} = {kvp.Value}"); } PrintToStdout(""); } CollectAndUploadCrashReports(options.EnableTelemetry); Telemetry.TelemetryShutdown(); return(result.ExitCode); }