changeset 1962:77ea95965bad

Security patches for netx+plugin. 2009-08-05 Lillian Angel <langel@redhat.com> * plugin/icedtea/netscape/javascript/JSObject.java: Security patch applied to disallow the ability to run unsigned code as signed under some cases. * plugin/icedtea/sun/applet/PluginAppletSecurityContext.java: Likewise. * netx/net/sourceforge/jnlp/SecurityDesc.java: Likewise. * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: Likewise. * plugin/icedtea/netscape/javascript/JSObjectCreatePermission.java: Likewise. * netx/netscape/javascript/JSObjectCreatePermission.java: Likewise.
author Andrew John Hughes <ahughes@redhat.com>
date Wed, 05 Aug 2009 15:22:13 +0100
parents adadd58eff31
children a6ecfd52e2db
files ChangeLog netx/net/sourceforge/jnlp/SecurityDesc.java netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java netx/netscape/javascript/JSObjectCreatePermission.java plugin/icedtea/netscape/javascript/JSObject.java plugin/icedtea/netscape/javascript/JSObjectCreatePermission.java plugin/icedtea/sun/applet/PluginAppletSecurityContext.java
diffstat 7 files changed, 349 insertions(+), 169 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Aug 05 15:02:51 2009 +0100
+++ b/ChangeLog	Wed Aug 05 15:22:13 2009 +0100
@@ -1,3 +1,16 @@
+2009-08-05  Lillian Angel  <langel@redhat.com>
+
+	* plugin/icedtea/netscape/javascript/JSObject.java: Security patch
+	applied to disallow the ability to run unsigned code as 
+	signed under some cases.
+	* plugin/icedtea/sun/applet/PluginAppletSecurityContext.java:
+	Likewise.
+	* netx/net/sourceforge/jnlp/SecurityDesc.java: Likewise.
+	* netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: Likewise.
+	* plugin/icedtea/netscape/javascript/JSObjectCreatePermission.java:
+	Likewise.
+	* netx/netscape/javascript/JSObjectCreatePermission.java: Likewise.
+
 2009-08-04  Andrew John Hughes  <ahughes@redhat.com>
 
 	* Makefile.am:
--- a/netx/net/sourceforge/jnlp/SecurityDesc.java	Wed Aug 05 15:02:51 2009 +0100
+++ b/netx/net/sourceforge/jnlp/SecurityDesc.java	Wed Aug 05 15:22:13 2009 +0100
@@ -166,6 +166,30 @@
 
         return permissions;
     }
+    
+    /**
+     * Returns a PermissionCollection containing the sandbox permissions
+     */
+    public PermissionCollection getSandBoxPermissions() {
+        
+        Permissions permissions = new Permissions();
+
+        for (int i=0; i < sandboxPermissions.length; i++)
+            permissions.add(sandboxPermissions[i]);
+
+        if (downloadHost != null)
+            permissions.add(new SocketPermission(downloadHost,
+                                                 "connect, accept"));
+
+        // properties
+        PropertyDesc props[] = file.getResources().getProperties();
+        for (int i=0; i < props.length; i++) {
+            // should only allow jnlp.* properties if in sandbox?
+            permissions.add(new PropertyPermission(props[i].getKey(), "read,write"));
+        }
+
+        return permissions;
+    }
 
 }
 
--- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Wed Aug 05 15:02:51 2009 +0100
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java	Wed Aug 05 15:22:13 2009 +0100
@@ -1,15 +1,15 @@
 
-// 
+//
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
 // version 2.1 of the License, or (at your option) any later version.
-// 
+//
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 // Lesser General Public License for more details.
-// 
+//
 // You should have received a copy of the GNU Lesser General Public
 // License along with this library; if not, write to the Free Software
 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
@@ -66,7 +66,7 @@
  * security context when the classloader was created.
  *
  * @author <a href="mailto:jmaxwell@users.sourceforge.net">Jon A. Maxwell (JAM)</a> - initial author
