Пример #1
0
        [InlineData(true, "foo.exe")]  // Filter should not match
        public async Task CmdWithTestShim_ShimNothingRunsChildProcessWithoutShim(bool shimAllProcesses, string processMatch)
        {
            var context = BuildXLContext.CreateInstanceForTesting();

            string currentCodeFolder = Path.GetDirectoryName(AssemblyHelper.GetAssemblyLocation(Assembly.GetExecutingAssembly()));

            Contract.Assume(currentCodeFolder != null);

            string executable = CmdHelper.CmdX64;

            string shimProgram = Path.Combine(currentCodeFolder, "TestSubstituteProcessExecutionShim.exe");

            Assert.True(File.Exists(shimProgram), $"Shim test program not found at {shimProgram}");
            var shimProgramPath = AbsolutePath.Create(context.PathTable, shimProgram);

            var fam =
                new FileAccessManifest(context.PathTable)
            {
                FailUnexpectedFileAccesses     = false,
                IgnoreCodeCoverage             = false,
                ReportFileAccesses             = false,
                ReportUnexpectedFileAccesses   = false,
                MonitorChildProcesses          = false,
                SubstituteProcessExecutionInfo = new SubstituteProcessExecutionInfo(
                    shimProgramPath,
                    shimAllProcesses: false,
                    processMatch == null ? new ShimProcessMatch[0] : new[] { new ShimProcessMatch(PathAtom.Create(context.StringTable, processMatch), PathAtom.Invalid) })
            };

            Guid   sessionId      = Guid.NewGuid();
            string sessionIdStr   = sessionId.ToString("N");
            var    loggingContext = new LoggingContext(sessionId, "TestSession", new LoggingContext.SessionInfo(sessionIdStr, "env", sessionId));

            string childOutput = "Child cmd that should not be shimmed";
            string childArgs   = $"{executable} /D /C @echo {childOutput}";
            string args        = "/D /C echo Top-level cmd. Running child process && " + childArgs;

            var stdoutSb = new StringBuilder(128);
            var stderrSb = new StringBuilder();

            var sandboxedProcessInfo = new SandboxedProcessInfo(
                context.PathTable,
                new LocalSandboxedFileStorage(),
                executable,
                disableConHostSharing: true,
                loggingContext: loggingContext,
                fileAccessManifest: fam)
            {
                PipDescription   = executable,
                Arguments        = args,
                WorkingDirectory = Environment.CurrentDirectory,

                StandardOutputEncoding = Encoding.UTF8,
                StandardOutputObserver = stdoutStr => stdoutSb.AppendLine(stdoutStr),

                StandardErrorEncoding = Encoding.UTF8,
                StandardErrorObserver = stderrStr => stderrSb.AppendLine(stderrStr),

                EnvironmentVariables = BuildParameters.GetFactory().PopulateFromEnvironment(),

                Timeout = TimeSpan.FromMinutes(1),
            };

            ISandboxedProcess sandboxedProcess =
                await SandboxedProcessFactory.StartAsync(sandboxedProcessInfo, forceSandboxing : true)
                .ConfigureAwait(false);

            SandboxedProcessResult result = await sandboxedProcess.GetResultAsync().ConfigureAwait(false);

            Assert.Equal(0, result.ExitCode);

            string stdout = stdoutSb.ToString();

            m_output.WriteLine($"stdout: {stdout}");

            string stderr = stderrSb.ToString();

            m_output.WriteLine($"stderr: {stderr}");
            Assert.Equal(0, stderr.Length);

            string shimOutput  = "TestShim: Entered with command line";
            int    indexOfShim = stdout.IndexOf(shimOutput, StringComparison.Ordinal);

            Assert.True(indexOfShim == -1);
            int indexOfChild = stdout.LastIndexOf(childOutput, StringComparison.Ordinal);

            Assert.True(indexOfChild > 0, "Child should have run and written output");
        }
