Initial sandboxing implementation

This commit is contained in:
Oiltanker
2022-04-09 21:29:55 +03:00
parent 429557ad7d
commit 0b501ab4a1
2 changed files with 53 additions and 80 deletions
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection.Metadata;
partial class NetScript partial class NetScript
{ {
@@ -13,18 +14,34 @@ partial class NetScript
{ {
private const bool useWhitelist = false; private const bool useWhitelist = false;
private static string[] classesPermited = new string[] {}; private static string[] typesPermited = new string[] {
private static string[] classesProhibited = new string[] { }; // Basics
public static bool IsClassAllowed(string usingName) "System.Runtime.CompilerServices.CompilationRelaxationsAttribute",
"System.Runtime.CompilerServices.RuntimeCompatibilityAttribute",
"System.Diagnostics.DebuggableAttribute",
"System.Object",
"System.String",
"System.Collections",
// Some roslyn magic
".DebuggingModes",
// Barotrauma
"Barotrauma",
};
private static string[] typessProhibited = new string[] {
//"System.Reflection",
"System.IO.File",
};
public static bool IsTypeAllowed(string usingName)
{ {
if (useWhitelist && !classesPermited.Any(u => u.Equals(usingName))) return false; if (useWhitelist && !typesPermited.Any(u => u.StartsWith(usingName))) return false;
if (classesProhibited.Any(u => u.Equals(usingName))) return false; if (typessProhibited.Any(u => u.StartsWith(usingName))) return false;
return true; return true;
} }
public static string FilterSyntaxTree(CSharpSyntaxTree tree) public static string FilterSyntaxTree(CSharpSyntaxTree tree)
{ {
if (tree == null) throw new ArgumentNullException("Syntax tree must not be null."); if (tree == null) throw new ArgumentNullException("Syntax tree must not be null.");
{ // Disallow top-level statements { // Disallow top-level statements
var nodeCheck = tree.GetRoot().DescendantNodes(); var nodeCheck = tree.GetRoot().DescendantNodes();
@@ -32,64 +49,33 @@ partial class NetScript
if (tlStatements.Count > 0) if (tlStatements.Count > 0)
{ {
string errStr = "Cmopilation Error:"; string errStr = "Cmopilation Error:";
foreach (var tls in tlStatements) tls.GetDiagnostics().ToList().ForEach(d => errStr += "\n" + d.ToString()); foreach (var tls in tlStatements) tls.GetDiagnostics().ToList().ForEach(d => errStr += $"\n {d.ToString()}");
return errStr; return errStr;
} }
} }
var compRoot = tree.GetCompilationUnitRoot(); return null;
var refDirs = compRoot.GetReferenceDirectives().ToList(); }
Console.WriteLine($"Reference Directives [{refDirs.Count}]:");
refDirs.ForEach(d => Console.WriteLine(d.ToFullString()));
List<string> allUsedTypes = new List<string>(); public static string FilterMetadata(MetadataReader reader)
{ // Find all used types {
} if (reader == null) throw new ArgumentNullException("Metadata Reader must not be null.");
List<string> allResolvedTypes = new List<string>(); var conflictingTypes = new List<string>();
{ // Resolve all types reader.TypeReferences.ToList().ForEach(t =>
}
{ // Check all used types
}
if (!Directory.Exists("./SyntaxTrees")) Directory.CreateDirectory("./SyntaxTrees");
string fileName = "./SyntaxTrees/" + tree.FilePath.Replace("/", "--") + ".txt";
if (File.Exists(fileName)) File.Delete(fileName);
var fileWriter = File.CreateText(fileName);
var nodes = new Queue<(SyntaxNode, int)>();
nodes.Enqueue((tree.GetRoot(), 0));
while (nodes.Count > 0)
{ {
var nodeElem = nodes.Dequeue(); var tRef = reader.GetTypeReference(t);
var node = nodeElem.Item1; var typeName = $"{reader.GetString(tRef.Namespace)}.{reader.GetString(tRef.Name)}";
var indent = nodeElem.Item2; if (!IsTypeAllowed(typeName)) conflictingTypes.Add(typeName);
});
node.ChildNodes().ToList().ForEach(n => { if (conflictingTypes.Count > 0)
if (n.ChildNodes().Count() > 0) nodes.Enqueue((n, indent + 1)); {
if (!( string errStr = "Metadata Error:";
n is MemberAccessExpressionSyntax || conflictingTypes.ForEach(t => errStr += $"\n Usage of type '{t}' in mods is prohibited.");
n is UsingDirectiveSyntax || return errStr;
n is BaseTypeSyntax ||
n is TypeSyntax
)) return;
//Console.WriteLine(new String(' ', indent * 2) + n.GetType().Name + " | " + n.GetText()?.ToString() ?? "null");
fileWriter.WriteLine(new String(' ', indent * 2) + n.GetType().Name + " | " + n.GetText()?.ToString() ?? "null");
});
node.DescendantNodes().ToList().ForEach(n => {
if (n.DescendantNodes().Count() > 0 && !nodes.Contains((n, indent + 1))) nodes.Enqueue((n, indent + 1));
if (!(
n is MemberAccessExpressionSyntax ||
n is UsingDirectiveSyntax ||
n is BaseTypeSyntax ||
n is TypeSyntax
)) return;
//Console.WriteLine(new String(' ', indent * 2) + n.GetType().Name + " | " + n.GetText()?.ToString() ?? "null");
fileWriter.WriteLine(new String(' ', indent * 2) + n.GetType().Name + " | " + n.GetText()?.ToString() ?? "null");
});
} }
fileWriter.Close();
return null; return null;
} }
} }
@@ -5,14 +5,11 @@ using Microsoft.CodeAnalysis.Scripting;
using System.Reflection; using System.Reflection;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using System.Linq; using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
using System.Runtime.Loader; using System.Runtime.Loader;
using static NetScript;
using Microsoft.CodeAnalysis.Emit;
using System.Reflection.PortableExecutable; using System.Reflection.PortableExecutable;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using static NetScript;
namespace Barotrauma namespace Barotrauma
{ {
@@ -113,29 +110,19 @@ namespace Barotrauma
string errStr = "NET MODS NOT LOADED | Mod cmopilation errors:"; string errStr = "NET MODS NOT LOADED | Mod cmopilation errors:";
foreach (Diagnostic diagnostic in failures) foreach (Diagnostic diagnostic in failures)
{
errStr = $"\n{diagnostic}"; errStr = $"\n{diagnostic}";
}
NetSetup.PrintMessage(errStr); NetSetup.PrintMessage(errStr);
} }
else else
{ {
mem.Seek(0, SeekOrigin.Begin); mem.Seek(0, SeekOrigin.Begin);
var reader = new PEReader(mem); var errStr = NetScriptFilter.FilterMetadata(new PEReader(mem).GetMetadataReader());
var mdReader = reader.GetMetadataReader(); if (errStr == null)
mdReader.AssemblyReferences.ToList().ForEach(a => {
{ mem.Seek(0, SeekOrigin.Begin);
var aRef = mdReader.GetAssemblyReference(a); Assembly = LoadFromStream(mem);
Console.WriteLine(aRef.GetAssemblyName() + " " + aRef.Version); }
}); else NetSetup.PrintMessage(errStr);
Console.WriteLine();
mdReader.TypeReferences.ToList().ForEach(t =>
{
var tRef = mdReader.GetTypeReference(t);
Console.WriteLine(mdReader.GetString(tRef.Namespace) + " - " + mdReader.GetString(tRef.Name));
});
mem.Seek(0, SeekOrigin.Begin);
Assembly = LoadFromStream(mem);
} }
} }
syntaxTrees.Clear(); syntaxTrees.Clear();