- * @version $Revision: 1.20 $ 
+ * @version $Revision: 1.20 $
  */
 public class JNLPClassLoader extends URLClassLoader {
 
@@ -115,29 +115,29 @@
 
     /** the security section */
     private SecurityDesc security;
-    
+
     /** Permissions granted by the user during runtime. */
     private ArrayList<Permission> runtimePermissions = new ArrayList<Permission>();
 
     /** all jars not yet part of classloader or active */
     private List available = new ArrayList();
 
-	/** all of the jar files that were verified */
-	private ArrayList<String> verifiedJars = null;
+        /** all of the jar files that were verified */
+        private ArrayList<String> verifiedJars = null;
 
-	/** all of the jar files that were not verified */
-	private ArrayList<String> unverifiedJars = null;
+        /** all of the jar files that were not verified */
+        private ArrayList<String> unverifiedJars = null;
 
-	/** the jarsigner tool to verify our jars */
-	private JarSigner js = null;
+        /** the jarsigner tool to verify our jars */
+        private JarSigner js = null;
+
+        private boolean signing = false;
 
-	private boolean signing = false;
-	
-	/** ArrayList containing jar indexes for various jars available to this classloader */
-	private ArrayList<JarIndex> jarIndexes = new ArrayList<JarIndex>();
-	
-	/** File entries in the jar files available to this classloader */
-	private TreeSet jarEntries = new TreeSet();
+        /** ArrayList containing jar indexes for various jars available to this classloader */
+        private ArrayList<JarIndex> jarIndexes = new ArrayList<JarIndex>();
+
+        /** File entries in the jar files available to this classloader */
+        private TreeSet jarEntries = new TreeSet();
 
     /**
      * Create a new JNLPClassLoader from the specified file.
@@ -167,41 +167,41 @@
     }
 
     private void setSecurity() {
-		/**
-		 * When we're trying to load an applet, file.getSecurity() will return
-		 * null since there is no jnlp file to specify permissions. We
-		 * determine security settings here, after trying to verify jars.
-		 */
-		if (file instanceof PluginBridge) {
-			if (signing == true) {
-				this.security = new SecurityDesc(file, 
-					SecurityDesc.ALL_PERMISSIONS,
-					file.getCodeBase().getHost());
-			} else {
-				this.security = new SecurityDesc(file, 
-					SecurityDesc.SANDBOX_PERMISSIONS, 
-					file.getCodeBase().getHost());
-			}
-		} else { //regular jnlp file
-			
-			/**
-			 * If the application is signed, then we set the SecurityDesc to the
-			 * <security> tag in the jnlp file. Note that if an application is
-			 * signed, but there is no <security> tag in the jnlp file, the
-			 * application will get sandbox permissions.
-			 * If the application is unsigned, we ignore the <security> tag and 
-			 * use a sandbox instead. 
-			 */
-			if (signing == true) {
-				this.security = file.getSecurity();
-			} else {
-				this.security = new SecurityDesc(file, 
-						SecurityDesc.SANDBOX_PERMISSIONS, 
-						file.getCodeBase().getHost());
-			}
-		}
+                /**
+                 * When we're trying to load an applet, file.getSecurity() will return
+                 * null since there is no jnlp file to specify permissions. We
+                 * determine security settings here, after trying to verify jars.
+                 */
+                if (file instanceof PluginBridge) {
+                        if (signing == true) {
+                                this.security = new SecurityDesc(file,
+                                        SecurityDesc.ALL_PERMISSIONS,
+                                        file.getCodeBase().getHost());
+                        } else {
+                                this.security = new SecurityDesc(file,
+                                        SecurityDesc.SANDBOX_PERMISSIONS,
+                                        file.getCodeBase().getHost());
+                        }
+                } else { //regular jnlp file
+
+                        /**
+                         * If the application is signed, then we set the SecurityDesc to the
+                         * <security> tag in the jnlp file. Note that if an application is
+                         * signed, but there is no <security> tag in the jnlp file, the
+                         * application will get sandbox permissions.
+                         * If the application is unsigned, we ignore the <security> tag and
+                         * use a sandbox instead.
+                         */
+                        if (signing == true) {
+                                this.security = file.getSecurity();
+                        } else {
+                                this.security = new SecurityDesc(file,
+                                                SecurityDesc.SANDBOX_PERMISSIONS,
+                                                file.getCodeBase().getHost());
+                        }
+                }
     }
-    
+
     /**
      * Returns a JNLP classloader for the specified JNLP file.
      *
@@ -215,12 +215,12 @@
         if (location != null)
             loader = (JNLPClassLoader) urlToLoader.get(location);
 
-		try {
-        	if (loader == null)
-            	loader = new JNLPClassLoader(file, policy);
-		} catch (LaunchException e) {
-			throw e;
-		}
+                try {
+                if (loader == null)
+                loader = new JNLPClassLoader(file, policy);
+                } catch (LaunchException e) {
+                        throw e;
+                }
 
         if (file.getInformation().isSharingAllowed())
             urlToLoader.put(location, loader);
@@ -230,7 +230,7 @@
 
     /**
      * Returns a JNLP classloader for the JNLP file at the specified
-     * location. 
+     * location.
      *
      * @param location the file's location
      * @param version the file's version
@@ -256,17 +256,17 @@
 
         loaderList.add(this);
 
-		//if (ext != null) {
-        	for (int i=0; i < ext.length; i++) {
-            	try {
-               		JNLPClassLoader loader = getInstance(ext[i].getLocation(), ext[i].getVersion(), updatePolicy);
-                	loaderList.add(loader);
-            	}
-            	catch (Exception ex) {
-                	ex.printStackTrace();
-            	}
-        	}
-		//}
+                //if (ext != null) {
+                for (int i=0; i < ext.length; i++) {
+                try {
+                        JNLPClassLoader loader = getInstance(ext[i].getLocation(), ext[i].getVersion(), updatePolicy);
+                        loaderList.add(loader);
+                }
+                catch (Exception ex) {
+                        ex.printStackTrace();
+                }
+                }
+                //}
 
         loaders = (JNLPClassLoader[]) loaderList.toArray(new JNLPClassLoader[ loaderList.size()]);
     }
@@ -283,10 +283,10 @@
                                                        jars[i].getVersion());
 
             if (JNLPRuntime.isDebug()) {
-            	if (p == null)
-            		System.out.println("Unable to add permission for " + jars[i].getLocation());
-            	else
-            		System.out.println("Permission added: " + p.toString());
+                if (p == null)
+                        System.out.println("Unable to add permission for " + jars[i].getLocation());
+                else
+                        System.out.println("Permission added: " + p.toString());
             }
             if (p != null)
                 resourcePermissions.add(p);
@@ -299,14 +299,14 @@
      */
     void initializeResources() throws LaunchException {
         JARDesc jars[] = resources.getJARs();
-		if (jars == null || jars.length == 0)
-			return;
-		/*
-		if (jars == null || jars.length == 0) {
-			throw new LaunchException(null, null, R("LSFatal"),
-			                    R("LCInit"), R("LFatalVerification"), "No jars!");
-		}
-		*/
+                if (jars == null || jars.length == 0)
+                        return;
+                /*
+                if (jars == null || jars.length == 0) {
+                        throw new LaunchException(null, null, R("LSFatal"),
+                                            R("LCInit"), R("LFatalVerification"), "No jars!");
+                }
+                */
         List initialJars = new ArrayList();
 
         for (int i=0; i < jars.length; i++) {
@@ -317,7 +317,7 @@
                 initialJars.add(jars[i]); // regardless of part
 
             tracker.addResource(jars[i].getLocation(),
-                                jars[i].getVersion(), 
+                                jars[i].getVersion(),
                                 jars[i].isCacheable() ? JNLPRuntime.getDefaultUpdatePolicy() : UpdatePolicy.FORCE
                                );
         }
@@ -325,42 +325,42 @@
         if (strict)
             fillInPartJars(initialJars); // add in each initial part's lazy jars
 
-		if (JNLPRuntime.isVerifying()) {
+                if (JNLPRuntime.isVerifying()) {
 
-			JarSigner js;
-			waitForJars(initialJars); //download the jars first.
+                        JarSigner js;
+                        waitForJars(initialJars); //download the jars first.
 
-			try {
-				js = verifyJars(initialJars);
-			} catch (Exception e) {
-				//we caught an Exception from the JarSigner class.
-				//Note: one of these exceptions could be from not being able
-				//to read the cacerts or trusted.certs files.
-				e.printStackTrace();
-				throw new LaunchException(null, null, R("LSFatal"),
-					R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo"));
-			}
+                        try {
+                                js = verifyJars(initialJars);
+                        } catch (Exception e) {
+                                //we caught an Exception from the JarSigner class.
+                                //Note: one of these exceptions could be from not being able
+                                //to read the cacerts or trusted.certs files.
+                                e.printStackTrace();
+                                throw new LaunchException(null, null, R("LSFatal"),
+                                        R("LCInit"), R("LFatalVerification"), R("LFatalVerificationInfo"));
+                        }
 
-			//Case when at least one jar has some signing
-			if (js.anyJarsSigned()){
-				signing = true;
+                        //Case when at least one jar has some signing
+                        if (js.anyJarsSigned()){
+                                signing = true;
 
-				//user does not trust this publisher
-				if (!js.getAlreadyTrustPublisher()) {
-				    checkTrustWithUser(js);
-				} else {
-					/**
-					 * If the user trusts this publisher (i.e. the publisher's certificate
-					 * is in the user's trusted.certs file), we do not show any dialogs.
-					 */
-				}
-			} else {
+                                //user does not trust this publisher
+                                if (!js.getAlreadyTrustPublisher()) {
+                                    checkTrustWithUser(js);
+                                } else {
+                                        /**
+                                         * If the user trusts this publisher (i.e. the publisher's certificate
+                                         * is in the user's trusted.certs file), we do not show any dialogs.
+                                         */
+                                }
+                        } else {
 
-				signing = false;
-				//otherwise this jar is simply unsigned -- make sure to ask
-				//for permission on certain actions
-			}
-		}
+                                signing = false;
+                                //otherwise this jar is simply unsigned -- make sure to ask
+                                //for permission on certain actions
+                        }
+                }
 
         activateJars(initialJars);
     }
@@ -370,7 +370,7 @@
             boolean b = SecurityWarningDialog.showCertWarningDialog(
                 SecurityWarningDialog.AccessType.UNVERIFIED, file, js);
             if (!b)
-                throw new LaunchException(null, null, R("LSFatal"), 
+                throw new LaunchException(null, null, R("LSFatal"),
                     R("LCLaunching"), R("LNotVerified"), "");
         } else if (js.getRootInCacerts()) { //root cert is in cacerts
             boolean b = false;
@@ -435,11 +435,29 @@
         // access w/o security dialog once we actually check certificates.
 
         // copy security permissions from SecurityDesc element
-		if (security != null) {
-        	Enumeration e = security.getPermissions().elements();
-        	while (e.hasMoreElements())
-            	result.add((Permission) e.nextElement());
-		}
+        if (security != null) {
+            // Security desc. is used only to track security settings for the
+            // application. However, an application may comprise of multiple
+            // jars, and as such, security must be evaluated on a per jar basis.
+
+            // set default perms
+            PermissionCollection permissions = security.getSandBoxPermissions();
+
+            // If more than default is needed, evaluate based on codesource
+            if (security.getSecurityType().equals(SecurityDesc.ALL_PERMISSIONS) ||
+                security.getSecurityType().equals(SecurityDesc.J2EE_PERMISSIONS)) {
+
+                 if (cs.getCodeSigners() != null) {
+                    permissions = security.getPermissions();
+                }
+            }
+
+            Enumeration<Permission> e = permissions.elements();
+            while (e.hasMoreElements())
+                result.add(e.nextElement());
+        }
+
+
 
         // add in permission to read the cached JAR files
         for (int i=0; i < resourcePermissions.size(); i++)
@@ -447,15 +465,15 @@
 
         // add in the permissions that the user granted.
         for (int i=0; i < runtimePermissions.size(); i++)
-        	result.add(runtimePermissions.get(i));
+                result.add(runtimePermissions.get(i));
 
         return result;
     }
 
     protected void addPermission(Permission p) {
-    	runtimePermissions.add(p);
+        runtimePermissions.add(p);
     }
-    
+
     /**
      * Adds to the specified list of JARS any other JARs that need
      * to be loaded at the same time as the JARs specified (ie, are
@@ -501,25 +519,25 @@
                         URL location = jar.getLocation(); // non-cacheable, use source location
                         if (localFile != null) {
                             location = localFile.toURL(); // cached file
-                            
-                            // This is really not the best way.. but we need some way for 
-                            // PluginAppletViewer::getCachedImageRef() to check if the image 
-                            // is available locally, and it cannot use getResources() because 
-                            // that prefetches the resource, which confuses MediaTracker.waitForAll() 
-                            // which does a wait(), waiting for notification (presumably 
+
+                            // This is really not the best way.. but we need some way for
+                            // PluginAppletViewer::getCachedImageRef() to check if the image
+                            // is available locally, and it cannot use getResources() because
+                            // that prefetches the resource, which confuses MediaTracker.waitForAll()
+                            // which does a wait(), waiting for notification (presumably
                             // thrown after a resource is fetched). This bug manifests itself
                             // particularly when using The FileManager applet from Webmin.
-                            
+
                             JarFile jarFile = new JarFile(localFile);
                             Enumeration e = jarFile.entries();
                             while (e.hasMoreElements()) {
-                                
+
                                 JarEntry je = (JarEntry) e.nextElement();
-                                
-                                // another jar in my jar? it is more likely than you think  
+
+                                // another jar in my jar? it is more likely than you think
                                 if (je.getName().endsWith(".jar")) {
-                                    // We need to extract that jar so that it can be loaded 
-                                    // (inline loading with "jar:..!/..." path will not work 
+                                    // We need to extract that jar so that it can be loaded
+                                    // (inline loading with "jar:..!/..." path will not work
                                     // with standard classloader methods)
 
                                     String extractedJarLocation = localFile.getParent() + "/" + je.getName();
@@ -564,7 +582,7 @@
 
                         addURL(location);
 
-                        // there is currently no mechanism to cache files per 
+                        // there is currently no mechanism to cache files per
                         // instance.. so only index cached files
                         if (localFile != null) {
                             JarIndex index = JarIndex.getJarIndex(new JarFile(localFile.getAbsolutePath()), null);
@@ -636,11 +654,11 @@
      * calls.
      */
     protected File getNativeDir() {
-        nativeDir = new File(System.getProperty("java.io.tmpdir") 
-                             + File.separator + "netx-native-" 
+        nativeDir = new File(System.getProperty("java.io.tmpdir")
+                             + File.separator + "netx-native-"
                              + (new Random().nextInt() & 0xFFFF));
 
-        if (!nativeDir.mkdirs()) 
+        if (!nativeDir.mkdirs())
             return null;
         else
             return nativeDir;
@@ -703,16 +721,16 @@
     }
 
     /**
-	 * Verifies code signing of jars to be used.
-	 *
-	 * @param jars the jars to be verified.
-	 */
-	private JarSigner verifyJars(List<JARDesc> jars) throws Exception {
-	
-		js = new JarSigner();
-		js.verifyJars(jars, tracker);
-		return js;
-	}
+         * Verifies code signing of jars to be used.
+         *
+         * @param jars the jars to be verified.
+         */
+        private JarSigner verifyJars(List<JARDesc> jars) throws Exception {
+
+                js = new JarSigner();
+                js.verifyJars(jars, tracker);
+                return js;
+        }
 
     /**
      * Find the loaded class in this loader or any of its extension loaders.
@@ -765,7 +783,7 @@
 
                 // Not found in external loader either. As a last resort, look in any available indexes
 
-                // Currently this loads jars directly from the site. We cannot cache it because this 
+                // Currently this loads jars directly from the site. We cannot cache it because this
                 // call is initiated from within the applet, which does not have disk read/write permissions
                 for (JarIndex index: jarIndexes) {
                     LinkedList<String> jarList = index.get(name.replace('.', '/'));
@@ -783,7 +801,7 @@
                             available.add(desc);
 
                             tracker.addResource(desc.getLocation(),
-                                    desc.getVersion(), 
+                                    desc.getVersion(),
                                     JNLPRuntime.getDefaultUpdatePolicy()
                             );
 
@@ -807,7 +825,7 @@
 
                         }
 
-                        // If it still fails, let it error out                        
+                        // If it still fails, let it error out
                         result = loadClassExt(name);
                     }
                 }
@@ -891,7 +909,7 @@
 
             if (loaders[i] == this)
                 e = super.findResources(name);
-            else 
+            else
                 e = loaders[i].findResources(name);
 
             while (e.hasMoreElements())
@@ -900,10 +918,10 @@
 
         return resources.elements();
     }
-    
+
     /**
      * Returns if the specified resource is available locally from a cached jar
-     * 
+     *
      * @param s The name of the resource
      * @return Whether or not the resource is available locally
      */
@@ -949,8 +967,8 @@
 
         fillInPartJars(jars);
 
-		
-		activateJars(jars);
+
+                activateJars(jars);
 
         return this;
     }
@@ -979,13 +997,13 @@
         return file.getFileLocation().toString();
     }
 