Пример #2
0
        [InlineData(false, "cmd.exe")] // Filter should match child
        public async Task CmdWithTestShim(bool useQuotesForChildCmdExe, string processMatch)
        {
            var context = BuildXLContext.CreateInstanceForTesting();

            string currentCodeFolder = Path.GetDirectoryName(AssemblyHelper.GetAssemblyLocation(Assembly.GetExecutingAssembly()));

            Contract.Assume(currentCodeFolder != null);

            string executable       = CmdHelper.CmdX64;
            string childExecutable  = executable;
            string quotedExecutable = '"' + executable + '"';

            if (useQuotesForChildCmdExe)
            {
                childExecutable = quotedExecutable;
            }

            string shimProgram = Path.Combine(currentCodeFolder, "TestSubstituteProcessExecutionShim.exe");

            Assert.True(File.Exists(shimProgram), $"Shim test program not found at {shimProgram}");
            var shimProgramPath = AbsolutePath.Create(context.PathTable, shimProgram);

            var fam =
                new FileAccessManifest(context.PathTable)
            {
                FailUnexpectedFileAccesses     = false,
                IgnoreCodeCoverage             = false,
                ReportFileAccesses             = false,
                ReportUnexpectedFileAccesses   = false,
                MonitorChildProcesses          = false,
                SubstituteProcessExecutionInfo = new SubstituteProcessExecutionInfo(
                    shimProgramPath,
                    shimAllProcesses: processMatch == null,      // When we have a process to match, make the shim list opt-in to ensure a match
                    processMatch == null ? new ShimProcessMatch[0] : new[] { new ShimProcessMatch(PathAtom.Create(context.StringTable, processMatch), PathAtom.Invalid) })
            };

            Guid   sessionId      = Guid.NewGuid();
            string sessionIdStr   = sessionId.ToString("N");
            var    loggingContext = new LoggingContext(sessionId, "TestSession", new LoggingContext.SessionInfo(sessionIdStr, "env", sessionId));

            string childOutput = "Child cmd that should be shimmed";
            string childArgs   = $"{childExecutable} /D /C @echo {childOutput}";

            // Detours logic should wrap the initial cmd in quotes for easier parsing by shim logic.
            // However, since we're indirecting through a cmd.exe command line it gets dropped along the way.
            string childShimArgs = $"/D /C @echo {childOutput}";

            string args = "/D /C echo Top-level cmd. Running child process && " + childArgs;

            var stdoutSb = new StringBuilder(128);
            var stderrSb = new StringBuilder();

            var sandboxedProcessInfo = new SandboxedProcessInfo(
                context.PathTable,
                new LocalSandboxedFileStorage(),
                executable,
                disableConHostSharing: true,
                loggingContext: loggingContext,
                fileAccessManifest: fam)
            {
                PipDescription   = executable,
                Arguments        = args,
                WorkingDirectory = Environment.CurrentDirectory,

                StandardOutputEncoding = Encoding.UTF8,
                StandardOutputObserver = stdoutStr => stdoutSb.AppendLine(stdoutStr),

                StandardErrorEncoding = Encoding.UTF8,
                StandardErrorObserver = stderrStr => stderrSb.AppendLine(stderrStr),

                EnvironmentVariables = BuildParameters.GetFactory().PopulateFromEnvironment(),

                Timeout = TimeSpan.FromMinutes(1),
            };

            ISandboxedProcess sandboxedProcess =
                await SandboxedProcessFactory.StartAsync(sandboxedProcessInfo, forceSandboxing : true)
                .ConfigureAwait(false);

            SandboxedProcessResult result = await sandboxedProcess.GetResultAsync().ConfigureAwait(false);

            string stdout = stdoutSb.ToString();

            m_output.WriteLine($"stdout: {stdout}");

            string stderr = stderrSb.ToString();

            m_output.WriteLine($"stderr: {stderr}");

            Assert.Equal(0, result.ExitCode);
            Assert.Equal(0, stderr.Length);

            // The shim is an exe on netframework, dll in a temp dir on netcore, so don't try to match it.
            const string shimOutput  = "TestShim: Entered with command line: ";
            int          indexOfShim = stdout.IndexOf(shimOutput, StringComparison.Ordinal);

            Assert.True(indexOfShim > 0, shimOutput);

            m_output.WriteLine($"Expecting shim args: {childShimArgs}");
            int indexOfShimArgs = stdout.LastIndexOf(childShimArgs);

            Assert.True(indexOfShimArgs > indexOfShim);
        }
