6

I have a program and a simple plugin architecture where the plugins implement a generic interface and the main program loads all plugins that implement this interface. It's the most common custom plugin architecture I have found so far, so that's what I'm using.

I am not using Microsoft's MEF and I have my reasons for not doing so. I'll leave it at that.

The issue is that when the plugins are loaded, no matter how 'blind' they are to the main program and it's forms/classes/etc. it can still access System.Windows.Forms.Application and can therefore gain access to my application and its currently running forms/methods/controls/etc.

I do not want this. Is there an way to restrict a plugin's access to the main Application?

EDIT: More info about the plugin

We (my boss and I) are currently discussing what the plugins need to do. They all obviously need to add functionality, but we originally decided to give each plugin access to the currently running form so that it can add controls and events directly to the form. This was based on the assumption that only we, the developers, would be writing them.

Now we are considering the possibility of third party plugins and the original design, obviously, has about as much security as a "Do Not Enter" sign on an open door with no one around.

Or a "Take One" sign hanging on a bowl of individual skittles on Halloween.

Mike Webb
  • 8,855
  • 18
  • 78
  • 111

4 Answers4

4

If you can run your plugins in their own AppDomains, that would certainly increase the level of isolation. It can also make it a pain to communicate with them though. Without knowing more about what the plugins are meant to do, it's hard to know whether or not that's appropriate.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
4

One way of doing this is to host your plugins in their own AppDomains. You can configure these AppDomains to have limited security to prevent them from accessing resources in the main AppDomain. This does complicate things a lot, but will give you the sand-boxing you're after.

An additional benefit you receive from AppDomain hosting is that you can load and unload these domains if you wish to refresh plugins, plus you can protect your main AppDomain from crashes in your "child" domains.

Update

After seeing your update re. the capabilities of your plugin, AppDomains are not going to help if your plugin must have direct access to UI elements e.g. access to a form to add controls. You will not be able to give direct access to a form over an AppDomain boundary, or produce controls in one AppDomain and then marshal them across to another.

You could still consider hosting plugins in another AppDomain, but you will need to think about some sort of proxy mechanism so that actions like adding a control to a form can be done on behalf of a plugin, rather than letting the plugin access the form directly. For instance, you could pass in a form builder object which had methods such as AddButton. The proxy could then perform these actions of behalf of the plugin in the main domain. In this way you could provide a limited API for the plugin complete with required events.

This approach is by no means trivial, but once you have mastered the basics it's not too complicated.

Update 2

Things have moved on since rolling your own plugin frameworks with AppDomins back in the day. There is now support baked into the .Net framework since 3.5 for plugins:

MAF - Managed Addin Framework / System.Addin

It supports AppDomain isolation modes for plugins and has plugin loaders, etc. No need to roll your own.

Tim Lloyd
  • 37,954
  • 10
  • 100
  • 130
  • Is there an example website or anything explaining how to set this limited security? Is there one for how to communicate between them? – Mike Webb Jan 27 '11 at 18:22
  • @Mike I have just been on the hunt for good examples of roll-your-own plugin architectures with AppDomains. It has been a long time since I used this to write a plugin framework, and a lot of the samples I found were problematic. It's really quite tricky to get right so I didn't want to burden you with examples which would have you tearing your hair out. Then I remembered, MS actually baked a plugin framework into .Net 3.5 - MAF: Managed Addin Framework. This framework deals with a lot of the dirt out-of-the-box so you don't have to e.g. AppDomain isolation and plugin loading\unloading. – Tim Lloyd Jan 27 '11 at 19:15
  • @Mike Because it's an MS framework there is tonnes of documentation and on-line content, a much better bet. A good start is here: http://msdn.microsoft.com/en-us/magazine/cc163476.aspx. – Tim Lloyd Jan 27 '11 at 19:16
  • For now I am constrained to using .NET 2.0, but I actually found something. With some custom code based on the concepts used in these articles I think I can write a plugin architecture using sudo-message passing. Part 2 lays out the code for using AppDomains. Here is the website: http://www.15seconds.com/issue/040624.htm – Mike Webb Jan 27 '11 at 19:41
  • @Mike OK .Net 2.0 - System.Addin is out. Ok Re. AppDomains, this article has plenty to get you going although there are some comments about Assemblies being loaded into the default domain - still some very good basics: http://www.codeproject.com/KB/cs/dynamicpluginmanager.aspx – Tim Lloyd Jan 27 '11 at 19:43
