internal Info(Sandbox.ManagedFailureCallback failureCallback, SandboxedProcessUnix process, string reportsFifoPath, string famPath, string debugLogPath) { m_failureCallback = failureCallback; Process = process; ReportsFifoPath = reportsFifoPath; FamPath = famPath; DebugLogJailPath = debugLogPath; m_pathCache = new Dictionary <string, PathCacheRecord>(); m_activeProcesses = new ConcurrentDictionary <int, byte> { [process.ProcessId] = 1 }; m_activeProcessesChecker = new CancellableTimedAction( CheckActiveProcesses, intervalMs: Math.Min((int)process.ChildProcessTimeout.TotalMilliseconds, (int)ActiveProcessesCheckerInterval.TotalMilliseconds)); // create a write handle (used to keep the fifo open, i.e., // the 'read' syscall won't receive EOF until we close this writer m_lazyWriteHandle = new Lazy <SafeFileHandle>(() => { LogDebug($"Opening FIFO '{ReportsFifoPath}' for writing"); return(IO.Open(ReportsFifoPath, IO.OpenFlags.O_WRONLY, 0)); }); // start a background thread for reading from the FIFO m_workerThread = new Thread(StartReceivingAccessReports); m_workerThread.IsBackground = true; m_workerThread.Priority = ThreadPriority.Highest; }
internal Info(Sandbox.ManagedFailureCallback failureCallback, SandboxedProcessUnix process, string reportsFifoPath, string famPath) { m_failureCallback = failureCallback; Process = process; ReportsFifoPath = reportsFifoPath; FamPath = famPath; m_pathCache = new Dictionary <string, PathCacheRecord>(); m_activeProcesses = new HashSet <int> { process.ProcessId }; // create a write handle (used to keep the fifo open, i.e., // the 'read' syscall won't receive EOF until we close this writer m_lazyWriteHandle = new Lazy <SafeFileHandle>(() => { LogDebug($"Opening FIFO '{ReportsFifoPath}' for writing"); return(IO.Open(ReportsFifoPath, IO.OpenFlags.O_WRONLY, 0)); }); // start a background thread for reading from the FIFO m_workerThread = new Thread(StartReceivingAccessReports); m_workerThread.IsBackground = true; m_workerThread.Priority = ThreadPriority.Highest; }
/// <nodoc /> public SandboxConnectionLinuxDetours(Sandbox.ManagedFailureCallback failureCallback = null, bool isInTestMode = false) { IsInTestMode = isInTestMode; m_failureCallback = failureCallback; #if DEBUG BuildXL.Native.Processes.ProcessUtilities.SetNativeConfiguration(true); #else BuildXL.Native.Processes.ProcessUtilities.SetNativeConfiguration(false); #endif }
internal Info(Sandbox.ManagedFailureCallback failureCallback, SandboxedProcessUnix process, string reportsFifoPath, string famPath, string debugLogPath, bool isInTestMode) { m_isInTestMode = isInTestMode; m_stopRequestCounter = 0; m_completeAccessReportProcessingCounter = 0; m_failureCallback = failureCallback; Process = process; ReportsFifoPath = reportsFifoPath; FamPath = famPath; DebugLogJailPath = debugLogPath; m_waitToCompleteCts = new CancellationTokenSource(); m_pathCache = new Dictionary <string, PathCacheRecord>(); m_activeProcesses = new ConcurrentDictionary <int, byte> { [process.ProcessId] = 1 }; m_activeProcessesChecker = new CancellableTimedAction( CheckActiveProcesses, intervalMs: Math.Min((int)process.ChildProcessTimeout.TotalMilliseconds, (int)ActiveProcessesCheckerInterval.TotalMilliseconds)); // create a write handle (used to keep the fifo open, i.e., // the 'read' syscall won't receive EOF until we close this writer m_lazyWriteHandle = new Lazy <SafeFileHandle>(() => { LogDebug($"Opening FIFO '{ReportsFifoPath}' for writing"); return(IO.Open(ReportsFifoPath, IO.OpenFlags.O_WRONLY, 0)); }); // action block where parsing and processing of received ActionReport bytes is done m_accessReportProcessingBlock = new ActionBlock <(PooledObjectWrapper <byte[]> wrapper, int length)>(ProcessBytes, new ExecutionDataflowBlockOptions { BoundedCapacity = DataflowBlockOptions.Unbounded, MaxDegreeOfParallelism = 1, EnsureOrdered = true }); // start a background thread for reading from the FIFO m_workerThread = new Thread(StartReceivingAccessReports); m_workerThread.IsBackground = true; m_workerThread.Priority = ThreadPriority.Highest; }
/// <summary> /// Initializes the sandbox kernel extension connection manager, setting up the kernel extension connection and workers that drain the /// kernel event queue and report file accesses /// </summary> public KextConnection(Config config = null, bool skipDisposingForTests = false) { m_reportQueueLastEnqueueTime = 0; m_kextConnectionInfo = new Sandbox.KextConnectionInfo() { Error = Sandbox.KextSuccess }; m_sharedMemoryInfo = new Sandbox.KextSharedMemoryInfo() { Error = Sandbox.KextSuccess }; MeasureCpuTimes = config.MeasureCpuTimes; IsInTestMode = skipDisposingForTests; // initialize kext connection Sandbox.InitializeKextConnection(ref m_kextConnectionInfo); if (m_kextConnectionInfo.Error != Sandbox.KextSuccess) { throw new BuildXLException($@"Unable to connect to sandbox kernel extension (Code: {m_kextConnectionInfo.Error}) - make sure it is loaded and retry! {KextInstallHelper}"); } // check and set if the sandbox is running in debug configuration bool isDebug = false; Sandbox.CheckForDebugMode(ref isDebug, m_kextConnectionInfo); ProcessUtilities.SetNativeConfiguration(isDebug); #if DEBUG if (!ProcessUtilities.IsNativeInDebugConfiguration()) #else if (ProcessUtilities.IsNativeInDebugConfiguration()) #endif { throw new BuildXLException($"Sandbox kernel extension build flavor missmatch - the extension must match the engine build flavor, Debug != Release. {KextInstallHelper}"); } // check if the sandbox version matches var stringBufferLength = MaxVersionNumberLength + 1; var version = new StringBuilder(stringBufferLength); Sandbox.KextVersionString(version, stringBufferLength); if (!RequiredKextVersionNumber.Equals(version.ToString().TrimEnd('\0'))) { throw new BuildXLException($"Sandbox kernel extension version mismatch, the loaded kernel extension version '{version}' does not match the required version '{RequiredKextVersionNumber}'. {KextInstallHelper}"); } if (config?.KextConfig != null) { if (!Sandbox.Configure(config.KextConfig.Value, m_kextConnectionInfo)) { throw new BuildXLException($"Unable to configure sandbox kernel extension"); } } m_failureCallback = config?.FailureCallback; // Initialize the shared memory region Sandbox.InitializeKextSharedMemory(m_kextConnectionInfo, ref m_sharedMemoryInfo); if (m_sharedMemoryInfo.Error != Sandbox.KextSuccess) { throw new BuildXLException($"Unable to allocate shared memory region for worker (Code:{m_sharedMemoryInfo.Error})"); } if (!SetFailureNotificationHandler()) { throw new BuildXLException($"Unable to set sandbox kernel extension failure notification callback handler"); } m_workerThread = new Thread(() => StartReceivingAccessReports(m_sharedMemoryInfo.Address, m_sharedMemoryInfo.Port)); m_workerThread.IsBackground = true; m_workerThread.Priority = ThreadPriority.Highest; m_workerThread.Start(); unsafe bool SetFailureNotificationHandler() { return(Sandbox.SetFailureNotificationHandler(KextFailureCallback, m_kextConnectionInfo)); void KextFailureCallback(void *refCon, int status) { m_failureCallback?.Invoke(status, $"Unrecoverable kernel extension failure happened - try reloading the kernel extension or restart your system. {KextInstallHelper}"); } } }