Skip to content

Commit

Permalink
Merged PR 687849: Enable generation of file access trace files on Linux
Browse files Browse the repository at this point in the history
Enable generation of file access trace files on Linux

Related work items: #1989281
  • Loading branch information
Oleksii Kononenko committed Nov 12, 2022
1 parent 9b12b7e commit 0fcb2c6
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 27 deletions.
15 changes: 13 additions & 2 deletions Public/Src/Engine/Processes/SandboxedProcessUnix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public sealed class SandboxedProcessUnix : UnsandboxedProcess
{
private readonly SandboxedProcessReports m_reports;

private readonly SandboxedProcessTraceBuilder? m_traceBuilder;

private readonly ActionBlock<AccessReport> m_pendingReports;

private readonly CancellableTimedAction? m_perfCollector;
Expand Down Expand Up @@ -167,6 +169,11 @@ public SandboxedProcessUnix(SandboxedProcessInfo info, bool ignoreReportedAccess
intervalMs: (int)info.MonitoringConfig.RefreshInterval.TotalMilliseconds);
}

// We cannot create a trace file if we are ignoring file accesses.
m_traceBuilder = info.CreateSandboxTraceFile && !ignoreReportedAccesses
? new SandboxedProcessTraceBuilder(info.FileStorage, info.PathTable)
: null;

m_reports = new SandboxedProcessReports(
info.FileAccessManifest,
info.PathTable,
Expand All @@ -175,7 +182,8 @@ public SandboxedProcessUnix(SandboxedProcessInfo info, bool ignoreReportedAccess
info.LoggingContext,
info.DetoursEventListener,
info.SidebandWriter,
info.FileSystemView);
info.FileSystemView,
m_traceBuilder);

var useSingleProducer = !(SandboxConnection.Kind == SandboxKind.MacOsHybrid || SandboxConnection.Kind == SandboxKind.MacOsDetours);

Expand Down Expand Up @@ -397,7 +405,7 @@ public override async Task KillAsync()
}

/// <summary>
/// Waits for all child processes to finish within a timeout limit and then termiantes all still running children after that point.
/// Waits for all child processes to finish within a timeout limit and then terminates all still running children after that point.
/// After all the children have been taken care of, the method waits for pending report processing to finish, then returns the
/// collected reports.
/// </summary>
Expand All @@ -424,6 +432,9 @@ public override async Task KillAsync()
return IgnoreReportedAccesses ? null : m_reports;
}

/// <inheritdoc />
internal override SandboxedProcessTraceBuilder? GetTraceFileBuilderAsync() => m_traceBuilder;

