4

I'm writing a plug-in system that requires me to load .net DLLs into an environment. I need to know whether or not they contain any pointer usage or any other usage of the "unsafe" keyword. I have a good reflection browswer running so that I can look up all the types in the assembly, all the methods, all the external references and even all the CIL instructions in the DLL. To my knowledge however, the unsafe keyword is not kept around after it's been used to determine whether or not the DLL may be compiled.

Is there a place in the meta data where the unsafe tag persists? Are there specific CIL instructions that are unsafe? Is there another way to determine that a random DLL has unsafe code?

Of course unsafe code is not the only security concern, but it's the one I'm trying to deal with right now.

svick
  • 236,525
  • 50
  • 385
  • 514
  • 1
    unsafe is a c# feature, not a .net one – Daniel A. White Nov 09 '16 at 17:49
  • ah, that's unfortunate. Do you know if there's a way to detect the programming features that it is used in C# to indicate? – Jesse Joudrey Nov 09 '16 at 17:59
  • not that i know of. what is your end game? – Daniel A. White Nov 09 '16 at 18:00
  • 2
    Not as much a duplicate as I'd originally thought, but see [Is there a C#'s unsafe equivalent in C++/CLI?](http://stackoverflow.com/q/6792315), as it includes discussion with links to relevant documentation. In particular, probably what you actually want to know is how to detect if an assembly is _verifiable_. Note that typically, if your own assembly provides guarantees of being verifiable, it won't be able to load assemblies that don't. – Peter Duniho Nov 09 '16 at 18:24
  • 1
    Most directly useful existing question is probably [Is there an API for verifying the MSIL of a dynamic assembly at runtime?](http://stackoverflow.com/q/7290893). See also https://stackoverflow.com/questions/792735/why-does-this-code-work-without-the-unsafe-keyword and https://blogs.msdn.microsoft.com/shawnfa/2004/10/25/creating-an-appdomain-with-limited-permissions/ for useful information related to preventing execution of unsafe code. – Peter Duniho Nov 09 '16 at 18:42
  • 2
    There are specific IL instructions that result in an unverifiable module, but there are more cases like a `.locals` directive without `init`. Also there is the `System.Security.UnverifiableCodeAttribute`, but that can probably removed if someone has ill intentions. – thehennyy Nov 09 '16 at 18:51
  • @thehennyy - if you write a method in pure CIL from the start, you might not even apply the UnverifiableCodeAttribute in the first place. Also, I have yet to see that attribute applied to any of my own unsafe methods by the C# compiler. – hoodaticus Nov 09 '16 at 21:50

1 Answers1

2

I would use this heuristic to detect unsafe code: check for fixed blocks where objects are pinned to take their address.

To do this, reflect on the methods in the assembly and get their LocalVariableInfos. If any of their IsPinned properties is true, then the method is unsafe.

The only unsafe operation that will be missed by doing this is stackalloc because it does not require pinning. You can catch that by checking the method body for the presence of the Localloc opcode that is used for allocating space on the stack.

Do both of these checks and the only unsafe methods you should miss are ones that manipulate value types on the stack via pointers into the local variable. Unfortunately taking the address of local variables is a normal compiler operation used for many normal tasks, and you cannot filter that out.

Note that compilers other than C# are free to use these as part of normal compilation of safe methods, however, for C# this heuristic should work perfectly.

hoodaticus
  • 3,772
  • 1
  • 18
  • 28
  • 1
    Awesome, thanks! I am detecting both these cases now. There is a case that this method misses... public unsafe int UnsafeMethod2(int input) { int* thePointer = (int*)input; *thePointer = 42; return *thePointer; } This function must be unsafe to compile, but it doesn't require pinning (and is obviously bad). I'm thinking I'll just say that all types with "*" are forbidden, but I thought you might be interested in this case and could possibly have some other thoughts. – Jesse Joudrey Nov 10 '16 at 18:42
  • @JesseJoudrey - I think taking the address of value type arguments and local variables is something that the C# compiler will occasionally do though. I remember seeing it but not sure where. – hoodaticus Nov 10 '16 at 19:30