Hi Gary, On Mon, 2005-12-12 at 17:55 +0000, Gary Benson wrote: > Gary Benson wrote: > > Robert Lougher wrote: > > > Do you have a testcase? > > > > If you build and run the attached testcase you ought to see only one > > checkPermission() between "Calling checkRead()" and "Done". ... In > > reality, JamVM chokes on it pretty hard. I _think_ what is > > happening is that the System.out.println in checkPermission() is > > itself doing some initialisation which causes security checks, > > causing an infinite loop. > > The initialisation in question turns out to be: > > 1. Loading java.lang.StringBuffer to build the message. > 2. Loading java.io.PrintStream to print it out. > 3. Converting the message to bytes using String.getBytes(encoding). > > Any one of them will trigger a security check and hence an infinite > loop.
Aha! There is your clue. libgcj hasn't merged in the new nio charset provider setup. And indeed creating a new CharsetProvider requires a RuntimePermission("charsetProvider"). Even for creating the default provider. Which obviously should always be created, otherwise nothing works. It is safe in this case since we know the default provider doesn't do nasty things (or at least we hope so). So you need the attached patch to gnu/java/nio/charset/Provider.java. But even then you need some more workaround. There are two steps needed: - Before the SecurityManager is installer we make sure that the whole System.out pipeline gets initialized. - In the user defined TestSecurityManager we make sure that all classes that are used in the checkPermission() method are loaded before it gets installed. That is System and StringBuffer (because we use +). Modified Test.java attached. All this seems to come from having a user defined security manager loaded by a user defined class loader (the default System/Application class loader). We need to do ClassLoader.loadClass() checks in that case. But as shown in this example that leads very easily to recursive checkPermission() calls. I don't have a good idea how to make this easier. Any ideas? Cheers, Mark
import java.security.*; class Test { static class TestSecurityManager extends SecurityManager { TestSecurityManager() { // Make sure the classes needed by checkPermission() are loaded. Class c = System.class; c = StringBuffer.class; } public void checkPermission(Permission perm) { System.out.println(" checkPermission(" + perm + ")"); } } public static void main(String[] args) { try { // Make sure System is loaded // and the full System.out pipeline is initialized. System.out.println("Installing TestSecurityManager"); SecurityManager sm = new TestSecurityManager(); System.setSecurityManager(sm); System.out.println("Calling checkRead()"); sm.checkRead("/"); System.out.println("Done"); } catch (Throwable t) { t.printStackTrace(); } } }
Index: gnu/java/nio/charset/Provider.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/nio/charset/Provider.java,v retrieving revision 1.6 diff -u -r1.6 Provider.java --- gnu/java/nio/charset/Provider.java 2 Jul 2005 20:32:13 -0000 1.6 +++ gnu/java/nio/charset/Provider.java 13 Dec 2005 18:38:18 -0000 @@ -39,6 +39,8 @@ import java.nio.charset.Charset; import java.nio.charset.spi.CharsetProvider; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -232,8 +234,16 @@ public static synchronized Provider provider () { + // The default provider is safe to instantiate. if (singleton == null) - singleton = new Provider (); + singleton = (Provider) AccessController.doPrivileged + (new PrivilegedAction() + { + public Object run() + { + return new Provider(); + } + }); return singleton; } }
signature.asc
Description: This is a digitally signed message part
_______________________________________________ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath