Monobjc / monobjc

Git Repository for the Monobjc Project
http://www.monobjc.net/
17 stars 3 forks source link

Sandboxed apps don't work because GetCurrentDirectory () fails #419

Closed aarononeal closed 11 years ago

aarononeal commented 11 years ago

See this trace:

UnauthorizedAccessException: Access to the path is denied.
  at System.IO.Directory.GetCurrentDirectory () [0x0003f] in /Applications/buildAgent/work/84669f285f6a667f/mcs/class/corlib/System.IO/Directory.cs:266 
  at System.Reflection.Emit.AssemblyBuilder..ctor (System.Reflection.AssemblyName n, System.String directory, AssemblyBuilderAccess access, Boolean corlib_internal) [0x000e7] in /Applications/buildAgent/work/84669f285f6a667f/mcs/class/corlib/System.Reflection.Emit/AssemblyBuilder.cs:184 
  at System.AppDomain.DefineDynamicAssembly (System.Reflection.AssemblyName name, AssemblyBuilderAccess access, System.String dir, System.Security.Policy.Evidence evidence, System.Security.PermissionSet requiredPermissions, System.Security.PermissionSet optionalPermissions, System.Security.PermissionSet refusedPermissions, Boolean isSynchronized) [0x0001c] in /Applications/buildAgent/work/84669f285f6a667f/mcs/class/corlib/System/AppDomain.cs:529 
  at (wrapper remoting-invoke-with-check) System.AppDomain:DefineDynamicAssembly (System.Reflection.AssemblyName,System.Reflection.Emit.AssemblyBuilderAccess,string,System.Security.Policy.Evidence,System.Security.PermissionSet,System.Security.PermissionSet,System.Security.PermissionSet,bool)
  at System.AppDomain.DefineDynamicAssembly (System.Reflection.AssemblyName name, AssemblyBuilderAccess access) [0x00000] in /Applications/buildAgent/work/84669f285f6a667f/mcs/class/corlib/System/AppDomain.cs:461 
  at (wrapper remoting-invoke-with-check) System.AppDomain:DefineDynamicAssembly (System.Reflection.AssemblyName,System.Reflection.Emit.AssemblyBuilderAccess)
  at SpicyPixel.Cocoa.Generators.DynamicAssembly..ctor (System.String assemblyName, System.String moduleName) [0x00000] in <filename unknown>:0 
  at SpicyPixel.Cocoa.ObjectiveCRuntime.Initialize () [0x00000] in <filename unknown>:0 
aarononeal commented 11 years ago

Here is one possible fix which makes the dynamic assembly transient instead of persistent. I don't know if you want to use this particular env var or another mechanism to toggle whether the dynamic assembly is transient.

An alternate solution might be to use NSHomeDirectory to get the sandboxed app location and specify an absolute path, but that requires a native call.

public DynamicAssembly (String assemblyName, String moduleName)
{
    this.assemblyName = assemblyName;
    this.moduleName = moduleName;

    // Default mode is transient
    AssemblyBuilderAccess access = AssemblyBuilderAccess.Run;

    // If the environment variable is set then switch to persistent mode
    String dump = Environment.GetEnvironmentVariable ("MONOBJC_DUMP_ASSEMBLY");
    if (String.Equals (dump, "YES", StringComparison.OrdinalIgnoreCase) ||
        String.Equals (dump, "TRUE", StringComparison.OrdinalIgnoreCase)) {
        access = AssemblyBuilderAccess.RunAndSave;
    }

    // Define dynamic assembly
    AssemblyName name = new AssemblyName {Name = this.assemblyName, Version = Assembly.GetExecutingAssembly().GetName().Version};
    this.assembly = AppDomain.CurrentDomain.DefineDynamicAssembly (name, access);

    // Define dynamic module
    if (access == AssemblyBuilderAccess.Run) {
        // Transient
        this.module = this.assembly.DefineDynamicModule (this.moduleName);
    } else {
        // Persistent
        this.module = this.assembly.DefineDynamicModule (this.moduleName, this.assemblyName + ".dll");
    }
}
aarononeal commented 11 years ago

I updated this and added Pull #421.

letiemble commented 11 years ago

I don't really understand the circumstances of the failure. Do you mean that a sandboxed application always crash or it crashes only when dumping the assemblies ?

I have successfully sandboxed some applications and I never encounter a crash.

aarononeal commented 11 years ago

It always crashes, you don't need to initiate an assembly dump. Dynamic assemblies right now are configured with RunAndSave, so it saves when defining the assembly before the first type is even added.

aarononeal commented 11 years ago

To be clear, the problem isn't dumping the assembly, it's where the assembly is being saved due to the fact that it relies on GetCurrentDirectory() which fails in the sandbox.

Since normal use of the bridge doesn't require persistent dynamic assemblies, the workaround I implemented in the pull was to just make dynamic assemblies transient that are created by the bridge unless the env var is set.

letiemble commented 11 years ago

Humm, this is very strange. My understanding is that the dynamic assembly is only written to the disk if the Save method is called. When you run a non-sandboxed application, are the assemblies also dumped ?

PS: I have two applications in the MacAppStore and they do not exhibit the described behavior.

aarononeal commented 11 years ago

Here's a little more info from AssemblyBuilder.cs:

// don't call GetCurrentDirectory for Run-only builders (CAS may not like that)
if (IsSave && (directory == null || directory.Length == 0)) {
    dir = Directory.GetCurrentDirectory ();
} else {
    dir = directory;
}

It's not that it's persisting to disk, it's that it wants a directory for AssemblyDir. The call to GetCurrentDirectory() is failing in my environment.

letiemble commented 11 years ago

Allright, I get it. I will try to reproduce.

By the way, I forgot to ask: iOS or OS X ?

aarononeal commented 11 years ago

It's OS X 10.8 running on Mono 2.6 and built with Mono 3.2.1 using the mcs -sdk:2 option, although you can't build Monobjc in that way without some other patches due to some recent .NET 4 dependencies (like ManualResetEventSlim). Those specifics aside, as the Mono comment points out, even in a newer environment CAS policy could still be configured to deny GetCurrentDirectory().

aarononeal commented 11 years ago

Also worth mentioning, I was launching the dev signed, sandboxed app from the build folder and not the system Applications folder where sandboxed apps have slightly elevated privileges. If you've been running your sandboxed app from the Applications folder, try moving it elsewhere to see if this repros. I'll test myself when I can to see if the launch location makes a difference, but I have to first prepare new Monobjc and app builds without the patch and that takes some doing.

letiemble commented 11 years ago

I think it will be too time-consuming to try to reproduce. I have applied the pull request monobjc#421.