/// <inheritdoc />
public override void Dispose()
{
Expand Down
12 changes: 11 additions & 1 deletion Public/Src/Engine/Processes/UnSandboxedProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ public async Task<SandboxedProcessResult> GetResultAsync()

var fileAccesses = ShouldReportFileAccesses ? (reports?.FileAccesses ?? EmptyFileAccessesSet) : null;

var traceBuilder = GetTraceFileBuilderAsync();

return new SandboxedProcessResult
{
ExitCode = m_processExecutor.TimedOut ? ExitCodes.Timeout : (Process?.ExitCode ?? ExitCodes.Timeout),
Expand All @@ -312,7 +314,7 @@ public async Task<SandboxedProcessResult> GetResultAsync()
JobAccountingInformation = GetJobAccountingInfo(),
StandardOutput = m_output.Freeze(),
StandardError = m_error.Freeze(),
TraceFile = null,
TraceFile = traceBuilder?.Freeze(),
HasReadWriteToReadFileAccessRequest = reports?.HasReadWriteToReadFileAccessRequest ?? false,
AllUnexpectedFileAccesses = reports?.FileUnexpectedAccesses ?? EmptyFileAccessesSet,
FileAccesses = fileAccesses,
Expand Down Expand Up @@ -446,6 +448,14 @@ internal void LogProcessState(string message)
/// </summary>
internal virtual Task<SandboxedProcessReports?>? GetReportsAsync() => Task.FromResult<SandboxedProcessReports?>(null);

/// <summary>
/// Returns a trace file builder if one was created.
/// </summary>
/// <remarks>
/// If there is a builder, it should only be used when SandboxedProcessReports (<see cref="GetReportsAsync"/>) are frozen.
/// </remarks>
internal virtual SandboxedProcessTraceBuilder? GetTraceFileBuilderAsync() => null;

internal static void FeedOutputBuilder(SandboxedProcessOutputBuilder output, string line)
{
if (line != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ public TraceFileBuilderTests(ITestOutputHelper output) : base(output)
{
}

// TODO (olkonone): Bug 1989281: Enable trace file for Linux and MacOS
[FactIfSupported(requiresWindowsBasedOperatingSystem: true)]
[Fact]
public void AddingTraceFileCausesCacheMiss()
{
var builder = CreatePipBuilder(new[]
Expand All @@ -51,8 +50,7 @@ public void AddingTraceFileCausesCacheMiss()
RunScheduler().AssertCacheHit(pip.PipId);
}

// TODO (olkonone): Bug 1989281: Enable trace file for Linux and MacOS
[FactIfSupported(requiresWindowsBasedOperatingSystem: true)]
[Fact]
public void TraceFileExistsAndContainsFileAccessesPerformedByPipAndItIsReplayedOnCacheHit()
{
var input = CreateSourceFile();
Expand Down Expand Up @@ -81,16 +79,27 @@ public void TraceFileExistsAndContainsFileAccessesPerformedByPipAndItIsReplayedO
// Obviously, the path of a trace file itself is not in the trace file.
XAssert.IsFalse(traceFileContent.Contains(traceFilePath));

// The following paths must appear exactly two times -- once in the command line of a test process (test infra puts details
// about all operations there) and once at their appropriate place in the file.
// On Windows, the following paths must appear exactly two times -- once in the command line of a test process (test infra
// puts details about all operations there) and once at their appropriate place in the file. On Unix, our sandbox is not
// reporting process arguments, so there should be exactly one match.
var expectedMatchCount = OperatingSystemHelper.IsWindowsOS ? 2 : 1;
var regexOptions = OperatingSystemHelper.IsPathComparisonCaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase;
XAssert.AreEqual(2, Regex.Matches(traceFileContent, Regex.Escape(inputPath), regexOptions).Count);
XAssert.AreEqual(2, Regex.Matches(traceFileContent, Regex.Escape(outputPath), regexOptions).Count);
XAssert.AreEqual(expectedMatchCount, Regex.Matches(traceFileContent, Regex.Escape(inputPath), regexOptions).Count);
XAssert.AreEqual(expectedMatchCount, Regex.Matches(traceFileContent, Regex.Escape(outputPath), regexOptions).Count);

// There must be exactly one write operation, and more than one Read operation
// There should be more than one Read operation
// (",0,0,\r?$" is for a successful, non-augmented operation without any enumeration pattern).
XAssert.IsTrue(Regex.Matches(traceFileContent, @$",{(byte)RequestedAccess.Read},0,0,\r?$", RegexOptions.Multiline).Count > 1);
XAssert.AreEqual(1, Regex.Matches(traceFileContent, @$",{(byte)RequestedAccess.Write},0,0,\r?$", RegexOptions.Multiline).Count);
if (OperatingSystemHelper.IsWindowsOS)
{
// On Windows, there must be exactly one write operation (for the 'output' file).
XAssert.AreEqual(1, Regex.Matches(traceFileContent, @$",{(byte)RequestedAccess.Write},0,0,\r?$", RegexOptions.Multiline).Count);
}
else
{
// On Unix, the sandbox reports writes to in/out pipes, so we have more than one write access.
XAssert.IsTrue(Regex.Matches(traceFileContent, @$",{(byte)RequestedAccess.Write},0,0,\r?$", RegexOptions.Multiline).Count > 1);
}

// Now delete the file.
File.Delete(traceFilePath);
Expand Down
9 changes: 0 additions & 9 deletions Public/Src/Pips/Dll/Builders/ProcessBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -697,15 +697,6 @@ public bool TryFinish(PipConstructionHelper pipConstructionHelper, out Process p
return false;
}

// TODO (olkonone): Bug 1989281: Enable trace file for Linux and MacOS
if (m_traceFile.IsValid && !OperatingSystemHelper.IsWindowsOS)
{
processOutputs = null;
process = null;

return false;
}

process = new Process(
executable: Executable,
workingDirectory: WorkingDirectory.IsValid ? WorkingDirectory : defaultDirectory,
Expand Down
10 changes: 5 additions & 5 deletions Public/Src/Utilities/Configuration/SandboxKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,27 @@ public enum SandboxKind : byte
WinDetours,

/// <summary>
/// macOs-specifc: using kernel extension
/// macOs-specific: using kernel extension
/// </summary>
MacOsKext,

/// <summary>
/// Like <see cref="MacOsKext"/> except that it gnores all reported file accesses.
/// Like <see cref="MacOsKext"/> except that it ignores all reported file accesses.
/// </summary>
MacOsKextIgnoreFileAccesses,

/// <summary>
/// macOs-specifc: Using the EndpointSecurity subsystem for sandboxing (available from 10.15+)
/// macOs-specific: Using the EndpointSecurity subsystem for sandboxing (available from 10.15+)
/// </summary>
MacOsEndpointSecurity,

/// <summary>
/// macOs-specifc: Using DYLD interposing for sandboxing
/// macOs-specific: Using DYLD interposing for sandboxing
/// </summary>
MacOsDetours,

/// <summary>
/// macOs-specifc: Using the EndpointSecurity subsystem (available from 10.15+) and DYLD interposing together for sandboxing
/// macOs-specific: Using the EndpointSecurity subsystem (available from 10.15+) and DYLD interposing together for sandboxing
/// </summary>
MacOsHybrid,

Expand Down

0 comments on commit 0fcb2c6

Please sign in to comment.