private IEnumerable <ValidationResult> ValidateAgainstWhitelist(Whitelist whitelist, MethodDefinition method, TypeReference type, string member = null) { // Allow own defined types if (type is TypeDefinition) { yield break; } // Filter in the whitelist whether there is any rule var result = Search(whitelist, type, member); // Return a validation result if search result is negative (any of the denied results) switch (result) { case WhitelistSearchResult.DeniedNamespace: var ns = string.IsNullOrWhiteSpace(type.Namespace) ? @"""" : type.Namespace; yield return(new WhitelistValidationResult($"{ns} is not allowed.") .WithInfo(method.Name, type.Namespace, type.Name, member)); break; case WhitelistSearchResult.DeniedType: yield return(new WhitelistValidationResult($"{type.Name} in {type.Namespace} is not allowed.") .WithInfo(method.Name, type.Namespace, type.Name, member)); break; case WhitelistSearchResult.DeniedMember: yield return(new WhitelistValidationResult($"{member} in {type.FullName} is not allowed.") .WithInfo(method.Name, type.Namespace, type.Name, member)); break; } }
private IEnumerable <ValidationResult> Validate(Whitelist whitelist, MethodDefinition method, Instruction instruction) { if (!(instruction.Operand is MemberReference reference)) { return(Enumerable.Empty <ValidationResult>()); } if (reference is MethodReference methodReference) { var results = new List <ValidationResult>(); results.AddRange(ValidateReference(whitelist, method, methodReference.DeclaringType, methodReference.Name)); results.AddRange(ValidateReference(whitelist, method, methodReference.ReturnType)); return(results); } if (reference is FieldReference fieldReference) { var results = new List <ValidationResult>(); results.AddRange( ValidateReference(whitelist, method, fieldReference.DeclaringType, fieldReference.Name)); results.AddRange(ValidateReference(whitelist, method, fieldReference.FieldType)); return(results); } if (reference is TypeReference typeReference) { return(ValidateReference(whitelist, method, typeReference)); } return(Enumerable.Empty <ValidationResult>()); }
private void WhitelistAElfTypes(Whitelist whitelist) { whitelist // Selectively allowed types and members .Namespace("AElf.Cryptography.SecretSharing", Permission.Denied, type => type .Type(typeof(SecretSharingHelper), Permission.Denied, member => member .Member(nameof(SecretSharingHelper.DecodeSecret), Permission.Allowed))); }
private WhitelistSearchResult Search(Whitelist whitelist, TypeReference type, string member = null) { var typeNs = GetNameSpace(type); // Fail if there is no rule for the namespace if (!whitelist.TryGetNamespaceRule(typeNs, out var namespaceRule)) { // If no exact match for namespace, check for wildcard matching if (whitelist.ContainsWildcardMatchedNamespaceRule(typeNs)) { return(WhitelistSearchResult.Allowed); } return(WhitelistSearchResult.DeniedNamespace); } // Fail if the type is not allowed in the namespace if (!namespaceRule.Types.TryGetValue(type.Name, out var typeRule) || typeRule.Permission == Permission.Denied && !typeRule.Members.Any()) { return(namespaceRule.Permission == Permission.Allowed ? WhitelistSearchResult.Allowed : WhitelistSearchResult.DeniedType); } if (typeRule.Permission == Permission.Denied && !typeRule.Members.Any()) { return(WhitelistSearchResult.DeniedType); } if (member == null) { return(WhitelistSearchResult.Allowed); } if (!typeRule.Members.TryGetValue(member, out var memberRule)) { if (!member.StartsWith("get_") && !member.StartsWith("set_")) { return(typeRule.Permission == Permission.Allowed ? WhitelistSearchResult.Allowed : WhitelistSearchResult.DeniedMember); } // Check without the prefix as well member = member.Split(new[] { '_' }, 2)[1]; if (!typeRule.Members.TryGetValue(member, out memberRule)) { return(typeRule.Permission == Permission.Allowed ? WhitelistSearchResult.Allowed : WhitelistSearchResult.DeniedMember); } } return(memberRule.Permission == Permission.Allowed ? WhitelistSearchResult.Allowed : WhitelistSearchResult.DeniedMember); }
public Whitelist GetWhitelist() { if (_whitelist != null) { return(_whitelist); } _whitelist = CreateWhitelist(); return(_whitelist); }
private void WhitelistLinqAndCollections(Whitelist whitelist) { whitelist .Namespace("System.Linq", Permission.Allowed) .Namespace("System.Collections", Permission.Allowed) .Namespace("System.Collections.Generic", Permission.Allowed) .Namespace("System.Collections.ObjectModel", Permission.Allowed) ; }
private Whitelist CreateWhitelist() { var whitelist = new Whitelist(); WhitelistAssemblies(whitelist); WhitelistSystemTypes(whitelist); WhitelistReflectionTypes(whitelist); WhitelistLinqAndCollections(whitelist); WhitelistOthers(whitelist); return(whitelist); }
private void WhitelistReflectionTypes(Whitelist whitelist) { whitelist // Used by protobuf generated code .Namespace("System.Reflection", Permission.Denied, type => type .Type(nameof(AssemblyCompanyAttribute), Permission.Allowed) .Type(nameof(AssemblyConfigurationAttribute), Permission.Allowed) .Type(nameof(AssemblyFileVersionAttribute), Permission.Allowed) .Type(nameof(AssemblyInformationalVersionAttribute), Permission.Allowed) .Type(nameof(AssemblyProductAttribute), Permission.Allowed) .Type(nameof(AssemblyTitleAttribute), Permission.Allowed)) ; }
private IEnumerable <ValidationResult> ValidateReference(Whitelist whitelist, MethodDefinition method, TypeReference type, string member = null) { var results = new List <ValidationResult>(); // If the type is a generic parameter, stop going deeper if (type.IsGenericParameter) { return(results); } // If referred type is from a fully trusted assembly, stop going deeper if (whitelist.CheckAssemblyFullyTrusted(type.Resolve()?.Module.Assembly.Name)) { return(results); } // Dig deeper by calling ValidateReference until reaching base type if (type.IsByReference) { results.AddRange(ValidateReference(whitelist, method, type.GetElementType())); return(results); } if (type is GenericInstanceType generic) { results.AddRange(ValidateReference(whitelist, method, generic.ElementType)); foreach (var argument in generic.GenericArguments) { results.AddRange(ValidateReference(whitelist, method, argument)); } return(results); } // If the type is an array, then validate the element type of the array if (type.IsArray) { results.AddRange(ValidateReference(whitelist, method, type.GetElementType())); return(results); } // Reached the most base type, now we can validate against the whitelist results.AddRange(ValidateAgainstWhitelist(whitelist, method, type, member)); return(results); }
private void WhitelistSystemTypes(Whitelist whitelist) { whitelist // Selectively allowed types and members .Namespace("System", Permission.Denied, type => type .Type(typeof(Array), Permission.Denied, member => member .Member(nameof(Array.AsReadOnly), Permission.Allowed)) .Type("Func`1", Permission.Allowed) // Required for protobuf generated code .Type("Func`2", Permission.Allowed) // Required for protobuf generated code .Type("Func`3", Permission.Allowed) // Required for protobuf generated code .Type("Nullable`1", Permission.Allowed) // Required for protobuf generated code .Type(typeof(BitConverter), Permission.Denied, member => member .Member(nameof(BitConverter.GetBytes), Permission.Allowed)) .Type(typeof(Uri), Permission.Denied, member => member .Member(nameof(Uri.TryCreate), Permission.Allowed) .Member(nameof(Uri.Scheme), Permission.Allowed) .Member(nameof(Uri.UriSchemeHttp), Permission.Allowed) .Member(nameof(Uri.UriSchemeHttps), Permission.Allowed)) .Type(typeof(NotImplementedException), Permission.Allowed) // Required for protobuf generated code .Type(typeof(NotSupportedException), Permission.Allowed) // Required for protobuf generated code .Type(typeof(ArgumentOutOfRangeException), Permission.Allowed) // From AEDPoS .Type(nameof(DateTime), Permission.Allowed, member => member .Member(nameof(DateTime.Now), Permission.Denied) .Member(nameof(DateTime.UtcNow), Permission.Denied) .Member(nameof(DateTime.Today), Permission.Denied)) .Type(typeof(void).Name, Permission.Allowed) .Type(nameof(Object), Permission.Allowed) .Type(nameof(Type), Permission.Allowed) .Type(nameof(IDisposable), Permission.Allowed) .Type(nameof(Convert), Permission.Allowed) .Type(nameof(Math), Permission.Allowed) // Primitive types .Type(nameof(Boolean), Permission.Allowed) .Type(nameof(Byte), Permission.Allowed) .Type(nameof(SByte), Permission.Allowed) .Type(nameof(Char), Permission.Allowed) .Type(nameof(Int32), Permission.Allowed) .Type(nameof(UInt32), Permission.Allowed) .Type(nameof(Int64), Permission.Allowed) .Type(nameof(UInt64), Permission.Allowed) .Type(nameof(Decimal), Permission.Allowed) .Type(nameof(String), Permission.Allowed, member => member .Constructor(Permission.Denied)) .Type(typeof(Byte[]).Name, Permission.Allowed) ); }
private void WhitelistAssemblies(Whitelist whitelist) { whitelist .Assembly(System.Reflection.Assembly.Load("netstandard"), Trust.Partial) .Assembly(System.Reflection.Assembly.Load("System.Runtime"), Trust.Partial) .Assembly(System.Reflection.Assembly.Load("System.Runtime.Extensions"), Trust.Partial) .Assembly(System.Reflection.Assembly.Load("System.Private.CoreLib"), Trust.Partial) .Assembly(System.Reflection.Assembly.Load("System.ObjectModel"), Trust.Partial) .Assembly(System.Reflection.Assembly.Load("System.Linq"), Trust.Full) .Assembly(System.Reflection.Assembly.Load("System.Collections"), Trust.Full) .Assembly(System.Reflection.Assembly.Load("Google.Protobuf"), Trust.Full) .Assembly(typeof(CSharpSmartContract).Assembly, Trust.Full) // AElf.Sdk.CSharp .Assembly(typeof(Address).Assembly, Trust.Full) // AElf.Types .Assembly(typeof(IMethod).Assembly, Trust.Full) // AElf.CSharp.Core .Assembly(typeof(SecretSharingHelper).Assembly, Trust.Partial) // AElf.Cryptography .Assembly(typeof(ISmartContractBridgeContext).Assembly, Trust.Full) // AElf.Kernel.SmartContract.Shared ; }
private void WhitelistOthers(Whitelist whitelist) { whitelist // Used for converting numbers to strings .Namespace("System.Globalization", Permission.Denied, type => type .Type(nameof(CultureInfo), Permission.Denied, m => m .Member(nameof(CultureInfo.InvariantCulture), Permission.Allowed))) // Used for initializing large arrays hardcoded in the code, array validator will take care of the size .Namespace("System.Runtime.CompilerServices", Permission.Denied, type => type .Type(nameof(RuntimeHelpers), Permission.Denied, member => member .Member(nameof(RuntimeHelpers.InitializeArray), Permission.Allowed))) .Namespace("System.Text", Permission.Denied, type => type .Type(nameof(Encoding), Permission.Denied, member => member .Member(nameof(Encoding.UTF8), Permission.Allowed) .Member(nameof(Encoding.UTF8.GetByteCount), Permission.Allowed))) ; }
private IEnumerable <ValidationResult> Validate(Whitelist whitelist, TypeDefinition type, CancellationToken ct) { var results = new List <ValidationResult>(); foreach (var method in type.Methods) { if (ct.IsCancellationRequested) { throw new ContractAuditTimeoutException(); } if (!method.HasBody) { continue; } foreach (var instruction in method.Body.Instructions) { results.AddRange(Validate(whitelist, method, instruction)); } } return(results); }