-	public boolean getSigning() {
-		return signing;
-	}
+        public boolean getSigning() {
+                return signing;
+        }
 
-	protected SecurityDesc getSecurity() {
-		return security;
-	}
+        protected SecurityDesc getSecurity() {
+                return security;
+        }
 }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/netscape/javascript/JSObjectCreatePermission.java	Wed Aug 05 15:22:13 2009 +0100
@@ -0,0 +1,47 @@
+/* JSObjectCreatePermission.java
+   Copyright (C) 2009  Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+ 
+package netscape.javascript;
+
+import java.security.BasicPermission;
+
+
+public class JSObjectCreatePermission extends BasicPermission {
+    public JSObjectCreatePermission() {
+        super("JSObjectCreate");
+    }
+}
--- a/plugin/icedtea/netscape/javascript/JSObject.java	Wed Aug 05 15:02:51 2009 +0100
+++ b/plugin/icedtea/netscape/javascript/JSObject.java	Wed Aug 05 15:22:13 2009 +0100
@@ -47,6 +47,10 @@
 package netscape.javascript;
 
 import java.applet.Applet;
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.BasicPermission;
 
 import sun.applet.PluginAppletViewer;
 import sun.applet.PluginDebug;
@@ -102,13 +106,37 @@
     /**
      * it is illegal to construct a JSObject manually
      */
