public void ThrowsGuardException_ForLocalsThatExceedSizeLimit() { // found by Stanislav Lukeš (@exyi) var compiled = TestHelper.Compile(@" using System; struct A_1 { public int A; public int B; } struct A_2 { public A_1 A; public A_1 B; } struct A_3 { public A_2 A; public A_2 B; } struct A_4 { public A_3 A; public A_3 B; } struct A_5 { public A_4 A; public A_4 B; } struct A_6 { public A_5 A; public A_5 B; } struct A_7 { public A_6 A; public A_6 B; } struct A_8 { public A_7 A; public A_7 B; } struct A_9 { public A_8 A; public A_8 B; } struct A_10 { public A_9 A; public A_9 B; } struct A_11 { public A_10 A; public A_10 B; } struct A_12 { public A_11 A; public A_11 B; } struct A_13 { public A_12 A; public A_12 B; } struct A_14 { public A_13 A; public A_13 B; } struct A_15 { public A_14 A; public A_14 B; } struct A_16 { public A_15 A; public A_15 B; } struct A_17 { public A_16 A; public A_16 B; } struct A_18 { public A_17 A; public A_17 B; } class C { int M() { A_18 a; return 0; } } "); Assert.Throws <AssemblyGuardException>( () => AssemblyGuard.Rewrite(compiled, new MemoryStream()) ); }
public void ThrowsGuardException_ForAsyncMethodWithTry() { var compiled = TestHelper.Compile(@" using System; using System.Threading.Tasks; class Program { async Task Main() { Console.WriteLine(); try { await Task.Yield(); } catch { } } } "); var ex = Assert.Throws <AssemblyGuardException>( () => AssemblyGuard.Rewrite(compiled, Stream.Null, new AssemblyGuardSettings { ApiPolicy = ApiPolicy.SafeDefault() .Namespace("System.Runtime.CompilerServices", ApiAccess.Allowed) .Namespace("System.Threading.Tasks", ApiAccess.Allowed) }) ); Assert.Contains("System.Console", ex.Message); }
public ExecutionResult Execute(Stream assemblyStream, Stream symbolStream, IWorkSession session) { AssemblyDefinition assembly; using (assemblyStream) using (symbolStream) { assembly = AssemblyDefinition.ReadAssembly(assemblyStream, new ReaderParameters { ReadSymbols = true, SymbolStream = symbolStream, AssemblyResolver = PreCachedAssemblyResolver.Instance }); } /* #if DEBUG * assembly.Write(@"d:\Temp\assembly\" + DateTime.Now.Ticks + "-before-rewrite.dll"); #endif */ foreach (var rewriter in _rewriters) { rewriter.Rewrite(assembly, session); } if (assembly.EntryPoint == null) { throw new ArgumentException("Failed to find an entry point (Main?) in assembly.", nameof(assemblyStream)); } var guardToken = AssemblyGuard.Rewrite(assembly, GuardSettings); using (var rewrittenStream = _memoryStreamManager.GetStream()) { assembly.Write(rewrittenStream); /* #if DEBUG * assembly.Write(@"d:\Temp\assembly\" + DateTime.Now.Ticks + ".dll"); #endif */ rewrittenStream.Seek(0, SeekOrigin.Begin); var currentSetup = AppDomain.CurrentDomain.SetupInformation; using (var context = AppDomainContext.Create(new AppDomainSetup { ApplicationBase = currentSetup.ApplicationBase, PrivateBinPath = currentSetup.PrivateBinPath })) { context.LoadAssembly(LoadMethod.LoadFrom, Assembly.GetExecutingAssembly().GetAssemblyFile().FullName); var(result, exception) = RemoteFunc.Invoke(context.Domain, rewrittenStream, guardToken, Remote.Execute); if (ShouldMonitorException(exception)) { _monitor.Exception(exception, session); } return(result); } } }
public void Allows_ReasonablySafePointerOperations(string code) { var compiled = TestHelper.Compile(@" // required for records namespace System.Runtime.CompilerServices { class IsExternalInit {} } " + code + @" "); // Assert.DoesNotThrow AssemblyGuard.Rewrite(compiled, new MemoryStream()); }
[InlineData("void M(ref int i) => i++;")] // public void Allows_ReasonablySafePointerOperations(string code) { var compiled = TestHelper.Compile(@" class C { " + code + @" } "); // Assert.DoesNotThrow AssemblyGuard.Rewrite(compiled, new MemoryStream()); }
public void ThrowsGuardException_ForCustomTypesWithKnownTypeNames(string @namespace, string name) { var compiled = TestHelper.Compile(@" namespace " + @namespace + @" { class @" + name + @" {} } "); var exception = Record.Exception( () => AssemblyGuard.Rewrite(compiled, new MemoryStream()) ); Assert.IsType <AssemblyGuardException>(exception); }
private ResultViewModel Run(string code) { var totalStopwatch = Stopwatch.StartNew(); var compilationStopwatch = new Stopwatch(); var rewriteStopwatch = new Stopwatch(); var executionStopwatch = new Stopwatch(); ResultViewModel resultModel(string?output) => new ResultViewModel( output, compilationStopwatch.Elapsed, rewriteStopwatch.Elapsed, executionStopwatch.Elapsed, totalStopwatch.Elapsed ); try { compilationStopwatch.Start(); CSharpRoslynGuard.Validate(code); var compilation = CSharpCompilation.Create( "_", new[] { CSharpSyntaxTree.ParseText(code) }, MetadataReferences, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) ); using (var assemblyStream = MemoryStreamManager.GetStream()) using (var rewrittenStream = MemoryStreamManager.GetStream()) { var compilationResult = compilation.Emit(assemblyStream); compilationStopwatch.Stop(); if (!compilationResult.Success) { return(resultModel(string.Join("\r\n", compilationResult.Diagnostics))); } assemblyStream.Seek(0, SeekOrigin.Begin); rewriteStopwatch.Start(); var guardToken = AssemblyGuard.Rewrite(assemblyStream, rewrittenStream); rewriteStopwatch.Stop(); var currentSetup = AppDomain.CurrentDomain.SetupInformation; using (var context = AppDomainContext.Create(new AppDomainSetup { ApplicationBase = currentSetup.ApplicationBase, PrivateBinPath = currentSetup.PrivateBinPath })) { context.LoadAssembly(LoadMethod.LoadFrom, Assembly.GetExecutingAssembly().GetAssemblyFile().FullName); executionStopwatch.Start(); var result = RemoteFunc.Invoke(context.Domain, rewrittenStream, guardToken, RemoteRun); executionStopwatch.Stop(); return(resultModel(result?.ToString())); } } } catch (Exception ex) { return(resultModel(ex.ToString())); } }
[InlineData("void M() { var x = new IntPtr(0); }")] // crash, found by Alexandre Mutel (@xoofx) public void ThrowsGuardException_ForDeniedApi(string code) { var compiled = TestHelper.Compile(@" using System; class C { " + code + @" }" ); Assert.Throws <AssemblyGuardException>( () => AssemblyGuard.Rewrite(compiled, new MemoryStream()) ); }
public void ThrowsGuardException_ForFinalizers() { // found by George Pollard (@porges) var compiled = TestHelper.Compile(@" class X { ~X() {} } "); Assert.Throws <AssemblyGuardException>( () => AssemblyGuard.Rewrite(compiled, new MemoryStream()) ); }
public void Allows_AnonymousTypes() { var compiled = TestHelper.Compile(@" class C { object M() { return new { a = ""x"" }; } } "); // Assert.DoesNotThrow AssemblyGuard.Rewrite(compiled, new MemoryStream(), AssemblyGuardSettings.DefaultForCSharpAssembly()); }
public void ThrowsGuardException_ForPInvoke() { // found by Igal Tabachnik (@hmemcpy) var compiled = TestHelper.Compile(@" using System.Runtime.InteropServices; static class X { [DllImport(""kernel32.dll"")] static extern void ExitProcess(int uExitCode); } "); Assert.Throws <AssemblyGuardException>( () => AssemblyGuard.Rewrite(compiled, new MemoryStream()) ); }
public void ThrowsAssemblyGuardException_IfTimeoutIsProvidedManually(string code) { var compiled = TestHelper.Compile(@" using System; using System.Text.RegularExpressions; class C { public void M() => " + code + @"; } "); var ex = Record.Exception(() => AssemblyGuard.Rewrite(compiled, new MemoryStream())); Assert.IsType <AssemblyGuardException>(ex); Assert.Contains("Timeout", ex.Message, StringComparison.OrdinalIgnoreCase); }
[Fact] // https://github.com/ashmind/SharpLab/issues/323 public void Allows_CallsToRefReadOnlyMethods() { var compiled = TestHelper.Compile(@" class C { static ref readonly int MRef(ref int i) => ref i; static void M() { int x = 0; ref readonly int r = ref MRef(ref x); } } "); // Assert.DoesNotThrow AssemblyGuard.Rewrite(compiled, new MemoryStream(), AssemblyGuardSettings.DefaultForCSharpAssembly()); }
public void ThrowsGuardException_ForDelegateBeginEndInvoke() { // found by Llewellyn Pritchard (@leppie) var compiled = TestHelper.Compile(@" using System; class C { delegate void D(); void M() { D d = () => {}; d.BeginInvoke(null, null); } }" ); Assert.Throws <AssemblyGuardException>( () => AssemblyGuard.Rewrite(compiled, new MemoryStream()) ); }
public static Invoke RewriteAndGetMethodWrappedInScope(string code, string typeName, string methodName, AssemblyGuardSettings guardSettings = null) { var assemblySourceStream = Compile(code); var assemblyTargetStream = new MemoryStream(); var token = AssemblyGuard.Rewrite(assemblySourceStream, assemblyTargetStream, guardSettings); return(args => { using (token.Scope(new RuntimeGuardSettings { TimeLimit = TimeSpan.FromMilliseconds(100) })) { var method = GetInstanceMethod(assemblyTargetStream, typeName, methodName); return method(args); } }); }
public void Allows_ReasonableAmountOfNullableLocals() { var compiled = TestHelper.Compile(@" class C { void M() { int? a = 1; int? b = 1; int? c = a + b; int? d = a + b; } } "); // Assert.DoesNotThrow AssemblyGuard.Rewrite(compiled, new MemoryStream()); }
public void Allows_ExternMethods() { // crash, found by Alexandre Mutel (@xoofx) var compiled = TestHelper.Compile(@" class C { static extern void Extern(); int M() { Extern(); return 0; } } "); // Assert.DoesNotThrow AssemblyGuard.Rewrite(compiled, new MemoryStream()); }
public void ThrowsGuardException_ForExplicitStructLayout() { // found by Alexandre Mutel (@xoofx) var compiled = TestHelper.Compile(@" using System.Runtime.InteropServices; [StructLayout(LayoutKind.Explicit)] struct S { [FieldOffset(0)] int x; } "); Assert.Throws <AssemblyGuardException>( () => AssemblyGuard.Rewrite(compiled, new MemoryStream()) ); }
public void ThrowsGuardException_ForPointerTypes(string code) { // pointers, available in local functions due to a Roslyn bug, reported by Andy Gocke (@andygocke) var policy = ApiPolicy.SafeDefault() .Namespace("System.Security", ApiAccess.Neutral, n => n.Type(typeof(UnverifiableCodeAttribute), ApiAccess.Allowed)); var compiled = TestHelper.Compile(@" class X { unsafe void M(int a) { " + code + @" } } ", allowUnsafe: true); Assert.Throws <AssemblyGuardException>( () => AssemblyGuard.Rewrite(compiled, new MemoryStream(), new AssemblyGuardSettings { ApiPolicy = policy }) ); }
public void ThrowsGuardException_ForDelegatesCreatedFromMethodsWithRewriters(string code) { var compiled = TestHelper.Compile(@" using System; using System.Linq.Expressions; class C { void M() { " + code + @" } }" ); var policy = ApiPolicy.SafeDefault() .Namespace("System.Linq.Expressions", ApiAccess.Allowed) .Namespace("System.Reflection", ApiAccess.Allowed); Assert.Throws <AssemblyGuardException>( () => AssemblyGuard.Rewrite(compiled, new MemoryStream(), new AssemblyGuardSettings { ApiPolicy = policy }) ); }
public ExecutionResult Execute(CompilationStreamPair streams, IWorkSession session) { var readerParameters = new ReaderParameters { ReadSymbols = streams.SymbolStream != null, SymbolStream = streams.SymbolStream, AssemblyResolver = _assemblyResolver, SymbolReaderProvider = streams.SymbolStream != null ? _symbolReaderProvider : null }; using (streams) using (var definition = AssemblyDefinition.ReadAssembly(streams.AssemblyStream, readerParameters)) { foreach (var rewriter in _rewriters) { rewriter.Rewrite(definition, session); } PerformanceLog.Checkpoint("Executor.Rewrite.Flow.End"); AssemblyLog.Log("2.WithFlow", definition); if (definition.EntryPoint == null) { Output.Reset(); Flow.Reset(); Output.WriteWarning("Could not find any code to run (either a Main method or any top level code)."); return(new ExecutionResult(Output.Stream, Flow.Steps)); } var guardToken = AssemblyGuard.Rewrite(definition, _guardSettings); using (var rewrittenStream = _memoryStreamManager.GetStream()) { definition.Write(rewrittenStream); AssemblyLog.Log("3.Unbreakable", definition); rewrittenStream.Seek(0, SeekOrigin.Begin); PerformanceLog.Checkpoint("Executor.Rewrite.Unbreakable.End"); using (var context = new CustomAssemblyLoadContext(shouldShareAssembly: ShouldShareAssembly)) { var assembly = context.LoadFromStream(rewrittenStream); PerformanceLog.Checkpoint("Executor.AssemblyLoad.End"); return(Execute(assembly, guardToken, session)); } } } }
public ExecutionResult Execute(CompilationStreamPair streams, IWorkSession session) { var readerParameters = new ReaderParameters { ReadSymbols = streams.SymbolStream != null, SymbolStream = streams.SymbolStream, AssemblyResolver = _assemblyResolver, SymbolReaderProvider = streams.SymbolStream != null ? _symbolReaderProvider : null }; using (streams) using (var definition = AssemblyDefinition.ReadAssembly(streams.AssemblyStream, readerParameters)) { AssemblyLog.Log("1.Initial", definition); foreach (var rewriter in _rewriters) { rewriter.Rewrite(definition, session); } PerformanceLog.Checkpoint("Executor.Rewrite.Flow.End"); AssemblyLog.Log("2.WithFlow", definition); if (definition.EntryPoint == null) { throw new ArgumentException("Failed to find an entry point (Main?) in assembly.", nameof(streams)); } var guardToken = AssemblyGuard.Rewrite(definition, _guardSettings); using (var rewrittenStream = _memoryStreamManager.GetStream()) { definition.Write(rewrittenStream); AssemblyLog.Log("3.Unbreakable", definition); rewrittenStream.Seek(0, SeekOrigin.Begin); PerformanceLog.Checkpoint("Executor.Rewrite.Unbreakable.End"); using (var context = new CustomAssemblyLoadContext(shouldShareAssembly: ShouldShareAssembly)) { var assembly = context.LoadFromStream(rewrittenStream); PerformanceLog.Checkpoint("Executor.AssemblyLoad.End"); return(Execute(assembly, guardToken, session)); } } } }
public void DoesNotEnforceApiPolicy_ForUserCode() { var compiled = TestHelper.Compile(@" namespace N { class C1 { void M(C2 c2) { c2.M(); } } class C2 { public void M() {} } } "); var exception = Record.Exception(() => AssemblyGuard.Rewrite(compiled, new MemoryStream(), new AssemblyGuardSettings { ApiPolicy = ApiPolicy.SafeDefault().Namespace("N", ApiAccess.Denied) })); Assert.Null(exception); }
public void ThrowsGuardException_ForFieldReadsThatExceedSizeLimit() { // found by Tereza Tomcova (@the-ress) var compiled = TestHelper.Compile(@" using System; using System.Collections.Generic; struct A_1 { public int A; public int B; } struct A_2 { public A_1 A; public A_1 B; } struct A_3 { public A_2 A; public A_2 B; } struct A_4 { public A_3 A; public A_3 B; } struct A_5 { public A_4 A; public A_4 B; } struct A_6 { public A_5 A; public A_5 B; } struct A_7 { public A_6 A; public A_6 B; } struct A_8 { public A_7 A; public A_7 B; } struct A_9 { public A_8 A; public A_8 B; } struct A_10 { public A_9 A; public A_9 B; } struct A_11 { public A_10 A; public A_10 B; } struct A_12 { public A_11 A; public A_11 B; } struct A_13 { public A_12 A; public A_12 B; } struct A_14 { public A_13 A; public A_13 B; } struct A_15 { public A_14 A; public A_14 B; } struct A_16 { public A_15 A; public A_15 B; } struct A_17 { public A_16 A; public A_16 B; } struct A_18 { public A_17 A; public A_17 B; } class C { static readonly A_18 Value = default(A_18); int M() { var d = new Dictionary<int, A_18>(); d.Add(0, Value); return 0; } } "); Assert.Throws <AssemblyGuardException>( () => AssemblyGuard.Rewrite(compiled, new MemoryStream()) ); }
public ExecutionResult Execute(Stream assemblyStream, Stream symbolStream, IWorkSession session) { var readerParameters = new ReaderParameters { ReadSymbols = symbolStream != null, SymbolStream = symbolStream, AssemblyResolver = _assemblyResolver, SymbolReaderProvider = symbolStream != null ? _symbolReaderProvider : null }; using (assemblyStream) using (symbolStream) using (var assembly = AssemblyDefinition.ReadAssembly(assemblyStream, readerParameters)) { /* #if DEBUG * assembly.Write(@"d:\Temp\assembly\" + DateTime.Now.Ticks + "-before-rewrite.dll"); #endif */ foreach (var rewriter in _rewriters) { rewriter.Rewrite(assembly, session); } if (assembly.EntryPoint == null) { throw new ArgumentException("Failed to find an entry point (Main?) in assembly.", nameof(assemblyStream)); } var guardToken = AssemblyGuard.Rewrite(assembly, GuardSettings); using (var rewrittenStream = _memoryStreamManager.GetStream()) { assembly.Write(rewrittenStream); /* #if DEBUG * assembly.Write(@"d:\Temp\assembly\" + DateTime.Now.Ticks + ".dll"); #endif */ rewrittenStream.Seek(0, SeekOrigin.Begin); return(ExecuteInAppDomain(rewrittenStream, guardToken, session)); } } }
private static Assembly RewriteNewtonsoftJson() { var assemblyPath = typeof(JsonSerializer).Assembly.GetAssemblyFileFromCodeBase().FullName; var definition = AssemblyDefinition.ReadAssembly(assemblyPath); definition.Name.HasPublicKey = false; definition.Name.PublicKey = new byte[0]; definition.Name.HashAlgorithm = AssemblyHashAlgorithm.None; definition.MainModule.Attributes &= ~ModuleAttributes.StrongNameSigned; AssemblyGuard.Rewrite(definition, new AssemblyGuardSettings { ApiPolicy = ApiRules, MethodLocalsSizeLimit = IntPtr.Size * 40, MethodStackPushSizeLimit = 120, AllowExplicitLayoutInTypesMatchingPattern = new Regex("<PrivateImplementationDetails>") }); var assemblyStream = new MemoryStream(); definition.Write(assemblyStream); definition.Write(Path.Combine(Path.GetDirectoryName(assemblyPath) !, "Newtonsoft.Json.Rewritten.dll")); return(Assembly.Load(assemblyStream.ToArray())); }
public ExecutionResult Execute(CompilationStreamPair streams, IWorkSession session) { var readerParameters = new ReaderParameters { ReadSymbols = streams.SymbolStream != null, SymbolStream = streams.SymbolStream, AssemblyResolver = _assemblyResolver, SymbolReaderProvider = streams.SymbolStream != null ? _symbolReaderProvider : null }; using (streams) using (var definition = AssemblyDefinition.ReadAssembly(streams.AssemblyStream, readerParameters)) { AssemblyLog.Log("1.Initial", definition); foreach (var rewriter in _rewriters) { rewriter.Rewrite(definition, session); } AssemblyLog.Log("2.WithFlow", definition); if (definition.EntryPoint == null) { throw new ArgumentException("Failed to find an entry point (Main?) in assembly.", nameof(streams)); } var guardToken = AssemblyGuard.Rewrite(definition, _guardSettings); using (var rewrittenStream = _memoryStreamManager.GetStream()) { definition.Write(rewrittenStream); AssemblyLog.Log("3.Unbreakable", definition); rewrittenStream.Seek(0, SeekOrigin.Begin); var(result, exception) = ExecuteWithIsolation(rewrittenStream, guardToken, session); if (ShouldMonitorException(exception)) { _monitor.Exception(exception !, session); } return(result); } } }
public static RuntimeGuardToken Rewrite(Stream source, Stream target) { return(AssemblyGuard.Rewrite(source, target, CreateGuardSettings())); }