/// <inheritdoc /> public void NotifyRootProcessExited(long pipId, SandboxedProcessUnix process) { if (m_pipProcesses.TryGetValue(pipId, out var info)) { info.RemovePid(process.ProcessId); } }
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; }
/// <inheritdoc /> public bool NotifyPipFinished(long pipId, SandboxedProcessUnix process) { if (m_pipProcesses.TryRemove(pipId, out var info)) { info.Dispose(); return(true); } else { return(false); } }
/// <inheritdoc /> public bool NotifyPipFinished(long pipId, SandboxedProcessUnix process) { if (m_pipProcesses.TryRemove(pipId, out var proc)) { Contract.Assert(process == proc); return(true); } else { return(false); } }
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; }
/// <inheritdoc /> public bool NotifyPipStarted(LoggingContext loggingContext, FileAccessManifest fam, SandboxedProcessUnix process) { Contract.Requires(process.Started); Contract.Requires(process.PipId != 0); string rootDir = process.RootJail ?? Path.GetTempPath(); string fifoPath = Path.Combine(rootDir, $"bxl_Pip{process.PipSemiStableHash:X}.{process.ProcessId}.fifo"); string famPath = Path.ChangeExtension(fifoPath, ".fam"); string debugLogPath = null; if (IsInTestMode) { debugLogPath = process.ToPathInsideRootJail(Path.ChangeExtension(fifoPath, ".log")); fam.AddPath(toAbsPath(debugLogPath), mask: FileAccessPolicy.MaskAll, values: FileAccessPolicy.AllowAll); } // serialize FAM using (var wrapper = Pools.MemoryStreamPool.GetInstance()) { var debugFlags = true; ArraySegment <byte> manifestBytes = fam.GetPayloadBytes( loggingContext, new FileAccessSetup { DllNameX64 = string.Empty, DllNameX86 = string.Empty, ReportPath = process.ToPathInsideRootJail(fifoPath) }, wrapper.Instance, timeoutMins: 10, // don't care debugFlagsMatch: ref debugFlags); Contract.Assert(manifestBytes.Offset == 0); File.WriteAllBytes(famPath, manifestBytes.ToArray()); } process.LogDebug($"Saved FAM to '{famPath}'"); // create a FIFO (named pipe) if (IO.MkFifo(fifoPath, IO.FilePermissions.S_IRWXU) != 0) { m_failureCallback?.Invoke(1, $"Creating FIFO {fifoPath} failed"); return(false); } process.LogDebug($"Created FIFO at '{fifoPath}'"); // create and save info for this pip var info = new Info(m_failureCallback, process, fifoPath, famPath, debugLogPath); if (!m_pipProcesses.TryAdd(process.PipId, info)) { throw new BuildXLException($"Process with PidId {process.PipId} already exists"); } info.Start(); return(true); AbsolutePath toAbsPath(string path) => AbsolutePath.Create(process.PathTable, path); }
/// <inheritdoc /> public void NotifyRootProcessExited(long pipId, SandboxedProcessUnix process) { // this implementation keeps track of what the root process is an when it exits, // so it doesn't need to be notified about it separately }
/// <inheritdoc /> public bool NotifyPipStarted(LoggingContext loggingContext, FileAccessManifest fam, SandboxedProcessUnix process) { Contract.Requires(process.Started); Contract.Requires(fam.PipId != 0); if (!m_pipProcesses.TryAdd(fam.PipId, process)) { throw new BuildXLException($"Process with PidId {fam.PipId} already exists"); } var setup = new FileAccessSetup() { DllNameX64 = string.Empty, DllNameX86 = string.Empty, ReportPath = process.ExecutableAbsolutePath, // piggybacking on ReportPath to pass full executable path }; using (var wrapper = Pools.MemoryStreamPool.GetInstance()) { var debugFlags = true; ArraySegment <byte> manifestBytes = fam.GetPayloadBytes( loggingContext, setup, wrapper.Instance, timeoutMins: 10, // don't care because on Mac we don't kill the process from the Kext once it times out debugFlagsMatch: ref debugFlags); Contract.Assert(manifestBytes.Offset == 0); var result = Sandbox.SendPipStarted( processId: process.ProcessId, pipId: fam.PipId, famBytes: manifestBytes.Array, famBytesLength: manifestBytes.Count, type: Sandbox.ConnectionType.Kext, info: ref m_kextConnectionInfo); return(result); } }