From 1a01dce6c42b398cdd68d405828774a3ab366456 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Tue, 11 Jun 2013 16:25:48 +0200 Subject: 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 --- src/junit/com/jogamp/junit/sec/Applet01.java | 254 +++++++++++++++++++++ .../com/jogamp/junit/sec/TestSecIOUtil01.java | 209 +++++++++++++++++ 2 files changed, 463 insertions(+) create mode 100644 src/junit/com/jogamp/junit/sec/Applet01.java create mode 100644 src/junit/com/jogamp/junit/sec/TestSecIOUtil01.java (limited to 'src/junit/com/jogamp') 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 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(); + } + +} -- cgit v1.2.3