From 3ea4d4aa8fd24433d132fb996b2df071ea0884e1 Mon Sep 17 00:00:00 2001 From: jfrijters Date: Mon, 9 Nov 2009 06:38:30 +0000 Subject: [PATCH] Added support for adding "new-style" declarative security (i.e. .NET 2.0 compatible). --- refemit/AssemblyBuilder.cs | 8 +++++ refemit/ConstructorBuilder.cs | 5 ++++ refemit/CustomAttributeBuilder.cs | 42 ++++++++++++++++++++++++++ refemit/MethodBuilder.cs | 16 ++++++++++ refemit/ModuleBuilder.cs | 50 +++++++++++++++++++++++++++++++ refemit/TypeBuilder.cs | 15 ++++++++++ refemit/Writer/ByteBuffer.cs | 14 +++++++++ 7 files changed, 150 insertions(+) diff --git a/refemit/AssemblyBuilder.cs b/refemit/AssemblyBuilder.cs index eaf6f2d0..7db81524 100644 --- a/refemit/AssemblyBuilder.cs +++ b/refemit/AssemblyBuilder.cs @@ -52,6 +52,7 @@ namespace IKVM.Reflection.Emit private List resourceFiles = new List(); private List modules = new List(); private List customAttributes = new List(); + private List declarativeSecurity = new List(); private struct ResourceFile { @@ -128,6 +129,11 @@ namespace IKVM.Reflection.Emit } } + public void __AddDeclarativeSecurity(CustomAttributeBuilder customBuilder) + { + declarativeSecurity.Add(customBuilder); + } + public void SetEntryPoint(MethodBuilder mb) { SetEntryPoint(mb, PEFileKinds.ConsoleApplication); @@ -221,6 +227,8 @@ namespace IKVM.Reflection.Emit manifestModule.SetAssemblyCustomAttribute(cab); } + manifestModule.AddDeclarativeSecurity(0x20000001, declarativeSecurity); + foreach (ResourceFile resfile in resourceFiles) { int fileToken = AddFile(manifestModule, resfile.FileName, 1 /*ContainsNoMetaData*/); diff --git a/refemit/ConstructorBuilder.cs b/refemit/ConstructorBuilder.cs index 0e4e799d..d4175bff 100644 --- a/refemit/ConstructorBuilder.cs +++ b/refemit/ConstructorBuilder.cs @@ -56,6 +56,11 @@ namespace IKVM.Reflection.Emit methodBuilder.SetCustomAttribute(customBuilder); } + public void __AddDeclarativeSecurity(CustomAttributeBuilder customBuilder) + { + methodBuilder.__AddDeclarativeSecurity(customBuilder); + } + public void AddDeclarativeSecurity(System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet) { methodBuilder.AddDeclarativeSecurity(securityAction, permissionSet); diff --git a/refemit/CustomAttributeBuilder.cs b/refemit/CustomAttributeBuilder.cs index a37a8821..069947c6 100644 --- a/refemit/CustomAttributeBuilder.cs +++ b/refemit/CustomAttributeBuilder.cs @@ -121,6 +121,37 @@ namespace IKVM.Reflection.Emit return str.ToArray(); } + internal void WriteNamedArgForDeclSecurity(ByteBuffer bb) + { + // NumNamed + int named = 0; + if (cab.namedFields != null) + { + named += cab.namedFields.Length; + } + if (cab.namedProperties != null) + { + named += cab.namedProperties.Length; + } + WritePackedLen(named); + if (cab.namedFields != null) + { + for (int i = 0; i < cab.namedFields.Length; i++) + { + WriteNamedArg(0x53, cab.namedFields[i].FieldType, cab.namedFields[i].Name, cab.fieldValues[i]); + } + } + if (cab.namedProperties != null) + { + for (int i = 0; i < cab.namedProperties.Length; i++) + { + WriteNamedArg(0x54, cab.namedProperties[i].PropertyType, cab.namedProperties[i].Name, cab.propertyValues[i]); + } + } + str.Position = 0; + bb.Write(str); + } + private void WriteNamedArg(byte fieldOrProperty, Type type, string name, object value) { str.WriteByte(fieldOrProperty); @@ -459,6 +490,11 @@ namespace IKVM.Reflection.Emit return constructorArgs[pos]; } + internal int ConstructorArgumentCount + { + get { return constructorArgs == null ? 0 : constructorArgs.Length; } + } + internal object GetFieldValue(string name) { if (namedFields != null) @@ -473,5 +509,11 @@ namespace IKVM.Reflection.Emit } return null; } + + internal void WriteNamedArgumentsForDeclSecurity(ModuleBuilder moduleBuilder, ByteBuffer bb) + { + BlobWriter bw = new BlobWriter(moduleBuilder, this); + bw.WriteNamedArgForDeclSecurity(bb); + } } } diff --git a/refemit/MethodBuilder.cs b/refemit/MethodBuilder.cs index 8bc03c65..35828ab1 100644 --- a/refemit/MethodBuilder.cs +++ b/refemit/MethodBuilder.cs @@ -51,6 +51,7 @@ namespace IKVM.Reflection.Emit private readonly CallingConventions callingConvention; private List parameters; private GenericTypeParameterBuilder[] gtpb; + private List declarativeSecurity; internal MethodBuilder(TypeBuilder typeBuilder, string name, MethodAttributes attributes, CallingConventions callingConvention) { @@ -282,6 +283,16 @@ namespace IKVM.Reflection.Emit } } + public void __AddDeclarativeSecurity(CustomAttributeBuilder customBuilder) + { + attributes |= MethodAttributes.HasSecurity; + if (declarativeSecurity == null) + { + declarativeSecurity = new List(); + } + declarativeSecurity.Add(customBuilder); + } + public void AddDeclarativeSecurity(System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet) { this.ModuleBuilder.AddDeclaritiveSecurity(pseudoToken, securityAction, permissionSet); @@ -508,6 +519,11 @@ namespace IKVM.Reflection.Emit { rva = -1; } + + if (declarativeSecurity != null) + { + this.ModuleBuilder.AddDeclarativeSecurity(pseudoToken, declarativeSecurity); + } } internal ModuleBuilder ModuleBuilder diff --git a/refemit/ModuleBuilder.cs b/refemit/ModuleBuilder.cs index e4b13d42..a8aafd87 100644 --- a/refemit/ModuleBuilder.cs +++ b/refemit/ModuleBuilder.cs @@ -332,6 +332,56 @@ namespace IKVM.Reflection.Emit this.Tables.DeclSecurity.AddRecord(rec); } + internal void AddDeclarativeSecurity(int token, List declarativeSecurity) + { + Dictionary> ordered = new Dictionary>(); + foreach (CustomAttributeBuilder cab in declarativeSecurity) + { + int action; + // check for HostProtectionAttribute without SecurityAction + if (cab.ConstructorArgumentCount == 0) + { + action = (int)System.Security.Permissions.SecurityAction.LinkDemand; + } + else + { + action = (int)cab.GetConstructorArgument(0); + } + List list; + if (!ordered.TryGetValue(action, out list)) + { + list = new List(); + ordered.Add(action, list); + } + list.Add(cab); + } + foreach (KeyValuePair> kv in ordered) + { + TableHeap.DeclSecurityTable.Record rec = new TableHeap.DeclSecurityTable.Record(); + rec.Action = (short)kv.Key; + rec.Parent = token; + rec.PermissionSet = WriteDeclSecurityBlob(kv.Value); + this.Tables.DeclSecurity.AddRecord(rec); + } + } + + private int WriteDeclSecurityBlob(List list) + { + ByteBuffer namedArgs = new ByteBuffer(100); + ByteBuffer bb = new ByteBuffer(list.Count * 100); + bb.Write((byte)'.'); + bb.WriteCompressedInt(list.Count); + foreach (CustomAttributeBuilder cab in list) + { + bb.Write(cab.Constructor.DeclaringType.AssemblyQualifiedName); + namedArgs.Clear(); + cab.WriteNamedArgumentsForDeclSecurity(this, namedArgs); + bb.WriteCompressedInt(namedArgs.Length); + bb.Write(namedArgs); + } + return this.Blobs.Add(bb); + } + public void DefineManifestResource(string name, Stream stream, ResourceAttributes attribute) { TableHeap.ManifestResourceTable.Record rec = new TableHeap.ManifestResourceTable.Record(); diff --git a/refemit/TypeBuilder.cs b/refemit/TypeBuilder.cs index 6921d720..b71f6925 100644 --- a/refemit/TypeBuilder.cs +++ b/refemit/TypeBuilder.cs @@ -184,6 +184,7 @@ namespace IKVM.Reflection.Emit private TypeAttributes attribs; private TypeFlags typeFlags; private GenericTypeParameterBuilder[] gtpb; + private List declarativeSecurity; [Flags] private enum TypeFlags @@ -453,6 +454,16 @@ namespace IKVM.Reflection.Emit } } + public void __AddDeclarativeSecurity(CustomAttributeBuilder customBuilder) + { + attribs |= TypeAttributes.HasSecurity; + if (declarativeSecurity == null) + { + declarativeSecurity = new List(); + } + declarativeSecurity.Add(customBuilder); + } + public void AddDeclarativeSecurity(System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet) { this.ModuleBuilder.AddDeclaritiveSecurity(token, securityAction, permissionSet); @@ -515,6 +526,10 @@ namespace IKVM.Reflection.Emit } events = null; } + if (declarativeSecurity != null) + { + this.ModuleBuilder.AddDeclarativeSecurity(token, declarativeSecurity); + } return new BakedType(this); } diff --git a/refemit/Writer/ByteBuffer.cs b/refemit/Writer/ByteBuffer.cs index e5a41d62..8b6d6d37 100644 --- a/refemit/Writer/ByteBuffer.cs +++ b/refemit/Writer/ByteBuffer.cs @@ -160,6 +160,20 @@ namespace IKVM.Reflection.Emit.Writer Write(BitConverter.DoubleToInt64Bits(value)); } + internal void Write(string str) + { + if (str == null) + { + Write((byte)0xFF); + } + else + { + byte[] buf = Encoding.UTF8.GetBytes(str); + WriteCompressedInt(buf.Length); + Write(buf); + } + } + internal void WriteCompressedInt(int value) { if (value <= 0x7F)