1

So to restate your primary concern:

... and can therefore gain access to my application and its currently running forms/methods/controls/etc.

Before embarking on a complex and difficult means of loading, isolating, and restricting these extensions you should know a few things about Windows and the CLR. First, any program running on the box can use a number of Windows APIs to inject code into your process. Once code is loaded into your process, either by you or by the OS, accessing the CLR runtime and loading assemblies and/or running code in your existing AppDomain is fairly easy.

Knowing this you should weigh and balance the effort you excerpt to restrict 'extensions'. If I where building something like this I would be more concerned about other things than a malicious piece of extension code manipulating the state of my application. For example these are things you might consider:

  1. Only load extensions that are approved by your user, allow them to control what is allowed and allow them to revoke an extension later if desired. Look at Office or VStudio as an example.
  2. Ensure these approved extensions are untampered by using a code signing requirement (strong names, or code signing certificates).
  3. Consider having the ability to revoke an extension's ability to run remotely if it's found to be malicious.
  4. Prove a well-appointed Interface API to allow developers to easily implement desired behavior. If it's easy for them to use your interfaces to accomplish their task they won't need to 'hack'.

Beyond this there really isn't much else you can do. As I said, anyone can attack your application even with the above safe-guards. Your primary concern should be to not surprise your users. Thus the due-care in what code YOUR application runs is advisable, but what those extensions do once your users grant them access is not really something you can completely control.

This isn't to say that an AppDomain isolation won't provide you value, it may; however, IMHO getting the security restricted enough without limiting their ability to function will prove to be difficult.

UPDATE

... but if you load a plugin into an AppDomain which is configured with limited permissions how can it use this vector?

Correct, as I said in my closing statements, you can limit their access to unmanaged code within the AppDomain. This also limits their ability to develop a usable Windows experience. I expect that most WinForms applications use at least one PInvoke call or unmanaged COM control. This limitation imposed may be acceptable, I really can't say without more information about what functionality they are trying to provide.

All I was trying to say is that by installing and approving the extension your users are accepting the responsibility of allowing that extension to run. What that extension does and how malicious it may attempt to be is not your responsibility, assuming of course that you loaded the correct code. This is why I recommend focusing your energy on running approved code rather than worrying about what that code might do once it's in your process.

csharptest.net
  • 62,602
  • 11
  • 71
  • 89
  • I see the point about another process using Win32 calls and code injection, but if you load a plugin into an AppDomain which is configured with limited permissions (e.g. no UnmanagedCode permission) how can it use this vector? – Tim Lloyd Jan 26 '11 at 21:27
  • Due the nature of SO notifications, a callout to my @username would be appreciated otherwise I am not notified of your response. I made my comment as the tone of your answer might lead people to think that using AppDomains was a hopeless cause re. code injection. – Tim Lloyd Jan 27 '11 at 02:19
0

The best way to handle this is expose a documented plugin API. If your plugins run with full trust, then even if you run the plugin in its own AppDomain it can inject itself back into the application - then all it takes is someone to make a wrapper available and all the plugins are back to the same state they started in. If your API allows plugins to provide the desired features in a straightforward, consistent and documented manner, then that's what plugin developers will use.

The following are external UI hooks for WPF, Windows Forms, and the classic Spy++ (all with source).

Sam Harwell
  • 97,721
  • 20
  • 209
  • 280