Java sets security permission of created instances

So, I have some code that instantiates a class.

Class<?> c = Class.forName("MyClass");
Constructor<?> cons = c.getConstructor();
cons.setAccessible(true);
Object instance = cons.newInstance();

      

Now I want to put some restrictions on this instance. When I call:

instance.doSomething();

      

I want to set limits for this bit of code (instance). Thus, methods called from this isntance cannot do anything suspicious (system calls, file operations ...).

I tried to install the security manager, but that limits all the code (I still want to read / write files for the rest of my code). Can I restrict only certain objects?

+1


source to share


1 answer


TL; DR: Code


The question is basically "How to call a method on a specific instance with lower privileges than usual?" There are three requirements here:
  • The code must be authorized for each instance. The default instance has the privilege.
  • An instance can be selectively blacklisted, i.e. it may be granted lower privileges than it would normally be for the duration of the method call it receives.
  • The blacklist should cover the code executed in the recipient's name, in particular, any objects of the same type with which it interacts is itself included; otherwise, if, say, the receiver, in turn, called

    AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
        this.doSomethingElse();
        return null;
    });
    
          

    doSomethingElse()

    will come out of the sandbox.

All three are problematic:

  • The first one is not really 1 reachable because it assumes that the runtime maintains and exposes information about instances (not just classes) to thread execution stacks, which it does not 2 .
  • The second and third can only be achieved if any blacklist does not assert its own (default, class-based) privileges through AccessController.doPrivileged(...)

    which it can choose at any time at its discretion.

Is there any alternative?
Well, how far do you want to go? Change internals AccessController

/ AccessControlContext

? Or worse, the internals of the VM? Or maybe provide your own SecurityManager

that overloads the functionality of the aforementioned components from scratch in a way that suits your requirements? If the answer to all is “no,” I fear that your options are limited.

As an aside, ideally you should be able to make a binary choice when asked, "Can or cannot this particular code, ie, a class , be entrusted with specific privileges?" As that would make things extremely simple 3 . Unfortunately, you cannot; and worse, you can't seem to modify the implementation of the class so that all instances of it can be considered - with respect to a particular set of privileges - trustworthy or not, and you don't want to just mark the class and thus all of it instances as unreliable (which I suppose you need!) and live with it.

Let's move on to the proposed workaround. To overcome the disadvantages listed earlier, the original question will be rephrased as follows: "How do I call a method with the elevated privileges provided to the method receiverProtectionDomain

?" Instead, I'll answer this derivative question by suggesting, as opposed to the original, that:

  • The code must be resolved by ProtectionDomain

    its class, as is usually the case. The code is sandboxed by default.
  • Code can be selectively whitelisted as long as the method is called under a specific thread.
  • Whitelisting should extend 4 to code of the same class called by the receiver.

Revised requirements will be met with custom ClassLoader

and DomainCombiner

. The goal of the first is to assign a separate one ProtectionDomain

for each class 5 ; another is to temporarily replace the domains of individual classes in the current one AccessControlContext

for on-demand whitelisting purposes. SecurityManager

is further extended to prevent unprivileged code 4 from creating streams .


Note. I have moved the code to this gist to keep the post length below the limit.
Standard disclaimer: Confirm code with a few tablespoons of salt!

Running the example
Compile and deploy the code as suggested in the sample policy configuration file, i.e. There should be two unrelated class members (for example, sibling directories at the filesystem level) - one for the package classes com.example.trusted

and one for the com.example.untrusted.Nasty

.

Make sure you replace the policy configuration with one example and change the paths where necessary.

Finally, run (after modifying the classpath entries correctly, of course):

java -cp /path/to/classpath-entry-for-trusted-code:/path/to/classpath-entry-for-untrusted-code -Djava.system.class.loader=com.example.trusted.DiscriminatingClasspathClassLoader com.example.trusted.Main

      

The first call to the unreliable method will hopefully succeed, and the second will fail.




1Perhaps instances of a specially crafted class (having, for example, their own domain assigned by some trusted component) could themselves exercise their own privileges (which in this case fails, since you have no control over the implementation of the class instance

, it appears). However, this still does not satisfy the second and third requirements.

2Recall that the default is SecurityManager

granted Permission

when all ProtectionDomain

s-to, to which classes, rather than instances, are normally mapped are flow AccessControlContext

implicitly imply this permission.

3 Then you just need to grant policy-level permissions if you consider the class to be trustworthy or otherwise for nothing, and not worry about per-instance permissions for the security context and whatever.
4This is a hard decision: if the whitelist does not affect subsequent calls of the same type, the instance will not be able to call any privileged methods on itself. Now that this happens, on the other hand, any other instance of the same type that the original receiver of the whitelisted method interacts with becomes privileged too! Thus, you must make sure that the receiver does not call any "untrusted" instances of its kind. For the same reason, it is a bad idea to allow the receiver to create any streams.
fiveAs opposed to the default strategy used by the application ClassLoader

, which is to group all classes that are under the same pathpath within one ProtectionDomain

.
<br / "> 6The reason for the inconvenience is that the parent ProtectionDomain

that our application class is referring to ClassLoader

has CodeSource

, implied, all CodeSource

the files referencing in the loader class's pathpath. So far, so good. Now when asked to load a class, our loader tries to distinguish between the system / extension classes (which it delegates to its parent to load) and the application classes by checking if the .class file is below JAVA_HOME

. Naturally, to do this, they need read access to the filesystem subtree underJAVA_HOME

... Unfortunately, granting the appropriate privilege to our bootstrap (notoriously wide) domain implicitly grants the privilege to the domains of all other classes under the loader class element, including untrusted ones. And that will hopefully explain why isolation of the entry-level classpath between trusted and untrusted code is necessary. Workarounds of course, as always; for example, provided that the trusted code must be additionally signed to obtain any privileges; or perhaps using a more flexible URL scheme to identify the source of the code and / or change the semantics of the implication of the source code.

Further reading:

<h / "> Historical note: Originally this answer offered a nearly identical solution that abused relied on JAAS SubjectDomainCombiner

, not custom, to dynamically modify permissions." Custom " Principal

would be tied to specific domains, which would then be charged extra Permission

when scored with Policy

based on their compound identifier CodeSource

- Principal

.

+1


source







All Articles