Re: Security manager problem
Hi Mark, Thanks for your quick reply, and apologies for my egregiously slow one... Mark Wielaard wrote: > On Mon, 2005-12-12 at 17:55 +, 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. Works perfectly, thanks. > But even then you need some more workaround. [snip] > > 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? Not really. It'd be interesting to see how other JVMs handle this, but I doubt it matters much as extending SecurityManager isn't really necessary these days. Cheers (and Merry Christmas!) Gary ___ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath
Re: Security manager problem
Hi Gary, On Mon, 2005-12-12 at 17:55 +, 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 - 1.6 +++ gnu/java/nio/charset/Provider.java 13 Dec 2005 18:38:18 - @@ -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
Re: Security manager problem
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. There's an awful lot I still don't undertstand here, but I'm a step closer... MaƱana. In case anyone's interested I've attached a patched testcase and a patch for classpath which together work on JamVM. Cheers, Gary import java.security.Permission; class Test { static class TestSecurityManager extends SecurityManager { public void checkPermission(Permission perm) { System.out.println(" checkPermission(" + perm + ")"); } } public static void main(String[] args) { java.lang.StringBuffer XXX1 = new java.lang.StringBuffer(); java.io.PrintStream XXX2 = new java.io.PrintStream(null); try { SecurityManager sm = new TestSecurityManager(); System.setSecurityManager(sm); System.out.println("Calling checkRead()"); sm.checkRead("/"); System.out.println("Done"); } catch (Throwable t) { t.printStackTrace(); } } } Index: java/lang/String.java === RCS file: /cvsroot/classpath/classpath/java/lang/String.java,v retrieving revision 1.77 diff -u -r1.77 String.java --- java/lang/String.java 6 Dec 2005 18:52:25 - 1.77 +++ java/lang/String.java 12 Dec 2005 17:40:55 - @@ -680,35 +680,9 @@ */ public byte[] getBytes(String enc) throws UnsupportedEncodingException { -try - { - CharsetEncoder cse = Charset.forName(enc).newEncoder(); - cse.onMalformedInput(CodingErrorAction.REPLACE); - cse.onUnmappableCharacter(CodingErrorAction.REPLACE); - ByteBuffer bbuf = cse.encode(CharBuffer.wrap(value, offset, count)); - if(bbuf.hasArray()) - return bbuf.array(); - - // Doubt this will happen. But just in case. - byte[] bytes = new byte[bbuf.remaining()]; - bbuf.get(bytes); - return bytes; - } -catch(IllegalCharsetNameException e) - { - throw new UnsupportedEncodingException("Encoding: " + enc - + " not found."); - } -catch(UnsupportedCharsetException e) - { - throw new UnsupportedEncodingException("Encoding: " + enc - + " not found."); - } -catch(CharacterCodingException e) - { - // This shouldn't ever happen. - throw (InternalError) new InternalError().initCause(e); - } +byte[] bytes = new byte[length()]; +getBytes(0, length(), bytes, 0); +return bytes; } /** ___ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath
Re: Security manager problem
Robert Lougher wrote: > On 12/6/05, Gary Benson <[EMAIL PROTECTED]> wrote: > > ...I was just looking at an some code in an > > AccessController.doPrivileged() that was doing security checks. > > Perhaps JamVM's AccessController.doPrivileged() is not in fact > > doing anything. > > What version of JamVM are you using? I'm using cvs HEAD, with Classpath HEAD. > As far as I'm aware, JamVMs implementation of VMAccessController is > complete (it was provided by Casey Marshall, if I remember > correctly). I've made some recent changes to the native method that > obtains the stack, so it _could_ have broken in 1.4.1. > > 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". GCJ (for example) makes this of it: $ gij Test Calling checkRead() checkPermission((java.io.FilePermission / read)) Done checkPermission((java.lang.RuntimePermission exitVM )) checkPermission((java.lang.RuntimePermission exitVM )) Based on what I'm seeing in Mauve you _should_ see a load of extra stuff before the actual checkPermission you're interested in if you run the testcase with JamVM: $ jamvm Test Calling checkRead() checkPermission((java.io.FilePermission /path/to/JamVM.security read)) checkPermission((java.io.FilePermission /path/to/JamVM.security read)) checkPermission((java.io.FilePermission /path/to/classpath.security read)) checkPermission((java.io.FilePermission /path/to/classpath.security read)) checkPermission((java.io.FilePermission /path/to/classpath.security read)) checkPermission((java.util.PropertyPermission java.util.logging.manager read)) checkPermission(null) checkPermission(null) checkPermission(null) checkPermission(null) checkPermission((java.util.PropertyPermission java.util.logging.config.class read)) checkPermission((java.util.PropertyPermission java.util.logging.config.file read)) checkPermission((java.util.PropertyPermission gnu.classpath.home.url read)) checkPermission((java.io.FilePermission /path/to/logging.properties read)) checkPermission((java.io.FilePermission /path/to/logging.properties read)) checkPermission((java.util.logging.LoggingPermission control )) checkPermission((java.util.logging.LoggingPermission control )) checkPermission((java.security.SecurityPermission getProperty.package.access )) checkPermission((java.io.FilePermission / read)) 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. It's hard to say, though, not knowing JamVM or Classpath particularly well. Cheers, Gary import java.security.Permission; class Test { static class TestSecurityManager extends SecurityManager { public void checkPermission(Permission perm) { System.out.println(" checkPermission(" + perm + ")"); } } public static void main(String[] args) { try { SecurityManager sm = new TestSecurityManager(); System.setSecurityManager(sm); System.out.println("Calling checkRead()"); sm.checkRead("/"); System.out.println("Done"); } catch (Throwable t) { t.printStackTrace(); } } } ___ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath
Re: Security manager problem
Hi, On 12/6/05, Gary Benson <[EMAIL PROTECTED]> wrote: > Anthony Green wrote: > > It's been a long time since I've read anything about this kind of > > stuff, but my understanding is that you simply wrap things like this > > up in a AccessController.doPrivileged(), since the access control > > context of the bootstrap or system class loader will permit file > > I/O. > > That's interesting, as I was just looking at an some code in an > AccessController.doPrivileged() that was doing security checks. > Perhaps JamVM's AccessController.doPrivileged() is not in fact doing > anything. > What version of JamVM are you using? As far as I'm aware, JamVMs implementation of VMAccessController is complete (it was provided by Casey Marshall, if I remember correctly). I've made some recent changes to the native method that obtains the stack, so it _could_ have broken in 1.4.1. Do you have a testcase? Thanks, Rob. > Cheers, > Gary ___ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath
Re: Security manager problem
> "Anthony" == Anthony Green <[EMAIL PROTECTED]> writes: Anthony> It's been a long time since I've read anything about this Anthony> kind of stuff, but my understanding is that you simply wrap Anthony> things like this up in a AccessController.doPrivileged(), Anthony> since the access control context of the bootstrap or system Anthony> class loader will permit file I/O. Yes. Finding and solving all the instances of this problem in Classpath is, unfortunately, a good part of the required security work. If you dig around a bit you'll find other places where this treatment has already been applied. Tom ___ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath
Re: Security manager problem
> "Anthony" == Anthony Green <[EMAIL PROTECTED]> writes: Anthony> Perhaps. Implementing proper sandbox behaviour is easy to defer. I Anthony> think it will take the kind of work you are doing to drive VMs to take Anthony> care of details like this. Do we even do it properly in libgcj (being Anthony> careful to account for reflection, etc)? I would be surprised. Nope. There is a big 'XXX' in AccessController. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13604 Tom ___ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath
Re: Security manager problem
On Tue, 2005-12-06 at 17:16 +, Gary Benson wrote: > That's interesting, as I was just looking at an some code in an > AccessController.doPrivileged() that was doing security checks. > Perhaps JamVM's AccessController.doPrivileged() is not in fact doing > anything. Perhaps. Implementing proper sandbox behaviour is easy to defer. I think it will take the kind of work you are doing to drive VMs to take care of details like this. Do we even do it properly in libgcj (being careful to account for reflection, etc)? I would be surprised. AG ___ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath
Re: Security manager problem
Anthony Green wrote: > On Tue, 2005-12-06 at 16:14 +, Gary Benson wrote: > > I'm having security manager problems, with JamVM at least. > > Various initialisations happen the first time a permission is > > checked, including java.security.Security's method which > > reads the provider files $vendor.security and classpath.security. > > By this time you are most likely running under a security manager, > > so if that doesn't allow those files to be read then you get > > SecurityExceptions you weren't expecting. > > It's been a long time since I've read anything about this kind of > stuff, but my understanding is that you simply wrap things like this > up in a AccessController.doPrivileged(), since the access control > context of the bootstrap or system class loader will permit file > I/O. That's interesting, as I was just looking at an some code in an AccessController.doPrivileged() that was doing security checks. Perhaps JamVM's AccessController.doPrivileged() is not in fact doing anything. Cheers, Gary ___ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath
Re: Security manager problem
On Tue, 2005-12-06 at 16:14 +, Gary Benson wrote: > I'm having security manager problems, with JamVM at least. Various > initialisations happen the first time a permission is checked, > including java.security.Security's method which reads the > provider files $vendor.security and classpath.security. By this time > you are most likely running under a security manager, so if that > doesn't allow those files to be read then you get SecurityExceptions > you weren't expecting. It's been a long time since I've read anything about this kind of stuff, but my understanding is that you simply wrap things like this up in a AccessController.doPrivileged(), since the access control context of the bootstrap or system class loader will permit file I/O. AG ___ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath
Security manager problem
Hi all, I'm having security manager problems, with JamVM at least. Various initialisations happen the first time a permission is checked, including java.security.Security's method which reads the provider files $vendor.security and classpath.security. By this time you are most likely running under a security manager, so if that doesn't allow those files to be read then you get SecurityExceptions you weren't expecting. It's not the only thing: if java.util.logging wasn't initialized then that's when it'll initialise. That reads a bunch of system properties, which again will cause SecurityExceptions you weren't expecting if your security manager doesn't allow you to read system properties. I have a workaround in my local mauve, but it's not a proper fix. Trouble is, I can't quite see what a proper fix would be or where it would go. Any ideas? Cheers, Gary ___ Classpath mailing list Classpath@gnu.org http://lists.gnu.org/mailman/listinfo/classpath