예제 #1
0
        /// <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();
            }
        }
예제 #2
0
        public void MultipleActionStartsTest()
        {
            var mre     = new ManualResetEvent(false);
            int counter = 0;

            using (var timedAction = new CancellableTimedAction(() =>
            {
                // Signal that thread is started
                mre.Set();
                ++counter;
            }, 10, nameof(MultipleActionStartsTest)))
            {
                XAssert.IsTrue(timedAction.Start());
                XAssert.IsFalse(timedAction.Start());
                Thread.Sleep(500);
                XAssert.IsFalse(timedAction.Start());
                timedAction.Cancel();
                timedAction.Join();
                XAssert.IsTrue(counter > 2, "Value of counter is " + counter);
            }
        }
예제 #3
0
        public void LongIntervalTest()
        {
            int counter = 0;

            using (var timedAction = new CancellableTimedAction(() => Interlocked.Increment(ref counter), 1000, nameof(LongIntervalTest)))
            {
                var sw = System.Diagnostics.Stopwatch.StartNew();
                XAssert.IsTrue(timedAction.Start());
                Thread.Sleep(100);
                timedAction.Cancel();
                timedAction.Join();
                sw.Stop();
                XAssert.AreEqual(1, counter);
                XAssert.IsTrue(sw.ElapsedMilliseconds < 1000);
            }
        }
예제 #4
0
            /// <summary>
            /// Removes <paramref name="pid" /> from the set of active processes.
            /// If no active processes are left thereafter, calls <see cref="RequestStop"/>.
            /// </summary>
            internal void RemovePid(int pid)
            {
                bool removed = m_activeProcesses.TryRemove(pid, out var _);

                LogDebug($"RemovePid({pid}) :: removed: {removed}; size: {m_activeProcesses.Count()}");
                if (m_activeProcesses.Count == 0)
                {
                    RequestStop();
                }
                else if (removed && pid == Process.ProcessId)
                {
                    // We just removed the root process and there are still active processes left
                    //   => start periodically checking if they are still alive, because we don't
                    //      have a reliable mechanism for receiving those events straight from the
                    //      child processes (e.g., if they crash, we might not hear about it)
                    //
                    // Observe also that we do have a reliable mechanism for detecting when the
                    // root process exits (even if it crashes): see NotifyRootProcessExited below,
                    // which is guaranteed to be called by SandboxedProcessUnix.
                    m_activeProcessesChecker.Start();
                }
            }
예제 #5
0
        public void BasicFunctionalityTest()
        {
            var mre     = new ManualResetEvent(false);
            int counter = 0;

            using (var timedAction = new CancellableTimedAction(() =>
            {
                // Signal that thread is started
                mre.Set();
                ++counter;
            }, 10, nameof(BasicFunctionalityTest)))
            {
                XAssert.IsTrue(timedAction.Start());

                // Wait for thread to start
                mre.WaitOne();

                Thread.Sleep(500);
                timedAction.Cancel();
                timedAction.Join();
                XAssert.IsTrue(counter > 2, "Value of counter is " + counter);
            }
        }