diff options
20 files changed, 881 insertions, 225 deletions
diff --git a/make/build-test.xml b/make/build-test.xml index b700808..3c7da12 100644 --- a/make/build-test.xml +++ b/make/build-test.xml @@ -132,6 +132,9 @@ <fileset dir="${build_t.java}"> <include name="${test.junit.rel}/**/*.class"/> </fileset> + <fileset dir="${build_t.lib}"> + <include name="*${native.library.suffix}" /> + </fileset> <fileset dir="resources/assets-test"> <include name="**" /> </fileset> diff --git a/make/scripts/runtest-secmgr.sh b/make/scripts/runtest-secmgr.sh new file mode 100755 index 0000000..24f1b58 --- /dev/null +++ b/make/scripts/runtest-secmgr.sh @@ -0,0 +1,117 @@ +#! /bin/bash + +TDIR=`pwd` +SDIR=`dirname $0` #scripts +cd $SDIR +SDIR=`pwd` #scripts +cd $TDIR +MDIR=`dirname $SDIR` #make +RDIR=`dirname $MDIR` #gluegen + +builddir=$1 +shift + +if [ -z "$builddir" ] ; then + echo Usage $0 build-dir + exit 1 +fi + +BDIR=$RDIR/`basename $builddir` + +if [ -e /opt-share/apache-ant ] ; then + ANT_PATH=/opt-share/apache-ant + PATH=$ANT_PATH/bin:$PATH + export ANT_PATH +fi +if [ -z "$ANT_PATH" ] ; then + TMP_ANT_PATH=$(dirname `which ant`)/.. + if [ -e $TMP_ANT_PATH/lib/ant.jar ] ; then + ANT_PATH=$TMP_ANT_PATH + export ANT_PATH + echo autosetting ANT_PATH to $ANT_PATH + fi +fi +if [ -z "$ANT_PATH" ] ; then + if [ -e /usr/share/ant/bin/ant -a -e /usr/share/ant/lib/ant.jar ] ; then + ANT_PATH=/usr/share/ant + export ANT_PATH + echo autosetting ANT_PATH to $ANT_PATH + fi +fi +if [ -z "$ANT_PATH" ] ; then + echo ANT_PATH does not exist, set it + print_usage + exit +fi + +ANT_JARS=$ANT_PATH/lib/ant.jar:$ANT_PATH/lib/ant-junit.jar:$ANT_PATH/lib/ant-launcher.jar + +LOG=runtest.log +rm -f $LOG + +#D_ARGS="-Djogamp.debug.ProcAddressHelper=true -Djogamp.debug.NativeLibrary=true" +#D_ARGS="-Djogamp.debug.TraceLock" +#D_ARGS="-Djogamp.debug.Platform -Djogamp.debug.NativeLibrary" +#D_ARGS="-Djogamp.debug.JarUtil" +#D_ARGS="-Djogamp.debug.TempJarCache" +#D_ARGS="-Djogamp.debug.TempFileCache" +#D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.JNILibLoader -Djogamp.debug.TempFileCache -Djogamp.debug.JarUtil -Djava.io.tmpdir=/run/tmp" +#D_ARGS="-Djogamp.debug.IOUtil -Djogamp.debug.JNILibLoader -Djogamp.debug.TempFileCache -Djogamp.debug.JarUtil -Djogamp.debug.TempJarCache" +#D_ARGS="-Djogamp.debug.JNILibLoader -Djogamp.gluegen.UseTempJarCache=false" +#D_ARGS="-Djogamp.debug.JNILibLoader" +#D_ARGS="-Djogamp.debug.Lock" +#D_ARGS="-Djogamp.debug.Lock -Djogamp.debug.Lock.TraceLock" +#D_ARGS="-Djogamp.debug.Lock.TraceLock" +#D_ARGS="-Djogamp.debug.IOUtil" +D_ARGS="-Djogamp.debug=all" + +SPFILE=$BDIR/java.policy.secure + +echo "grant codeBase \"file:$BDIR/*\" {" > $SPFILE +echo " permission java.security.AllPermission;" >> $SPFILE +echo "};" >> $SPFILE + +function onetest() { + CLASSPATH=lib/junit.jar:$ANT_JARS:$RDIR/make/lib/TestJarsInJar.jar:$BDIR/gluegen-rt.jar:$BDIR/test/build/gluegen-test.jar + libspath=$BDIR/test/build/natives + echo LD_LIBRARY_PATH $LD_LIBRARY_PATH + echo CLASSPATH $CLASSPATH + which java + echo java -Djava.security.policy=$SPFILE -Dfile.encoding=UTF-8 -cp $CLASSPATH $D_ARGS $* + java -Djava.security.manager -Djava.security.policy=$SPFILE -Dfile.encoding=UTF-8 -cp $CLASSPATH $D_ARGS $* + echo +} +# +#onetest com.jogamp.common.GlueGenVersion 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestSystemPropsAndEnvs 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestVersionInfo 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestVersionNumber 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestIteratorIndexCORE 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.locks.TestRecursiveLock01 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.locks.TestRecursiveThreadGroupLock01 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.locks.TestSingletonServerSocket00 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.locks.TestSingletonServerSocket01 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.locks.TestSingletonServerSocket02 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestFloatStack01 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestIntegerStack01 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestArrayHashSet01 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.IntIntHashMapTest 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.IntObjectHashMapTest 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.LongIntHashMapTest 2>&1 | tee -a $LOG +#onetest com.jogamp.common.nio.TestBuffersFloatDoubleConversion 2>&1 | tee -a $LOG +#onetest com.jogamp.gluegen.PCPPTest 2>&1 | tee -a $LOG +#onetest com.jogamp.common.nio.TestPointerBufferEndian 2>&1 | tee -a $LOG +#onetest com.jogamp.common.nio.TestStructAccessorEndian 2>&1 | tee -a $LOG +#onetest com.jogamp.common.os.TestElfReader01 2>&1 | tee -a $LOG +#onetest com.jogamp.gluegen.test.junit.generation.Test1p1JavaEmitter 2>&1 | tee -a $LOG +#onetest com.jogamp.gluegen.test.junit.generation.Test1p2ProcAddressEmitter 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestPlatform01 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestRunnableTask01 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestIOUtil01 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestTempJarCache 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestJarUtil 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestValueConversion 2>&1 | tee -a $LOG +#onetest com.jogamp.common.net.AssetURLConnectionUnregisteredTest 2>&1 | tee -a $LOG +#onetest com.jogamp.common.net.AssetURLConnectionRegisteredTest 2>&1 | tee -a $LOG +#onetest com.jogamp.common.net.URLCompositionTest 2>&1 | tee -a $LOG +onetest com.jogamp.junit.sec.TestSecIOUtil01 2>&1 | tee -a $LOG diff --git a/make/scripts/runtest.sh b/make/scripts/runtest.sh index a068c90..165f64d 100755 --- a/make/scripts/runtest.sh +++ b/make/scripts/runtest.sh @@ -100,8 +100,9 @@ function onetest() { #onetest com.jogamp.common.util.TestRunnableTask01 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.TestIOUtil01 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.TestTempJarCache 2>&1 | tee -a $LOG -onetest com.jogamp.common.util.TestJarUtil 2>&1 | tee -a $LOG +#onetest com.jogamp.common.util.TestJarUtil 2>&1 | tee -a $LOG #onetest com.jogamp.common.util.TestValueConversion 2>&1 | tee -a $LOG #onetest com.jogamp.common.net.AssetURLConnectionUnregisteredTest 2>&1 | tee -a $LOG #onetest com.jogamp.common.net.AssetURLConnectionRegisteredTest 2>&1 | tee -a $LOG #onetest com.jogamp.common.net.URLCompositionTest 2>&1 | tee -a $LOG +onetest com.jogamp.junit.sec.TestSecIOUtil01 2>&1 | tee -a $LOG diff --git a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java index 5621396..456c35a 100644 --- a/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java +++ b/src/java/com/jogamp/common/jvm/JNILibLoaderBase.java @@ -386,7 +386,7 @@ public class JNILibLoaderBase { } } if(null==launcherClass) { - String launcherClassName = PropertyAccess.getProperty("jnlp.launcher.class", false, null); + String launcherClassName = PropertyAccess.getProperty("jnlp.launcher.class", false); if(null!=launcherClassName) { try { launcherClass = Class.forName(launcherClassName); diff --git a/src/java/com/jogamp/common/os/DynamicLinker.java b/src/java/com/jogamp/common/os/DynamicLinker.java index a0da9fb..32aa7eb 100644 --- a/src/java/com/jogamp/common/os/DynamicLinker.java +++ b/src/java/com/jogamp/common/os/DynamicLinker.java @@ -46,8 +46,8 @@ public interface DynamicLinker { public static final boolean DEBUG = NativeLibrary.DEBUG; public static final boolean DEBUG_LOOKUP = NativeLibrary.DEBUG_LOOKUP; - public long openLibraryGlobal(String pathname, boolean debug); - public long openLibraryLocal(String pathname, boolean debug); + public long openLibraryGlobal(String pathname, boolean debug) throws SecurityException; + public long openLibraryLocal(String pathname, boolean debug) throws SecurityException; public long lookupSymbol(long libraryHandle, String symbolName); public long lookupSymbolGlobal(String symbolName); public void closeLibrary(long libraryHandle); diff --git a/src/java/com/jogamp/common/os/Platform.java b/src/java/com/jogamp/common/os/Platform.java index aa9bccd..0ae3cbb 100644 --- a/src/java/com/jogamp/common/os/Platform.java +++ b/src/java/com/jogamp/common/os/Platform.java @@ -162,49 +162,69 @@ public class Platform extends PlatformPropsImpl { /** <code>true</code> if AWT is available and not in headless mode, otherwise <code>false</code>. */ public static final boolean AWT_AVAILABLE; - private static final URI platformClassJarURI; + private static final boolean isRunningFromJarURL; static { - PlatformPropsImpl.initSingleton(); // just documenting the order of static initialization - - { - URI _platformClassJarURI; - try { - _platformClassJarURI = JarUtil.getJarURI(Platform.class.getName(), Platform.class.getClassLoader()); - } catch (Exception e) { - _platformClassJarURI = null; - } - platformClassJarURI = _platformClassJarURI; - } - - USE_TEMP_JAR_CACHE = (OS_TYPE != OSType.ANDROID) && isRunningFromJarURL() && - Debug.getBooleanProperty(useTempJarCachePropName, true, true); + final boolean[] _isRunningFromJarURL = new boolean[] { false }; + final boolean[] _USE_TEMP_JAR_CACHE = new boolean[] { false }; + final boolean[] _AWT_AVAILABLE = new boolean[] { false }; + + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { - AWT_AVAILABLE = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { - public Boolean run() { - // load GluegenRT native library - loadGlueGenRTImpl(); + PlatformPropsImpl.initSingleton(); // documenting the order of static initialization - // JVM bug workaround - JVMUtil.initSingleton(); // requires gluegen-rt, one-time init. + final ClassLoader cl = Platform.class.getClassLoader(); - // detect AWT availability - boolean awtAvailable = false; + final URI platformClassJarURI; { - final ClassLoader cl = Platform.class.getClassLoader(); - if( !Debug.getBooleanProperty("java.awt.headless", true) && - ReflectionUtil.isClassAvailable(ReflectionUtil.AWTNames.ComponentClass, cl) && - ReflectionUtil.isClassAvailable(ReflectionUtil.AWTNames.GraphicsEnvironmentClass, cl) ) { - try { - awtAvailable = false == ((Boolean)ReflectionUtil.callStaticMethod(ReflectionUtil.AWTNames.GraphicsEnvironmentClass, ReflectionUtil.AWTNames.isHeadlessMethod, null, null, cl)).booleanValue(); - } catch (Throwable t) { } + URI _platformClassJarURI = null; + try { + _platformClassJarURI = JarUtil.getJarURI(Platform.class.getName(), cl); + } catch (Exception e) { } + platformClassJarURI = _platformClassJarURI; + } + _isRunningFromJarURL[0] = null != platformClassJarURI; + + _USE_TEMP_JAR_CACHE[0] = ( OS_TYPE != OSType.ANDROID ) && ( null != platformClassJarURI ) && + Debug.getBooleanProperty(useTempJarCachePropName, true, true); + + // load GluegenRT native library + if(_USE_TEMP_JAR_CACHE[0] && TempJarCache.initSingleton()) { + String nativeJarName = null; + URI jarUriRoot = null; + URI nativeJarURI = null; + try { + final String jarName = JarUtil.getJarBasename( platformClassJarURI ); + final String nativeJarBasename = jarName.substring(0, jarName.indexOf(".jar")); // ".jar" already validated w/ JarUtil.getJarBasename(..) + nativeJarName = nativeJarBasename+"-natives-"+PlatformPropsImpl.os_and_arch+".jar"; + jarUriRoot = JarUtil.getURIDirname( JarUtil.getJarSubURI( platformClassJarURI ) ); + nativeJarURI = JarUtil.getJarFileURI(jarUriRoot, nativeJarName); + TempJarCache.bootstrapNativeLib(Platform.class, libBaseName, nativeJarURI); + } catch (Exception e0) { + // IllegalArgumentException, IOException + System.err.println("Catched "+e0.getClass().getSimpleName()+": "+e0.getMessage()+", while TempJarCache.bootstrapNativeLib() of "+nativeJarURI+" ("+jarUriRoot+" + "+nativeJarName+")"); } } - return new Boolean(awtAvailable); - } - }).booleanValue(); - - + DynamicLibraryBundle.GlueJNILibLoader.loadLibrary(libBaseName, false, cl); + + // JVM bug workaround + JVMUtil.initSingleton(); // requires gluegen-rt, one-time init. + + // AWT Headless determination + if( !Debug.getBooleanProperty("java.awt.headless", true) && + ReflectionUtil.isClassAvailable(ReflectionUtil.AWTNames.ComponentClass, cl) && + ReflectionUtil.isClassAvailable(ReflectionUtil.AWTNames.GraphicsEnvironmentClass, cl) ) { + try { + _AWT_AVAILABLE[0] = false == ((Boolean)ReflectionUtil.callStaticMethod(ReflectionUtil.AWTNames.GraphicsEnvironmentClass, ReflectionUtil.AWTNames.isHeadlessMethod, null, null, cl)).booleanValue(); + } catch (Throwable t) { } + } + return null; + } } ); + isRunningFromJarURL = _isRunningFromJarURL[0]; + USE_TEMP_JAR_CACHE = _USE_TEMP_JAR_CACHE[0]; + AWT_AVAILABLE = _AWT_AVAILABLE[0]; + MachineDescription md = MachineDescriptionRuntime.getRuntime(); if(null == md) { MachineDescription.StaticConfig smd = MachineDescriptionRuntime.getStatic(); @@ -228,27 +248,7 @@ public class Platform extends PlatformPropsImpl { * @return true if we're running from a Jar URL, otherwise false */ public static final boolean isRunningFromJarURL() { - return null != platformClassJarURI; - } - - private static final void loadGlueGenRTImpl() { - if(USE_TEMP_JAR_CACHE && TempJarCache.initSingleton()) { - String nativeJarName = null; - URI jarUriRoot = null; - URI nativeJarURI = null; - try { - final String jarName = JarUtil.getJarBasename(platformClassJarURI); - final String nativeJarBasename = jarName.substring(0, jarName.indexOf(".jar")); // ".jar" already validated w/ JarUtil.getJarBasename(..) - nativeJarName = nativeJarBasename+"-natives-"+PlatformPropsImpl.os_and_arch+".jar"; - jarUriRoot = JarUtil.getURIDirname( JarUtil.getJarSubURI( platformClassJarURI ) ); - nativeJarURI = JarUtil.getJarFileURI(jarUriRoot, nativeJarName); - TempJarCache.bootstrapNativeLib(Platform.class, libBaseName, nativeJarURI); - } catch (Exception e0) { - // IllegalArgumentException, IOException - System.err.println("Catched "+e0.getClass().getSimpleName()+": "+e0.getMessage()+", while TempJarCache.bootstrapNativeLib() of "+nativeJarURI+" ("+jarUriRoot+" + "+nativeJarName+")"); - } - } - DynamicLibraryBundle.GlueJNILibLoader.loadLibrary(libBaseName, false, Platform.class.getClassLoader()); + return isRunningFromJarURL; } /** diff --git a/src/java/com/jogamp/common/util/IOUtil.java b/src/java/com/jogamp/common/util/IOUtil.java index 46d6b24..2f0c77f 100644 --- a/src/java/com/jogamp/common/util/IOUtil.java +++ b/src/java/com/jogamp/common/util/IOUtil.java @@ -33,12 +33,10 @@ import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; +import java.io.FilePermission; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.lang.reflect.Constructor; import java.net.URI; import java.net.URISyntaxException; @@ -817,20 +815,12 @@ public class IOUtil { * @param dir the directory to process * @param create true if the directory shall be created if not existing * @param executable true if the user intents to launch executables from the temporary directory, otherwise false. - * @param acc The security {@link AccessControlContext} to create directories and test <i>executability</i> * @throws SecurityException if file creation and process execution is not allowed within the current security context */ - public static File testDir(final File dir, final boolean create, final boolean executable, AccessControlContext acc) + public static File testDir(final File dir, final boolean create, final boolean executable) throws SecurityException { - if( null != acc ) { - return AccessController.doPrivileged(new PrivilegedAction<File>() { - public File run() { - return testDirImpl(dir, create, executable); - } }, acc); - } else { - return testDirImpl(dir, create, executable); - } + return testDirImpl(dir, create, executable); } private static boolean isStringSet(String s) { return null != s && 0 < s.length(); } @@ -873,9 +863,35 @@ public class IOUtil { return tmpBaseDir; } - private static File getTempDirImpl(boolean executable) + /** + * Returns a platform independent writable directory for temporary files + * consisting of the platform's {@code temp-root} + {@link #tmpSubDir}, + * e.g. {@code /tmp/jogamp_0000/}. + * <p> + * On standard Java the {@code temp-root} folder is specified by <code>java.io.tempdir</code>. + * </p> + * <p> + * On Android the {@code temp-root} folder is relative to the applications local folder + * (see {@link Context#getDir(String, int)}) is returned, if + * the Android application/activity has registered it's Application Context + * via {@link jogamp.common.os.android.StaticContext.StaticContext#init(Context, ClassLoader) StaticContext.init(..)}. + * This allows using the temp folder w/o the need for <code>sdcard</code> + * access, which would be the <code>java.io.tempdir</code> location on Android! + * </p> + * <p> + * In case {@code temp-root} is the users home folder, + * a dot is being prepended to {@link #tmpSubDir}, i.e.: {@code /home/user/.jogamp_0000/}. + * </p> + * @param executable true if the user intents to launch executables from the temporary directory, otherwise false. + * @throws RuntimeException if no temporary directory could be determined + * @throws SecurityException if access to <code>java.io.tmpdir</code> is not allowed within the current security context + * + * @see PropertyAccess#getProperty(String, boolean) + * @see Context#getDir(String, int) + */ + public static File getTempDir(final boolean executable) throws SecurityException, RuntimeException - { + { if(!tempRootSet) { // volatile: ok synchronized(IOUtil.class) { if(!tempRootSet) { @@ -889,8 +905,8 @@ public class IOUtil { } } - final String java_io_tmpdir = PropertyAccess.getProperty(java_io_tmpdir_propkey, false, null); - final String user_home = PropertyAccess.getProperty(user_home_propkey, false, null); + final String java_io_tmpdir = PropertyAccess.getProperty(java_io_tmpdir_propkey, false); + final String user_home = PropertyAccess.getProperty(user_home_propkey, false); final String xdg_cache_home; { @@ -951,6 +967,8 @@ public class IOUtil { if(null == r) { throw new RuntimeException("Could not determine a temporary directory"); } + final FilePermission fp = new FilePermission(r.getAbsolutePath(), "read,write,delete"); + SecurityUtil.checkPermission(fp); return r; } private static File tempRootExec = null; // writeable and executable @@ -958,53 +976,13 @@ public class IOUtil { private static volatile boolean tempRootSet = false; /** - * Returns a platform independent writable directory for temporary files - * consisting of the platform's {@code temp-root} + {@link #tmpSubDir}, - * e.g. {@code /tmp/jogamp_0000/}. - * <p> - * On standard Java the {@code temp-root} folder is specified by <code>java.io.tempdir</code>. - * </p> - * <p> - * On Android the {@code temp-root} folder is relative to the applications local folder - * (see {@link Context#getDir(String, int)}) is returned, if - * the Android application/activity has registered it's Application Context - * via {@link jogamp.common.os.android.StaticContext.StaticContext#init(Context, ClassLoader) StaticContext.init(..)}. - * This allows using the temp folder w/o the need for <code>sdcard</code> - * access, which would be the <code>java.io.tempdir</code> location on Android! - * </p> - * <p> - * In case {@code temp-root} is the users home folder, - * a dot is being prepended to {@link #tmpSubDir}, i.e.: {@code /home/user/.jogamp_0000/}. - * </p> - * @param executable true if the user intents to launch executables from the temporary directory, otherwise false. - * @param acc The security {@link AccessControlContext} to access properties, environment vars, create directories and test <i>executability</i> - * @throws SecurityException if access to <code>java.io.tmpdir</code> is not allowed within the current security context - * @throws RuntimeException if no temporary directory could be determined - * - * @see PropertyAccess#getProperty(String, boolean, java.security.AccessControlContext) - * @see Context#getDir(String, int) - */ - public static File getTempDir(final boolean executable, AccessControlContext acc) - throws SecurityException, RuntimeException - { - if( null != acc ) { - return AccessController.doPrivileged(new PrivilegedAction<File>() { - public File run() { - return getTempDirImpl(executable); - } }, acc); - } else { - return getTempDirImpl(executable); - } - } - - /** * Utilizing {@link File#createTempFile(String, String, File)} using - * {@link #getTempRoot(AccessControlContext, boolean)} as the directory parameter, ie. location + * {@link #getTempDir(boolean)} as the directory parameter, ie. location * of the root temp folder. * * @see File#createTempFile(String, String) * @see File#createTempFile(String, String, File) - * @see #getTempRoot(AccessControlContext, boolean) + * @see #getTempDir(boolean) * * @param prefix * @param suffix @@ -1014,10 +992,10 @@ public class IOUtil { * @throws IOException * @throws SecurityException */ - public static File createTempFile(String prefix, String suffix, boolean executable, AccessControlContext acc) + public static File createTempFile(String prefix, String suffix, boolean executable) throws IllegalArgumentException, IOException, SecurityException { - return File.createTempFile( prefix, suffix, getTempDir(executable, acc) ); + return File.createTempFile( prefix, suffix, getTempDir(executable) ); } public static void close(Closeable stream, boolean throwRuntimeException) throws RuntimeException { diff --git a/src/java/com/jogamp/common/util/PropertyAccess.java b/src/java/com/jogamp/common/util/PropertyAccess.java index 51b9533..dde6b50 100644 --- a/src/java/com/jogamp/common/util/PropertyAccess.java +++ b/src/java/com/jogamp/common/util/PropertyAccess.java @@ -48,12 +48,13 @@ public class PropertyAccess { // 'jogamp.' and maybe other trusted prefixes will be added later via 'addTrustedPrefix()' } - public static final void addTrustedPrefix(String prefix, Class<?> certClass) { - if(SecurityUtil.equalsLocalCert(certClass)) { - trustedPrefixes.add(prefix); - } else { - throw new SecurityException("Illegal Access - prefix "+prefix+", with cert class "+certClass); - } + /** + * @param prefix New prefix to be registered as trusted. + * @throws AccessControlException as thrown by {@link SecurityUtil#checkAllPermissions()}. + */ + protected static final void addTrustedPrefix(String prefix) throws AccessControlException { + SecurityUtil.checkAllPermissions(); + trustedPrefixes.add(prefix); } public static final boolean isTrusted(String propertyKey) { @@ -65,11 +66,11 @@ public class PropertyAccess { } } - /** @see #getProperty(String, boolean, AccessControlContext) */ - public static final int getIntProperty(final String property, final boolean jnlpAlias, final AccessControlContext acc, int defaultValue) { + /** @see #getProperty(String, boolean) */ + public static final int getIntProperty(final String property, final boolean jnlpAlias, int defaultValue) { int i=defaultValue; try { - final String sv = PropertyAccess.getProperty(property, jnlpAlias, acc); + final String sv = PropertyAccess.getProperty(property, jnlpAlias); if(null!=sv) { i = Integer.valueOf(sv).intValue(); } @@ -77,11 +78,11 @@ public class PropertyAccess { return i; } - /** @see #getProperty(String, boolean, AccessControlContext) */ - public static final long getLongProperty(final String property, final boolean jnlpAlias, final AccessControlContext acc, long defaultValue) { + /** @see #getProperty(String, boolean) */ + public static final long getLongProperty(final String property, final boolean jnlpAlias, long defaultValue) { long l=defaultValue; try { - final String sv = PropertyAccess.getProperty(property, jnlpAlias, acc); + final String sv = PropertyAccess.getProperty(property, jnlpAlias); if(null!=sv) { l = Long.valueOf(sv).longValue(); } @@ -89,23 +90,23 @@ public class PropertyAccess { return l; } - /** @see #getProperty(String, boolean, AccessControlContext) */ - public static final boolean getBooleanProperty(final String property, final boolean jnlpAlias, final AccessControlContext acc) { - return Boolean.valueOf(PropertyAccess.getProperty(property, jnlpAlias, acc)).booleanValue(); + /** @see #getProperty(String, boolean) */ + public static final boolean getBooleanProperty(final String property, final boolean jnlpAlias) { + return Boolean.valueOf(PropertyAccess.getProperty(property, jnlpAlias)).booleanValue(); } - /** @see #getProperty(String, boolean, AccessControlContext) */ - public static final boolean getBooleanProperty(final String property, final boolean jnlpAlias, final AccessControlContext acc, boolean defaultValue) { - final String valueS = PropertyAccess.getProperty(property, jnlpAlias, acc); + /** @see #getProperty(String, boolean) */ + public static final boolean getBooleanProperty(final String property, final boolean jnlpAlias, boolean defaultValue) { + final String valueS = PropertyAccess.getProperty(property, jnlpAlias); if(null != valueS) { return Boolean.valueOf(valueS).booleanValue(); } return defaultValue; } - /** @see #getProperty(String, boolean, AccessControlContext) */ - public static final boolean isPropertyDefined(final String property, final boolean jnlpAlias, final AccessControlContext acc) { - return (PropertyAccess.getProperty(property, jnlpAlias, acc) != null) ? true : false; + /** @see #getProperty(String, boolean) */ + public static final boolean isPropertyDefined(final String property, final boolean jnlpAlias) { + return (PropertyAccess.getProperty(property, jnlpAlias) != null) ? true : false; } /** @@ -119,8 +120,6 @@ public class PropertyAccess { * @param propertyKey the property name to query. * @param jnlpAlias true if a fallback attempt to query the JNLP aliased <i>trusted property</i> shall be made, * otherwise false. - * @param acc the AccessControlerContext to be used for privileged access to the system property, or null. - * * @return the property value if exists, or null * * @throws NullPointerException if the property name is null @@ -129,7 +128,7 @@ public class PropertyAccess { * * @see System#getProperty(String) */ - public static final String getProperty(final String propertyKey, final boolean jnlpAlias, final AccessControlContext acc) + public static final String getProperty(final String propertyKey, final boolean jnlpAlias) throws SecurityException, NullPointerException, IllegalArgumentException { if(null == propertyKey) { throw new NullPointerException("propertyKey is NULL"); @@ -138,23 +137,13 @@ public class PropertyAccess { throw new IllegalArgumentException("propertyKey is empty"); } String s=null; - // int cause = 0; if( isTrusted(propertyKey) ) { // 'trusted' property (jnlp., javaws., jogamp., ..) s = getTrustedPropKey(propertyKey); - // cause = null != s ? 1 : 0; } else { - if( null != acc ) { - s = AccessController.doPrivileged(new PrivilegedAction<String>() { - public String run() { - return System.getProperty(propertyKey); - } }, acc); - // cause = null != s ? 2 : 0; - } else { - s = System.getProperty(propertyKey); - // cause = null != s ? 3 : 0; - } + // may throw SecurityException, AccessControlerException + s = System.getProperty(propertyKey); } if( null == s && jnlpAlias ) { // Try 'jnlp.' aliased property .. @@ -162,11 +151,8 @@ public class PropertyAccess { // Properties within the namespace "jnlp." or "javaws." should be considered trusted, // i.e. always granted w/o special privileges. s = getTrustedPropKey(jnlp_prefix + propertyKey); - // cause = null != s ? 4 : 0; } - } - // System.err.println("Prop: <"+propertyKey+"> = <"+s+">, cause "+cause); - + } return s; } @@ -177,7 +163,6 @@ public class PropertyAccess { return System.getProperty(propertyKey); } catch (SecurityException se) { throw new SecurityException("Could not access trusted property '"+propertyKey+"'", se); - } } }); diff --git a/src/java/com/jogamp/common/util/SecurityUtil.java b/src/java/com/jogamp/common/util/SecurityUtil.java index 4583201..4d7aa5d 100644 --- a/src/java/com/jogamp/common/util/SecurityUtil.java +++ b/src/java/com/jogamp/common/util/SecurityUtil.java @@ -27,30 +27,127 @@ */ package com.jogamp.common.util; -import java.security.AccessControlContext; import java.security.AccessController; +import java.security.AllPermission; import java.security.CodeSource; +import java.security.Permission; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.security.cert.Certificate; public class SecurityUtil { - /* package private */ static final AccessControlContext localACC; - /* package private */ static final Certificate[] localCerts; + private static final SecurityManager securityManager; + private static final Permission allPermissions; + private static final boolean DEBUG = false; static { - localACC = AccessController.doPrivileged(new PrivilegedAction<AccessControlContext>() { - public AccessControlContext run() { - return AccessController.getContext(); - } } ); - localCerts = getCerts(SecurityUtil.class); + allPermissions = new AllPermission(); + securityManager = System.getSecurityManager(); + + if( DEBUG ) { + final boolean hasAllPermissions; + { + final ProtectionDomain insecPD = AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() { + public ProtectionDomain run() { + return SecurityUtil.class.getProtectionDomain(); + } } ); + boolean _hasAllPermissions; + try { + insecPD.implies(allPermissions); + _hasAllPermissions = true; + } catch( SecurityException ace ) { + _hasAllPermissions = false; + } + hasAllPermissions = _hasAllPermissions; + } + + System.err.println("SecurityUtil: Has SecurityManager: "+ ( null != securityManager ) ) ; + System.err.println("SecurityUtil: Has AllPermissions: "+hasAllPermissions); + final Certificate[] certs = AccessController.doPrivileged(new PrivilegedAction<Certificate[]>() { + public Certificate[] run() { + return getCerts(SecurityUtil.class); + } } ); + System.err.println("SecurityUtil: Cert count: "+ ( null != certs ? certs.length : 0 )); + if( null != certs ) { + for(int i=0; i<certs.length; i++) { + System.err.println("\t cert["+i+"]: "+certs[i].toString()); + } + } + } + } + + /** + * Returns <code>true</code> if no {@link SecurityManager} has been installed + * or the installed {@link SecurityManager}'s <code>checkPermission(new AllPermission())</code> + * passes. Otherwise method returns <code>false</code>. + */ + public static final boolean hasAllPermissions() { + return hasPermission(allPermissions); + } + + /** + * Returns <code>true</code> if no {@link SecurityManager} has been installed + * or the installed {@link SecurityManager}'s <code>checkPermission(perm)</code> + * passes. Otherwise method returns <code>false</code>. + */ + public static final boolean hasPermission(Permission perm) { + try { + checkPermission(perm); + return true; + } catch( SecurityException ace ) { + return false; + } + } + + /** + * Throws an {@link SecurityException} if an installed {@link SecurityManager} + * does not permit the requested {@link AllPermission}. + */ + public static final void checkAllPermissions() throws SecurityException { + checkPermission(allPermissions); + } + + /** + * Throws an {@link SecurityException} if an installed {@link SecurityManager} + * does not permit the requested {@link Permission}. + */ + public static final void checkPermission(Permission perm) throws SecurityException { + if( null != securityManager ) { + securityManager.checkPermission(perm); + } + } + + /** + * Returns <code>true</code> if no {@link SecurityManager} has been installed + * or the installed {@link SecurityManager}'s <code>checkLink(libName)</code> + * passes. Otherwise method returns <code>false</code>. + */ + public static final boolean hasLinkPermission(String libName) { + try { + checkLinkPermission(libName); + return true; + } catch( SecurityException ace ) { + return false; + } } - public static final Certificate[] getCerts(final Class<?> clz) { - final ProtectionDomain pd = AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() { - public ProtectionDomain run() { - return clz.getProtectionDomain(); - } } ); + /** + * Throws an {@link SecurityException} if an installed {@link SecurityManager} + * does not permit to dynamically link the given libName. + */ + public static final void checkLinkPermission(String libName) throws SecurityException { + if( null != securityManager ) { + securityManager.checkLink(libName); + } + } + + /** + * @param clz + * @return + * @throws SecurityException if the caller has no permission to access the ProtectedDomain of the given class. + */ + public static final Certificate[] getCerts(final Class<?> clz) throws SecurityException { + final ProtectionDomain pd = clz.getProtectionDomain(); final CodeSource cs = (null != pd) ? pd.getCodeSource() : null; final Certificate[] certs = (null != cs) ? cs.getCertificates() : null; return (null != certs && certs.length>0) ? certs : null; @@ -72,21 +169,5 @@ public class SecurityUtil { i++; } return i == a.length; - } - - public static final boolean equalsLocalCert(Certificate[] b) { - return equals(localCerts, b); - } - - public static final boolean equalsLocalCert(Class<?> clz) { - return equalsLocalCert(getCerts(clz)); - } - - public static final AccessControlContext getCommonAccessControlContext(Class<?> clz) { - if(equalsLocalCert(clz)) { - return localACC; - } else { - return null; - } - } + } } diff --git a/src/java/com/jogamp/common/util/cache/TempFileCache.java b/src/java/com/jogamp/common/util/cache/TempFileCache.java index 755ed7b..32f5c2a 100644 --- a/src/java/com/jogamp/common/util/cache/TempFileCache.java +++ b/src/java/com/jogamp/common/util/cache/TempFileCache.java @@ -33,10 +33,8 @@ import java.io.FilenameFilter; import java.io.IOException; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; -import java.security.AccessControlContext; import com.jogamp.common.util.IOUtil; -import com.jogamp.common.util.SecurityUtil; import jogamp.common.Debug; @@ -72,8 +70,6 @@ public class TempFileCache { private File individualTmpDir; static { - final AccessControlContext acc = SecurityUtil.getCommonAccessControlContext(TempFileCache.class); - // Global Lock ! synchronized (System.out) { // Create / initialize the temp root directory, starting the Reaper @@ -81,8 +77,8 @@ public class TempFileCache { // exception, set an error code. File _tmpBaseDir = null; try { - _tmpBaseDir = new File(IOUtil.getTempDir(true /* executable */, acc), tmpDirPrefix); - _tmpBaseDir = IOUtil.testDir(_tmpBaseDir, true /* create */, false /* executable */, acc); // executable already checked + _tmpBaseDir = new File(IOUtil.getTempDir(true /* executable */), tmpDirPrefix); + _tmpBaseDir = IOUtil.testDir(_tmpBaseDir, true /* create */, false /* executable */); // executable already checked } catch (Exception ex) { System.err.println("Warning: Catched Exception while retrieving temp base directory:"); ex.printStackTrace(); diff --git a/src/java/com/jogamp/gluegen/Logging.java b/src/java/com/jogamp/gluegen/Logging.java index 87d6196..d8c1b5a 100644 --- a/src/java/com/jogamp/gluegen/Logging.java +++ b/src/java/com/jogamp/gluegen/Logging.java @@ -38,7 +38,6 @@ import java.util.logging.LogRecord; import java.util.logging.Logger; import com.jogamp.common.util.PropertyAccess; -import com.jogamp.common.util.SecurityUtil; /** * @@ -48,11 +47,11 @@ public class Logging { static void init() { final String packageName = Logging.class.getPackage().getName(); - final String property = PropertyAccess.getProperty(packageName+".level", true, SecurityUtil.getCommonAccessControlContext(Logging.class)); + final String property = PropertyAccess.getProperty(packageName+".level", true); Level level; if(property != null) { level = Level.parse(property); - }else{ + } else { level = Level.WARNING; } diff --git a/src/java/jogamp/common/Debug.java b/src/java/jogamp/common/Debug.java index 19e2fd7..b8a32d8 100644 --- a/src/java/jogamp/common/Debug.java +++ b/src/java/jogamp/common/Debug.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 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 @@ -39,6 +40,9 @@ package jogamp.common; +import java.security.AccessController; +import java.security.PrivilegedAction; + import com.jogamp.common.util.PropertyAccess; /** Helper routines for logging and debugging. */ @@ -49,28 +53,16 @@ public class Debug extends PropertyAccess { private static final boolean debugAll; static { - PropertyAccess.addTrustedPrefix("jogamp.", Debug.class); + AccessController.doPrivileged(new PrivilegedAction<Object>() { + public Object run() { + PropertyAccess.addTrustedPrefix("jogamp."); + return null; + } } ); verbose = isPropertyDefined("jogamp.verbose", true); debugAll = isPropertyDefined("jogamp.debug", true); } - public static final boolean isPropertyDefined(final String property, final boolean jnlpAlias) { - return PropertyAccess.isPropertyDefined(property, jnlpAlias, null); - } - - public static final boolean getBooleanProperty(final String property, final boolean jnlpAlias) { - return PropertyAccess.getBooleanProperty(property, jnlpAlias, null); - } - - public static final boolean getBooleanProperty(final String property, final boolean jnlpAlias, boolean defaultValue) { - return PropertyAccess.getBooleanProperty(property, jnlpAlias, null, defaultValue); - } - - public static final long getLongProperty(final String property, final boolean jnlpAlias, long defaultValue) { - return PropertyAccess.getLongProperty(property, jnlpAlias, null, defaultValue); - } - public static boolean verbose() { return verbose; } diff --git a/src/java/jogamp/common/os/MacOSXDynamicLinkerImpl.java b/src/java/jogamp/common/os/MacOSXDynamicLinkerImpl.java index 4eb381f..95f7e63 100644 --- a/src/java/jogamp/common/os/MacOSXDynamicLinkerImpl.java +++ b/src/java/jogamp/common/os/MacOSXDynamicLinkerImpl.java @@ -3,6 +3,7 @@ package jogamp.common.os; import com.jogamp.common.os.DynamicLinker; +import com.jogamp.common.util.SecurityUtil; public class MacOSXDynamicLinkerImpl implements DynamicLinker { @@ -28,7 +29,7 @@ public class MacOSXDynamicLinkerImpl implements DynamicLinker { // --- Begin CustomJavaCode .cfg declarations - public long openLibraryLocal(String pathname, boolean debug) { + public long openLibraryLocal(String pathname, boolean debug) throws SecurityException { // Note we use RTLD_LOCAL visibility to _NOT_ allow this functionality to // be used to pre-resolve dependent libraries of JNI code without // requiring that all references to symbols in those libraries be @@ -36,10 +37,11 @@ public class MacOSXDynamicLinkerImpl implements DynamicLinker { // other words, one can actually link against the library instead of // having to dlsym all entry points. System.loadLibrary() uses // RTLD_LOCAL visibility so can't be used for this purpose. + SecurityUtil.checkLinkPermission(pathname); return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL); } - public long openLibraryGlobal(String pathname, boolean debug) { + public long openLibraryGlobal(String pathname, boolean debug) throws SecurityException { // Note we use RTLD_GLOBAL visibility to allow this functionality to // be used to pre-resolve dependent libraries of JNI code without // requiring that all references to symbols in those libraries be @@ -47,6 +49,7 @@ public class MacOSXDynamicLinkerImpl implements DynamicLinker { // other words, one can actually link against the library instead of // having to dlsym all entry points. System.loadLibrary() uses // RTLD_LOCAL visibility so can't be used for this purpose. + SecurityUtil.checkLinkPermission(pathname); return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL); } diff --git a/src/java/jogamp/common/os/UnixDynamicLinkerImpl.java b/src/java/jogamp/common/os/UnixDynamicLinkerImpl.java index 29998bd..2258dfa 100644 --- a/src/java/jogamp/common/os/UnixDynamicLinkerImpl.java +++ b/src/java/jogamp/common/os/UnixDynamicLinkerImpl.java @@ -3,6 +3,7 @@ package jogamp.common.os; import com.jogamp.common.os.DynamicLinker; +import com.jogamp.common.util.SecurityUtil; public class UnixDynamicLinkerImpl implements DynamicLinker { @@ -27,7 +28,7 @@ public class UnixDynamicLinkerImpl implements DynamicLinker { // --- Begin CustomJavaCode .cfg declarations - public long openLibraryLocal(String pathname, boolean debug) { + public long openLibraryLocal(String pathname, boolean debug) throws SecurityException { // Note we use RTLD_GLOBAL visibility to _NOT_ allow this functionality to // be used to pre-resolve dependent libraries of JNI code without // requiring that all references to symbols in those libraries be @@ -35,10 +36,11 @@ public class UnixDynamicLinkerImpl implements DynamicLinker { // other words, one can actually link against the library instead of // having to dlsym all entry points. System.loadLibrary() uses // RTLD_LOCAL visibility so can't be used for this purpose. + SecurityUtil.checkLinkPermission(pathname); return dlopen(pathname, RTLD_LAZY | RTLD_LOCAL); } - public long openLibraryGlobal(String pathname, boolean debug) { + public long openLibraryGlobal(String pathname, boolean debug) throws SecurityException { // Note we use RTLD_GLOBAL visibility to allow this functionality to // be used to pre-resolve dependent libraries of JNI code without // requiring that all references to symbols in those libraries be @@ -46,6 +48,7 @@ public class UnixDynamicLinkerImpl implements DynamicLinker { // other words, one can actually link against the library instead of // having to dlsym all entry points. System.loadLibrary() uses // RTLD_LOCAL visibility so can't be used for this purpose. + SecurityUtil.checkLinkPermission(pathname); return dlopen(pathname, RTLD_LAZY | RTLD_GLOBAL); } diff --git a/src/java/jogamp/common/os/WindowsDynamicLinkerImpl.java b/src/java/jogamp/common/os/WindowsDynamicLinkerImpl.java index e7f5b52..eb02584 100644 --- a/src/java/jogamp/common/os/WindowsDynamicLinkerImpl.java +++ b/src/java/jogamp/common/os/WindowsDynamicLinkerImpl.java @@ -3,6 +3,7 @@ package jogamp.common.os; import com.jogamp.common.os.DynamicLinker; +import com.jogamp.common.util.SecurityUtil; public class WindowsDynamicLinkerImpl implements DynamicLinker { @@ -20,13 +21,14 @@ public class WindowsDynamicLinkerImpl implements DynamicLinker { // --- Begin CustomJavaCode .cfg declarations - public long openLibraryLocal(String libraryName, boolean debug) { + public long openLibraryLocal(String libraryName, boolean debug) throws SecurityException { // How does that work under Windows ? // Don't know .. so it's an alias for the time being return openLibraryGlobal(libraryName, debug); } - public long openLibraryGlobal(String libraryName, boolean debug) { + public long openLibraryGlobal(String libraryName, boolean debug) throws SecurityException { + SecurityUtil.checkLinkPermission(libraryName); long handle = LoadLibraryW(libraryName); if(0==handle && debug) { int err = GetLastError(); 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(); + } + +} diff --git a/test/applet/applet01.html b/test/applet/applet01.html new file mode 100644 index 0000000..df8a926 --- /dev/null +++ b/test/applet/applet01.html @@ -0,0 +1,11 @@ +<html> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> +<body> +<p> +Provoke AccessControlException while writing to file! +</p> +<applet code=com.jogamp.junit.sec.Applet01 width="200" height="200" + archive="jar/gluegen-rt.jar,gluegen-test.jar"> +</applet> +</body> +</html> diff --git a/test/applet/java.policy.applet b/test/applet/java.policy.applet new file mode 100644 index 0000000..a1ac2a0 --- /dev/null +++ b/test/applet/java.policy.applet @@ -0,0 +1,5 @@ + +grant codeBase "file:/home/sven/projects/JOGL/gluegen/test/applet/jar/*" { + permission java.security.AllPermission; +}; + diff --git a/test/applet/runapplet.sh b/test/applet/runapplet.sh new file mode 100644 index 0000000..cc14554 --- /dev/null +++ b/test/applet/runapplet.sh @@ -0,0 +1,17 @@ +#! /bin/bash + +RDIR=`pwd` + +rm -rf jar +rm -f gluegen-test.jar + +mkdir jar +cp ../../build/*jar jar/ +cp ../../build/test/build/gluegen-test.jar . + +/opt-linux-x86_64/jdk1.6.0_35/bin/java \ + -Djogamp.debug.IOUtil -Djogamp.debug.JNILibLoader -Djogamp.debug.TempFileCache -Djogamp.debug.JarUtil -Djogamp.debug.TempJarCache \ + -Djava.security.policy=$RDIR/java.policy.applet \ + -Dfile.encoding=UTF-8 \ + sun.applet.AppletViewer $RDIR/applet01.html + |