* Implements AppDomain Security for MRM Scripts.

* Added permissionLevel attribute to [MRM] section in OpenSim.ini. Default is 'Internet', however may be any of the following (case sensitive), FullTrust, SkipVerification, Execution, Nothing, LocalIntranet, Internet, Everything. For previous functionality, set to FullTrust or Execution.
arthursv
Adam Frisby 2009-08-17 02:25:00 +10:00
parent cbd454d692
commit fa921ec147
1 changed files with 101 additions and 2 deletions

View File

@ -27,9 +27,14 @@
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Text;
using log4net;
using Microsoft.CSharp;
@ -54,6 +59,9 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule
private readonly MicroScheduler m_microthreads = new MicroScheduler();
private IConfig m_config;
public void RegisterExtension<T>(T instance)
{
m_extensions[typeof (T)] = instance;
@ -63,6 +71,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule
{
if (source.Configs["MRM"] != null)
{
m_config = source.Configs["MRM"];
if (source.Configs["MRM"].GetBoolean("Enabled", false))
{
m_log.Info("[MRM] Enabling MRM Module");
@ -112,6 +122,91 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule
return script;
}
/// <summary>
/// Create an AppDomain that contains policy restricting code to execute
/// with only the permissions granted by a named permission set
/// </summary>
/// <param name="permissionSetName">name of the permission set to restrict to</param>
/// <param name="appDomainName">'friendly' name of the appdomain to be created</param>
/// <exception cref="ArgumentNullException">
/// if <paramref name="permissionSetName"/> is null
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// if <paramref name="permissionSetName"/> is empty
/// </exception>
/// <returns>AppDomain with a restricted security policy</returns>
/// <remarks>Substantial portions of this function from: http://blogs.msdn.com/shawnfa/archive/2004/10/25/247379.aspx
/// Valid permissionSetName values are:
/// * FullTrust
/// * SkipVerification
/// * Execution
/// * Nothing
/// * LocalIntranet
/// * Internet
/// * Everything
/// </remarks>
public static AppDomain CreateRestrictedDomain(string permissionSetName, string appDomainName)
{
if (permissionSetName == null)
throw new ArgumentNullException("permissionSetName");
if (permissionSetName.Length == 0)
throw new ArgumentOutOfRangeException("permissionSetName", permissionSetName,
"Cannot have an empty permission set name");
// Default to all code getting nothing
PolicyStatement emptyPolicy = new PolicyStatement(new PermissionSet(PermissionState.None));
UnionCodeGroup policyRoot = new UnionCodeGroup(new AllMembershipCondition(), emptyPolicy);
bool foundName = false;
PermissionSet setIntersection = new PermissionSet(PermissionState.Unrestricted);
// iterate over each policy level
IEnumerator levelEnumerator = SecurityManager.PolicyHierarchy();
while (levelEnumerator.MoveNext())
{
PolicyLevel level = levelEnumerator.Current as PolicyLevel;
// if this level has defined a named permission set with the
// given name, then intersect it with what we've retrieved
// from all the previous levels
if (level != null)
{
PermissionSet levelSet = level.GetNamedPermissionSet(permissionSetName);
if (levelSet != null)
{
foundName = true;
if (setIntersection != null)
setIntersection = setIntersection.Intersect(levelSet);
}
}
}
// Intersect() can return null for an empty set, so convert that
// to an empty set object. Also return an empty set if we didn't find
// the named permission set we were looking for
if (setIntersection == null || !foundName)
setIntersection = new PermissionSet(PermissionState.None);
else
setIntersection = new NamedPermissionSet(permissionSetName, setIntersection);
// if no named permission sets were found, return an empty set,
// otherwise return the set that was found
PolicyStatement permissions = new PolicyStatement(setIntersection);
policyRoot.AddChild(new UnionCodeGroup(new AllMembershipCondition(), permissions));
// create an AppDomain policy level for the policy tree
PolicyLevel appDomainLevel = PolicyLevel.CreateAppDomainLevel();
appDomainLevel.RootCodeGroup = policyRoot;
// create an AppDomain where this policy will be in effect
string domainName = appDomainName;
AppDomain restrictedDomain = AppDomain.CreateDomain(domainName);
restrictedDomain.SetAppDomainPolicy(appDomainLevel);
return restrictedDomain;
}
void EventManager_OnRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource)
{
if (script.StartsWith("//MRM:C#"))
@ -125,9 +220,13 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule
try
{
m_log.Info("[MRM] Found C# MRM");
m_log.Info("[MRM] Found C# MRM - Starting in AppDomain with " + m_config.GetString("permissionLevel", "Internet") + "-level security.");
MRMBase mmb = (MRMBase)AppDomain.CurrentDomain.CreateInstanceFromAndUnwrap(
string domainName = UUID.Random().ToString();
AppDomain target = CreateRestrictedDomain(m_config.GetString("permissionLevel", "Internet"),
domainName);
MRMBase mmb = (MRMBase) target.CreateInstanceFromAndUnwrap(
CompileFromDotNetText(script, itemID.ToString()),
"OpenSim.MiniModule");