diff options
author | Sven Gothel <[email protected]> | 2013-06-11 16:25:48 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-06-11 16:25:48 +0200 |
commit | 1a01dce6c42b398cdd68d405828774a3ab366456 (patch) | |
tree | dcbc917b0dbd80c7c5be0b4a9ad35c5489ee64dc /src/junit | |
parent | 377d9de1ff1e2fabcd9bb7f65c0318f3c890392c (diff) |
Bug 752: Review Code Vulnerabilities (Permission Checks of new exposed code and privileged access)
This review focuses on how we perform permission checks,
or better - do we circumvent some assuming full privileges ?
Some native methods do need extra permission validation, i.e. loading native libraries.
Further more AccessController.doPrivileged(..) shall not cover generic code
exposing a critical feature to the user.
Further more .. we should rely on the SecuritManager, i.e. AccessControlContext's
'checkPermission(Permission)' code to comply w/ fine grained permission access.
It is also possible to have full permission w/o having any certificates (-> policy file).
+++
We remove implicit AccessController.doPrivileged(..) from within our trusted code
for generic methods, like Property access, temp. files.
+++
SecurityUtil:
- Remove 'getCommonAccessControlContext(Class<?> clz)',
which returned a local AccessControlContext for later restriction
if the passed class contains all certificates as the 'trusted' GlueGen class has.
- Simply expose convenient permission check methods relying on
SecurityManager / AccessControlContext.
PropertyAccess:
- 'protected static void addTrustedPrefix(..)' requires AllPermissions if SecurityManager is installed.
- Remove implicit doPrivileged(..) triggered by passed AccessControlContext instance,
only leave it for trusted prefixes.
IOUtil:
- Remove all doPrivileged(..) - Elevation shall be performed by caller.
DynamicLinker:
- 'public long openLibraryLocal(..)' and 'public long openLibraryGlobal(..)'
may throw SecurityException, if a SecurityManager is installed and the dyn. link permission
is not granted in the calling code.
Implemented in their respective Unix, OSX and Windows manifestation.
Caller has to elevate privileges via 'doPrivileged(..) {}' !
+++
Tests:
- Property access
- File access
- Native library loading
Manual Applet test (unsigned, but w/ SecurityManager and policy file):
> gluegen/test/applet
Applet has been tested w/ signed JAR w/ Firefox and Java7 on GNU/Linux as well.
Manual Application test (unsigned, but w/ SecurityManager and policy file):
com.jogamp.junit.sec.TestSecIOUtil01
- Run w/ SecurityManager and policy file:
- gluegen/scripts/runtest-secmgr.sh
- Run w/o SecurityManager:
- gluegen/scripts/runtest.sh
Diffstat (limited to 'src/junit')
-rw-r--r-- | src/junit/com/jogamp/junit/sec/Applet01.java | 254 | ||||
-rw-r--r-- | src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java | 209 |
2 files changed, 463 insertions, 0 deletions
diff --git a/src/junit/com/jogamp/junit/sec/Applet01.java b/src/junit/com/jogamp/junit/sec/Applet01.java new file mode 100644 index 0000000..12e8f48 --- /dev/null +++ b/src/junit/com/jogamp/junit/sec/Applet01.java @@ -0,0 +1,254 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.junit.sec; + +import java.applet.Applet; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.security.AccessControlException; + +import com.jogamp.common.os.MachineDescription; +import com.jogamp.common.os.NativeLibrary; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.IOUtil; +import com.jogamp.common.util.JarUtil; + +/** + * Applet: Provoke AccessControlException while writing to file! + */ +@SuppressWarnings("serial") +public class Applet01 extends Applet { + static final String java_io_tmpdir_propkey = "java.io.tmpdir"; + static final String java_home_propkey = "java.home"; + static final String os_name_propkey = "os.name"; + + static final String tfilename = "test.bin" ; + static final MachineDescription machine = Platform.getMachineDescription(); + static final int tsz = machine.pageSizeInBytes(); + + static final boolean usesSecurityManager; + + static { + if( null == System.getSecurityManager() ) { + usesSecurityManager = false; + System.err.println("No SecurityManager Installed"); + } else { + usesSecurityManager = true; + System.err.println("SecurityManager Already Installed"); + } + } + + static void testPropImpl(String propKey, boolean isSecure) { + isSecure |= !usesSecurityManager; + + Exception se0 = null; + try { + String p0 = System.getProperty(propKey); + System.err.println(propKey+": "+p0); + } catch (AccessControlException e) { + se0 = e; + if( !isSecure ) { + System.err.println("Expected exception for insecure property <"+propKey+">"); + System.err.println("Message: "+se0.getMessage()); + } else { + System.err.println("Unexpected exception for secure property <"+propKey+">"); + se0.printStackTrace(); + } + } + if( isSecure ) { + if( null != se0 ) { + throw new Error("AccessControlException thrown on secure property <"+propKey+">", se0); + } + } else { + if( null == se0 ) { + throw new Error("AccessControlException not thrown on secure property <"+propKey+">"); + } + } + } + + static void testTempDirImpl(boolean isSecure) { + isSecure |= !usesSecurityManager; + + Exception se0 = null; + try { + File tmp = IOUtil.getTempDir(true); + System.err.println("Temp: "+tmp); + } catch (AccessControlException e) { + se0 = e; + if( !isSecure ) { + System.err.println("Expected exception for insecure temp dir"); + System.err.println("Message: "+se0.getMessage()); + } else { + System.err.println("Unexpected exception for secure temp dir"); + se0.printStackTrace(); + } + } + if( isSecure ) { + if( null != se0 ) { + throw new Error("AccessControlException thrown on secure temp dir", se0); + } + } else { + if( null == se0 ) { + throw new Error("AccessControlException not thrown on secure temp dir"); + } + } + } + + private void testWriteFile() { + AccessControlException sec01 = null; + try { + File tmp = IOUtil.getTempDir(true); + System.err.println("Temp: "+tmp); + byte[] orig = new byte[tsz]; + final File tfile = new File(tmp, tfilename); + final OutputStream tout = new BufferedOutputStream(new FileOutputStream(tfile)); + for(int i=0; i<tsz; i++) { + final byte b = (byte) (i%256); + orig[i] = b; + tout.write(b); + } + tout.close(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } catch (AccessControlException ace) { + // GOOD! + sec01 = ace; + System.err.println("Expected:"+ace.getMessage()); + } + if( !usesSecurityManager ) { + if( null != sec01 ) { + throw new Error("SecurityException thrown on writing to temp", sec01); + } + } else { + if( null == sec01 ) { + throw new Error("SecurityException not thrown on writing to temp"); + } + } + } + + private void testOpenLibrary(boolean global) { + final ClassLoader cl = getClass().getClassLoader(); + System.err.println("CL "+cl); + + String libBaseName = null; + final Class<?> clazz = this.getClass(); + URL libURL = clazz.getResource("/libtest1.so"); + if( null != libURL ) { + libBaseName = "libtest1.so"; + } else { + libURL = clazz.getResource("/test1.dll"); + if( null != libURL ) { + libBaseName = "test1.dll"; + } + } + System.err.println("Untrusted Library (URL): "+libURL); + + String libDir1 = null; + if( null != libURL ) { + try { + libDir1 = JarUtil.getJarSubURI(libURL.toURI()).getPath(); + } catch (Exception e) { + e.printStackTrace(); + } + if( null != libDir1 ) { + System.err.println("libDir1.1: "+libDir1); + try { + libDir1= IOUtil.getParentOf(libDir1); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + System.err.println("libDir1.2: "+libDir1); + } + } + System.err.println("Untrusted Library Dir1 (abs): "+libDir1); + final String absLib = libDir1 + "natives/" + libBaseName; + Exception sec01 = null; + try { + NativeLibrary nlib = NativeLibrary.open(absLib, cl); + System.err.println("NativeLibrary: "+nlib); + } catch (SecurityException e) { + sec01 = e; + if( usesSecurityManager ) { + System.err.println("Expected exception for loading native library"); + System.err.println("Message: "+sec01.getMessage()); + } else { + System.err.println("Unexpected exception for loading native library"); + sec01.printStackTrace(); + } + } + if( !usesSecurityManager ) { + if( null != sec01 ) { + throw new Error("SecurityException thrown on loading native library", sec01); + } + } else { + if( null == sec01 ) { + throw new Error("SecurityException not thrown on loading native library"); + } + } + } + + public void init() { + + } + + public void start() { + Platform.initSingleton(); + + { + testPropImpl(os_name_propkey, true); + } + System.err.println("p0: OK"); + { + testPropImpl(java_home_propkey, false); + } + System.err.println("p1: OK"); + { + testPropImpl(java_io_tmpdir_propkey, false); + } + System.err.println("p2: OK"); + { + testTempDirImpl(false); + } + System.err.println("temp0: OK"); + + testWriteFile(); + System.err.println("writeFile: OK"); + + testOpenLibrary(true); + System.err.println("lib0: OK"); + } + + public void stop() { + + } +} diff --git a/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java b/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java new file mode 100644 index 0000000..c47e2df --- /dev/null +++ b/src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java @@ -0,0 +1,209 @@ +/** + * Copyright 2013 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.junit.sec; + +import java.net.URISyntaxException; +import java.net.URL; +import java.security.AccessControlException; +import java.io.File; +import java.io.IOException; + +import junit.framework.Assert; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.jogamp.common.os.NativeLibrary; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.IOUtil; +import com.jogamp.common.util.JarUtil; +import com.jogamp.junit.util.JunitTracer; + +public class TestSecIOUtil01 extends JunitTracer { + static final String java_io_tmpdir_propkey = "java.io.tmpdir"; + static final String java_home_propkey = "java.home"; + static final String os_name_propkey = "os.name"; + static final boolean usesSecurityManager; + + static { + if( null == System.getSecurityManager() ) { + usesSecurityManager = false; + System.err.println("No SecurityManager Installed"); + } else { + usesSecurityManager = true; + System.err.println("SecurityManager Already Installed"); + } + } + + @BeforeClass + public static void setup() throws IOException { + Platform.initSingleton(); + } + + static void testPropImpl01(String propKey, boolean isSecure) { + isSecure |= !usesSecurityManager; + + Exception se0 = null; + try { + String p0 = System.getProperty(propKey); + System.err.println(propKey+": "+p0); + } catch (AccessControlException e) { + se0 = e; + if( !isSecure ) { + System.err.println("Expected exception for insecure property <"+propKey+">"); + System.err.println("Message: "+se0.getMessage()); + } else { + System.err.println("Unexpected exception for secure property <"+propKey+">"); + se0.printStackTrace(); + } + } + if( isSecure ) { + Assert.assertNull("AccessControlException thrown on secure property <"+propKey+">", se0); + } else { + Assert.assertNotNull("AccessControlException not thrown on insecure property <"+propKey+">", se0); + } + } + + @Test + public void testProp00_Temp() { + testPropImpl01(os_name_propkey, true); + } + + @Test + public void testProp01_Temp() { + testPropImpl01(java_home_propkey, false); + } + + @Test + public void testProp02_Temp() { + testPropImpl01(java_io_tmpdir_propkey, false); + } + + static void testTempDirImpl(boolean isSecure) { + isSecure |= !usesSecurityManager; + + Exception se0 = null; + try { + File tmp = IOUtil.getTempDir(true); + System.err.println("Temp: "+tmp); + } catch (AccessControlException e) { + se0 = e; + if( !isSecure ) { + System.err.println("Expected exception for insecure temp dir"); + System.err.println("Message: "+se0.getMessage()); + } else { + System.err.println("Unexpected exception for secure temp dir"); + se0.printStackTrace(); + } + } + if( isSecure ) { + Assert.assertNull("AccessControlException thrown on secure temp dir", se0); + } else { + Assert.assertNotNull("AccessControlException not thrown on insecure temp dir", se0); + } + } + + @Test + public void testTempDir00() { + testTempDirImpl(false); + } + + private void testOpenLibraryImpl(boolean global) { + final ClassLoader cl = getClass().getClassLoader(); + System.err.println("CL "+cl); + + String libBaseName = null; + final Class<?> clazz = this.getClass(); + URL libURL = clazz.getResource("/libtest1.so"); + if( null != libURL ) { + libBaseName = "libtest1.so"; + } else { + libURL = clazz.getResource("/test1.dll"); + if( null != libURL ) { + libBaseName = "test1.dll"; + } + } + System.err.println("Untrusted Library (URL): "+libURL); + + String libDir1 = null; + if( null != libURL ) { + try { + libDir1 = JarUtil.getJarSubURI(libURL.toURI()).getPath(); + } catch (Exception e) { + e.printStackTrace(); + } + if( null != libDir1 ) { + System.err.println("libDir1.1: "+libDir1); + try { + libDir1= IOUtil.getParentOf(libDir1); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + System.err.println("libDir1.2: "+libDir1); + } + } + System.err.println("Untrusted Library Dir1 (abs): "+libDir1); + final String absLib = libDir1 + "natives/" + libBaseName; + Exception se0 = null; + try { + NativeLibrary nlib = NativeLibrary.open(absLib, cl); + System.err.println("NativeLibrary: "+nlib); + } catch (SecurityException e) { + se0 = e; + if( usesSecurityManager ) { + System.err.println("Expected exception for loading native library"); + System.err.println("Message: "+se0.getMessage()); + } else { + System.err.println("Unexpected exception for loading native library"); + se0.printStackTrace(); + } + } + if( !usesSecurityManager ) { + Assert.assertNull("SecurityException thrown on loading native library", se0); + } else { + Assert.assertNotNull("SecurityException not thrown on loading native library", se0); + } + } + + public void testOpenLibrary() { + testOpenLibraryImpl(true); + } + + public static void main(String args[]) throws IOException { + TestSecIOUtil01.setup(); + + TestSecIOUtil01 aa = new TestSecIOUtil01(); + aa.testProp00_Temp(); + aa.testProp01_Temp(); + aa.testProp02_Temp(); + aa.testTempDir00(); + aa.testOpenLibrary(); + } + +} |