Пример #3
0
        public async Task CmdWithStartQuoteOnlyFailsToRunFullCommandLine()
        {
            var context = BuildXLContext.CreateInstanceForTesting();

            string currentCodeFolder = Path.GetDirectoryName(AssemblyHelper.GetAssemblyLocation(Assembly.GetExecutingAssembly()));

            Contract.Assume(currentCodeFolder != null);

            string shimProgram = Path.Combine(currentCodeFolder, "TestSubstituteProcessExecutionShim.exe");

            Assert.True(File.Exists(shimProgram), $"Shim test program not found at {shimProgram}");
            var shimProgramPath = AbsolutePath.Create(context.PathTable, shimProgram);

            var fam =
                new FileAccessManifest(context.PathTable)
            {
                FailUnexpectedFileAccesses     = false,
                IgnoreCodeCoverage             = false,
                ReportFileAccesses             = false,
                ReportUnexpectedFileAccesses   = false,
                MonitorChildProcesses          = false,
                SubstituteProcessExecutionInfo = new SubstituteProcessExecutionInfo(
                    shimProgramPath,
                    shimAllProcesses: true,
                    new ShimProcessMatch[0])
            };

            Guid   sessionId      = Guid.NewGuid();
            string sessionIdStr   = sessionId.ToString("N");
            var    loggingContext = new LoggingContext(sessionId, "TestSession", new LoggingContext.SessionInfo(sessionIdStr, "env", sessionId));

            string executable      = CmdHelper.CmdX64;
            string childExecutable = '"' + executable;  // Only an open quote
            string childOutput     = "Child cmd that should be shimmed";
            string childArgs       = $"{childExecutable} /D /C @echo {childOutput}";

            string args = "/D /C echo Top-level cmd. Running child process && " + childArgs;

            var stdoutSb = new StringBuilder(128);
            var stderrSb = new StringBuilder();

            var sandboxedProcessInfo = new SandboxedProcessInfo(
                context.PathTable,
                new LocalSandboxedFileStorage(),
                executable,
                disableConHostSharing: true,
                loggingContext: loggingContext,
                fileAccessManifest: fam)
            {
                PipDescription   = executable,
                Arguments        = args,
                WorkingDirectory = Environment.CurrentDirectory,

                StandardOutputEncoding = Encoding.UTF8,
                StandardOutputObserver = stdoutStr => stdoutSb.AppendLine(stdoutStr),

                StandardErrorEncoding = Encoding.UTF8,
                StandardErrorObserver = stderrStr => stderrSb.AppendLine(stderrStr),

                EnvironmentVariables = BuildParameters.GetFactory().PopulateFromEnvironment(),

                Timeout = TimeSpan.FromMinutes(1),
            };

            ISandboxedProcess sandboxedProcess =
                await SandboxedProcessFactory.StartAsync(sandboxedProcessInfo, forceSandboxing : true)
                .ConfigureAwait(false);

            SandboxedProcessResult result = await sandboxedProcess.GetResultAsync().ConfigureAwait(false);

            string stdout = stdoutSb.ToString();

            m_output.WriteLine($"stdout: {stdout}");

            string stderr = stderrSb.ToString();

            m_output.WriteLine($"stderr: {stderr}");

            Assert.Equal(1, result.ExitCode);
            Assert.Equal("The system cannot find the path specified.\r\n", stderr);
        }
Пример #4
0
 protected static Task <ISandboxedProcess> StartProcessAsync(SandboxedProcessInfo info, bool forceSandboxing = true)
 {
     return(SandboxedProcessFactory.StartAsync(info, forceSandboxing));
 }
Пример #5
0
        /// <summary>
        /// Runs the a tool in a sandboxed process and returns the result.
        /// These optional callback Actions can be provided:
        ///     beforeLaunch is invoked right before the process is launched
        ///     onResult is invoked after getting a successful result
        /// </summary>>
        public static async Task <SandboxedProcessResult> RunSandboxedToolAsync(FrontEndContext context,
                                                                                string pathToTool,
                                                                                string buildStorageDirectory,
                                                                                FileAccessManifest fileAccessManifest,
                                                                                string arguments,
                                                                                string workingDirectory,
                                                                                string description,
                                                                                BuildParameters.IBuildParameters buildParameters,
                                                                                Action beforeLaunch = null, // Invoked right before the process starts
                                                                                Action onResult     = null  // Action to be taken after getting a successful result
                                                                                )
        {
            var info =
                new SandboxedProcessInfo(
                    context.PathTable,
                    new ToolBuildStorage(buildStorageDirectory),
                    pathToTool,
                    fileAccessManifest,
                    disableConHostSharing: true,
                    ContainerConfiguration.DisabledIsolation,
                    loggingContext: context.LoggingContext)
            {
                Arguments            = arguments,
                WorkingDirectory     = workingDirectory,
                PipSemiStableHash    = 0,
                PipDescription       = description,
                EnvironmentVariables = buildParameters
            };

            var process = await SandboxedProcessFactory.StartAsync(info, forceSandboxing : true);

            var registration = context.CancellationToken.Register(
                () =>
            {
                try
                {
                    process.KillAsync().GetAwaiter().GetResult();
                }
                catch (TaskCanceledException)
                {
                    // If the process has already terminated or doesn't exist, an TaskCanceledException is raised.
                    // In either case, we swallow the exception, cancellation is already requested by the user
                }
            });


            beforeLaunch?.Invoke();
            var result = process.GetResultAsync().ContinueWith(
                r =>
            {
                // Dispose the registration for the cancellation token once the process is done
                registration.Dispose();


                //
                onResult?.Invoke();

                return(r.GetAwaiter().GetResult());
            });

            return(await result);
        }
        [InlineData(false, "cmd.exe")]  // Filter should match child
        public async Task CmdWithTestShimAsync(bool useQuotesForChildCmdExe, string processMatch)
        {
            var context         = BuildXLContext.CreateInstanceForTesting();
            var shimProgramPath = GetShimProgramPath(context);

            string executable       = CmdHelper.CmdX64;
            string childExecutable  = executable;
            string quotedExecutable = '"' + executable + '"';

            if (useQuotesForChildCmdExe)
            {
                childExecutable = quotedExecutable;
            }

            var fam = CreateCommonFileAccessManifest(context.PathTable);

            fam.SubstituteProcessExecutionInfo = new SubstituteProcessExecutionInfo(
                shimProgramPath,
                shimAllProcesses: processMatch == null,  // When we have a process to match, make the shim list opt-in to ensure a match
                processMatches: processMatch == null
                    ? new ShimProcessMatch[0]
                    : new[] { new ShimProcessMatch(PathAtom.Create(context.StringTable, processMatch), PathAtom.Invalid) });

            string childOutput = "Child cmd that should be shimmed";
            string childArgs   = $"{childExecutable} /D /C @echo {childOutput}";

            // Detours logic should wrap the initial cmd in quotes for easier parsing by shim logic.
            // However, since we're indirecting through a cmd.exe command line it gets dropped along the way.
            string childShimArgs = $"/D /C @echo {childOutput}";

            string args = $"/D /C echo Top-level cmd. Running child process && {childArgs}";

            var stdOutSb = new StringBuilder(128);
            var stdErrSb = new StringBuilder();

            SandboxedProcessInfo sandboxedProcessInfo = CreateCommonSandboxedProcessInfo(
                context,
                executable,
                args,
                fam,
                stdOutSb,
                stdErrSb);

            ISandboxedProcess sandboxedProcess =
                await SandboxedProcessFactory.StartAsync(sandboxedProcessInfo, forceSandboxing : true)
                .ConfigureAwait(false);

            SandboxedProcessResult result = await sandboxedProcess.GetResultAsync().ConfigureAwait(false);

            string stdOut = stdOutSb.ToString();
            string stdErr = stdErrSb.ToString();

            m_output.WriteLine($"stdout: {stdOut}");
            m_output.WriteLine($"stderr: {stdErr}");

            AssertSuccess(result, stdErr);

            // The shim is an exe on netframework, dll in a temp dir on netcore, so don't try to match it.
            AssertShimmed(stdOut);
            AssertShimArgs(stdOut, childShimArgs);
        }