-    // FIXME: make private!
     public JSObject(int jsobj_addr) {
-        PluginDebug.debug ("JSObject int CONSTRUCTOR");
-        internal = jsobj_addr;
+        this((long) jsobj_addr);
     }
 
     public JSObject(long jsobj_addr) {
+        
+        // See if the caller has permission
+        
+        try {
+            AccessController.getContext().checkPermission(new JSObjectCreatePermission());
+        } catch (AccessControlException ace) {
+            
+            // If not, only caller with JSObject.getWindow on the stack may 
+            // make this call unprivileged.
+            
+            // Although this check is inefficient, it should happen only once
+            // during applet init, so we look the other way
+
+            StackTraceElement[] stack =  Thread.currentThread().getStackTrace();
+            boolean mayProceed = false;
+            
+            for (int i=0; i < stack.length; i++) {
+                if (stack[i].getClassName().equals("netscape.javascript.JSObject") &&
+                    stack[i].getMethodName().equals("getWindow")) {
+                    mayProceed = true;
+                }
+            }
+
+            if (!mayProceed) throw ace;
+        }
+
         PluginDebug.debug ("JSObject long CONSTRUCTOR");
         internal = jsobj_addr;
     }
@@ -234,7 +262,7 @@
         internal = ((PluginAppletViewer)
                     applet.getAppletContext()).getWindow();
         PluginDebug.debug ("GOT IT: " + internal);
