/// <summary> /// Called right after the process starts executing. /// /// Since we set the process file name to be /bin/sh and its arguments to be empty (<see cref="CreateProcess"/>), /// the process will effectively start in a "suspended" mode, with /bin/sh just waiting for some content to be /// piped to its standard input. Therefore, in this handler we first notify the sandbox of the new process (so that /// it starts tracking it) and then just send the actual process command line to /bin/sh via its standard input. /// </summary> private async Task OnProcessStartedAsync(SandboxedProcessInfo info) { // Generate "Process Created" report because the rest of the system expects to see it before any other file access reports // // IMPORTANT: do this before notifying sandbox kernel extension, because otherwise it can happen that a report // from the extension is received before the "process created" report is handled, causing // a "Should see a process creation before its accesses" assertion exception. ReportProcessCreated(); // Allow read access for /bin/sh // When executed using external tool, the manifest tree has been sealed, and cannot be modified. // We take care of adding this path in the manifest in SandboxedProcessPipExecutor.cs; // see AddUnixSpecificSandcboxedProcessFileAccessPolicies if (!info.FileAccessManifest.IsManifestTreeBlockSealed) { info.FileAccessManifest.AddPath( AbsolutePath.Create(PathTable, Process.StartInfo.FileName), mask: FileAccessPolicy.MaskNothing, values: FileAccessPolicy.AllowReadAlways); } if (OperatingSystemHelper.IsLinuxOS) { m_perfCollector?.Start(); } string processStdinFileName = await FlushStandardInputToFileIfNeededAsync(info); if (!SandboxConnection.NotifyPipStarted(info.LoggingContext, info.FileAccessManifest, this)) { ThrowCouldNotStartProcess("Failed to initialize the sandbox for process observation, make sure BuildXL is setup correctly!"); } try { await FeedStdInAsync(info, processStdinFileName); m_processTreeTimeoutTask = ProcessTreeTimeoutTask(); } catch (IOException e) { // IOException can happen if the process is forcefully killed while we're feeding its std in. // When that happens, instead of crashing, just make sure the process is killed. LogProcessState($"IOException caught while feeding the standard input: {e.ToString()}"); await KillAsync(); } finally { // release the FileAccessManifest memory // NOTE: just by not keeping any references to 'info' should make the FileAccessManifest object // unreachable and thus available for garbage collection. We call Release() here explicitly // just to emphasize the importance of reclaiming this memory. info.FileAccessManifest.Release(); } }