Пример #7
0
        /// <nodoc />
        public Task <SandboxedProcessResult> Run(SandboxOptions option)
        {
            var pathToProcess = option.args[0];

            var workingDir = option.working_dir != AbsolutePath.Invalid ? option.working_dir.ToString(m_pathTable) : Environment.CurrentDirectory;
            var fam        = CreateManifest(AbsolutePath.Create(m_pathTable, pathToProcess), option, workingDir);

            Action <string> stdoutCallback;

            if (option.stdout_path != AbsolutePath.Invalid)
            {
                m_stdoutF      = new StreamWriter(option.stdout_path.ToString(m_pathTable));
                stdoutCallback = s => m_stdoutF.WriteLine(s);
            }
            else
            {
                stdoutCallback = s => Console.WriteLine(s);
            }

            Action <string> stderrCallback;

            if (option.stderr_path != AbsolutePath.Invalid)
            {
                m_stderrF      = new StreamWriter(option.stderr_path.ToString(m_pathTable));
                stderrCallback = s => m_stderrF.WriteLine(s);
            }
            else
            {
                stderrCallback = s => Console.Error.WriteLine(s);
            }

            var info = new SandboxedProcessInfo(
                m_pathTable,
                this,
                pathToProcess,
                fam,
                disableConHostSharing: true,
                containerConfiguration: ContainerConfiguration.DisabledIsolation,
                loggingContext: m_loggingContext)
            {
                Arguments        = EscapeArgvRest(option.args.Skip(1)),
                WorkingDirectory = workingDir,
                // PipSemiStableHash = 0,
                PipDescription = "BazelSandboxedProcess",

                StandardOutputEncoding = Encoding.UTF8,
                StandardOutputObserver = stdoutCallback,

                StandardErrorEncoding = Encoding.UTF8,
                StandardErrorObserver = stderrCallback,

                SandboxedKextConnection = OperatingSystemHelper.IsUnixOS ? new KextConnection() : null
            };

            if (option.timeout_secs != SandboxOptions.kInfiniteTime)
            {
                info.Timeout = TimeSpan.FromSeconds(option.timeout_secs);
            }

            if (option.kill_delay_secs != SandboxOptions.kInfiniteTime)
            {
                info.NestedProcessTerminationTimeout = TimeSpan.FromSeconds(option.kill_delay_secs);
            }

            var process = SandboxedProcessFactory.StartAsync(info, forceSandboxing: true).GetAwaiter().GetResult();

            return(process.GetResultAsync());
        }