private FileAccessManifest GenerateFileAccessManifest(AbsolutePath toolDirectory, AbsolutePath outputFile) { // We make no attempt at understanding what the graph generation process is going to do // We just configure the manifest to not fail on unexpected accesses, so they can be collected // later if needed var fileAccessManifest = new FileAccessManifest(m_context.PathTable) { FailUnexpectedFileAccesses = false, ReportFileAccesses = true, MonitorNtCreateFile = true, MonitorZwCreateOpenQueryFile = true, MonitorChildProcesses = true, }; fileAccessManifest.AddScope( AbsolutePath.Create(m_context.PathTable, SpecialFolderUtilities.GetFolderPath(Environment.SpecialFolder.Windows)), FileAccessPolicy.MaskAll, FileAccessPolicy.AllowAllButSymlinkCreation); fileAccessManifest.AddScope( AbsolutePath.Create(m_context.PathTable, SpecialFolderUtilities.GetFolderPath(Environment.SpecialFolder.InternetCache)), FileAccessPolicy.MaskAll, FileAccessPolicy.AllowAllButSymlinkCreation); fileAccessManifest.AddScope( AbsolutePath.Create(m_context.PathTable, SpecialFolderUtilities.GetFolderPath(Environment.SpecialFolder.History)), FileAccessPolicy.MaskAll, FileAccessPolicy.AllowAllButSymlinkCreation); fileAccessManifest.AddScope(toolDirectory, FileAccessPolicy.MaskAll, FileAccessPolicy.AllowReadAlways); fileAccessManifest.AddPath(outputFile, FileAccessPolicy.MaskAll, FileAccessPolicy.AllowWrite); return(fileAccessManifest); }
/// <summary> /// The manifest is configured so all file accesses are allowed but reported, including child processes. /// </summary> /// <remarks> /// Some special folders (Windows, InternetCache and History) are added as known scopes. Everything else will be flagged /// as an 'unexpected' access. However, unexpected accesses are configured so they are not blocked. /// </remarks> private static FileAccessManifest CreateManifestToAllowAllAccesses(PathTable pathTable) { var fileAccessManifest = new FileAccessManifest(pathTable) { FailUnexpectedFileAccesses = false, ReportFileAccesses = true, MonitorChildProcesses = true, }; fileAccessManifest.AddScope( AbsolutePath.Create(pathTable, SpecialFolderUtilities.GetFolderPath(Environment.SpecialFolder.Windows)), FileAccessPolicy.MaskAll, FileAccessPolicy.AllowAll); fileAccessManifest.AddScope( AbsolutePath.Create(pathTable, SpecialFolderUtilities.GetFolderPath(Environment.SpecialFolder.InternetCache)), FileAccessPolicy.MaskAll, FileAccessPolicy.AllowAll); fileAccessManifest.AddScope( AbsolutePath.Create(pathTable, SpecialFolderUtilities.GetFolderPath(Environment.SpecialFolder.History)), FileAccessPolicy.MaskAll, FileAccessPolicy.AllowAll); return(fileAccessManifest); }
public void BreakawayProcessCanReportAugmentedAccesses() { var fam = new FileAccessManifest( Context.PathTable, childProcessesToBreakawayFromSandbox: new[] { TestProcessToolName }) { FailUnexpectedFileAccesses = false, ReportUnexpectedFileAccesses = true, ReportFileAccesses = true }; var srcFile = CreateSourceFile(); var output = CreateOutputFileArtifact(); fam.AddScope(srcFile, FileAccessPolicy.MaskNothing, FileAccessPolicy.ReportAccess); fam.AddScope(output, FileAccessPolicy.MaskNothing, FileAccessPolicy.ReportAccess); var info = ToProcessInfo( ToProcess( Operation.AugmentedRead(srcFile), Operation.AugmentedWrite(output)), fileAccessManifest: fam); var result = RunProcess(info).GetAwaiter().GetResult(); XAssert.AreEqual(0, result.ExitCode); var observedAccesses = result.FileAccesses.Select(fa => fa.ManifestPath); XAssert.Contains(observedAccesses, srcFile.Path, output.Path); }
/// <summary> /// The manifest is configured so all accesses under the provided collection of directories to block are blocked /// </summary> private FileAccessManifest CreateManifest(AbsolutePath pathToProcess, IEnumerable <AbsolutePath> directoriesToBlock) { var fileAccessManifest = new FileAccessManifest(m_pathTable) { FailUnexpectedFileAccesses = true, ReportFileAccesses = true, MonitorChildProcesses = true, }; // We allow all file accesses at the root level, so by default everything is allowed fileAccessManifest.AddScope(AbsolutePath.Invalid, FileAccessPolicy.MaskNothing, FileAccessPolicy.AllowAll); // We explicitly allow reading from the tool path fileAccessManifest.AddPath(pathToProcess, FileAccessPolicy.MaskAll, FileAccessPolicy.AllowRead); // We block access on all provided directories foreach (var directoryToBlock in directoriesToBlock) { fileAccessManifest.AddScope( directoryToBlock, FileAccessPolicy.MaskAll, FileAccessPolicy.Deny & FileAccessPolicy.ReportAccess); } return(fileAccessManifest); }
public void MaskedReportAugmentedAccessIsNotReported() { var fam = new FileAccessManifest( Context.PathTable, childProcessesToBreakawayFromSandbox: new[] { TestProcessToolName }) { FailUnexpectedFileAccesses = false, ReportUnexpectedFileAccesses = true, ReportFileAccesses = true }; var basePath = TestBinRootPath.Combine(Context.PathTable, "foo"); var output1 = CreateOutputFileArtifact(basePath); var output2 = CreateOutputFileArtifact(basePath); // We mask reporting accesses for output1 and enable it for output2 fam.AddScope(output1.Path, ~FileAccessPolicy.ReportAccess, FileAccessPolicy.AllowAll); fam.AddScope(output2.Path, FileAccessPolicy.MaskNothing, FileAccessPolicy.AllowAll | FileAccessPolicy.ReportAccess); var info = ToProcessInfo( ToProcess( Operation.AugmentedWrite(output1), Operation.AugmentedWrite(output2)), fileAccessManifest: fam); var result = RunProcess(info).GetAwaiter().GetResult(); XAssert.AreEqual(0, result.ExitCode); // We should get a single access with output2, since output1 should be ignored var accessPath = result.FileAccesses.Single(rfa => rfa.Method == FileAccessStatusMethod.TrustedTool).ManifestPath; XAssert.AreEqual(output2.Path, accessPath); }
public void MaskedReportAugmentedAccessIsNotReported(bool reportFileAccesses) { var fam = new FileAccessManifest( Context.PathTable, childProcessesToBreakawayFromSandbox: new[] { TestProcessToolName }) { FailUnexpectedFileAccesses = false, ReportUnexpectedFileAccesses = true, ReportFileAccesses = reportFileAccesses }; var basePath = TestBinRootPath.Combine(Context.PathTable, "foo"); var output1 = CreateOutputFileArtifact(basePath); var output2 = CreateOutputFileArtifact(basePath); // We mask reporting accesses for output1 and enable it for output2 fam.AddScope(output1.Path, ~FileAccessPolicy.ReportAccess, FileAccessPolicy.AllowAll); fam.AddScope(output2.Path, FileAccessPolicy.MaskNothing, FileAccessPolicy.AllowAll | FileAccessPolicy.ReportAccess); var collector = new FileAccessCollector(Context.PathTable); var info = ToProcessInfo( ToProcess( Operation.AugmentedWrite(output1), Operation.AugmentedWrite(output2)), fileAccessManifest: fam, detoursListener: collector); var result = RunProcess(info).GetAwaiter().GetResult(); XAssert.AreEqual(0, result.ExitCode); // We should get a single explicit access with output2, since output1 shouldn't be reported var accessPath = result.ExplicitlyReportedFileAccesses.Single(rfa => rfa.Method == FileAccessStatusMethod.TrustedTool).ManifestPath; XAssert.AreEqual(output2.Path, accessPath); // We should get both accesses as part of the (optional) FileAccess on request if (reportFileAccesses) { var allTrustedAcceses = result.FileAccesses.Where(rfa => rfa.Method == FileAccessStatusMethod.TrustedTool).Select(rfa => rfa.ManifestPath); XAssert.Contains(allTrustedAcceses, output1.Path, output2.Path); } else { // Make sure the access related to output1 is not actually reported, and the only one the listener got is output2 XAssert.Contains(collector.FileAccessPaths, output2.Path); XAssert.ContainsNot(collector.FileAccessPaths, output1.Path); } }
public void AugmentedAccessHasTheRightManifestPath() { var fam = new FileAccessManifest( Context.PathTable, childProcessesToBreakawayFromSandbox: new[] { TestProcessToolName }) { FailUnexpectedFileAccesses = false, ReportUnexpectedFileAccesses = true, ReportFileAccesses = true }; var basePath = TestBinRootPath.Combine(Context.PathTable, "foo"); var output = CreateOutputFileArtifact(basePath); fam.AddScope(basePath, FileAccessPolicy.MaskNothing, FileAccessPolicy.AllowAll | FileAccessPolicy.ReportAccess); var info = ToProcessInfo( ToProcess( Operation.AugmentedWrite(output)), fileAccessManifest: fam); var result = RunProcess(info).GetAwaiter().GetResult(); XAssert.AreEqual(0, result.ExitCode); var fileAccess = result.ExplicitlyReportedFileAccesses.Single(rfa => rfa.Method == FileAccessStatusMethod.TrustedTool); XAssert.AreEqual(basePath, fileAccess.ManifestPath); }
private void AddBlockedPath(FileAccessManifest fam, SandboxOptions option, AbsolutePath path) { if (option.debug) { Console.Error.WriteLine($"na: {path.ToString(m_pathTable)}"); } fam.AddScope(path, FileAccessPolicy.MaskAll, FileAccessPolicy.Deny); }
/// <nodoc /> private FileAccessManifest CreateManifest(AbsolutePath pathToProcess, SandboxOptions option, string workingDir) { var fam = new FileAccessManifest(m_pathTable) { FailUnexpectedFileAccesses = true, ReportFileAccesses = false, ReportUnexpectedFileAccesses = false, MonitorChildProcesses = true, MonitorNtCreateFile = true, MonitorZwCreateOpenQueryFile = true, }; // We make whole filesystem as read-only. fam.AddScope(AbsolutePath.Invalid, FileAccessPolicy.MaskAll, FileAccessPolicy.AllowRead); // Block working dir AddBlockedPath(fam, option, AbsolutePath.Create(m_pathTable, workingDir)); // We explicitly allow reading from the tool path AddReadOnlyPath(fam, option, pathToProcess); // We allow access on all provided files/directories // Note: if C:\A is allowed, its subtree is allowed too. foreach (var path in option.readonly_files) { AddReadOnlyPath(fam, option, path); } foreach (var path in option.writable_files) { AddReadWritePath(fam, option, path); } foreach (var path in option.blocked_files) { AddBlockedPath(fam, option, path); } return(fam); }