-        return new JSObject(internal);
+        return new JSObject((long) internal);
     }
 
 
@@ -259,5 +287,4 @@
 
         return false;
     }
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin/icedtea/netscape/javascript/JSObjectCreatePermission.java	Wed Aug 05 15:22:13 2009 +0100
@@ -0,0 +1,47 @@
+/* JSObjectCreatePermission.java
+   Copyright (C) 2009  Red Hat
+
+This file is part of IcedTea.
+
+IcedTea is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+IcedTea is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with IcedTea; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+ 
+package netscape.javascript;
+
+import java.security.BasicPermission;
+
+
+public class JSObjectCreatePermission extends BasicPermission {
+    public JSObjectCreatePermission() {
+        super("JSObjectCreate");
+    }
+}
--- a/plugin/icedtea/sun/applet/PluginAppletSecurityContext.java	Wed Aug 05 15:02:51 2009 +0100
+++ b/plugin/icedtea/sun/applet/PluginAppletSecurityContext.java	Wed Aug 05 15:22:13 2009 +0100
@@ -58,6 +58,7 @@
 import java.util.List;
 
 import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import netscape.javascript.JSObjectCreatePermission;
 
 
 
@@ -1285,12 +1286,15 @@
 
 		CodeSource cs = new CodeSource((URL) null, (java.security.cert.Certificate  [])null);
 		
-		if (src != null) {
+		if (src != null && src.length() > 0) {
 			try {
 				cs = new CodeSource(new URL(src + "/"), (java.security.cert.Certificate[]) null);
 			} catch (MalformedURLException mfue) {
 				// do nothing
 			}
+		} else {
+		    JSObjectCreatePermission perm = new JSObjectCreatePermission();
+		    grantedPermissions.add(perm);
 		}
 
 		ProtectionDomain pd = new ProtectionDomain(cs, grantedPermissions, null, null);