StructLayoutAttribute and type safety
-
So I have the following structure definition:
[StructLayout(LayoutKind.Explicit)] struct MyStruct { [FieldOffset(0)] public float f; [FieldOffset(0)] public int i; [FieldOffset(4)] public object o; [FieldOffset(4)] public ArrayList al; }
And the following program:static void Main(string[] args) { MyStruct s; s.i = 1; s.f = 1.0f; s.al = null; s.o = new object(); Console.WriteLine("float = {0}", s.f); Console.WriteLine("int = {0:x}", s.i); Console.WriteLine("object = {0}", s.o); Console.WriteLine("arraylist = {0}", s.al); Console.WriteLine("arraylen = {0}", s.al.Capacity); s.al.Remove(s.o); Console.ReadLine(); }
Essentially, I'm forcing an ArrayList reference to point to an object of type Object, then calling ArrayList member functions on that Object. As you might imagine, this leads to some fairly disastrous consequences in the runtime. Calling various members of the ArrayList results in an exception being thrown: s.al.Add(s.o): RemotingException ("Cannot load type") s.al.Remove(s.o): AccessViolationException s.al.BinarySearch(s.o): SEHException Obviously this program is no longer type-safe, but running the peverify utility on the generated executable gives a thumbs-up. All of this brings me to the actual question.. is this the intended behavior of the language and runtime, or is this a bug? Googling brings me to http://discuss.develop.com/archives/wa.exe?A2=ind0112c&L=dotnet&D=0&P=53651, but this was written five years ago and doesn't actually provide an answer to the question. What do you guys think about this behavior? Am I justified in seeing this as a security vulnerability (perhaps a plugin commits a privilege escalation attack) rather than a simple bug? -
So I have the following structure definition:
[StructLayout(LayoutKind.Explicit)] struct MyStruct { [FieldOffset(0)] public float f; [FieldOffset(0)] public int i; [FieldOffset(4)] public object o; [FieldOffset(4)] public ArrayList al; }
And the following program:static void Main(string[] args) { MyStruct s; s.i = 1; s.f = 1.0f; s.al = null; s.o = new object(); Console.WriteLine("float = {0}", s.f); Console.WriteLine("int = {0:x}", s.i); Console.WriteLine("object = {0}", s.o); Console.WriteLine("arraylist = {0}", s.al); Console.WriteLine("arraylen = {0}", s.al.Capacity); s.al.Remove(s.o); Console.ReadLine(); }
Essentially, I'm forcing an ArrayList reference to point to an object of type Object, then calling ArrayList member functions on that Object. As you might imagine, this leads to some fairly disastrous consequences in the runtime. Calling various members of the ArrayList results in an exception being thrown: s.al.Add(s.o): RemotingException ("Cannot load type") s.al.Remove(s.o): AccessViolationException s.al.BinarySearch(s.o): SEHException Obviously this program is no longer type-safe, but running the peverify utility on the generated executable gives a thumbs-up. All of this brings me to the actual question.. is this the intended behavior of the language and runtime, or is this a bug? Googling brings me to http://discuss.develop.com/archives/wa.exe?A2=ind0112c&L=dotnet&D=0&P=53651, but this was written five years ago and doesn't actually provide an answer to the question. What do you guys think about this behavior? Am I justified in seeing this as a security vulnerability (perhaps a plugin commits a privilege escalation attack) rather than a simple bug?I see this as possible problem. Imagine having [StructLayout(LayoutKind.Explicit)] struct MyStruct { [FieldOffset(0)] public int i; [FieldOffset(0)] public byte[] o; } now if you set: x.i = 0x4899; then you'd be able to access data from any address. I don't know if peverify can check those.
-
I see this as possible problem. Imagine having [StructLayout(LayoutKind.Explicit)] struct MyStruct { [FieldOffset(0)] public int i; [FieldOffset(0)] public byte[] o; } now if you set: x.i = 0x4899; then you'd be able to access data from any address. I don't know if peverify can check those.
The CLR will not allow object references to overlap value types using FieldOffset, but it will allow object references to overlap other object references. But I think I just answered my own question. Changing the security permission set to require assembly verification causes the runtime to throw an exception when it tries to load the MyStruct type. Could not load type 'StructLayout.MyStruct' from assembly 'StructLayout, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because objects overlapped at offset 4 and the assembly must be verifiable. So it looks like the runtime only allows you to do this only if you already had the proper security permission set to execute unsafe code to begin with, which I think should be fine. Still somewhat strange that the peverify utility says that the assembly is verifiable, though.