Merge
diff --git a/src/share/bin/emessages.h b/src/share/bin/emessages.h
index 311a8fa..dfb95a6 100644
--- a/src/share/bin/emessages.h
+++ b/src/share/bin/emessages.h
@@ -50,6 +50,12 @@
#define JAR_ERROR2 "Error: Unable to access jarfile %s"
#define JAR_ERROR3 "Error: Invalid or corrupt jarfile %s"
+#define CLS_ERROR1 "Error: Could not find the main class %s.\n" JNI_ERROR
+#define CLS_ERROR2 "Error: Failed to load Main Class: %s\n%s"
+#define CLS_ERROR3 "Error: No main method found in specified class.\n" GEN_ERROR
+#define CLS_ERROR4 "Error: Main method not public\n" GEN_ERROR
+#define CLS_ERROR5 "Error: main-class: attribute exceeds system limits of %d bytes\n" GEN_ERROR
+
#define CFG_WARN1 "Warning: %s VM not supported; %s VM will be used"
#define CFG_WARN2 "Warning: No leading - on line %d of `%s'"
#define CFG_WARN3 "Warning: Missing VM type on line %d of `%s'"
diff --git a/src/share/bin/java.c b/src/share/bin/java.c
index 0feafc1..1801633 100644
--- a/src/share/bin/java.c
+++ b/src/share/bin/java.c
@@ -915,8 +915,14 @@
* to avoid locating, expanding and parsing the manifest extra
* times.
*/
- if (info.main_class != NULL)
- (void)JLI_StrCat(env_entry, info.main_class);
+ if (info.main_class != NULL) {
+ if (JLI_StrLen(info.main_class) <= MAXNAMELEN) {
+ (void)JLI_StrCat(env_entry, info.main_class);
+ } else {
+ JLI_ReportErrorMessage(CLS_ERROR5, MAXNAMELEN);
+ exit(1);
+ }
+ }
(void)putenv(env_entry);
ExecJRE(jre, new_argv);
JLI_FreeManifest();
diff --git a/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java b/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java
index cb94371..e10773a 100644
--- a/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java
+++ b/src/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java
@@ -22,7 +22,6 @@
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
-
package com.sun.jmx.remote.internal;
import java.io.IOException;
@@ -34,6 +33,7 @@
import java.util.Map;
import java.util.concurrent.Executor;
+import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.security.auth.Subject;
@@ -54,7 +54,10 @@
public abstract class ClientNotifForwarder {
- public ClientNotifForwarder(Map<String, ?> env) {
+
+ private final AccessControlContext acc;
+
+ public ClientNotifForwarder(Map env) {
this(null, env);
}
@@ -87,6 +90,8 @@
this.command = command;
if (thread == null) {
thread = new Thread() {
+
+ @Override
public void run() {
while (true) {
Runnable r;
@@ -130,6 +135,7 @@
this.defaultClassLoader = defaultClassLoader;
this.executor = ex;
+ this.acc = AccessController.getContext();
}
/**
@@ -380,28 +386,85 @@
setState(TERMINATED);
}
-// -------------------------------------------------
-// private classes
-// -------------------------------------------------
+
+ // -------------------------------------------------
+ // private classes
+ // -------------------------------------------------
//
+
private class NotifFetcher implements Runnable {
+
+ private volatile boolean alreadyLogged = false;
+
+ private void logOnce(String msg, SecurityException x) {
+ if (alreadyLogged) return;
+ // Log only once.
+ logger.config("setContextClassLoader",msg);
+ if (x != null) logger.fine("setContextClassLoader", x);
+ alreadyLogged = true;
+ }
+
+ // Set new context class loader, returns previous one.
+ private final ClassLoader setContextClassLoader(final ClassLoader loader) {
+ final AccessControlContext ctxt = ClientNotifForwarder.this.acc;
+ // if ctxt is null, log a config message and throw a
+ // SecurityException.
+ if (ctxt == null) {
+ logOnce("AccessControlContext must not be null.",null);
+ throw new SecurityException("AccessControlContext must not be null");
+ }
+ return AccessController.doPrivileged(
+ new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ try {
+ // get context class loader - may throw
+ // SecurityException - though unlikely.
+ final ClassLoader previous =
+ Thread.currentThread().getContextClassLoader();
+
+ // if nothing needs to be done, break here...
+ if (loader == previous) return previous;
+
+ // reset context class loader - may throw
+ // SecurityException
+ Thread.currentThread().setContextClassLoader(loader);
+ return previous;
+ } catch (SecurityException x) {
+ logOnce("Permission to set ContextClassLoader missing. " +
+ "Notifications will not be dispatched. " +
+ "Please check your Java policy configuration: " +
+ x, x);
+ throw x;
+ }
+ }
+ }, ctxt);
+ }
+
public void run() {
+ final ClassLoader previous;
+ if (defaultClassLoader != null) {
+ previous = setContextClassLoader(defaultClassLoader);
+ } else {
+ previous = null;
+ }
+ try {
+ doRun();
+ } finally {
+ if (defaultClassLoader != null) {
+ setContextClassLoader(previous);
+ }
+ }
+ }
+
+ private void doRun() {
synchronized (ClientNotifForwarder.this) {
currentFetchThread = Thread.currentThread();
- if (state == STARTING)
+ if (state == STARTING) {
setState(STARTED);
+ }
}
- if (defaultClassLoader != null) {
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run() {
- Thread.currentThread().
- setContextClassLoader(defaultClassLoader);
- return null;
- }
- });
- }
NotificationResult nr = null;
if (!shouldStop() && (nr = fetchNotifs()) != null) {
@@ -434,8 +497,9 @@
// check if an mbean unregistration notif
if (!listenerID.equals(mbeanRemovedNotifID)) {
final ClientListenerInfo li = infoList.get(listenerID);
- if (li != null)
- listeners.put(listenerID,li);
+ if (li != null) {
+ listeners.put(listenerID, li);
+ }
continue;
}
final Notification notif = tn.getNotification();
@@ -799,9 +863,7 @@
private long clientSequenceNumber = -1;
private final int maxNotifications;
private final long timeout;
-
private Integer mbeanRemovedNotifID = null;
-
private Thread currentFetchThread;
// state
diff --git a/src/share/classes/com/sun/jmx/remote/security/MBeanServerAccessController.java b/src/share/classes/com/sun/jmx/remote/security/MBeanServerAccessController.java
index d75f829..71e6f6f 100644
--- a/src/share/classes/com/sun/jmx/remote/security/MBeanServerAccessController.java
+++ b/src/share/classes/com/sun/jmx/remote/security/MBeanServerAccessController.java
@@ -111,6 +111,22 @@
*/
protected abstract void checkWrite();
+ /**
+ * Check if the caller can create the named class. The default
+ * implementation of this method calls {@link #checkWrite()}.
+ */
+ protected void checkCreate(String className) {
+ checkWrite();
+ }
+
+ /**
+ * Check if the caller can unregister the named MBean. The default
+ * implementation of this method calls {@link #checkWrite()}.
+ */
+ protected void checkUnregister(ObjectName name) {
+ checkWrite();
+ }
+
//--------------------------------------------
//--------------------------------------------
//
@@ -148,7 +164,7 @@
}
/**
- * Call <code>checkWrite()</code>, then forward this method to the
+ * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public ObjectInstance createMBean(String className, ObjectName name)
@@ -158,7 +174,7 @@
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException {
- checkWrite();
+ checkCreate(className);
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
Object object = getMBeanServer().instantiate(className);
@@ -170,7 +186,7 @@
}
/**
- * Call <code>checkWrite()</code>, then forward this method to the
+ * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public ObjectInstance createMBean(String className, ObjectName name,
@@ -181,7 +197,7 @@
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException {
- checkWrite();
+ checkCreate(className);
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
Object object = getMBeanServer().instantiate(className,
@@ -196,7 +212,7 @@
}
/**
- * Call <code>checkWrite()</code>, then forward this method to the
+ * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public ObjectInstance createMBean(String className,
@@ -209,7 +225,7 @@
MBeanException,
NotCompliantMBeanException,
InstanceNotFoundException {
- checkWrite();
+ checkCreate(className);
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
Object object = getMBeanServer().instantiate(className,
@@ -222,7 +238,7 @@
}
/**
- * Call <code>checkWrite()</code>, then forward this method to the
+ * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public ObjectInstance createMBean(String className,
@@ -237,7 +253,7 @@
MBeanException,
NotCompliantMBeanException,
InstanceNotFoundException {
- checkWrite();
+ checkCreate(className);
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
Object object = getMBeanServer().instantiate(className,
@@ -394,45 +410,45 @@
}
/**
- * Call <code>checkWrite()</code>, then forward this method to the
+ * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className)
throws ReflectionException, MBeanException {
- checkWrite();
+ checkCreate(className);
return getMBeanServer().instantiate(className);
}
/**
- * Call <code>checkWrite()</code>, then forward this method to the
+ * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className,
Object params[],
String signature[])
throws ReflectionException, MBeanException {
- checkWrite();
+ checkCreate(className);
return getMBeanServer().instantiate(className, params, signature);
}
/**
- * Call <code>checkWrite()</code>, then forward this method to the
+ * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className, ObjectName loaderName)
throws ReflectionException, MBeanException, InstanceNotFoundException {
- checkWrite();
+ checkCreate(className);
return getMBeanServer().instantiate(className, loaderName);
}
/**
- * Call <code>checkWrite()</code>, then forward this method to the
+ * Call <code>checkCreate(className)</code>, then forward this method to the
* wrapped object.
*/
public Object instantiate(String className, ObjectName loaderName,
Object params[], String signature[])
throws ReflectionException, MBeanException, InstanceNotFoundException {
- checkWrite();
+ checkCreate(className);
return getMBeanServer().instantiate(className, loaderName,
params, signature);
}
@@ -579,12 +595,12 @@
}
/**
- * Call <code>checkWrite()</code>, then forward this method to the
+ * Call <code>checkUnregister()</code>, then forward this method to the
* wrapped object.
*/
public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException, MBeanRegistrationException {
- checkWrite();
+ checkUnregister(name);
getMBeanServer().unregisterMBean(name);
}
diff --git a/src/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java b/src/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java
index 66c78f2..a753e3a 100644
--- a/src/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java
+++ b/src/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java
@@ -31,11 +31,17 @@
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedAction;
-import java.util.Collection;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.Properties;
import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
import javax.management.MBeanServer;
+import javax.management.ObjectName;
import javax.security.auth.Subject;
/**
@@ -46,7 +52,8 @@
* not allowed; in this case the request is not forwarded to the
* wrapped object.</p>
*
- * <p>This class implements the {@link #checkRead()} and {@link #checkWrite()}
+ * <p>This class implements the {@link #checkRead()}, {@link #checkWrite()},
+ * {@link #checkCreate(String)}, and {@link #checkUnregister(ObjectName)}
* methods based on an access level properties file containing username/access
* level pairs. The set of username/access level pairs is passed either as a
* filename which denotes a properties file on disk, or directly as an instance
@@ -56,14 +63,50 @@
* has exactly one access level. The same access level can be shared by several
* usernames.</p>
*
- * <p>The supported access level values are <i>readonly</i> and
- * <i>readwrite</i>.</p>
+ * <p>The supported access level values are {@code readonly} and
+ * {@code readwrite}. The {@code readwrite} access level can be
+ * qualified by one or more <i>clauses</i>, where each clause looks
+ * like <code>create <i>classNamePattern</i></code> or {@code
+ * unregister}. For example:</p>
+ *
+ * <pre>
+ * monitorRole readonly
+ * controlRole readwrite \
+ * create javax.management.timer.*,javax.management.monitor.* \
+ * unregister
+ * </pre>
+ *
+ * <p>(The continuation lines with {@code \} come from the parser for
+ * Properties files.)</p>
*/
public class MBeanServerFileAccessController
extends MBeanServerAccessController {
- public static final String READONLY = "readonly";
- public static final String READWRITE = "readwrite";
+ static final String READONLY = "readonly";
+ static final String READWRITE = "readwrite";
+
+ static final String CREATE = "create";
+ static final String UNREGISTER = "unregister";
+
+ private enum AccessType {READ, WRITE, CREATE, UNREGISTER};
+
+ private static class Access {
+ final boolean write;
+ final String[] createPatterns;
+ private boolean unregister;
+
+ Access(boolean write, boolean unregister, List<String> createPatternList) {
+ this.write = write;
+ int npats = (createPatternList == null) ? 0 : createPatternList.size();
+ if (npats == 0)
+ this.createPatterns = NO_STRINGS;
+ else
+ this.createPatterns = createPatternList.toArray(new String[npats]);
+ this.unregister = unregister;
+ }
+
+ private final String[] NO_STRINGS = new String[0];
+ }
/**
* <p>Create a new MBeanServerAccessController that forwards all the
@@ -87,8 +130,8 @@
throws IOException {
super();
this.accessFileName = accessFileName;
- props = propertiesFromFile(accessFileName);
- checkValues(props);
+ Properties props = propertiesFromFile(accessFileName);
+ parseProperties(props);
}
/**
@@ -123,14 +166,14 @@
* #setMBeanServer} method after doing access checks based on read and
* write permissions.</p>
*
- * <p>This instance is initialized from the specified properties instance.
- * This constructor makes a copy of the properties instance using its
- * <code>clone</code> method and it is the copy that is consulted to check
- * the username and access level of an incoming connection. The original
- * properties object can be modified without affecting the copy. If the
- * {@link #refresh} method is then called, the
- * <code>MBeanServerFileAccessController</code> will make a new copy of the
- * properties object at that time.</p>
+ * <p>This instance is initialized from the specified properties
+ * instance. This constructor makes a copy of the properties
+ * instance and it is the copy that is consulted to check the
+ * username and access level of an incoming connection. The
+ * original properties object can be modified without affecting
+ * the copy. If the {@link #refresh} method is then called, the
+ * <code>MBeanServerFileAccessController</code> will make a new
+ * copy of the properties object at that time.</p>
*
* @param accessFileProps properties list containing the username/access
* level entries.
@@ -145,8 +188,7 @@
if (accessFileProps == null)
throw new IllegalArgumentException("Null properties");
originalProps = accessFileProps;
- props = (Properties) accessFileProps.clone();
- checkValues(props);
+ parseProperties(accessFileProps);
}
/**
@@ -155,14 +197,14 @@
* #setMBeanServer} method after doing access checks based on read and
* write permissions.</p>
*
- * <p>This instance is initialized from the specified properties instance.
- * This constructor makes a copy of the properties instance using its
- * <code>clone</code> method and it is the copy that is consulted to check
- * the username and access level of an incoming connection. The original
- * properties object can be modified without affecting the copy. If the
- * {@link #refresh} method is then called, the
- * <code>MBeanServerFileAccessController</code> will make a new copy of the
- * properties object at that time.</p>
+ * <p>This instance is initialized from the specified properties
+ * instance. This constructor makes a copy of the properties
+ * instance and it is the copy that is consulted to check the
+ * username and access level of an incoming connection. The
+ * original properties object can be modified without affecting
+ * the copy. If the {@link #refresh} method is then called, the
+ * <code>MBeanServerFileAccessController</code> will make a new
+ * copy of the properties object at that time.</p>
*
* @param accessFileProps properties list containing the username/access
* level entries.
@@ -184,16 +226,36 @@
* Check if the caller can do read operations. This method does
* nothing if so, otherwise throws SecurityException.
*/
+ @Override
public void checkRead() {
- checkAccessLevel(READONLY);
+ checkAccess(AccessType.READ, null);
}
/**
* Check if the caller can do write operations. This method does
* nothing if so, otherwise throws SecurityException.
*/
+ @Override
public void checkWrite() {
- checkAccessLevel(READWRITE);
+ checkAccess(AccessType.WRITE, null);
+ }
+
+ /**
+ * Check if the caller can create MBeans or instances of the given class.
+ * This method does nothing if so, otherwise throws SecurityException.
+ */
+ @Override
+ public void checkCreate(String className) {
+ checkAccess(AccessType.CREATE, className);
+ }
+
+ /**
+ * Check if the caller can do unregister operations. This method does
+ * nothing if so, otherwise throws SecurityException.
+ */
+ @Override
+ public void checkUnregister(ObjectName name) {
+ checkAccess(AccessType.UNREGISTER, null);
}
/**
@@ -218,14 +280,13 @@
* @exception IllegalArgumentException if any of the supplied access
* level values differs from "readonly" or "readwrite".
*/
- public void refresh() throws IOException {
- synchronized (props) {
- if (accessFileName == null)
- props = (Properties) originalProps.clone();
- else
- props = propertiesFromFile(accessFileName);
- checkValues(props);
- }
+ public synchronized void refresh() throws IOException {
+ Properties props;
+ if (accessFileName == null)
+ props = (Properties) originalProps;
+ else
+ props = propertiesFromFile(accessFileName);
+ parseProperties(props);
}
private static Properties propertiesFromFile(String fname)
@@ -240,7 +301,7 @@
}
}
- private void checkAccessLevel(String accessLevel) {
+ private synchronized void checkAccess(AccessType requiredAccess, String arg) {
final AccessControlContext acc = AccessController.getContext();
final Subject s =
AccessController.doPrivileged(new PrivilegedAction<Subject>() {
@@ -249,39 +310,235 @@
}
});
if (s == null) return; /* security has not been enabled */
- final Set<Principal> principals = s.getPrincipals();
- for (Principal p : principals) {
- String grantedAccessLevel;
- synchronized (props) {
- grantedAccessLevel = props.getProperty(p.getName());
- }
- if (grantedAccessLevel != null) {
- if (accessLevel.equals(READONLY) &&
- (grantedAccessLevel.equals(READONLY) ||
- grantedAccessLevel.equals(READWRITE)))
- return;
- if (accessLevel.equals(READWRITE) &&
- grantedAccessLevel.equals(READWRITE))
+ final Set principals = s.getPrincipals();
+ String newPropertyValue = null;
+ for (Iterator i = principals.iterator(); i.hasNext(); ) {
+ final Principal p = (Principal) i.next();
+ Access access = accessMap.get(p.getName());
+ if (access != null) {
+ boolean ok;
+ switch (requiredAccess) {
+ case READ:
+ ok = true; // all access entries imply read
+ break;
+ case WRITE:
+ ok = access.write;
+ break;
+ case UNREGISTER:
+ ok = access.unregister;
+ if (!ok && access.write)
+ newPropertyValue = "unregister";
+ break;
+ case CREATE:
+ ok = checkCreateAccess(access, arg);
+ if (!ok && access.write)
+ newPropertyValue = "create " + arg;
+ break;
+ default:
+ throw new AssertionError();
+ }
+ if (ok)
return;
}
}
- throw new SecurityException("Access denied! Invalid access level for " +
- "requested MBeanServer operation.");
+ SecurityException se = new SecurityException("Access denied! Invalid " +
+ "access level for requested MBeanServer operation.");
+ // Add some more information to help people with deployments that
+ // worked before we required explicit create clauses. We're not giving
+ // any information to the bad guys, other than that the access control
+ // is based on a file, which they could have worked out from the stack
+ // trace anyway.
+ if (newPropertyValue != null) {
+ SecurityException se2 = new SecurityException("Access property " +
+ "for this identity should be similar to: " + READWRITE +
+ " " + newPropertyValue);
+ se.initCause(se2);
+ }
+ throw se;
}
- private void checkValues(Properties props) {
- Collection<?> c = props.values();
- for (Iterator<?> i = c.iterator(); i.hasNext(); ) {
- final String accessLevel = (String) i.next();
- if (!accessLevel.equals(READONLY) &&
- !accessLevel.equals(READWRITE)) {
- throw new IllegalArgumentException(
- "Syntax error in access level entry [" + accessLevel + "]");
- }
+ private static boolean checkCreateAccess(Access access, String className) {
+ for (String classNamePattern : access.createPatterns) {
+ if (classNameMatch(classNamePattern, className))
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean classNameMatch(String pattern, String className) {
+ // We studiously avoided regexes when parsing the properties file,
+ // because that is done whenever the VM is started with the
+ // appropriate -Dcom.sun.management options, even if nobody ever
+ // creates an MBean. We don't want to incur the overhead of loading
+ // all the regex code whenever those options are specified, but if we
+ // get as far as here then the VM is already running and somebody is
+ // doing the very unusual operation of remotely creating an MBean.
+ // Because that operation is so unusual, we don't try to optimize
+ // by hand-matching or by caching compiled Pattern objects.
+ StringBuilder sb = new StringBuilder();
+ StringTokenizer stok = new StringTokenizer(pattern, "*", true);
+ while (stok.hasMoreTokens()) {
+ String tok = stok.nextToken();
+ if (tok.equals("*"))
+ sb.append("[^.]*");
+ else
+ sb.append(Pattern.quote(tok));
+ }
+ return className.matches(sb.toString());
+ }
+
+ private void parseProperties(Properties props) {
+ this.accessMap = new HashMap<String, Access>();
+ for (Map.Entry<Object, Object> entry : props.entrySet()) {
+ String identity = (String) entry.getKey();
+ String accessString = (String) entry.getValue();
+ Access access = Parser.parseAccess(identity, accessString);
+ accessMap.put(identity, access);
}
}
- private Properties props;
+ private static class Parser {
+ private final static int EOS = -1; // pseudo-codepoint "end of string"
+ static {
+ assert !Character.isWhitespace(EOS);
+ }
+
+ private final String identity; // just for better error messages
+ private final String s; // the string we're parsing
+ private final int len; // s.length()
+ private int i;
+ private int c;
+ // At any point, either c is s.codePointAt(i), or i == len and
+ // c is EOS. We use int rather than char because it is conceivable
+ // (if unlikely) that a classname in a create clause might contain
+ // "supplementary characters", the ones that don't fit in the original
+ // 16 bits for Unicode.
+
+ private Parser(String identity, String s) {
+ this.identity = identity;
+ this.s = s;
+ this.len = s.length();
+ this.i = 0;
+ if (i < len)
+ this.c = s.codePointAt(i);
+ else
+ this.c = EOS;
+ }
+
+ static Access parseAccess(String identity, String s) {
+ return new Parser(identity, s).parseAccess();
+ }
+
+ private Access parseAccess() {
+ skipSpace();
+ String type = parseWord();
+ Access access;
+ if (type.equals(READONLY))
+ access = new Access(false, false, null);
+ else if (type.equals(READWRITE))
+ access = parseReadWrite();
+ else {
+ throw syntax("Expected " + READONLY + " or " + READWRITE +
+ ": " + type);
+ }
+ if (c != EOS)
+ throw syntax("Extra text at end of line");
+ return access;
+ }
+
+ private Access parseReadWrite() {
+ List<String> createClasses = new ArrayList<String>();
+ boolean unregister = false;
+ while (true) {
+ skipSpace();
+ if (c == EOS)
+ break;
+ String type = parseWord();
+ if (type.equals(UNREGISTER))
+ unregister = true;
+ else if (type.equals(CREATE))
+ parseCreate(createClasses);
+ else
+ throw syntax("Unrecognized keyword " + type);
+ }
+ return new Access(true, unregister, createClasses);
+ }
+
+ private void parseCreate(List<String> createClasses) {
+ while (true) {
+ skipSpace();
+ createClasses.add(parseClassName());
+ skipSpace();
+ if (c == ',')
+ next();
+ else
+ break;
+ }
+ }
+
+ private String parseClassName() {
+ // We don't check that classname components begin with suitable
+ // characters (so we accept 1.2.3 for example). This means that
+ // there are only two states, which we can call dotOK and !dotOK
+ // according as a dot (.) is legal or not. Initially we're in
+ // !dotOK since a classname can't start with a dot; after a dot
+ // we're in !dotOK again; and after any other characters we're in
+ // dotOK. The classname is only accepted if we end in dotOK,
+ // so we reject an empty name or a name that ends with a dot.
+ final int start = i;
+ boolean dotOK = false;
+ while (true) {
+ if (c == '.') {
+ if (!dotOK)
+ throw syntax("Bad . in class name");
+ dotOK = false;
+ } else if (c == '*' || Character.isJavaIdentifierPart(c))
+ dotOK = true;
+ else
+ break;
+ next();
+ }
+ String className = s.substring(start, i);
+ if (!dotOK)
+ throw syntax("Bad class name " + className);
+ return className;
+ }
+
+ // Advance c and i to the next character, unless already at EOS.
+ private void next() {
+ if (c != EOS) {
+ i += Character.charCount(c);
+ if (i < len)
+ c = s.codePointAt(i);
+ else
+ c = EOS;
+ }
+ }
+
+ private void skipSpace() {
+ while (Character.isWhitespace(c))
+ next();
+ }
+
+ private String parseWord() {
+ skipSpace();
+ if (c == EOS)
+ throw syntax("Expected word at end of line");
+ final int start = i;
+ while (c != EOS && !Character.isWhitespace(c))
+ next();
+ String word = s.substring(start, i);
+ skipSpace();
+ return word;
+ }
+
+ private IllegalArgumentException syntax(String msg) {
+ return new IllegalArgumentException(
+ msg + " [" + identity + " " + s + "]");
+ }
+ }
+
+ private Map<String, Access> accessMap;
private Properties originalProps;
private String accessFileName;
}
diff --git a/src/share/classes/com/sun/jndi/ldap/LdapCtx.java b/src/share/classes/com/sun/jndi/ldap/LdapCtx.java
index bec6fd0..5f9462c 100644
--- a/src/share/classes/com/sun/jndi/ldap/LdapCtx.java
+++ b/src/share/classes/com/sun/jndi/ldap/LdapCtx.java
@@ -302,7 +302,16 @@
schemaTrees = new Hashtable(11, 0.75f);
initEnv();
- connect(false);
+ try {
+ connect(false);
+ } catch (NamingException e) {
+ try {
+ close();
+ } catch (Exception e2) {
+ // Nothing
+ }
+ throw e;
+ }
}
LdapCtx(LdapCtx existing, String newDN) throws NamingException {
diff --git a/src/share/classes/com/sun/jndi/ldap/VersionHelper12.java b/src/share/classes/com/sun/jndi/ldap/VersionHelper12.java
index a413116..0f6a70e 100644
--- a/src/share/classes/com/sun/jndi/ldap/VersionHelper12.java
+++ b/src/share/classes/com/sun/jndi/ldap/VersionHelper12.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1999 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,12 +33,33 @@
final class VersionHelper12 extends VersionHelper {
+ // System property to control whether classes may be loaded from an
+ // arbitrary URL code base.
+ private static final String TRUST_URL_CODEBASE_PROPERTY =
+ "com.sun.jndi.ldap.object.trustURLCodebase";
+
+ // Determine whether classes may be loaded from an arbitrary URL code base.
+ private static final String trustURLCodebase =
+ AccessController.doPrivileged(
+ new PrivilegedAction<String>() {
+ public String run() {
+ return System.getProperty(TRUST_URL_CODEBASE_PROPERTY,
+ "false");
+ }
+ }
+ );
+
VersionHelper12() {} // Disallow external from creating one of these.
ClassLoader getURLClassLoader(String[] url)
throws MalformedURLException {
ClassLoader parent = getContextClassLoader();
- if (url != null) {
+ /*
+ * Classes may only be loaded from an arbitrary URL code base when
+ * the system property com.sun.jndi.ldap.object.trustURLCodebase
+ * has been set to "true".
+ */
+ if (url != null && "true".equalsIgnoreCase(trustURLCodebase)) {
return URLClassLoader.newInstance(getUrlArray(url), parent);
} else {
return parent;
diff --git a/src/share/classes/java/awt/Font.java b/src/share/classes/java/awt/Font.java
index 01f401e..f73e0e9 100644
--- a/src/share/classes/java/awt/Font.java
+++ b/src/share/classes/java/awt/Font.java
@@ -37,6 +37,8 @@
import java.awt.peer.FontPeer;
import java.io.*;
import java.lang.ref.SoftReference;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
import java.text.AttributedCharacterIterator.Attribute;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
@@ -51,6 +53,7 @@
import sun.font.AttributeValues;
import sun.font.EAttribute;
import sun.font.CompositeFont;
+import sun.font.CreatedFontTracker;
import sun.font.Font2D;
import sun.font.Font2DHandle;
import sun.font.FontManager;
@@ -575,14 +578,16 @@
}
/* used to implement Font.createFont */
- private Font(File fontFile, int fontFormat, boolean isCopy)
+ private Font(File fontFile, int fontFormat,
+ boolean isCopy, CreatedFontTracker tracker)
throws FontFormatException {
this.createdFont = true;
/* Font2D instances created by this method track their font file
* so that when the Font2D is GC'd it can also remove the file.
*/
this.font2DHandle =
- FontManager.createFont2D(fontFile, fontFormat, isCopy).handle;
+ FontManager.createFont2D(fontFile, fontFormat,
+ isCopy, tracker).handle;
this.name = this.font2DHandle.font2D.getFontName(Locale.getDefault());
this.style = Font.PLAIN;
this.size = 1;
@@ -788,6 +793,29 @@
}
/**
+ * Used with the byte count tracker for fonts created from streams.
+ * If a thread can create temp files anyway, no point in counting
+ * font bytes.
+ */
+ private static boolean hasTempPermission() {
+
+ if (System.getSecurityManager() == null) {
+ return true;
+ }
+ File f = null;
+ boolean hasPerm = false;
+ try {
+ f = File.createTempFile("+~JT", ".tmp", null);
+ f.delete();
+ f = null;
+ hasPerm = true;
+ } catch (Throwable t) {
+ /* inc. any kind of SecurityException */
+ }
+ return hasPerm;
+ }
+
+ /**
* Returns a new <code>Font</code> using the specified font type
* and input data. The new <code>Font</code> is
* created with a point size of 1 and style {@link #PLAIN PLAIN}.
@@ -822,58 +850,96 @@
fontFormat != Font.TYPE1_FONT) {
throw new IllegalArgumentException ("font format not recognized");
}
- final InputStream fStream = fontStream;
- Object ret = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction() {
- public Object run() {
- File tFile = null;
- FileOutputStream outStream = null;
- try {
- tFile = File.createTempFile("+~JF", ".tmp", null);
- /* Temp file deleted by font shutdown hook */
- BufferedInputStream inStream =
- new BufferedInputStream(fStream);
- outStream = new FileOutputStream(tFile);
- int bytesRead = 0;
- int bufSize = 8192;
- byte [] buf = new byte[bufSize];
- while (bytesRead != -1) {
- try {
- bytesRead = inStream.read(buf, 0, bufSize);
- } catch (Throwable t) {
- throw new IOException();
- }
- if (bytesRead != -1) {
- outStream.write(buf, 0, bytesRead);
- }
- }
- /* don't close the input stream */
- outStream.close();
- } catch (IOException e) {
- if (outStream != null) {
- try {
- outStream.close();
- } catch (Exception e1) {
- }
- }
- if (tFile != null) {
- try {
- tFile.delete();
- } catch (Exception e2) {
- }
- }
- return e;
- }
- return tFile;
- }
- });
+ boolean copiedFontData = false;
- if (ret instanceof File) {
- return new Font((File)ret, fontFormat, true);
- } else if (ret instanceof IOException) {
- throw (IOException)ret;
- } else {
- throw new FontFormatException("Couldn't access font stream");
+ try {
+ final File tFile = AccessController.doPrivileged(
+ new PrivilegedExceptionAction<File>() {
+ public File run() throws IOException {
+ return File.createTempFile("+~JF", ".tmp", null);
+ }
+ }
+ );
+
+ int totalSize = 0;
+ CreatedFontTracker tracker = null;
+ try {
+ final OutputStream outStream =
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<OutputStream>() {
+ public OutputStream run() throws IOException {
+ return new FileOutputStream(tFile);
+ }
+ }
+ );
+ if (!hasTempPermission()) {
+ tracker = CreatedFontTracker.getTracker();
+ }
+ try {
+ byte[] buf = new byte[8192];
+ for (;;) {
+ int bytesRead = fontStream.read(buf);
+ if (bytesRead < 0) {
+ break;
+ }
+ if (tracker != null) {
+ if (totalSize+bytesRead > tracker.MAX_FILE_SIZE) {
+ throw new IOException("File too big.");
+ }
+ if (totalSize+tracker.getNumBytes() >
+ tracker.MAX_TOTAL_BYTES)
+ {
+ throw new IOException("Total files too big.");
+ }
+ totalSize += bytesRead;
+ tracker.addBytes(bytesRead);
+ }
+ outStream.write(buf, 0, bytesRead);
+ }
+ /* don't close the input stream */
+ } finally {
+ outStream.close();
+ }
+ /* After all references to a Font2D are dropped, the file
+ * will be removed. To support long-lived AppContexts,
+ * we need to then decrement the byte count by the size
+ * of the file.
+ * If the data isn't a valid font, the implementation will
+ * delete the tmp file and decrement the byte count
+ * in the tracker object before returning from the
+ * constructor, so we can set 'copiedFontData' to true here
+ * without waiting for the results of that constructor.
+ */
+ copiedFontData = true;
+ Font font = new Font(tFile, fontFormat, true, tracker);
+ return font;
+ } finally {
+ if (!copiedFontData) {
+ if (tracker != null) {
+ tracker.subBytes(totalSize);
+ }
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Void>() {
+ public Void run() {
+ tFile.delete();
+ return null;
+ }
+ }
+ );
+ }
+ }
+ } catch (Throwable t) {
+ if (t instanceof FontFormatException) {
+ throw (FontFormatException)t;
+ }
+ if (t instanceof IOException) {
+ throw (IOException)t;
+ }
+ Throwable cause = t.getCause();
+ if (cause instanceof FontFormatException) {
+ throw (FontFormatException)cause;
+ }
+ throw new IOException("Problem reading font data.");
}
}
@@ -913,6 +979,9 @@
*/
public static Font createFont(int fontFormat, File fontFile)
throws java.awt.FontFormatException, java.io.IOException {
+
+ fontFile = new File(fontFile.getPath());
+
if (fontFormat != Font.TRUETYPE_FONT &&
fontFormat != Font.TYPE1_FONT) {
throw new IllegalArgumentException ("font format not recognized");
@@ -926,7 +995,7 @@
if (!fontFile.canRead()) {
throw new IOException("Can't read " + fontFile);
}
- return new Font(fontFile, fontFormat, false);
+ return new Font(fontFile, fontFormat, false, null);
}
/**
diff --git a/src/share/classes/java/util/Calendar.java b/src/share/classes/java/util/Calendar.java
index 7fa8296..5b7e275 100644
--- a/src/share/classes/java/util/Calendar.java
+++ b/src/share/classes/java/util/Calendar.java
@@ -41,9 +41,14 @@
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.io.OptionalDataException;
import java.io.Serializable;
+import java.security.AccessControlContext;
import java.security.AccessController;
+import java.security.PermissionCollection;
+import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import sun.util.BuddhistCalendar;
@@ -2628,6 +2633,18 @@
}
}
+ private static class CalendarAccessControlContext {
+ private static final AccessControlContext INSTANCE;
+ static {
+ RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
+ PermissionCollection perms = perm.newPermissionCollection();
+ perms.add(perm);
+ INSTANCE = new AccessControlContext(new ProtectionDomain[] {
+ new ProtectionDomain(null, perms)
+ });
+ }
+ }
+
/**
* Reconstitutes this object from a stream (i.e., deserialize it).
*/
@@ -2657,17 +2674,30 @@
serialVersionOnStream = currentSerialVersion;
// If there's a ZoneInfo object, use it for zone.
+ ZoneInfo zi = null;
try {
- ZoneInfo zi = (ZoneInfo) AccessController.doPrivileged(
- new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- return input.readObject();
- }
- });
- if (zi != null) {
- zone = zi;
+ zi = AccessController.doPrivileged(
+ new PrivilegedExceptionAction<ZoneInfo>() {
+ public ZoneInfo run() throws Exception {
+ return (ZoneInfo) input.readObject();
+ }
+ },
+ CalendarAccessControlContext.INSTANCE);
+ } catch (PrivilegedActionException pae) {
+ Exception e = pae.getException();
+ if (!(e instanceof OptionalDataException)) {
+ if (e instanceof RuntimeException) {
+ throw (RuntimeException) e;
+ } else if (e instanceof IOException) {
+ throw (IOException) e;
+ } else if (e instanceof ClassNotFoundException) {
+ throw (ClassNotFoundException) e;
+ }
+ throw new RuntimeException(e);
}
- } catch (Exception e) {
+ }
+ if (zi != null) {
+ zone = zi;
}
// If the deserialized object has a SimpleTimeZone, try to
@@ -2676,9 +2706,9 @@
// implementation as much as possible.
if (zone instanceof SimpleTimeZone) {
String id = zone.getID();
- TimeZone zi = TimeZone.getTimeZone(id);
- if (zi != null && zi.hasSameRules(zone) && zi.getID().equals(id)) {
- zone = zi;
+ TimeZone tz = TimeZone.getTimeZone(id);
+ if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
+ zone = tz;
}
}
}
diff --git a/src/share/classes/javax/management/monitor/CounterMonitor.java b/src/share/classes/javax/management/monitor/CounterMonitor.java
index b27e57f..cb1244e 100644
--- a/src/share/classes/javax/management/monitor/CounterMonitor.java
+++ b/src/share/classes/javax/management/monitor/CounterMonitor.java
@@ -599,7 +599,7 @@
*/
@Override
public MBeanNotificationInfo[] getNotificationInfo() {
- return notifsInfo;
+ return notifsInfo.clone();
}
/*
diff --git a/src/share/classes/javax/management/monitor/GaugeMonitor.java b/src/share/classes/javax/management/monitor/GaugeMonitor.java
index ab71f10..2662c42 100644
--- a/src/share/classes/javax/management/monitor/GaugeMonitor.java
+++ b/src/share/classes/javax/management/monitor/GaugeMonitor.java
@@ -481,7 +481,7 @@
*/
@Override
public MBeanNotificationInfo[] getNotificationInfo() {
- return notifsInfo;
+ return notifsInfo.clone();
}
/*
diff --git a/src/share/classes/javax/management/monitor/Monitor.java b/src/share/classes/javax/management/monitor/Monitor.java
index fb3e1a4..2e37d8f 100644
--- a/src/share/classes/javax/management/monitor/Monitor.java
+++ b/src/share/classes/javax/management/monitor/Monitor.java
@@ -32,7 +32,10 @@
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -163,7 +166,10 @@
/**
* AccessControlContext of the Monitor.start() caller.
*/
- private AccessControlContext acc;
+ private static final AccessControlContext noPermissionsACC =
+ new AccessControlContext(
+ new ProtectionDomain[] {new ProtectionDomain(null, null)});
+ private volatile AccessControlContext acc = noPermissionsACC;
/**
* Scheduler Service.
@@ -173,14 +179,20 @@
new DaemonThreadFactory("Scheduler"));
/**
+ * Map containing the thread pool executor per thread group.
+ */
+ private static final Map<ThreadPoolExecutor, Void> executors =
+ new WeakHashMap<ThreadPoolExecutor, Void>();
+
+ /**
+ * Lock for executors map.
+ */
+ private static final Object executorsLock = new Object();
+
+ /**
* Maximum Pool Size
*/
private static final int maximumPoolSize;
-
- /**
- * Executor Service.
- */
- private static final ThreadPoolExecutor executor;
static {
final String maximumPoolSizeSysProp = "jmx.x.monitor.maximum.pool.size";
final String maximumPoolSizeStr = AccessController.doPrivileged(
@@ -210,22 +222,9 @@
maximumPoolSize = maximumPoolSizeTmp;
}
}
- executor = new ThreadPoolExecutor(
- maximumPoolSize,
- maximumPoolSize,
- 60L,
- TimeUnit.SECONDS,
- new LinkedBlockingQueue<Runnable>(),
- new DaemonThreadFactory("Executor"));
- executor.allowCoreThreadTimeOut(true);
}
/**
- * Monitor task to be executed by the Executor Service.
- */
- private final MonitorTask monitorTask = new MonitorTask();
-
- /**
* Future associated to the current monitor task.
*/
private Future<?> monitorFuture;
@@ -233,7 +232,7 @@
/**
* Scheduler task to be executed by the Scheduler Service.
*/
- private final SchedulerTask schedulerTask = new SchedulerTask(monitorTask);
+ private final SchedulerTask schedulerTask = new SchedulerTask();
/**
* ScheduledFuture associated to the current scheduler task.
@@ -719,6 +718,7 @@
// Start the scheduler.
//
cleanupFutures();
+ schedulerTask.setMonitorTask(new MonitorTask());
schedulerFuture = scheduler.schedule(schedulerTask,
getGranularityPeriod(),
TimeUnit.MILLISECONDS);
@@ -748,7 +748,7 @@
// Reset the AccessControlContext.
//
- acc = null;
+ acc = noPermissionsACC;
// Reset the complex type attribute information
// such that it is recalculated again.
@@ -1467,7 +1467,7 @@
*/
private class SchedulerTask implements Runnable {
- private Runnable task = null;
+ private MonitorTask task;
/*
* ------------------------------------------
@@ -1475,7 +1475,16 @@
* ------------------------------------------
*/
- public SchedulerTask(Runnable task) {
+ public SchedulerTask() {
+ }
+
+ /*
+ * ------------------------------------------
+ * GETTERS/SETTERS
+ * ------------------------------------------
+ */
+
+ public void setMonitorTask(MonitorTask task) {
this.task = task;
}
@@ -1487,7 +1496,7 @@
public void run() {
synchronized (Monitor.this) {
- Monitor.this.monitorFuture = executor.submit(task);
+ Monitor.this.monitorFuture = task.submit();
}
}
}
@@ -1500,6 +1509,8 @@
*/
private class MonitorTask implements Runnable {
+ private ThreadPoolExecutor executor;
+
/*
* ------------------------------------------
* CONSTRUCTORS
@@ -1507,6 +1518,38 @@
*/
public MonitorTask() {
+ // Find out if there's already an existing executor for the calling
+ // thread and reuse it. Otherwise, create a new one and store it in
+ // the executors map. If there is a SecurityManager, the group of
+ // System.getSecurityManager() is used, else the group of the thread
+ // instantiating this MonitorTask, i.e. the group of the thread that
+ // calls "Monitor.start()".
+ SecurityManager s = System.getSecurityManager();
+ ThreadGroup group = (s != null) ? s.getThreadGroup() :
+ Thread.currentThread().getThreadGroup();
+ synchronized (executorsLock) {
+ for (ThreadPoolExecutor e : executors.keySet()) {
+ DaemonThreadFactory tf =
+ (DaemonThreadFactory) e.getThreadFactory();
+ ThreadGroup tg = tf.getThreadGroup();
+ if (tg == group) {
+ executor = e;
+ break;
+ }
+ }
+ if (executor == null) {
+ executor = new ThreadPoolExecutor(
+ maximumPoolSize,
+ maximumPoolSize,
+ 60L,
+ TimeUnit.SECONDS,
+ new LinkedBlockingQueue<Runnable>(),
+ new DaemonThreadFactory("ThreadGroup<" +
+ group.getName() + "> Executor", group));
+ executor.allowCoreThreadTimeOut(true);
+ executors.put(executor, null);
+ }
+ }
}
/*
@@ -1515,12 +1558,18 @@
* ------------------------------------------
*/
+ public Future<?> submit() {
+ return executor.submit(this);
+ }
+
public void run() {
final ScheduledFuture<?> sf;
+ final AccessControlContext ac;
synchronized (Monitor.this) {
sf = Monitor.this.schedulerFuture;
+ ac = Monitor.this.acc;
}
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
public Void run() {
if (Monitor.this.isActive()) {
final int an[] = alreadyNotifieds;
@@ -1533,7 +1582,11 @@
}
return null;
}
- }, Monitor.this.acc);
+ };
+ if (ac == null) {
+ throw new SecurityException("AccessControlContext cannot be null");
+ }
+ AccessController.doPrivileged(action, ac);
synchronized (Monitor.this) {
if (Monitor.this.isActive() &&
Monitor.this.schedulerFuture == sf) {
@@ -1573,6 +1626,15 @@
namePrefix = "JMX Monitor " + poolName + " Pool [Thread-";
}
+ public DaemonThreadFactory(String poolName, ThreadGroup threadGroup) {
+ group = threadGroup;
+ namePrefix = "JMX Monitor " + poolName + " Pool [Thread-";
+ }
+
+ public ThreadGroup getThreadGroup() {
+ return group;
+ }
+
public Thread newThread(Runnable r) {
Thread t = new Thread(group,
r,
diff --git a/src/share/classes/javax/management/monitor/StringMonitor.java b/src/share/classes/javax/management/monitor/StringMonitor.java
index 3c2bbc5..9b4af52 100644
--- a/src/share/classes/javax/management/monitor/StringMonitor.java
+++ b/src/share/classes/javax/management/monitor/StringMonitor.java
@@ -184,6 +184,7 @@
* @return The derived gauge of the specified object.
*
*/
+ @Override
public synchronized String getDerivedGauge(ObjectName object) {
return (String) super.getDerivedGauge(object);
}
@@ -199,6 +200,7 @@
* @return The derived gauge timestamp of the specified object.
*
*/
+ @Override
public synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
return super.getDerivedGaugeTimeStamp(object);
}
@@ -341,8 +343,9 @@
* the Java class of the notification and the notification types sent by
* the string monitor.
*/
+ @Override
public MBeanNotificationInfo[] getNotificationInfo() {
- return notifsInfo;
+ return notifsInfo.clone();
}
/*
diff --git a/src/share/classes/javax/print/attribute/standard/MediaSize.java b/src/share/classes/javax/print/attribute/standard/MediaSize.java
index 55cd1ae..3b6262d 100644
--- a/src/share/classes/javax/print/attribute/standard/MediaSize.java
+++ b/src/share/classes/javax/print/attribute/standard/MediaSize.java
@@ -123,8 +123,10 @@
if (x > y) {
throw new IllegalArgumentException("X dimension > Y dimension");
}
- mediaName = media;
- mediaMap.put(mediaName, this);
+ if (media != null && mediaMap.get(media) == null) {
+ mediaName = media;
+ mediaMap.put(mediaName, this);
+ }
sizeVector.add(this);
}
@@ -147,8 +149,10 @@
if (x > y) {
throw new IllegalArgumentException("X dimension > Y dimension");
}
- mediaName = media;
- mediaMap.put(mediaName, this);
+ if (media != null && mediaMap.get(media) == null) {
+ mediaName = media;
+ mediaMap.put(mediaName, this);
+ }
sizeVector.add(this);
}
diff --git a/src/share/classes/sun/awt/image/GifImageDecoder.java b/src/share/classes/sun/awt/image/GifImageDecoder.java
index aa87fb8..b0679af 100644
--- a/src/share/classes/sun/awt/image/GifImageDecoder.java
+++ b/src/share/classes/sun/awt/image/GifImageDecoder.java
@@ -585,9 +585,16 @@
System.out.print("Reading a " + width + " by " + height + " " +
(interlace ? "" : "non-") + "interlaced image...");
}
-
+ int initCodeSize = ExtractByte(block, 9);
+ if (initCodeSize >= 12) {
+ if (verbose) {
+ System.out.println("Invalid initial code size: " +
+ initCodeSize);
+ }
+ return false;
+ }
boolean ret = parseImage(x, y, width, height,
- interlace, ExtractByte(block, 9),
+ interlace, initCodeSize,
block, rasline, model);
if (!ret) {
diff --git a/src/share/classes/sun/font/CreatedFontTracker.java b/src/share/classes/sun/font/CreatedFontTracker.java
new file mode 100644
index 0000000..741337d
--- /dev/null
+++ b/src/share/classes/sun/font/CreatedFontTracker.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.font;
+
+public class CreatedFontTracker {
+
+ public static final int MAX_FILE_SIZE = 32 * 1024 * 1024;
+ public static final int MAX_TOTAL_BYTES = 10 * MAX_FILE_SIZE;
+
+ static int numBytes;
+ static CreatedFontTracker tracker;
+
+ public static synchronized CreatedFontTracker getTracker() {
+ if (tracker == null) {
+ tracker = new CreatedFontTracker();
+ }
+ return tracker;
+ }
+
+ public synchronized int getNumBytes() {
+ return numBytes;
+ }
+
+ public synchronized void addBytes(int sz) {
+ numBytes += sz;
+ }
+
+ public synchronized void subBytes(int sz) {
+ numBytes -= sz;
+ }
+}
diff --git a/src/share/classes/sun/font/FileFont.java b/src/share/classes/sun/font/FileFont.java
index b6a2099..5aad11b 100644
--- a/src/share/classes/sun/font/FileFont.java
+++ b/src/share/classes/sun/font/FileFont.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -125,9 +125,9 @@
return true;
}
- void setFileToRemove(File file) {
+ void setFileToRemove(File file, CreatedFontTracker tracker) {
Disposer.addObjectRecord(this,
- new CreatedFontFileDisposerRecord(file));
+ new CreatedFontFileDisposerRecord(file, tracker));
}
/* This is called when a font scaler is determined to
@@ -246,12 +246,16 @@
return getScaler().getUnitsPerEm();
}
- private static class CreatedFontFileDisposerRecord implements DisposerRecord {
+ private static class CreatedFontFileDisposerRecord
+ implements DisposerRecord {
File fontFile = null;
+ CreatedFontTracker tracker;
- private CreatedFontFileDisposerRecord(File file) {
+ private CreatedFontFileDisposerRecord(File file,
+ CreatedFontTracker tracker) {
fontFile = file;
+ this.tracker = tracker;
}
public void dispose() {
@@ -260,6 +264,9 @@
public Object run() {
if (fontFile != null) {
try {
+ if (tracker != null) {
+ tracker.subBytes((int)fontFile.length());
+ }
/* REMIND: is it possible that the file is
* still open? It will be closed when the
* font2D is disposed but could this code
diff --git a/src/share/classes/sun/font/FontManager.java b/src/share/classes/sun/font/FontManager.java
index f709f38..a537f3a 100644
--- a/src/share/classes/sun/font/FontManager.java
+++ b/src/share/classes/sun/font/FontManager.java
@@ -2348,19 +2348,21 @@
static Vector<File> tmpFontFiles = null;
public static Font2D createFont2D(File fontFile, int fontFormat,
- boolean isCopy)
+ boolean isCopy,
+ CreatedFontTracker tracker)
throws FontFormatException {
String fontFilePath = fontFile.getPath();
FileFont font2D = null;
final File fFile = fontFile;
+ final CreatedFontTracker _tracker = tracker;
try {
switch (fontFormat) {
case Font.TRUETYPE_FONT:
font2D = new TrueTypeFont(fontFilePath, null, 0, true);
break;
case Font.TYPE1_FONT:
- font2D = new Type1Font(fontFilePath, null);
+ font2D = new Type1Font(fontFilePath, null, isCopy);
break;
default:
throw new FontFormatException("Unrecognised Font Format");
@@ -2370,6 +2372,9 @@
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
+ if (_tracker != null) {
+ _tracker.subBytes((int)fFile.length());
+ }
fFile.delete();
return null;
}
@@ -2378,7 +2383,7 @@
throw(e);
}
if (isCopy) {
- font2D.setFileToRemove(fontFile);
+ font2D.setFileToRemove(fontFile, tracker);
synchronized (FontManager.class) {
if (tmpFontFiles == null) {
diff --git a/src/share/classes/sun/font/TrueTypeFont.java b/src/share/classes/sun/font/TrueTypeFont.java
index 5d9477b..13f0f69 100644
--- a/src/share/classes/sun/font/TrueTypeFont.java
+++ b/src/share/classes/sun/font/TrueTypeFont.java
@@ -175,8 +175,17 @@
super(platname, nativeNames);
useJavaRasterizer = javaRasterizer;
fontRank = Font2D.TTF_RANK;
- verify();
- init(fIndex);
+ try {
+ verify();
+ init(fIndex);
+ } catch (Throwable t) {
+ close();
+ if (t instanceof FontFormatException) {
+ throw (FontFormatException)t;
+ } else {
+ throw new FontFormatException("Unexpected runtime exception.");
+ }
+ }
Disposer.addObjectRecord(this, disposerRecord);
}
diff --git a/src/share/classes/sun/font/Type1Font.java b/src/share/classes/sun/font/Type1Font.java
index 36841b6..a117310 100644
--- a/src/share/classes/sun/font/Type1Font.java
+++ b/src/share/classes/sun/font/Type1Font.java
@@ -39,6 +39,7 @@
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import sun.java2d.Disposer;
+import sun.java2d.DisposerRecord;
import java.util.HashSet;
import java.util.HashMap;
import java.awt.Font;
@@ -76,6 +77,27 @@
*/
public class Type1Font extends FileFont {
+ private static class T1DisposerRecord implements DisposerRecord {
+ String fileName = null;
+
+ T1DisposerRecord(String name) {
+ fileName = name;
+ }
+
+ public synchronized void dispose() {
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Object run() {
+
+ if (fileName != null) {
+ (new java.io.File(fileName)).delete();
+ }
+ return null;
+ }
+ });
+ }
+ }
+
WeakReference bufferRef = new WeakReference(null);
private String psName = null;
@@ -125,18 +147,42 @@
/**
+ * Constructs a Type1 Font.
+ * @param platname - Platform identifier of the font. Typically file name.
+ * @param nativeNames - Native names - typically XLFDs on Unix.
+ */
+ public Type1Font(String platname, Object nativeNames)
+ throws FontFormatException {
+
+ this(platname, nativeNames, false);
+ }
+
+ /**
* - does basic verification of the file
* - reads the names (full, family).
* - determines the style of the font.
* @throws FontFormatException - if the font can't be opened
* or fails verification, or there's no usable cmap
*/
- public Type1Font(String platname, Object nativeNames)
+ public Type1Font(String platname, Object nativeNames, boolean createdCopy)
throws FontFormatException {
super(platname, nativeNames);
fontRank = Font2D.TYPE1_RANK;
checkedNatives = true;
- verify();
+ try {
+ verify();
+ } catch (Throwable t) {
+ if (createdCopy) {
+ T1DisposerRecord ref = new T1DisposerRecord(platname);
+ Disposer.addObjectRecord(bufferRef, ref);
+ bufferRef = null;
+ }
+ if (t instanceof FontFormatException) {
+ throw (FontFormatException)t;
+ } else {
+ throw new FontFormatException("Unexpected runtime exception.");
+ }
+ }
}
private synchronized ByteBuffer getBuffer() throws FontFormatException {
diff --git a/src/share/classes/sun/net/httpserver/Request.java b/src/share/classes/sun/net/httpserver/Request.java
index 80bc31d..542e8e8 100644
--- a/src/share/classes/sun/net/httpserver/Request.java
+++ b/src/share/classes/sun/net/httpserver/Request.java
@@ -52,6 +52,9 @@
os = rawout;
do {
startLine = readLine();
+ if (startLine == null) {
+ return;
+ }
/* skip blank lines */
} while (startLine == null ? false : startLine.equals (""));
}
diff --git a/src/share/classes/sun/net/httpserver/ServerImpl.java b/src/share/classes/sun/net/httpserver/ServerImpl.java
index cfff8dd..8f5c8be 100644
--- a/src/share/classes/sun/net/httpserver/ServerImpl.java
+++ b/src/share/classes/sun/net/httpserver/ServerImpl.java
@@ -433,6 +433,7 @@
rawin = sslStreams.getInputStream();
rawout = sslStreams.getOutputStream();
engine = sslStreams.getSSLEngine();
+ connection.sslStreams = sslStreams;
} else {
rawin = new BufferedInputStream(
new Request.ReadStream (
@@ -442,6 +443,8 @@
ServerImpl.this, chan
);
}
+ connection.raw = rawin;
+ connection.rawout = rawout;
}
Request req = new Request (rawin, rawout);
requestLine = req.requestLine();
diff --git a/src/share/classes/sun/security/krb5/KrbKdcReq.java b/src/share/classes/sun/security/krb5/KrbKdcReq.java
index e9ff9cc..259aedd 100644
--- a/src/share/classes/sun/security/krb5/KrbKdcReq.java
+++ b/src/share/classes/sun/security/krb5/KrbKdcReq.java
@@ -274,27 +274,31 @@
+ ",Attempt =" + i
+ ", #bytes=" + obuf.length);
}
- /*
- * Send the data to the kdc.
- */
+ try {
+ /*
+ * Send the data to the kdc.
+ */
kdcClient.send(obuf);
- /*
- * And get a response.
- */
- try {
- ibuf = kdcClient.receive();
- break;
- } catch (SocketTimeoutException se) {
- if (DEBUG) {
- System.out.println ("SocketTimeOutException with " +
- "attempt: " + i);
+ /*
+ * And get a response.
+ */
+ try {
+ ibuf = kdcClient.receive();
+ break;
+ } catch (SocketTimeoutException se) {
+ if (DEBUG) {
+ System.out.println ("SocketTimeOutException with " +
+ "attempt: " + i);
+ }
+ if (i == DEFAULT_KDC_RETRY_LIMIT) {
+ ibuf = null;
+ throw se;
+ }
}
- if (i == DEFAULT_KDC_RETRY_LIMIT) {
- ibuf = null;
- throw se;
- }
+ } finally {
+ kdcClient.close();
}
}
}
diff --git a/src/share/classes/sun/security/krb5/internal/UDPClient.java b/src/share/classes/sun/security/krb5/internal/UDPClient.java
index c9e440f..670df92 100644
--- a/src/share/classes/sun/security/krb5/internal/UDPClient.java
+++ b/src/share/classes/sun/security/krb5/internal/UDPClient.java
@@ -93,4 +93,7 @@
return data;
}
+ public void close() {
+ dgSocket.close();
+ }
}
diff --git a/src/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java b/src/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
index 701e104..1027df9 100644
--- a/src/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
+++ b/src/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,8 @@
import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
+import sun.security.rsa.RSAKeyFactory;
+
/**
* KeyPairGenerator implementation class. This class currently supports
* RSA, DSA, DH, and EC.
@@ -66,7 +68,7 @@
private AlgorithmParameterSpec params;
// for RSA, selected or default value of public exponent, always valid
- private BigInteger rsaPublicExponent;
+ private BigInteger rsaPublicExponent = RSAKeyGenParameterSpec.F4;
// SecureRandom instance, if specified in init
private SecureRandom random;
@@ -88,19 +90,19 @@
public void initialize(int keySize, SecureRandom random) {
token.ensureValid();
try {
- checkKeySize(keySize);
+ checkKeySize(keySize, null);
} catch (InvalidAlgorithmParameterException e) {
throw new InvalidParameterException(e.getMessage());
}
this.keySize = keySize;
this.params = null;
this.random = random;
- this.rsaPublicExponent = RSAKeyGenParameterSpec.F4;
if (algorithm.equals("EC")) {
params = P11ECKeyFactory.getECParameterSpec(keySize);
if (params == null) {
- throw new InvalidParameterException
- ("No EC parameters available for key size " + keySize + " bits");
+ throw new InvalidParameterException(
+ "No EC parameters available for key size "
+ + keySize + " bits");
}
}
}
@@ -115,8 +117,10 @@
("DHParameterSpec required for Diffie-Hellman");
}
DHParameterSpec dhParams = (DHParameterSpec)params;
- this.keySize = dhParams.getP().bitLength();
- this.params = params;
+ int tmpKeySize = dhParams.getP().bitLength();
+ checkKeySize(tmpKeySize, dhParams);
+ this.keySize = tmpKeySize;
+ this.params = dhParams;
// XXX sanity check params
} else if (algorithm.equals("RSA")) {
if (params instanceof RSAKeyGenParameterSpec == false) {
@@ -124,7 +128,9 @@
("RSAKeyGenParameterSpec required for RSA");
}
RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params;
- this.keySize = rsaParams.getKeysize();
+ int tmpKeySize = rsaParams.getKeysize();
+ checkKeySize(tmpKeySize, rsaParams);
+ this.keySize = tmpKeySize;
this.params = null;
this.rsaPublicExponent = rsaParams.getPublicExponent();
// XXX sanity check params
@@ -134,13 +140,16 @@
("DSAParameterSpec required for DSA");
}
DSAParameterSpec dsaParams = (DSAParameterSpec)params;
- this.keySize = dsaParams.getP().bitLength();
- this.params = params;
+ int tmpKeySize = dsaParams.getP().bitLength();
+ checkKeySize(tmpKeySize, dsaParams);
+ this.keySize = tmpKeySize;
+ this.params = dsaParams;
// XXX sanity check params
} else if (algorithm.equals("EC")) {
ECParameterSpec ecParams;
if (params instanceof ECParameterSpec) {
- ecParams = P11ECKeyFactory.getECParameterSpec((ECParameterSpec)params);
+ ecParams = P11ECKeyFactory.getECParameterSpec(
+ (ECParameterSpec)params);
if (ecParams == null) {
throw new InvalidAlgorithmParameterException
("Unsupported curve: " + params);
@@ -156,16 +165,17 @@
throw new InvalidAlgorithmParameterException
("ECParameterSpec or ECGenParameterSpec required for EC");
}
- this.keySize = ecParams.getCurve().getField().getFieldSize();
+ int tmpKeySize = ecParams.getCurve().getField().getFieldSize();
+ checkKeySize(tmpKeySize, ecParams);
+ this.keySize = tmpKeySize;
this.params = ecParams;
} else {
throw new ProviderException("Unknown algorithm: " + algorithm);
}
this.random = random;
- checkKeySize(keySize);
}
- private void checkKeySize(int keySize)
+ private void checkKeySize(int keySize, AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
if (algorithm.equals("EC")) {
if (keySize < 112) {
@@ -178,13 +188,28 @@
("Key size must be at most 2048 bit");
}
return;
+ } else if (algorithm.equals("RSA")) {
+ BigInteger tmpExponent = rsaPublicExponent;
+ if (params != null) {
+ // Already tested for instanceof RSAKeyGenParameterSpec above
+ tmpExponent =
+ ((RSAKeyGenParameterSpec)params).getPublicExponent();
+ }
+ try {
+ // This provider supports 64K or less.
+ RSAKeyFactory.checkKeyLengths(keySize, tmpExponent,
+ 512, 64 * 1024);
+ } catch (InvalidKeyException e) {
+ throw new InvalidAlgorithmParameterException(e.getMessage());
+ }
+ return;
}
+
if (keySize < 512) {
throw new InvalidAlgorithmParameterException
("Key size must be at least 512 bit");
}
- if (algorithm.equals("RSA") ||
- (algorithm.equals("DH") && (params != null))) {
+ if (algorithm.equals("DH") && (params != null)) {
// sanity check, nobody really wants keys this large
if (keySize > 64 * 1024) {
throw new InvalidAlgorithmParameterException
diff --git a/src/share/classes/sun/security/pkcs11/P11KeyStore.java b/src/share/classes/sun/security/pkcs11/P11KeyStore.java
index 839a2f3..b0e2071 100644
--- a/src/share/classes/sun/security/pkcs11/P11KeyStore.java
+++ b/src/share/classes/sun/security/pkcs11/P11KeyStore.java
@@ -80,6 +80,8 @@
import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
+import sun.security.rsa.RSAKeyFactory;
+
final class P11KeyStore extends KeyStoreSpi {
private static final CK_ATTRIBUTE ATTR_CLASS_CERT =
@@ -1328,6 +1330,15 @@
BigInteger modulus = attrs[0].getBigInteger();
keyLength = modulus.bitLength();
+ // This check will combine our "don't care" values here
+ // with the system-wide min/max values.
+ try {
+ RSAKeyFactory.checkKeyLengths(keyLength, null,
+ -1, Integer.MAX_VALUE);
+ } catch (InvalidKeyException e) {
+ throw new KeyStoreException(e.getMessage());
+ }
+
return P11Key.privateKey(session,
oHandle,
keyType,
diff --git a/src/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java b/src/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java
index 5f3cbbf..1bd764d 100644
--- a/src/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java
+++ b/src/share/classes/sun/security/pkcs11/P11RSAKeyFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,8 @@
import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
+import sun.security.rsa.RSAKeyFactory;
+
/**
* RSA KeyFactory implemenation.
*
@@ -131,6 +133,9 @@
} catch (PKCS11Exception e) {
throw new InvalidKeySpecException
("Could not create RSA public key", e);
+ } catch (InvalidKeyException e) {
+ throw new InvalidKeySpecException
+ ("Could not create RSA public key", e);
}
}
@@ -175,11 +180,15 @@
} catch (PKCS11Exception e) {
throw new InvalidKeySpecException
("Could not create RSA private key", e);
+ } catch (InvalidKeyException e) {
+ throw new InvalidKeySpecException
+ ("Could not create RSA private key", e);
}
}
private PublicKey generatePublic(BigInteger n, BigInteger e)
- throws PKCS11Exception {
+ throws PKCS11Exception, InvalidKeyException {
+ RSAKeyFactory.checkKeyLengths(n.bitLength(), e, -1, 64 * 1024);
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY),
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA),
@@ -200,7 +209,8 @@
}
private PrivateKey generatePrivate(BigInteger n, BigInteger d)
- throws PKCS11Exception {
+ throws PKCS11Exception, InvalidKeyException {
+ RSAKeyFactory.checkKeyLengths(n.bitLength(), null, -1, 64 * 1024);
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY),
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA),
@@ -222,7 +232,9 @@
private PrivateKey generatePrivate(BigInteger n, BigInteger e,
BigInteger d, BigInteger p, BigInteger q, BigInteger pe,
- BigInteger qe, BigInteger coeff) throws PKCS11Exception {
+ BigInteger qe, BigInteger coeff) throws PKCS11Exception,
+ InvalidKeyException {
+ RSAKeyFactory.checkKeyLengths(n.bitLength(), e, -1, 64 * 1024);
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY),
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA),
diff --git a/src/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/share/classes/sun/security/pkcs11/SunPKCS11.java
index b6eb1c2..6d0e045 100644
--- a/src/share/classes/sun/security/pkcs11/SunPKCS11.java
+++ b/src/share/classes/sun/security/pkcs11/SunPKCS11.java
@@ -120,11 +120,13 @@
}
/**
- * @deprecated use new SunPKCS11(String) or new SunPKCS11(InputStream) instead
+ * @deprecated use new SunPKCS11(String) or new SunPKCS11(InputStream)
+ * instead
*/
@Deprecated
public SunPKCS11(String configName, InputStream configStream) {
- super("SunPKCS11-" + Config.getConfig(configName, configStream).getName(),
+ super("SunPKCS11-" +
+ Config.getConfig(configName, configStream).getName(),
1.7d, Config.getConfig(configName, configStream).getDescription());
this.configName = configName;
this.config = Config.removeConfig(configName);
@@ -153,7 +155,8 @@
//
// If we are in Secmod mode and configured to use either the
// nssKeyStore or the nssTrustAnchors module, we automatically
- // switch to using the NSS trust attributes for trusted certs (KeyStore).
+ // switch to using the NSS trust attributes for trusted certs
+ // (KeyStore).
//
if (useSecmod) {
@@ -168,33 +171,40 @@
if (secmod.isInitialized()) {
if (nssSecmodDirectory != null) {
String s = secmod.getConfigDir();
- if ((s != null) && (s.equals(nssSecmodDirectory) == false)) {
+ if ((s != null) &&
+ (s.equals(nssSecmodDirectory) == false)) {
throw new ProviderException("Secmod directory "
+ nssSecmodDirectory
- + " invalid, NSS already initialized with " + s);
+ + " invalid, NSS already initialized with "
+ + s);
}
}
if (nssLibraryDirectory != null) {
String s = secmod.getLibDir();
- if ((s != null) && (s.equals(nssLibraryDirectory) == false)) {
+ if ((s != null) &&
+ (s.equals(nssLibraryDirectory) == false)) {
throw new ProviderException("NSS library directory "
+ nssLibraryDirectory
- + " invalid, NSS already initialized with " + s);
+ + " invalid, NSS already initialized with "
+ + s);
}
}
} else {
if (nssDbMode != DbMode.NO_DB) {
if (nssSecmodDirectory == null) {
- throw new ProviderException("Secmod not initialized and "
- + "nssSecmodDirectory not specified");
+ throw new ProviderException(
+ "Secmod not initialized and "
+ + "nssSecmodDirectory not specified");
}
} else {
if (nssSecmodDirectory != null) {
- throw new ProviderException
- ("nssSecmodDirectory must not be specified in noDb mode");
+ throw new ProviderException(
+ "nssSecmodDirectory must not be "
+ + "specified in noDb mode");
}
}
- secmod.initialize(nssDbMode, nssSecmodDirectory, nssLibraryDirectory);
+ secmod.initialize(nssDbMode, nssSecmodDirectory,
+ nssLibraryDirectory);
}
} catch (IOException e) {
// XXX which exception to throw
@@ -211,7 +221,8 @@
if (nssModule != null) {
moduleName = "fips";
} else {
- moduleName = (nssDbMode == DbMode.NO_DB) ? "crypto" : "keystore";
+ moduleName = (nssDbMode == DbMode.NO_DB) ?
+ "crypto" : "keystore";
}
}
if (moduleName.equals("fips")) {
@@ -253,10 +264,12 @@
+ ": only " + k + " external NSS modules available");
}
} else {
- throw new ProviderException("Unknown NSS module: " + moduleName);
+ throw new ProviderException(
+ "Unknown NSS module: " + moduleName);
}
if (nssModule == null) {
- throw new ProviderException("NSS module not available: " + moduleName);
+ throw new ProviderException(
+ "NSS module not available: " + moduleName);
}
if (nssModule.hasInitializedProvider()) {
throw new ProviderException("Secmod module already configured");
@@ -296,8 +309,9 @@
initArgs.flags = CKF_OS_LOCKING_OK;
PKCS11 tmpPKCS11;
try {
- tmpPKCS11 = PKCS11.getInstance
- (library, functionList, initArgs, config.getOmitInitialize());
+ tmpPKCS11 = PKCS11.getInstance(
+ library, functionList, initArgs,
+ config.getOmitInitialize());
} catch (PKCS11Exception e) {
if (debug != null) {
debug.println("Multi-threaded initialization failed: " + e);
@@ -312,8 +326,8 @@
} else {
initArgs.flags = 0;
}
- tmpPKCS11 = PKCS11.getInstance
- (library, functionList, initArgs, config.getOmitInitialize());
+ tmpPKCS11 = PKCS11.getInstance(library,
+ functionList, initArgs, config.getOmitInitialize());
}
p11 = tmpPKCS11;
@@ -336,8 +350,10 @@
System.out.println("Slots with tokens: " + toString(slots));
}
if (slotID < 0) {
- if ((slotListIndex < 0) || (slotListIndex >= slots.length)) {
- throw new ProviderException("slotListIndex is " + slotListIndex
+ if ((slotListIndex < 0)
+ || (slotListIndex >= slots.length)) {
+ throw new ProviderException("slotListIndex is "
+ + slotListIndex
+ " but token only has " + slots.length + " slots");
}
slotID = slots[slotListIndex];
@@ -575,12 +591,15 @@
d(KF, "DH", P11DHKeyFactory, s("DiffieHellman"),
m(CKM_DH_PKCS_KEY_PAIR_GEN, CKM_DH_PKCS_DERIVE));
d(KF, "EC", P11DHKeyFactory,
- m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE, CKM_ECDSA, CKM_ECDSA_SHA1));
+ m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE,
+ CKM_ECDSA, CKM_ECDSA_SHA1));
// AlgorithmParameters for EC.
// Only needed until we have an EC implementation in the SUN provider.
- d(AGP, "EC", "sun.security.ec.ECParameters", s("1.2.840.10045.2.1"),
- m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE, CKM_ECDSA, CKM_ECDSA_SHA1));
+ d(AGP, "EC", "sun.security.ec.ECParameters",
+ s("1.2.840.10045.2.1"),
+ m(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE,
+ CKM_ECDSA, CKM_ECDSA_SHA1));
d(KA, "DH", P11KeyAgreement, s("DiffieHellman"),
m(CKM_DH_PKCS_DERIVE));
@@ -654,12 +673,16 @@
d(SIG, "SHA512withRSA", P11Signature,
m(CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
- d(KG, "SunTlsRsaPremasterSecret", "sun.security.pkcs11.P11TlsRsaPremasterSecretGenerator",
+ d(KG, "SunTlsRsaPremasterSecret",
+ "sun.security.pkcs11.P11TlsRsaPremasterSecretGenerator",
m(CKM_SSL3_PRE_MASTER_KEY_GEN, CKM_TLS_PRE_MASTER_KEY_GEN));
- d(KG, "SunTlsMasterSecret", "sun.security.pkcs11.P11TlsMasterSecretGenerator",
+ d(KG, "SunTlsMasterSecret",
+ "sun.security.pkcs11.P11TlsMasterSecretGenerator",
m(CKM_SSL3_MASTER_KEY_DERIVE, CKM_TLS_MASTER_KEY_DERIVE,
- CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_MASTER_KEY_DERIVE_DH));
- d(KG, "SunTlsKeyMaterial", "sun.security.pkcs11.P11TlsKeyMaterialGenerator",
+ CKM_SSL3_MASTER_KEY_DERIVE_DH,
+ CKM_TLS_MASTER_KEY_DERIVE_DH));
+ d(KG, "SunTlsKeyMaterial",
+ "sun.security.pkcs11.P11TlsKeyMaterialGenerator",
m(CKM_SSL3_KEY_AND_MAC_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE));
d(KG, "SunTlsPrf", "sun.security.pkcs11.P11TlsPrfGenerator",
m(CKM_TLS_PRF, CKM_NSS_TLS_PRF_GENERAL));
@@ -773,6 +796,13 @@
System.out.println(token.tokenInfo);
}
long[] supportedMechanisms = p11.C_GetMechanismList(slotID);
+
+ // Create a map from the various Descriptors to the "most
+ // preferred" mechanism that was defined during the
+ // static initialization. For example, DES/CBC/PKCS5Padding
+ // could be mapped to CKM_DES_CBC_PAD or CKM_DES_CBC. Prefer
+ // the earliest entry. When asked for "DES/CBC/PKCS5Padding", we
+ // return a CKM_DES_CBC_PAD.
final Map<Descriptor,Integer> supportedAlgs =
new HashMap<Descriptor,Integer>();
for (int i = 0; i < supportedMechanisms.length; i++) {
@@ -807,6 +837,9 @@
supportedAlgs.put(d, integerMech);
continue;
}
+ // See if there is something "more preferred"
+ // than what we currently have in the supportedAlgs
+ // map.
int intOldMech = oldMech.intValue();
for (int j = 0; j < d.mechanisms.length; j++) {
int nextMech = d.mechanisms[j];
diff --git a/src/share/classes/sun/security/rsa/RSAKeyFactory.java b/src/share/classes/sun/security/rsa/RSAKeyFactory.java
index 17ce8cd..d877f28 100644
--- a/src/share/classes/sun/security/rsa/RSAKeyFactory.java
+++ b/src/share/classes/sun/security/rsa/RSAKeyFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,8 @@
import java.security.interfaces.*;
import java.security.spec.*;
+import sun.security.action.GetPropertyAction;
+
/**
* KeyFactory for RSA keys. Keys must be instances of PublicKey or PrivateKey
* and getAlgorithm() must return "RSA". For such keys, it supports conversion
@@ -68,6 +70,24 @@
private final static Class<?> x509KeySpecClass = X509EncodedKeySpec.class;
private final static Class<?> pkcs8KeySpecClass = PKCS8EncodedKeySpec.class;
+ public final static int MIN_MODLEN = 512;
+ public final static int MAX_MODLEN = 16384;
+
+ /*
+ * If the modulus length is above this value, restrict the size of
+ * the exponent to something that can be reasonably computed. We
+ * could simply hardcode the exp len to something like 64 bits, but
+ * this approach allows flexibility in case impls would like to use
+ * larger module and exponent values.
+ */
+ public final static int MAX_MODLEN_RESTRICT_EXP = 3072;
+ public final static int MAX_RESTRICTED_EXPLEN = 64;
+
+ private static final boolean restrictExpLen =
+ "true".equalsIgnoreCase(AccessController.doPrivileged(
+ new GetPropertyAction(
+ "sun.security.rsa.restrictRSAExponent", "true")));
+
// instance used for static translateKey();
private final static RSAKeyFactory INSTANCE = new RSAKeyFactory();
@@ -76,74 +96,79 @@
}
/**
- * Static method to convert Key into a useable instance of
- * RSAPublicKey or RSAPrivate(Crt)Key. Check the key and convert it
- * to a SunRsaSign key if necessary. If the key is not an RSA key
- * or cannot be used, throw an InvalidKeyException.
- *
- * The difference between this method and engineTranslateKey() is that
- * we do not convert keys of other providers that are already an
- * instance of RSAPublicKey or RSAPrivate(Crt)Key.
+ * Static method to convert Key into an instance of RSAPublicKeyImpl
+ * or RSAPrivate(Crt)KeyImpl. If the key is not an RSA key or cannot be
+ * used, throw an InvalidKeyException.
*
* Used by RSASignature and RSACipher.
*/
public static RSAKey toRSAKey(Key key) throws InvalidKeyException {
- if (key instanceof RSAKey) {
- RSAKey rsaKey = (RSAKey)key;
- checkKey(rsaKey);
- return rsaKey;
+ if ((key instanceof RSAPrivateKeyImpl) ||
+ (key instanceof RSAPrivateCrtKeyImpl) ||
+ (key instanceof RSAPublicKeyImpl)) {
+ return (RSAKey)key;
} else {
return (RSAKey)INSTANCE.engineTranslateKey(key);
}
}
- /**
- * Check that the given RSA key is valid.
+ /*
+ * Single test entry point for all of the mechanisms in the SunRsaSign
+ * provider (RSA*KeyImpls). All of the tests are the same.
+ *
+ * For compatibility, we round up to the nearest byte here:
+ * some Key impls might pass in a value within a byte of the
+ * real value.
*/
- private static void checkKey(RSAKey key) throws InvalidKeyException {
- // check for subinterfaces, omit additional checks for our keys
- if (key instanceof RSAPublicKey) {
- if (key instanceof RSAPublicKeyImpl) {
- return;
- }
- } else if (key instanceof RSAPrivateKey) {
- if ((key instanceof RSAPrivateCrtKeyImpl)
- || (key instanceof RSAPrivateKeyImpl)) {
- return;
- }
- } else {
- throw new InvalidKeyException("Neither a public nor a private key");
- }
- // RSAKey does not extend Key, so we need to do a cast
- String keyAlg = ((Key)key).getAlgorithm();
- if (keyAlg.equals("RSA") == false) {
- throw new InvalidKeyException("Not an RSA key: " + keyAlg);
- }
- BigInteger modulus;
- // some providers implement RSAKey for keys where the values are
- // not accessible (although they should). Detect those here
- // for a more graceful failure.
- try {
- modulus = key.getModulus();
- if (modulus == null) {
- throw new InvalidKeyException("Modulus is missing");
- }
- } catch (RuntimeException e) {
- throw new InvalidKeyException(e);
- }
- checkKeyLength(modulus);
+ static void checkRSAProviderKeyLengths(int modulusLen, BigInteger exponent)
+ throws InvalidKeyException {
+ checkKeyLengths(((modulusLen + 7) & ~7), exponent,
+ RSAKeyFactory.MIN_MODLEN, Integer.MAX_VALUE);
}
/**
- * Check the length of the modulus of an RSA key. We only support keys
- * at least 505 bits long.
+ * Check the length of an RSA key modulus/exponent to make sure it
+ * is not too short or long. Some impls have their own min and
+ * max key sizes that may or may not match with a system defined value.
+ *
+ * @param modulusLen the bit length of the RSA modulus.
+ * @param exponent the RSA exponent
+ * @param minModulusLen if > 0, check to see if modulusLen is at
+ * least this long, otherwise unused.
+ * @param maxModulusLen caller will allow this max number of bits.
+ * Allow the smaller of the system-defined maximum and this param.
+ *
+ * @throws InvalidKeyException if any of the values are unacceptable.
*/
- static void checkKeyLength(BigInteger modulus) throws InvalidKeyException {
- if (modulus.bitLength() < 505) {
- // some providers may generate slightly shorter keys
- // accept them if the encoding is at least 64 bytes long
- throw new InvalidKeyException
- ("RSA keys must be at least 512 bits long");
+ public static void checkKeyLengths(int modulusLen, BigInteger exponent,
+ int minModulusLen, int maxModulusLen) throws InvalidKeyException {
+
+ if ((minModulusLen > 0) && (modulusLen < (minModulusLen))) {
+ throw new InvalidKeyException( "RSA keys must be at least " +
+ minModulusLen + " bits long");
+ }
+
+ // Even though our policy file may allow this, we don't want
+ // either value (mod/exp) to be too big.
+
+ int maxLen = Math.min(maxModulusLen, MAX_MODLEN);
+
+ // If a RSAPrivateKey/RSAPublicKey, make sure the
+ // modulus len isn't too big.
+ if (modulusLen > maxLen) {
+ throw new InvalidKeyException(
+ "RSA keys must be no longer than " + maxLen + " bits");
+ }
+
+ // If a RSAPublicKey, make sure the exponent isn't too big.
+ if (restrictExpLen && (exponent != null) &&
+ (modulusLen > MAX_MODLEN_RESTRICT_EXP) &&
+ (exponent.bitLength() > MAX_RESTRICTED_EXPLEN)) {
+ throw new InvalidKeyException(
+ "RSA exponents can be no longer than " +
+ MAX_RESTRICTED_EXPLEN + " bits " +
+ " if modulus is greater than " +
+ MAX_MODLEN_RESTRICT_EXP + " bits");
}
}
diff --git a/src/share/classes/sun/security/rsa/RSAKeyPairGenerator.java b/src/share/classes/sun/security/rsa/RSAKeyPairGenerator.java
index f800dec..2898a3d 100644
--- a/src/share/classes/sun/security/rsa/RSAKeyPairGenerator.java
+++ b/src/share/classes/sun/security/rsa/RSAKeyPairGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,7 @@
// public exponent to use
private BigInteger publicExponent;
- // size of the key to generate, >= 512
+ // size of the key to generate, >= RSAKeyFactory.MIN_MODLEN
private int keySize;
// PRNG to use
@@ -60,15 +60,16 @@
// initialize the generator. See JCA doc
public void initialize(int keySize, SecureRandom random) {
- if (keySize < 512) {
- throw new InvalidParameterException
- ("Key size must be at least 512 bits");
+
+ // do not allow unreasonably small or large key sizes,
+ // probably user error
+ try {
+ RSAKeyFactory.checkKeyLengths(keySize, RSAKeyGenParameterSpec.F4,
+ 512, 64 * 1024);
+ } catch (InvalidKeyException e) {
+ throw new InvalidParameterException(e.getMessage());
}
- if (keySize > 64 * 1024) {
- // do not allow unreasonably large key sizes, probably user error
- throw new InvalidParameterException
- ("Key size must be 65536 bits or less");
- }
+
this.keySize = keySize;
this.random = random;
this.publicExponent = RSAKeyGenParameterSpec.F4;
@@ -77,35 +78,41 @@
// second initialize method. See JCA doc.
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
throws InvalidAlgorithmParameterException {
+
if (params instanceof RSAKeyGenParameterSpec == false) {
throw new InvalidAlgorithmParameterException
("Params must be instance of RSAKeyGenParameterSpec");
}
+
RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec)params;
- keySize = rsaSpec.getKeysize();
- publicExponent = rsaSpec.getPublicExponent();
- this.random = random;
- if (keySize < 512) {
- throw new InvalidAlgorithmParameterException
- ("Key size must be at least 512 bits");
- }
- if (keySize > 64 * 1024) {
- // do not allow unreasonably large key sizes, probably user error
- throw new InvalidAlgorithmParameterException
- ("Key size must be 65536 bits or less");
- }
- if (publicExponent == null) {
- publicExponent = RSAKeyGenParameterSpec.F4;
+ int tmpKeySize = rsaSpec.getKeysize();
+ BigInteger tmpPublicExponent = rsaSpec.getPublicExponent();
+
+ if (tmpPublicExponent == null) {
+ tmpPublicExponent = RSAKeyGenParameterSpec.F4;
} else {
- if (publicExponent.compareTo(RSAKeyGenParameterSpec.F0) < 0) {
+ if (tmpPublicExponent.compareTo(RSAKeyGenParameterSpec.F0) < 0) {
throw new InvalidAlgorithmParameterException
("Public exponent must be 3 or larger");
}
- if (publicExponent.bitLength() > keySize) {
+ if (tmpPublicExponent.bitLength() > tmpKeySize) {
throw new InvalidAlgorithmParameterException
("Public exponent must be smaller than key size");
}
}
+
+ // do not allow unreasonably large key sizes, probably user error
+ try {
+ RSAKeyFactory.checkKeyLengths(tmpKeySize, tmpPublicExponent,
+ 512, 64 * 1024);
+ } catch (InvalidKeyException e) {
+ throw new InvalidAlgorithmParameterException(
+ "Invalid key sizes", e);
+ }
+
+ this.keySize = tmpKeySize;
+ this.publicExponent = tmpPublicExponent;
+ this.random = random;
}
// generate the keypair. See JCA doc
diff --git a/src/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java b/src/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java
index ac296b4..640972a 100644
--- a/src/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java
+++ b/src/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -89,7 +89,7 @@
*/
RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException {
decode(encoded);
- RSAKeyFactory.checkKeyLength(n);
+ RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
}
/**
@@ -107,7 +107,8 @@
this.pe = pe;
this.qe = qe;
this.coeff = coeff;
- RSAKeyFactory.checkKeyLength(n);
+ RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
+
// generate the encoding
algid = rsaId;
try {
diff --git a/src/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java b/src/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java
index 1f883f4..860e770 100644
--- a/src/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java
+++ b/src/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -61,7 +61,7 @@
RSAPrivateKeyImpl(BigInteger n, BigInteger d) throws InvalidKeyException {
this.n = n;
this.d = d;
- RSAKeyFactory.checkKeyLength(n);
+ RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), null);
// generate the encoding
algid = RSAPrivateCrtKeyImpl.rsaId;
try {
diff --git a/src/share/classes/sun/security/rsa/RSAPublicKeyImpl.java b/src/share/classes/sun/security/rsa/RSAPublicKeyImpl.java
index c500ca2..6db08f6 100644
--- a/src/share/classes/sun/security/rsa/RSAPublicKeyImpl.java
+++ b/src/share/classes/sun/security/rsa/RSAPublicKeyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -56,10 +56,11 @@
* Construct a key from its components. Used by the
* RSAKeyFactory and the RSAKeyPairGenerator.
*/
- public RSAPublicKeyImpl(BigInteger n, BigInteger e) throws InvalidKeyException {
+ public RSAPublicKeyImpl(BigInteger n, BigInteger e)
+ throws InvalidKeyException {
this.n = n;
this.e = e;
- RSAKeyFactory.checkKeyLength(n);
+ RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
// generate the encoding
algid = RSAPrivateCrtKeyImpl.rsaId;
try {
@@ -80,7 +81,7 @@
*/
public RSAPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
decode(encoded);
- RSAKeyFactory.checkKeyLength(n);
+ RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
}
// see JCA doc
diff --git a/src/share/lib/management/jmxremote.access b/src/share/lib/management/jmxremote.access
index 765f118..ce80b47 100644
--- a/src/share/lib/management/jmxremote.access
+++ b/src/share/lib/management/jmxremote.access
@@ -8,7 +8,7 @@
# passwords. To be functional, a role must have an entry in
# both the password and the access files.
#
-# Default location of this file is $JRE/lib/management/jmxremote.access
+# The default location of this file is $JRE/lib/management/jmxremote.access
# You can specify an alternate location by specifying a property in
# the management config file $JRE/lib/management/management.properties
# (See that file for details)
@@ -16,7 +16,7 @@
# The file format for password and access files is syntactically the same
# as the Properties file format. The syntax is described in the Javadoc
# for java.util.Properties.load.
-# Typical access file has multiple lines, where each line is blank,
+# A typical access file has multiple lines, where each line is blank,
# a comment (like this one), or an access control entry.
#
# An access control entry consists of a role name, and an
@@ -29,10 +29,38 @@
# role can read measurements but cannot perform any action
# that changes the environment of the running program.
# "readwrite" grants access to read and write attributes of MBeans,
-# to invoke operations on them, and to create or remove them.
-# This access should be granted to only trusted clients,
-# since they can potentially interfere with the smooth
-# operation of a running program
+# to invoke operations on them, and optionally
+# to create or remove them. This access should be granted
+# only to trusted clients, since they can potentially
+# interfere with the smooth operation of a running program.
+#
+# The "readwrite" access level can optionally be followed by the "create" and/or
+# "unregister" keywords. The "unregister" keyword grants access to unregister
+# (delete) MBeans. The "create" keyword grants access to create MBeans of a
+# particular class or of any class matching a particular pattern. Access
+# should only be granted to create MBeans of known and trusted classes.
+#
+# For example, the following entry would grant readwrite access
+# to "controlRole", as well as access to create MBeans of the class
+# javax.management.monitor.CounterMonitor and to unregister any MBean:
+# controlRole readwrite \
+# create javax.management.monitor.CounterMonitorMBean \
+# unregister
+# or equivalently:
+# controlRole readwrite unregister create javax.management.monitor.CounterMBean
+#
+# The following entry would grant readwrite access as well as access to create
+# MBeans of any class in the packages javax.management.monitor and
+# javax.management.timer:
+# controlRole readwrite \
+# create javax.management.monitor.*,javax.management.timer.* \
+# unregister
+#
+# The \ character is defined in the Properties file syntax to allow continuation
+# lines as shown here. A * in a class pattern matches a sequence of characters
+# other than dot (.), so javax.management.monitor.* matches
+# javax.management.monitor.CounterMonitor but not
+# javax.management.monitor.foo.Bar.
#
# A given role should have at most one entry in this file. If a role
# has no entry, it has no access.
@@ -42,7 +70,10 @@
#
# Default access control entries:
# o The "monitorRole" role has readonly access.
-# o The "controlRole" role has readwrite access.
+# o The "controlRole" role has readwrite access and can create the standard
+# Timer and Monitor MBeans defined by the JMX API.
monitorRole readonly
-controlRole readwrite
+controlRole readwrite \
+ create javax.management.monitor.*,javax.management.timer.* \
+ unregister
diff --git a/src/share/native/com/sun/java/util/jar/pack/bands.cpp b/src/share/native/com/sun/java/util/jar/pack/bands.cpp
index c78644c..a0d64dc 100644
--- a/src/share/native/com/sun/java/util/jar/pack/bands.cpp
+++ b/src/share/native/com/sun/java/util/jar/pack/bands.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -94,6 +94,7 @@
assert(!valc->isMalloc);
}
xvs.init(u->rp, u->rplimit, valc);
+ CHECK;
int X = xvs.getInt();
if (valc->S() != 0) {
assert(valc->min <= -256);
@@ -117,6 +118,7 @@
byte XB_byte = (byte) XB;
byte* XB_ptr = &XB_byte;
cm.init(u->rp, u->rplimit, XB_ptr, 0, defc, length, null);
+ CHECK;
} else {
NOT_PRODUCT(byte* meta_rp0 = u->meta_rp);
assert(u->meta_rp != null);
@@ -215,8 +217,19 @@
if (length == 0) return 0;
if (total_memo > 0) return total_memo-1;
int total = getInt();
+ // overflow checks require that none of the addends are <0,
+ // and that the partial sums never overflow (wrap negative)
+ if (total < 0) {
+ abort("overflow detected");
+ return 0;
+ }
for (int k = length-1; k > 0; k--) {
+ int prev_total = total;
total += vs[0].getInt();
+ if (total < prev_total) {
+ abort("overflow detected");
+ return 0;
+ }
}
rewind();
total_memo = total+1;
diff --git a/src/share/native/com/sun/java/util/jar/pack/bytes.cpp b/src/share/native/com/sun/java/util/jar/pack/bytes.cpp
index ecc45ce..097c51c 100644
--- a/src/share/native/com/sun/java/util/jar/pack/bytes.cpp
+++ b/src/share/native/com/sun/java/util/jar/pack/bytes.cpp
@@ -56,7 +56,7 @@
return;
}
byte* oldptr = ptr;
- ptr = (byte*)::realloc(ptr, len_+1);
+ ptr = (len_ >= PSIZE_MAX) ? null : (byte*)::realloc(ptr, len_+1);
if (ptr != null) {
mtrace('r', oldptr, 0);
mtrace('m', ptr, len_+1);
@@ -128,7 +128,7 @@
// Make sure there are 'o' bytes beyond the fill pointer,
// advance the fill pointer, and return the old fill pointer.
byte* fillbytes::grow(size_t s) {
- size_t nlen = b.len+s;
+ size_t nlen = add_size(b.len, s);
if (nlen <= allocated) {
b.len = nlen;
return limit()-s;
diff --git a/src/share/native/com/sun/java/util/jar/pack/coding.cpp b/src/share/native/com/sun/java/util/jar/pack/coding.cpp
index dec681c..df02104 100644
--- a/src/share/native/com/sun/java/util/jar/pack/coding.cpp
+++ b/src/share/native/com/sun/java/util/jar/pack/coding.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2002-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -814,6 +814,7 @@
}
band_rp = vs.rp;
}
+ CHECK;
// Get an accurate upper limit now.
vs0.rplimit = band_rp;
diff --git a/src/share/native/com/sun/java/util/jar/pack/defines.h b/src/share/native/com/sun/java/util/jar/pack/defines.h
index 0bf25d5..87ce338 100644
--- a/src/share/native/com/sun/java/util/jar/pack/defines.h
+++ b/src/share/native/com/sun/java/util/jar/pack/defines.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,11 +47,13 @@
#define NOT_PRODUCT(xxx)
#define assert(p)
#define PRINTCR(args)
+#define VERSION_STRING "%s version %s\n"
#else
#define IF_PRODUCT(xxx)
#define NOT_PRODUCT(xxx) xxx
#define assert(p) ((p) || assert_failed(#p))
#define PRINTCR(args) u->verbose && u->printcr_if_verbose args
+#define VERSION_STRING "%s version non-product %s\n"
extern "C" void breakpoint();
extern int assert_failed(const char*);
#define BREAK (breakpoint())
@@ -79,9 +81,9 @@
#define lengthof(array) (sizeof(array)/sizeof(array[0]))
-#define NEW(T, n) (T*) must_malloc((int)(sizeof(T)*(n)))
-#define U_NEW(T, n) (T*) u->alloc(sizeof(T)*(n))
-#define T_NEW(T, n) (T*) u->temp_alloc(sizeof(T)*(n))
+#define NEW(T, n) (T*) must_malloc((int)(scale_size(n, sizeof(T))))
+#define U_NEW(T, n) (T*) u->alloc(scale_size(n, sizeof(T)))
+#define T_NEW(T, n) (T*) u->temp_alloc(scale_size(n, sizeof(T)))
// bytes and byte arrays
@@ -153,6 +155,8 @@
#define CHECK_NULL_(y,p) _CHECK_DO((p)==null, return y)
#define CHECK_NULL_0(p) _CHECK_DO((p)==null, return 0)
+#define CHECK_COUNT(t) if (t < 0){abort("bad value count");} CHECK
+
#define STR_TRUE "true"
#define STR_FALSE "false"
diff --git a/src/share/native/com/sun/java/util/jar/pack/main.cpp b/src/share/native/com/sun/java/util/jar/pack/main.cpp
index 789841d..104f38b 100644
--- a/src/share/native/com/sun/java/util/jar/pack/main.cpp
+++ b/src/share/native/com/sun/java/util/jar/pack/main.cpp
@@ -299,7 +299,7 @@
case 'J': argp += 1; break; // skip ignored -Jxxx parameter
case 'V':
- fprintf(u.errstrm, "%s version %s\n", nbasename(argv[0]), sccsver);
+ fprintf(u.errstrm, VERSION_STRING, nbasename(argv[0]), sccsver);
exit(0);
case 'h':
diff --git a/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
index 90b9f72..a6f4ca0 100644
--- a/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
+++ b/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -523,15 +523,39 @@
enum {
MAGIC_BYTES = 4,
AH_LENGTH_0 = 3, //minver, majver, options are outside of archive_size
+ AH_LENGTH_0_MAX = AH_LENGTH_0 + 1, // options might have 2 bytes
AH_LENGTH = 26, //maximum archive header length (w/ all fields)
// Length contributions from optional header fields:
AH_FILE_HEADER_LEN = 5, // sizehi/lo/next/modtime/files
+ AH_ARCHIVE_SIZE_LEN = 2, // sizehi/lo only; part of AH_FILE_HEADER_LEN
AH_CP_NUMBER_LEN = 4, // int/float/long/double
AH_SPECIAL_FORMAT_LEN = 2, // layouts/band-headers
AH_LENGTH_MIN = AH_LENGTH
-(AH_FILE_HEADER_LEN+AH_SPECIAL_FORMAT_LEN+AH_CP_NUMBER_LEN),
+ ARCHIVE_SIZE_MIN = AH_LENGTH_MIN - (AH_LENGTH_0 + AH_ARCHIVE_SIZE_LEN),
FIRST_READ = MAGIC_BYTES + AH_LENGTH_MIN
};
+
+ assert(AH_LENGTH_MIN == 15); // # of UNSIGNED5 fields required after archive_magic
+ assert(ARCHIVE_SIZE_MIN == 10); // # of UNSIGNED5 fields required after archive_size
+ // An absolute minimum null archive is magic[4], {minver,majver,options}[3],
+ // archive_size[0], cp_counts[8], class_counts[4], for a total of 19 bytes.
+ // (Note that archive_size is optional; it may be 0..10 bytes in length.)
+ // The first read must capture everything up through the options field.
+ // This happens to work even if {minver,majver,options} is a pathological
+ // 15 bytes long. Legal pack files limit those three fields to 1+1+2 bytes.
+ assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0 * B_MAX);
+
+ // Up through archive_size, the largest possible archive header is
+ // magic[4], {minver,majver,options}[4], archive_size[10].
+ // (Note only the low 12 bits of options are allowed to be non-zero.)
+ // In order to parse archive_size, we need at least this many bytes
+ // in the first read. Of course, if archive_size_hi is more than
+ // a byte, we probably will fail to allocate the buffer, since it
+ // will be many gigabytes long. This is a practical, not an
+ // architectural limit to Pack200 archive sizes.
+ assert(FIRST_READ >= MAGIC_BYTES + AH_LENGTH_0_MAX + 2*B_MAX);
+
bool foreign_buf = (read_input_fn == null);
byte initbuf[(int)FIRST_READ + (int)C_SLOP + 200]; // 200 is for JAR I/O
if (foreign_buf) {
@@ -547,7 +571,7 @@
// There is no way to tell the caller that we used only part of them.
// Therefore, the caller must use only a bare minimum of read-ahead.
if (inbytes.len > FIRST_READ) {
- abort("too much pushback");
+ abort("too much read-ahead");
return;
}
input.set(initbuf, sizeof(initbuf));
@@ -557,7 +581,7 @@
rplimit += inbytes.len;
bytes_read += inbytes.len;
}
- // Read only 19 bytes, which is certain to contain #archive_size fields,
+ // Read only 19 bytes, which is certain to contain #archive_options fields,
// but is certain not to overflow past the archive_header.
input.b.len = FIRST_READ;
if (!ensure_input(FIRST_READ))
@@ -629,26 +653,25 @@
#undef ORBIT
if ((archive_options & ~OPTION_LIMIT) != 0) {
fprintf(errstrm, "Warning: Illegal archive options 0x%x\n",
- archive_options);
- // Do not abort. If the format really changes, version numbers will bump.
- //abort("illegal archive options");
+ archive_options);
+ abort("illegal archive options");
+ return;
}
if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) {
uint hi = hdr.getInt();
uint lo = hdr.getInt();
- archive_size = band::makeLong(hi, lo);
+ julong x = band::makeLong(hi, lo);
+ archive_size = (size_t) x;
+ if (archive_size != x) {
+ // Silly size specified; force overflow.
+ archive_size = PSIZE_MAX+1;
+ }
hdrVals += 2;
} else {
hdrValsSkipped += 2;
}
- if (archive_size != (size_t)archive_size) {
- // Silly size specified.
- abort("archive too large");
- return;
- }
-
// Now we can size the whole archive.
// Read everything else into a mega-buffer.
rp = hdr.rp;
@@ -662,9 +685,18 @@
abort("EOF reading fixed input buffer");
return;
}
- } else if (archive_size > 0) {
- input.set(U_NEW(byte, (size_t)(header_size_0 + archive_size + C_SLOP)),
- (size_t) header_size_0 + (size_t)archive_size);
+ } else if (archive_size != 0) {
+ if (archive_size < ARCHIVE_SIZE_MIN) {
+ abort("impossible archive size"); // bad input data
+ return;
+ }
+ if (archive_size < header_size_1) {
+ abort("too much read-ahead"); // somehow we pre-fetched too much?
+ return;
+ }
+ input.set(U_NEW(byte, add_size(header_size_0, archive_size, C_SLOP)),
+ (size_t) header_size_0 + archive_size);
+ CHECK;
assert(input.limit()[0] == 0);
// Move all the bytes we read initially into the real buffer.
input.b.copyFrom(initbuf, header_size);
@@ -673,17 +705,17 @@
} else {
// It's more complicated and painful.
// A zero archive_size means that we must read until EOF.
- assert(archive_size == 0);
input.init(CHUNK*2);
CHECK;
input.b.len = input.allocated;
rp = rplimit = input.base();
// Set up input buffer as if we already read the header:
input.b.copyFrom(initbuf, header_size);
+ CHECK;
rplimit += header_size;
while (ensure_input(input.limit() - rp)) {
size_t dataSoFar = input_remaining();
- size_t nextSize = dataSoFar + CHUNK;
+ size_t nextSize = add_size(dataSoFar, CHUNK);
input.ensureSize(nextSize);
CHECK;
input.b.len = input.allocated;
@@ -715,8 +747,10 @@
if ((archive_options & AO_HAVE_FILE_HEADERS) != 0) {
archive_next_count = hdr.getInt();
+ CHECK_COUNT(archive_next_count);
archive_modtime = hdr.getInt();
file_count = hdr.getInt();
+ CHECK_COUNT(file_count);
hdrVals += 3;
} else {
hdrValsSkipped += 3;
@@ -724,7 +758,9 @@
if ((archive_options & AO_HAVE_SPECIAL_FORMATS) != 0) {
band_headers_size = hdr.getInt();
+ CHECK_COUNT(band_headers_size);
attr_definition_count = hdr.getInt();
+ CHECK_COUNT(attr_definition_count);
hdrVals += 2;
} else {
hdrValsSkipped += 2;
@@ -744,13 +780,16 @@
}
}
cp_counts[k] = hdr.getInt();
+ CHECK_COUNT(cp_counts[k]);
hdrVals += 1;
}
ic_count = hdr.getInt();
+ CHECK_COUNT(ic_count);
default_class_minver = hdr.getInt();
default_class_majver = hdr.getInt();
class_count = hdr.getInt();
+ CHECK_COUNT(class_count);
hdrVals += 4;
// done with archive_header
@@ -807,7 +846,6 @@
bytes::of(band_headers.limit(), C_SLOP).clear(_meta_error);
}
-
void unpacker::finish() {
if (verbose >= 1) {
fprintf(errstrm,
@@ -973,12 +1011,12 @@
// First band: Read lengths of shared prefixes.
if (len > PREFIX_SKIP_2)
cp_Utf8_prefix.readData(len - PREFIX_SKIP_2);
- NOT_PRODUCT(else cp_Utf8_prefix.readData(0)); // for asserts
+ NOT_PRODUCT(else cp_Utf8_prefix.readData(0)); // for asserts
// Second band: Read lengths of unshared suffixes:
if (len > SUFFIX_SKIP_1)
cp_Utf8_suffix.readData(len - SUFFIX_SKIP_1);
- NOT_PRODUCT(else cp_Utf8_suffix.readData(0)); // for asserts
+ NOT_PRODUCT(else cp_Utf8_suffix.readData(0)); // for asserts
bytes* allsuffixes = T_NEW(bytes, len);
CHECK;
@@ -2117,6 +2155,7 @@
field_descr.readData(field_count);
read_attrs(ATTR_CONTEXT_FIELD, field_count);
+ CHECK;
method_descr.readData(method_count);
read_attrs(ATTR_CONTEXT_METHOD, method_count);
@@ -2124,6 +2163,7 @@
CHECK;
read_attrs(ATTR_CONTEXT_CLASS, class_count);
+ CHECK;
read_code_headers();
@@ -2150,10 +2190,12 @@
assert(endsWith(xxx_flags_hi.name, "_flags_hi"));
if (haveLongFlags)
xxx_flags_hi.readData(obj_count);
+ CHECK;
band& xxx_flags_lo = ad.xxx_flags_lo();
assert(endsWith(xxx_flags_lo.name, "_flags_lo"));
xxx_flags_lo.readData(obj_count);
+ CHECK;
// pre-scan flags, counting occurrences of each index bit
julong indexMask = ad.flagIndexMask(); // which flag bits are index bits?
@@ -2176,11 +2218,13 @@
assert(endsWith(xxx_attr_count.name, "_attr_count"));
// There is one count element for each 1<<16 bit set in flags:
xxx_attr_count.readData(ad.predefCount(X_ATTR_OVERFLOW));
+ CHECK;
band& xxx_attr_indexes = ad.xxx_attr_indexes();
assert(endsWith(xxx_attr_indexes.name, "_attr_indexes"));
int overflowIndexCount = xxx_attr_count.getIntTotal();
xxx_attr_indexes.readData(overflowIndexCount);
+ CHECK;
// pre-scan attr indexes, counting occurrences of each value
for (i = 0; i < overflowIndexCount; i++) {
idx = xxx_attr_indexes.getInt();
@@ -2211,6 +2255,7 @@
}
}
ad.xxx_attr_calls().readData(backwardCounts);
+ CHECK;
// Read built-in bands.
// Mostly, these are hand-coded equivalents to readBandData().
@@ -2219,42 +2264,53 @@
count = ad.predefCount(CLASS_ATTR_SourceFile);
class_SourceFile_RUN.readData(count);
+ CHECK;
count = ad.predefCount(CLASS_ATTR_EnclosingMethod);
class_EnclosingMethod_RC.readData(count);
class_EnclosingMethod_RDN.readData(count);
+ CHECK;
count = ad.predefCount(X_ATTR_Signature);
class_Signature_RS.readData(count);
+ CHECK;
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
count = ad.predefCount(CLASS_ATTR_InnerClasses);
class_InnerClasses_N.readData(count);
+ CHECK;
+
count = class_InnerClasses_N.getIntTotal();
class_InnerClasses_RC.readData(count);
class_InnerClasses_F.readData(count);
+ CHECK;
// Drop remaining columns wherever flags are zero:
count -= class_InnerClasses_F.getIntCount(0);
class_InnerClasses_outer_RCN.readData(count);
class_InnerClasses_name_RUN.readData(count);
+ CHECK;
count = ad.predefCount(CLASS_ATTR_ClassFile_version);
class_ClassFile_version_minor_H.readData(count);
class_ClassFile_version_major_H.readData(count);
+ CHECK;
break;
case ATTR_CONTEXT_FIELD:
count = ad.predefCount(FIELD_ATTR_ConstantValue);
field_ConstantValue_KQ.readData(count);
+ CHECK;
count = ad.predefCount(X_ATTR_Signature);
field_Signature_RS.readData(count);
+ CHECK;
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
+ CHECK;
break;
case ATTR_CONTEXT_METHOD:
@@ -2266,15 +2322,18 @@
method_Exceptions_N.readData(count);
count = method_Exceptions_N.getIntTotal();
method_Exceptions_RC.readData(count);
+ CHECK;
count = ad.predefCount(X_ATTR_Signature);
method_Signature_RS.readData(count);
+ CHECK;
ad.readBandData(X_ATTR_RuntimeVisibleAnnotations);
ad.readBandData(X_ATTR_RuntimeInvisibleAnnotations);
ad.readBandData(METHOD_ATTR_RuntimeVisibleParameterAnnotations);
ad.readBandData(METHOD_ATTR_RuntimeInvisibleParameterAnnotations);
ad.readBandData(METHOD_ATTR_AnnotationDefault);
+ CHECK;
break;
case ATTR_CONTEXT_CODE:
@@ -2286,8 +2345,10 @@
return;
}
code_StackMapTable_N.readData(count);
+ CHECK;
count = code_StackMapTable_N.getIntTotal();
code_StackMapTable_frame_T.readData(count);
+ CHECK;
// the rest of it depends in a complicated way on frame tags
{
int fat_frame_count = 0;
@@ -2321,18 +2382,23 @@
// deal completely with fat frames:
offset_count += fat_frame_count;
code_StackMapTable_local_N.readData(fat_frame_count);
+ CHECK;
type_count += code_StackMapTable_local_N.getIntTotal();
code_StackMapTable_stack_N.readData(fat_frame_count);
type_count += code_StackMapTable_stack_N.getIntTotal();
+ CHECK;
// read the rest:
code_StackMapTable_offset.readData(offset_count);
code_StackMapTable_T.readData(type_count);
+ CHECK;
// (7) [RCH]
count = code_StackMapTable_T.getIntCount(7);
code_StackMapTable_RC.readData(count);
+ CHECK;
// (8) [PH]
count = code_StackMapTable_T.getIntCount(8);
code_StackMapTable_P.readData(count);
+ CHECK;
}
count = ad.predefCount(CODE_ATTR_LineNumberTable);
@@ -2654,6 +2720,7 @@
code_max_na_locals.readData();
code_handler_count.readData();
totalHandlerCount += code_handler_count.getIntTotal();
+ CHECK;
// Read handler specifications.
// Cf. PackageReader.readCodeHandlers.
@@ -2661,8 +2728,10 @@
code_handler_end_PO.readData(totalHandlerCount);
code_handler_catch_PO.readData(totalHandlerCount);
code_handler_class_RCN.readData(totalHandlerCount);
+ CHECK;
read_attrs(ATTR_CONTEXT_CODE, totalFlagsCount);
+ CHECK;
}
static inline bool is_in_range(uint n, uint min, uint max) {
diff --git a/src/share/native/com/sun/java/util/jar/pack/unpack.h b/src/share/native/com/sun/java/util/jar/pack/unpack.h
index 8bad674..4f5965d 100644
--- a/src/share/native/com/sun/java/util/jar/pack/unpack.h
+++ b/src/share/native/com/sun/java/util/jar/pack/unpack.h
@@ -204,7 +204,7 @@
// archive header fields
int magic, minver, majver;
- julong archive_size;
+ size_t archive_size;
int archive_next_count, archive_options, archive_modtime;
int band_headers_size;
int file_count, attr_definition_count, ic_count, class_count;
diff --git a/src/share/native/com/sun/java/util/jar/pack/utils.cpp b/src/share/native/com/sun/java/util/jar/pack/utils.cpp
index 9566e54..b812e73 100644
--- a/src/share/native/com/sun/java/util/jar/pack/utils.cpp
+++ b/src/share/native/com/sun/java/util/jar/pack/utils.cpp
@@ -46,14 +46,13 @@
#include "unpack.h"
-void* must_malloc(int size) {
- int msize = size;
- assert(size >= 0);
+void* must_malloc(size_t size) {
+ size_t msize = size;
#ifdef USE_MTRACE
- if (msize < sizeof(int))
+ if (msize >= 0 && msize < sizeof(int))
msize = sizeof(int); // see 0xbaadf00d below
#endif
- void* ptr = malloc(msize);
+ void* ptr = (msize > PSIZE_MAX) ? null : malloc(msize);
if (ptr != null) {
memset(ptr, 0, size);
} else {
diff --git a/src/share/native/com/sun/java/util/jar/pack/utils.h b/src/share/native/com/sun/java/util/jar/pack/utils.h
index 2fc1728..a4dc2c8 100644
--- a/src/share/native/com/sun/java/util/jar/pack/utils.h
+++ b/src/share/native/com/sun/java/util/jar/pack/utils.h
@@ -25,13 +25,31 @@
//Definitions of our util functions
-void* must_malloc(int size);
+void* must_malloc(size_t size);
#ifndef USE_MTRACE
#define mtrace(c, ptr, size)
#else
void mtrace(char c, void* ptr, size_t size);
#endif
+// overflow management
+#define OVERFLOW ((size_t)-1)
+#define PSIZE_MAX (OVERFLOW/2) /* normal size limit */
+
+inline size_t scale_size(size_t size, size_t scale) {
+ return (size > PSIZE_MAX / scale) ? OVERFLOW : size * scale;
+}
+
+inline size_t add_size(size_t size1, size_t size2) {
+ return ((size1 | size2 | (size1 + size2)) > PSIZE_MAX)
+ ? OVERFLOW
+ : size1 + size2;
+}
+
+inline size_t add_size(size_t size1, size_t size2, int size3) {
+ return add_size(add_size(size1, size2), size3);
+}
+
// These may be expensive, because they have to go via Java TSD,
// if the optional u argument is missing.
struct unpacker;
diff --git a/src/share/native/sun/awt/giflib/dgif_lib.c b/src/share/native/sun/awt/giflib/dgif_lib.c
index be91d3e..f20372f 100644
--- a/src/share/native/sun/awt/giflib/dgif_lib.c
+++ b/src/share/native/sun/awt/giflib/dgif_lib.c
@@ -722,6 +722,10 @@
GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
READ(GifFile, &CodeSize, 1); /* Read Code size from file. */
+ if (CodeSize >= 12) {
+ /* Invalid initial code size: report failure */
+ return GIF_ERROR;
+ }
BitsPerPixel = CodeSize;
Private->Buf[0] = 0; /* Input Buffer empty. */
@@ -964,10 +968,13 @@
/* If code cannot fit into RunningBits bits, must raise its size. Note
* however that codes above 4095 are used for special signaling. */
- if (++Private->RunningCode > Private->MaxCode1 &&
- Private->RunningBits < LZ_BITS) {
- Private->MaxCode1 <<= 1;
- Private->RunningBits++;
+ if (++Private->RunningCode > Private->MaxCode1) {
+ if (Private->RunningBits < LZ_BITS) {
+ Private->MaxCode1 <<= 1;
+ Private->RunningBits++;
+ } else {
+ Private->RunningCode = Private->MaxCode1;
+ }
}
return GIF_OK;
}
diff --git a/src/share/native/sun/awt/image/gif/gifdecoder.c b/src/share/native/sun/awt/image/gif/gifdecoder.c
index 1429931..893007f 100644
--- a/src/share/native/sun/awt/image/gif/gifdecoder.c
+++ b/src/share/native/sun/awt/image/gif/gifdecoder.c
@@ -191,6 +191,11 @@
int passht = passinc;
int len;
+ /* We have verified the initial code size on the java layer.
+ * Here we just check bounds for particular indexes. */
+ if (freeCode >= 4096 || maxCode >= 4096) {
+ return 0;
+ }
if (blockh == 0 || raslineh == 0
|| prefixh == 0 || suffixh == 0
|| outCodeh == 0)
diff --git a/src/share/native/sun/awt/medialib/awt_ImagingLib.c b/src/share/native/sun/awt/medialib/awt_ImagingLib.c
index 681f262..157827f 100644
--- a/src/share/native/sun/awt/medialib/awt_ImagingLib.c
+++ b/src/share/native/sun/awt/medialib/awt_ImagingLib.c
@@ -216,6 +216,16 @@
#endif /* ! DEBUG */
+static int
+getMlibEdgeHint(jint edgeHint) {
+ switch (edgeHint) {
+ case java_awt_image_ConvolveOp_EDGE_NO_OP:
+ return MLIB_EDGE_DST_COPY_SRC;
+ case java_awt_image_ConvolveOp_EDGE_ZERO_FILL:
+ default:
+ return MLIB_EDGE_DST_FILL_ZERO;
+ }
+}
/***************************************************************************
* External Functions *
@@ -400,22 +410,10 @@
}
}
- if (edgeHint == java_awt_image_ConvolveOp_EDGE_NO_OP) {
- int kw2 = kwidth>>1;
- int kh2 = kheight>>1;
- int bsize = mlib_ImageGetChannels(src)*
- (mlib_ImageGetType(src) == MLIB_BYTE ? 1 : 2);
-
- void *dstDataP = mlib_ImageGetData(dst);
- void *srcDataP = mlib_ImageGetData(src);
- /* REMIND: Copy a smaller area */
- memcpy(dstDataP, srcDataP, dst->width*dst->height*bsize);
- }
-
cmask = (1<<src->channels)-1;
status = (*sMlibFns[MLIB_CONVMxN].fptr)(dst, src, kdata, w, h,
(w-1)/2, (h-1)/2, scale, cmask,
- MLIB_EDGE_DST_NO_WRITE);
+ getMlibEdgeHint(edgeHint));
if (status != MLIB_SUCCESS) {
printMedialibError(status);
@@ -660,22 +658,10 @@
}
}
- if (edgeHint == java_awt_image_ConvolveOp_EDGE_NO_OP) {
- int kw2 = kwidth>>1;
- int kh2 = kheight>>1;
- int bsize = mlib_ImageGetChannels(src)*
- (mlib_ImageGetType(src) == MLIB_BYTE ? 1 : 2);
-
- void *dstDataP = mlib_ImageGetData(dst);
- void *srcDataP = mlib_ImageGetData(src);
- /* REMIND: Copy a smaller area */
- memcpy(dstDataP, srcDataP, dst->width*dst->height*bsize);
- }
-
cmask = (1<<src->channels)-1;
status = (*sMlibFns[MLIB_CONVMxN].fptr)(dst, src, kdata, w, h,
(w-1)/2, (h-1)/2, scale, cmask,
- MLIB_EDGE_DST_NO_WRITE);
+ getMlibEdgeHint(edgeHint));
if (status != MLIB_SUCCESS) {
printMedialibError(status);
diff --git a/src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.h b/src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.h
index 1c55702..32f7d4e 100644
--- a/src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.h
+++ b/src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.h
@@ -31,7 +31,7 @@
/* here come some very simple macros */
/* advance a pointer p by sizeof(type)*n bytes */
-#define INCPN(type,p,n) ((p) = (type*)(p)+n)
+#define INCPN(type,p,n) ((p) = (type*)(p)+(n))
/* advance a pointer by sizeof(type) */
#define INCP(type,p) INCPN(type,(p),1)
diff --git a/src/share/native/sun/awt/splashscreen/splashscreen_gif.c b/src/share/native/sun/awt/splashscreen/splashscreen_gif.c
index f6d9acb..f1651ab 100644
--- a/src/share/native/sun/awt/splashscreen/splashscreen_gif.c
+++ b/src/share/native/sun/awt/splashscreen/splashscreen_gif.c
@@ -62,6 +62,15 @@
return rc;
}
+/* These macro help to ensure that we only take part of frame that fits into
+ logical screen. */
+
+/* Ensure that p belongs to [pmin, pmax) interval. Returns fixed point (if fix is needed) */
+#define FIX_POINT(p, pmin, pmax) ( ((p) < (pmin)) ? (pmin) : (((p) > (pmax)) ? (pmax) : (p)))
+/* Ensures that line starting at point p does not exceed boundary pmax.
+ Returns fixed length (if fix is needed) */
+#define FIX_LENGTH(p, len, pmax) ( ((p) + (len)) > (pmax) ? ((pmax) - (p)) : (len))
+
int
SplashDecodeGif(Splash * splash, GifFileType * gif)
{
@@ -70,6 +79,7 @@
byte_t *pBitmapBits, *pOldBitmapBits;
int i, j;
int imageIndex;
+ int cx, cy, cw, ch; /* clamped coordinates */
const int interlacedOffset[] = { 0, 4, 2, 1, 0 }; /* The way Interlaced image should. */
const int interlacedJumps[] = { 8, 8, 4, 2, 1 }; /* be read - offsets and jumps... */
@@ -79,14 +89,31 @@
SplashCleanup(splash);
+ if (!SAFE_TO_ALLOC(gif->SWidth, splash->imageFormat.depthBytes)) {
+ return 0;
+ }
stride = gif->SWidth * splash->imageFormat.depthBytes;
if (splash->byteAlignment > 1)
stride =
(stride + splash->byteAlignment - 1) & ~(splash->byteAlignment - 1);
+ if (!SAFE_TO_ALLOC(gif->SHeight, stride)) {
+ return 0;
+ }
+
+ if (!SAFE_TO_ALLOC(gif->ImageCount, sizeof(SplashImage*))) {
+ return 0;
+ }
bufferSize = stride * gif->SHeight;
pBitmapBits = (byte_t *) malloc(bufferSize);
+ if (!pBitmapBits) {
+ return 0;
+ }
pOldBitmapBits = (byte_t *) malloc(bufferSize);
+ if (!pOldBitmapBits) {
+ free(pBitmapBits);
+ return 0;
+ }
memset(pBitmapBits, 0, bufferSize);
splash->width = gif->SWidth;
@@ -94,6 +121,11 @@
splash->frameCount = gif->ImageCount;
splash->frames = (SplashImage *)
malloc(sizeof(SplashImage) * gif->ImageCount);
+ if (!splash->frames) {
+ free(pBitmapBits);
+ free(pOldBitmapBits);
+ return 0;
+ }
memset(splash->frames, 0, sizeof(SplashImage) * gif->ImageCount);
splash->loopCount = 1;
@@ -109,6 +141,11 @@
int colorCount = 0;
rgbquad_t colorMapBuf[SPLASH_COLOR_MAP_SIZE];
+ cx = FIX_POINT(desc->Left, 0, gif->SWidth);
+ cy = FIX_POINT(desc->Top, 0, gif->SHeight);
+ cw = FIX_LENGTH(desc->Left, desc->Width, gif->SWidth);
+ ch = FIX_LENGTH(desc->Top, desc->Height, gif->SHeight);
+
if (colorMap) {
if (colorMap->ColorCount <= SPLASH_COLOR_MAP_SIZE) {
colorCount = colorMap->ColorCount;
@@ -195,13 +232,22 @@
for (; pass < npass; ++pass) {
int jump = interlacedJumps[pass];
int ofs = interlacedOffset[pass];
- int numLines = (desc->Height + jump - 1 - ofs) / jump;
+ /* Number of source lines for current pass */
+ int numPassLines = (desc->Height + jump - ofs - 1) / jump;
+ /* Number of lines that fits to dest buffer */
+ int numLines = (ch + jump - ofs - 1) / jump;
initRect(&srcRect, 0, 0, desc->Width, numLines, 1,
desc->Width, pSrc, &srcFormat);
- initRect(&dstRect, desc->Left, desc->Top + ofs, desc->Width,
- numLines, jump, stride, pBitmapBits, &splash->imageFormat);
- pSrc += convertRect(&srcRect, &dstRect, CVT_ALPHATEST);
+
+ if (numLines > 0) {
+ initRect(&dstRect, cx, cy + ofs, cw,
+ numLines , jump, stride, pBitmapBits, &splash->imageFormat);
+
+ pSrc += convertRect(&srcRect, &dstRect, CVT_ALPHATEST);
+ }
+ // skip extra source data
+ pSrc += (numPassLines - numLines) * srcRect.stride;
}
}
@@ -209,6 +255,12 @@
splash->frames[imageIndex].bitmapBits =
(rgbquad_t *) malloc(bufferSize);
+ if (!splash->frames[imageIndex].bitmapBits) {
+ free(pBitmapBits);
+ free(pOldBitmapBits);
+ /* Assuming that callee will take care of splash frames we have already allocated */
+ return 0;
+ }
memcpy(splash->frames[imageIndex].bitmapBits, pBitmapBits, bufferSize);
SplashInitFrameShape(splash, imageIndex);
@@ -224,27 +276,29 @@
{
ImageRect dstRect;
rgbquad_t fillColor = 0; // 0 is transparent
- if (transparentColor < 0) {
+
+ if (transparentColor > 0) {
fillColor= MAKE_QUAD_GIF(
colorMap->Colors[gif->SBackGroundColor], 0xff);
}
- initRect(&dstRect, desc->Left, desc->Top,
- desc->Width, desc->Height, 1, stride,
- pBitmapBits, &splash->imageFormat);
+ initRect(&dstRect,
+ cx, cy, cw, ch,
+ 1, stride,
+ pBitmapBits, &splash->imageFormat);
fillRect(fillColor, &dstRect);
}
break;
case GIF_DISPOSE_RESTORE:
{
-
- int lineSize = desc->Width * splash->imageFormat.depthBytes;
-
- for (j = 0; j < desc->Height; j++) {
- int lineIndex = stride * (j + desc->Top) +
- desc->Left * splash->imageFormat.depthBytes;
-
- memcpy(pBitmapBits + lineIndex, pOldBitmapBits + lineIndex,
- lineSize);
+ int lineSize = cw * splash->imageFormat.depthBytes;
+ if (lineSize > 0) {
+ int lineOffset = cx * splash->imageFormat.depthBytes;
+ int lineIndex = cy * stride + lineOffset;
+ for (j=0; j<ch; j++) {
+ memcpy(pBitmapBits + lineIndex, pOldBitmapBits + lineIndex,
+ lineSize);
+ lineIndex += stride;
+ }
}
}
break;
diff --git a/src/share/native/sun/awt/splashscreen/splashscreen_impl.h b/src/share/native/sun/awt/splashscreen/splashscreen_impl.h
index c6bad14..6f4e03e 100644
--- a/src/share/native/sun/awt/splashscreen/splashscreen_impl.h
+++ b/src/share/native/sun/awt/splashscreen/splashscreen_impl.h
@@ -155,6 +155,10 @@
void SplashInitFrameShape(Splash * splash, int imageIndex);
+#define SAFE_TO_ALLOC(c, sz) \
+ (((c) > 0) && ((sz) > 0) && \
+ ((0xffffffffu / ((unsigned int)(c))) > (unsigned int)(sz)))
+
#define dbgprintf printf
#endif
diff --git a/src/share/native/sun/awt/splashscreen/splashscreen_png.c b/src/share/native/sun/awt/splashscreen/splashscreen_png.c
index f0926ec..abc54dc 100644
--- a/src/share/native/sun/awt/splashscreen/splashscreen_png.c
+++ b/src/share/native/sun/awt/splashscreen/splashscreen_png.c
@@ -103,9 +103,17 @@
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ if (!SAFE_TO_ALLOC(rowbytes, height)) {
+ goto done;
+ }
+
if ((image_data = (unsigned char *) malloc(rowbytes * height)) == NULL) {
goto done;
}
+
+ if (!SAFE_TO_ALLOC(height, sizeof(png_bytep))) {
+ goto done;
+ }
if ((row_pointers = (png_bytepp) malloc(height * sizeof(png_bytep)))
== NULL) {
goto done;
@@ -121,13 +129,28 @@
splash->width = width;
splash->height = height;
+ if (!SAFE_TO_ALLOC(splash->width, splash->imageFormat.depthBytes)) {
+ goto done;
+ }
stride = splash->width * splash->imageFormat.depthBytes;
+ if (!SAFE_TO_ALLOC(splash->height, stride)) {
+ goto done;
+ }
splash->frameCount = 1;
splash->frames = (SplashImage *)
malloc(sizeof(SplashImage) * splash->frameCount);
+
+ if (splash->frames == NULL) {
+ goto done;
+ }
+
splash->loopCount = 1;
splash->frames[0].bitmapBits = malloc(stride * splash->height);
+ if (splash->frames[0].bitmapBits == NULL) {
+ free(splash->frames);
+ goto done;
+ }
splash->frames[0].delay = 0;
/* FIXME: sort out the real format */
diff --git a/src/windows/classes/sun/security/mscapi/RSAKeyPairGenerator.java b/src/windows/classes/sun/security/mscapi/RSAKeyPairGenerator.java
index 146d7c1..44dd25a 100644
--- a/src/windows/classes/sun/security/mscapi/RSAKeyPairGenerator.java
+++ b/src/windows/classes/sun/security/mscapi/RSAKeyPairGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
import java.security.spec.RSAKeyGenParameterSpec;
import sun.security.jca.JCAUtil;
+import sun.security.rsa.RSAKeyFactory;
/**
* RSA keypair generator.
@@ -43,8 +44,8 @@
public final class RSAKeyPairGenerator extends KeyPairGeneratorSpi {
// Supported by Microsoft Base, Strong and Enhanced Cryptographic Providers
- private static final int KEY_SIZE_MIN = 512; // disallow MSCAPI min. of 384
- private static final int KEY_SIZE_MAX = 16384;
+ static final int KEY_SIZE_MIN = 512; // disallow MSCAPI min. of 384
+ static final int KEY_SIZE_MAX = 16384;
private static final int KEY_SIZE_DEFAULT = 1024;
// size of the key to generate, KEY_SIZE_MIN <= keySize <= KEY_SIZE_MAX
@@ -59,7 +60,14 @@
// random is always ignored
public void initialize(int keySize, SecureRandom random) {
- checkKeySize(keySize);
+ try {
+ RSAKeyFactory.checkKeyLengths(keySize, null,
+ KEY_SIZE_MIN, KEY_SIZE_MAX);
+ } catch (InvalidKeyException e) {
+ throw new InvalidParameterException(e.getMessage());
+ }
+
+ this.keySize = keySize;
}
// second initialize method. See JCA doc
@@ -67,21 +75,31 @@
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
throws InvalidAlgorithmParameterException {
+ int tmpSize;
if (params == null) {
- checkKeySize(KEY_SIZE_DEFAULT);
-
+ tmpSize = KEY_SIZE_DEFAULT;
} else if (params instanceof RSAKeyGenParameterSpec) {
if (((RSAKeyGenParameterSpec) params).getPublicExponent() != null) {
throw new InvalidAlgorithmParameterException
("Exponent parameter is not supported");
}
- checkKeySize(((RSAKeyGenParameterSpec) params).getKeysize());
+ tmpSize = ((RSAKeyGenParameterSpec) params).getKeysize();
} else {
throw new InvalidAlgorithmParameterException
("Params must be an instance of RSAKeyGenParameterSpec");
}
+
+ try {
+ RSAKeyFactory.checkKeyLengths(tmpSize, null,
+ KEY_SIZE_MIN, KEY_SIZE_MAX);
+ } catch (InvalidKeyException e) {
+ throw new InvalidAlgorithmParameterException(
+ "Invalid Key sizes", e);
+ }
+
+ this.keySize = tmpSize;
}
// generate the keypair. See JCA doc
@@ -95,18 +113,6 @@
return new KeyPair(keys.getPublic(), keys.getPrivate());
}
- private void checkKeySize(int keySize) throws InvalidParameterException {
- if (keySize < KEY_SIZE_MIN) {
- throw new InvalidParameterException
- ("Key size must be at least " + KEY_SIZE_MIN + " bits");
- }
- if (keySize > KEY_SIZE_MAX) {
- throw new InvalidParameterException
- ("Key size must be " + KEY_SIZE_MAX + " bits or less");
- }
- this.keySize = keySize;
- }
-
private static native RSAKeyPair generateRSAKeyPair(int keySize,
String keyContainerName);
}
diff --git a/src/windows/classes/sun/security/mscapi/RSASignature.java b/src/windows/classes/sun/security/mscapi/RSASignature.java
index 606423d..982e183 100644
--- a/src/windows/classes/sun/security/mscapi/RSASignature.java
+++ b/src/windows/classes/sun/security/mscapi/RSASignature.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,9 @@
import java.security.Signature;
import java.security.SignatureSpi;
import java.security.SignatureException;
+import java.math.BigInteger;
+
+import sun.security.rsa.RSAKeyFactory;
/**
* RSA signature implementation. Supports RSA signing using PKCS#1 v1.5 padding.
@@ -124,7 +127,16 @@
// convert key to MSCAPI format
- byte[] modulusBytes = rsaKey.getModulus().toByteArray();
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger exponent = rsaKey.getPublicExponent();
+
+ // Check against the local and global values to make sure
+ // the sizes are ok. Round up to the nearest byte.
+ RSAKeyFactory.checkKeyLengths(((modulus.bitLength() + 7) & ~7),
+ exponent, -1, RSAKeyPairGenerator.KEY_SIZE_MAX);
+
+ byte[] modulusBytes = modulus.toByteArray();
+ byte[] exponentBytes = exponent.toByteArray();
// Adjust key length due to sign bit
int keyBitLength = (modulusBytes[0] == 0)
@@ -132,8 +144,7 @@
: modulusBytes.length * 8;
byte[] keyBlob = generatePublicKeyBlob(
- keyBitLength, modulusBytes,
- rsaKey.getPublicExponent().toByteArray());
+ keyBitLength, modulusBytes, exponentBytes);
publicKey = importPublicKey(keyBlob, keyBitLength);
@@ -166,12 +177,11 @@
}
privateKey = (sun.security.mscapi.RSAPrivateKey) key;
- // Determine byte length from bit length
- int keySize = (privateKey.bitLength() + 7) >> 3;
-
- if (keySize < 64)
- throw new InvalidKeyException(
- "RSA keys must be at least 512 bits long");
+ // Check against the local and global values to make sure
+ // the sizes are ok. Round up to nearest byte.
+ RSAKeyFactory.checkKeyLengths(((privateKey.bitLength() + 7) & ~7),
+ null, RSAKeyPairGenerator.KEY_SIZE_MIN,
+ RSAKeyPairGenerator.KEY_SIZE_MAX);
if (needsReset) {
messageDigest.reset();
diff --git a/test/java/awt/FontClass/CreateFont/A.ttf b/test/java/awt/FontClass/CreateFont/A.ttf
new file mode 100644
index 0000000..f80f5c3
--- /dev/null
+++ b/test/java/awt/FontClass/CreateFont/A.ttf
Binary files differ
diff --git a/test/java/awt/FontClass/CreateFont/BigFont.java b/test/java/awt/FontClass/CreateFont/BigFont.java
new file mode 100644
index 0000000..c148024
--- /dev/null
+++ b/test/java/awt/FontClass/CreateFont/BigFont.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.applet.*;
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+
+public class BigFont extends Applet {
+
+ static private class SizedInputStream extends InputStream {
+
+ int size;
+ int cnt = 0;
+
+ SizedInputStream(int size) {
+ this.size = size;
+ }
+
+ public int read() {
+ if (cnt < size) {
+ cnt++;
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+
+ public int getCurrentSize() {
+ return cnt;
+ }
+ }
+
+ String id;
+ String fileName;
+
+ public void init() {
+ id = getParameter("number");
+ fileName = getParameter("font");
+
+ System.out.println("Applet " + id + " "+
+ Thread.currentThread().getThreadGroup());
+ // Larger than size for a single font.
+ int fontSize = 64 * 1000 * 1000;
+ SizedInputStream sis = new SizedInputStream(fontSize);
+ try {
+ Font font = Font.createFont(Font.TRUETYPE_FONT, sis);
+ } catch (Throwable t) {
+ if (t instanceof FontFormatException ||
+ fontSize <= sis.getCurrentSize())
+ {
+ System.out.println(sis.getCurrentSize());
+ System.out.println(t);
+ throw new RuntimeException("Allowed file to be too large.");
+ }
+ }
+ // The following part of the test was verified manually but
+ // is impractical to enable because it requires a fairly large
+ // valid font to be part of the test, and we can't easily include
+ // that, nor dependably reference one from the applet environment.
+ /*
+ if (fileName == null) {
+ return;
+ }
+ int size = getFileSize(fileName);
+ if (size == 0) {
+ return;
+ }
+ int fontCnt = 1000 * 1000 * 1000 / size;
+ loadMany(size, fontCnt, fileName);
+ System.gc(); System.gc();
+ fontCnt = fontCnt / 2;
+ System.out.println("Applet " + id + " load more.");
+ loadMany(size, fontCnt, fileName);
+ */
+ System.out.println("Applet " + id + " finished.");
+ }
+
+ int getFileSize(String fileName) {
+ try {
+ URL url = new URL(getCodeBase(), fileName);
+ InputStream inStream = url.openStream();
+ BufferedInputStream fontStream = new BufferedInputStream(inStream);
+ int size = 0;
+ while (fontStream.read() != -1) {
+ size++;
+ }
+ fontStream.close();
+ return size;
+ } catch (IOException e) {
+ return 0;
+ }
+
+ }
+ void loadMany(int oneFont, int fontCnt, String fileName) {
+ System.out.println("fontcnt= " + fontCnt);
+ Font[] fonts = new Font[fontCnt];
+ int totalSize = 0;
+ boolean gotException = false;
+ for (int i=0; i<fontCnt; i++) {
+ try {
+ URL url = new URL(getCodeBase(), fileName);
+ InputStream inStream = url.openStream();
+ BufferedInputStream fontStream =
+ new BufferedInputStream(inStream);
+ fonts[i] = Font.createFont(Font.TRUETYPE_FONT, fontStream);
+ totalSize += oneFont;
+ fontStream.close();
+ } catch (Throwable t) {
+ gotException = true;
+ System.out.println("Applet " + id + " " + t);
+ }
+ }
+ if (!gotException) {
+ throw new RuntimeException("No expected exception");
+ }
+ }
+}
+
diff --git a/test/java/awt/FontClass/CreateFont/DeleteFont.java b/test/java/awt/FontClass/CreateFont/DeleteFont.java
new file mode 100644
index 0000000..361b0b4
--- /dev/null
+++ b/test/java/awt/FontClass/CreateFont/DeleteFont.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.awt.*;
+
+public class DeleteFont {
+
+ public static void main(String args[]) throws Exception {
+
+ String font = "A.ttf";
+ String sep = System.getProperty("file.separator");
+ String testSrc = System.getenv("TESTSRC");
+ if (testSrc != null) {
+ font = testSrc + sep + font;
+ }
+ System.out.println("Using font file: " + font);
+ FileInputStream fis = new FileInputStream(font);
+ Font f = Font.createFont(Font.TRUETYPE_FONT, fis);
+ f.toString();
+ f.deriveFont(Font.BOLD);
+ f.canDisplay('X');
+
+ InputStream in = new InputStream() {
+ public int read() {
+ throw new RuntimeException();
+ }
+ };
+ boolean gotException = false;
+ try {
+ Font.createFont(java.awt.Font.TRUETYPE_FONT, in);
+ } catch (IOException e) {
+ gotException = true;
+ }
+ if (!gotException) {
+ throw new RuntimeException("No expected IOException");
+ }
+ badRead(-2, Font.TRUETYPE_FONT);
+ badRead(8193, Font.TRUETYPE_FONT);
+
+ badRead(-2, Font.TYPE1_FONT);
+ badRead(8193, Font.TYPE1_FONT);
+
+ // Make sure GC has a chance to clean up before we exit.
+ System.gc(); System.gc();
+ }
+
+ static void badRead(final int retval, int fontType) {
+ int num = 2;
+ byte[] buff = new byte[16*8192]; // Multiple of 8192 is important.
+ for (int ct=0; ct<num; ++ct) {
+ try {
+ Font.createFont(
+ fontType,
+ new ByteArrayInputStream(buff) {
+ @Override
+ public int read(byte[] buff, int off, int len) {
+ int read = super.read(buff, off, len);
+ return read<0 ? retval : read;
+ }
+ }
+ );
+ } catch (Throwable exc) {
+ //exc.printStackTrace();
+ }
+ }
+ }
+}
+
diff --git a/test/java/awt/FontClass/CreateFont/DeleteFont.sh b/test/java/awt/FontClass/CreateFont/DeleteFont.sh
new file mode 100644
index 0000000..ba67380
--- /dev/null
+++ b/test/java/awt/FontClass/CreateFont/DeleteFont.sh
@@ -0,0 +1,66 @@
+# Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code 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
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+
+# @test
+# @bug 6189812 6380357 6632886
+# @summary Verify that temporary font files are deleted on exit.
+
+if [ -z "${TESTSRC}" ]; then
+ echo "TESTSRC undefined: defaulting to ."
+ TESTSRC=.
+fi
+
+if [ -z "${TESTCLASSES}" ]; then
+ echo "TESTCLASSES undefined: defaulting to ."
+ TESTCLASSES=.
+fi
+
+if [ -z "${TESTJAVA}" ]; then
+ echo "TESTJAVA undefined: can't continue."
+ exit 1
+fi
+
+echo "TESTJAVA=${TESTJAVA}"
+echo "TESTSRC=${TESTSRC}"
+echo "TESTCLASSES=${TESTCLASSES}"
+cd ${TESTSRC}
+${TESTJAVA}/bin/javac -d ${TESTCLASSES} DeleteFont.java
+
+cd ${TESTCLASSES}
+
+numfiles0=`ls ${TESTCLASSES} | wc -l`
+${TESTJAVA}/bin/java -Djava.io.tmpdir=${TESTCLASSES} DeleteFont
+
+if [ $? -ne 0 ]
+ then
+ echo "Test fails: exception thrown!"
+ exit 1
+fi
+
+numfiles1=`ls ${TESTCLASSES} | wc -l`
+
+if [ $numfiles0 -ne $numfiles1 ]
+ then
+ echo "Test fails: tmp file exists!"
+ ls ${TESTCLASSES}
+ exit 1
+fi
+exit 0
diff --git a/test/java/awt/FontClass/CreateFont/bigfont.html b/test/java/awt/FontClass/CreateFont/bigfont.html
new file mode 100644
index 0000000..523c61f
--- /dev/null
+++ b/test/java/awt/FontClass/CreateFont/bigfont.html
@@ -0,0 +1,48 @@
+<!--
+
+ Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ This code is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 only, as
+ published by the Free Software Foundation.
+
+ This code 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
+ version 2 for more details (a copy is included in the LICENSE file that
+ accompanied this code).
+
+ You should have received a copy of the GNU General Public License version
+ 2 along with this work; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ CA 95054 USA or visit www.sun.com if you need additional information or
+ have any questions.
+
+ @test
+ @bug 6522586
+ @run applet bigfont.html
+ @summary Enforce limits on font creation
+
+-->
+
+<html>
+ <head>
+ <title>Test Font Creation Limits</title>
+ </head>
+ <body>
+<hr>
+<APPLET CODE = BigFont.class WIDTH = 100 HEIGHT = 100 >
+<param name="number" value="1">
+<param name="font" value="A.ttf">
+</APPLET>
+<APPLET CODE = BigFont.class WIDTH = 100 HEIGHT = 100>
+<param name="number" value="2">
+<param name="font" value="A.ttf">
+</APPLET>
+<hr>
+ </body>
+</html>
+
diff --git a/test/java/awt/FontClass/CreateFont/fileaccess/FontFile.java b/test/java/awt/FontClass/CreateFont/fileaccess/FontFile.java
new file mode 100644
index 0000000..4441974
--- /dev/null
+++ b/test/java/awt/FontClass/CreateFont/fileaccess/FontFile.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6652929
+ * @summary verify handling of File.getPath()
+ */
+
+import java.awt.*;
+import java.io.*;
+
+public class FontFile {
+ public static void main(String[] args) throws Exception {
+ String sep = System.getProperty("file.separator");
+ String fname = ".." + sep + "A.ttf";
+ String dir = System.getProperty("test.src");
+ if (dir != null) {
+ fname = dir + sep + fname;
+ }
+ final String name = fname;
+ System.out.println("Will try to access " + name);
+ if (!(new File(name)).canRead()) {
+ System.out.println("File not available : can't run test");
+ return;
+ }
+ System.out.println("File is available. Verify no access under SM");
+
+ System.setSecurityManager(new SecurityManager());
+
+
+ // Check cannot read file.
+ try {
+ new FileInputStream(name);
+ throw new Error("Something wrong with test environment");
+ } catch (SecurityException exc) {
+ // Good.
+ }
+
+ try {
+ Font font = Font.createFont(Font.TRUETYPE_FONT,
+ new File("nosuchfile") {
+ private boolean read;
+ @Override public String getPath() {
+ if (read) {
+ return name;
+ } else {
+ read = true;
+ return "somefile";
+ }
+ }
+ @Override public boolean canRead() {
+ return true;
+ }
+ }
+ );
+ System.err.println(font.getFontName());
+ throw new RuntimeException("No expected exception");
+ } catch (IOException e) {
+ System.err.println("Test passed.");
+ }
+ }
+}
diff --git a/test/java/awt/image/ConvolveOp/EdgeNoOpCrash.java b/test/java/awt/image/ConvolveOp/EdgeNoOpCrash.java
new file mode 100644
index 0000000..5e1d2eb
--- /dev/null
+++ b/test/java/awt/image/ConvolveOp/EdgeNoOpCrash.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6726779
+ * @summary Test verifies that ConvolveOp with the EDGE_NO_OP edge condition
+ * does not cause JVM crash if size of source raster elements is
+ * greather than size of the destination raster element.
+ *
+ * @run main EdgeNoOpCrash
+ */
+import java.awt.Point;
+import java.awt.image.ConvolveOp;
+import java.awt.image.DataBuffer;
+import java.awt.image.ImagingOpException;
+import java.awt.image.Kernel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.util.Arrays;
+
+public class EdgeNoOpCrash {
+ private static final int w = 3000;
+ private static final int h = 200;
+
+ public static void main(String[] args) {
+ crashTest();
+ }
+
+ private static void crashTest() {
+ Raster src = createSrcRaster();
+ WritableRaster dst = createDstRaster();
+ ConvolveOp op = createConvolveOp(ConvolveOp.EDGE_NO_OP);
+ try {
+ op.filter(src, dst);
+ } catch (ImagingOpException e) {
+ /*
+ * The test pair of source and destination rasters
+ * may cause failure of the medialib convolution routine,
+ * so this exception is expected.
+ *
+ * The JVM crash is the only manifestation of this
+ * test failure.
+ */
+ }
+ System.out.println("Test PASSED.");
+ }
+
+ private static Raster createSrcRaster() {
+ WritableRaster r = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT,
+ w, h, 4, new Point(0, 0));
+
+ return r;
+ }
+
+ private static WritableRaster createDstRaster() {
+ WritableRaster r = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ w, h, 4, new Point(0, 0));
+
+ return r;
+ }
+
+ private static ConvolveOp createConvolveOp(int edgeHint) {
+ final int kw = 3;
+ final int kh = 3;
+ float[] kdata = new float[kw * kh];
+ float v = 1f / kdata.length;
+ Arrays.fill(kdata, v);
+
+ Kernel k = new Kernel(kw, kh, kdata);
+ ConvolveOp op = new ConvolveOp(k, edgeHint, null);
+
+ return op;
+ }
+}
\ No newline at end of file
diff --git a/test/javax/print/attribute/MediaMappingsTest.java b/test/javax/print/attribute/MediaMappingsTest.java
new file mode 100644
index 0000000..16110d8
--- /dev/null
+++ b/test/javax/print/attribute/MediaMappingsTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6652463
+ * @summary Verify media size-> media mappings can't be altered
+ * @run main MediaMappingsTest
+*/
+
+import javax.print.attribute.standard.MediaSize;
+import javax.print.attribute.standard.MediaSizeName;
+
+public class MediaMappingsTest {
+
+ public static void main(String args[]) {
+ MediaSize sizeA = MediaSize.getMediaSizeForName(MediaSizeName.A);
+ new MediaSize(1.0f, 2.0f, MediaSize.MM, MediaSizeName.A);
+ if (!sizeA.equals(MediaSize.getMediaSizeForName(MediaSizeName.A))) {
+ throw new RuntimeException("mapping changed");
+ }
+ MediaSize sizeB = MediaSize.getMediaSizeForName(MediaSizeName.B);
+ new MediaSize(1, 2, MediaSize.MM, MediaSizeName.B);
+ if (!sizeB.equals(MediaSize.getMediaSizeForName(MediaSizeName.B))) {
+ throw new RuntimeException("mapping changed");
+ }
+ }
+}
diff --git a/test/tools/launcher/MultipleJRE.sh b/test/tools/launcher/MultipleJRE.sh
index b3e1cf7..a6dfaaa 100644
--- a/test/tools/launcher/MultipleJRE.sh
+++ b/test/tools/launcher/MultipleJRE.sh
@@ -1,14 +1,14 @@
# @test MultipleJRE.sh
-# @bug 4811102 4953711 4955505 4956301 4991229 4998210 5018605 6387069
+# @bug 4811102 4953711 4955505 4956301 4991229 4998210 5018605 6387069 6733959
# @build PrintVersion
# @build UglyPrintVersion
+# @build ZipMeUp
# @run shell MultipleJRE.sh
# @summary Verify Multiple JRE version support
# @author Joseph E. Kowalski
-
#
-# Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+# Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -49,11 +49,26 @@
exit 1
fi
+JAVAEXE="$TESTJAVA/bin/java"
JAVA="$TESTJAVA/bin/java -classpath $TESTCLASSES"
JAR="$TESTJAVA/bin/jar"
OS=`uname -s`;
#
+# Tests whether we are on windows (true) or not.
+#
+IsWindows() {
+ case "$OS" in
+ Windows* | CYGWIN* )
+ printf "true"
+ ;;
+ * )
+ printf "false"
+ ;;
+ esac
+}
+
+#
# Shell routine to test for the proper rejection of syntactically incorrect
# version specifications.
#
@@ -139,7 +154,6 @@
$PACKAGE/UglyPrintVersion.class
}
-
#
# Constructs a jar file with a fair number of "zip directory" entries and
# the MANIFEST.MF entry at or near the end of that directory to validate
@@ -262,6 +276,29 @@
fi
}
+# Tests very long Main-Class attribute in the jar
+TestLongMainClass() {
+ JVER=$1
+ if [ "$JVER" = "mklink" ]; then
+ JVER=XX
+ JDKXX=jdk/j2re$JVER
+ rm -rf jdk
+ mkdir jdk
+ ln -s $TESTJAVA $JDKXX
+ JAVA_VERSION_PATH="`pwd`/jdk"
+ export JAVA_VERSION_PATH
+ fi
+ $JAVAEXE -cp $TESTCLASSES ZipMeUp UglyBetty.jar 4097
+ message="`$JAVAEXE -version:$JVER -jar UglyBetty.jar 2>&1`"
+ echo $message | grep "Error: main-class: attribute exceeds system limits" > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ printf "Long manifest test did not get expected error"
+ exit 1
+ fi
+ unset JAVA_VERSION_PATH
+ rm -rf jdk
+}
+
#
# Main test sequence starts here
#
@@ -280,14 +317,11 @@
LaunchVM "" "${RELEASE}"
CreateJar "" "0"
LaunchVM "" "${RELEASE}"
-case "$OS" in
- Windows* | CYGWIN* )
- MAXIMUM_PATH=255;
- ;;
- *)
- MAXIMUM_PATH=1024;
- ;;
-esac
+if [ `IsWindows` = "true" ]; then
+ MAXIMUM_PATH=255;
+else
+ MAXIMUM_PATH=1024;
+fi
PATH_LENGTH=`printf "%s" "$UGLYCLASS" | wc -c`
if [ ${PATH_LENGTH} -lt ${MAXIMUM_PATH} ]; then
@@ -346,7 +380,6 @@
LaunchVM "" "${RELEASE}"
fi
-
#
# Throw some syntactically challenged (illegal) version specifiers at
# the interface. Failure (of the launcher) is success for the test.
@@ -357,15 +390,28 @@
TestSyntax "1.2+.3" # Embedded modifier
TestSyntax "1.2.4+&1.2*&1++" # Long and invalid
+# On windows we see if there is another jre installed, usually
+# there is, then we test using that, otherwise links are created
+# to get through to SelectVersion.
+if [ `IsWindows` = "false" ]; then
+ TestLongMainClass "mklink"
+else
+ $JAVAEXE -version:1.0+
+ if [ $? -eq 0 ]; then
+ TestLongMainClass "1.0+"
+ else
+ printf "Warning: TestLongMainClass skipped as there is no"
+ printf "viable MJRE installed.\n"
+ fi
+fi
+
#
# Because scribbling in the registry can be rather destructive, only a
# subset of the tests are run on Windows.
#
-case "$OS" in
- Windows* | CYGWIN* )
- exit 0;
- ;;
-esac
+if [ `IsWindows` = "true" ]; then
+ exit 0;
+fi
#
# Additional version specifiers containing spaces. (Sigh, unable to
diff --git a/test/tools/launcher/ZipMeUp.java b/test/tools/launcher/ZipMeUp.java
new file mode 100644
index 0000000..84d3f18
--- /dev/null
+++ b/test/tools/launcher/ZipMeUp.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * A simple class to create our erring Jar with a very long Main-Class
+ * attribute in the manifest.
+ */
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedOutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+public class ZipMeUp {
+
+ static final CRC32 crc = new CRC32();
+
+ private static String SOME_KLASS = ".Some";
+
+ static byte[] getManifestAsBytes(int nchars) throws IOException {
+ crc.reset();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ CheckedOutputStream cos = new CheckedOutputStream(baos, crc);
+ PrintStream ps = new PrintStream(cos);
+ ps.println("Manifest-Version: 1.0");
+ ps.print("Main-Class: ");
+ for (int i = 0 ; i < nchars - SOME_KLASS.length() ; i++) {
+ ps.print(i%10);
+ }
+ ps.println(SOME_KLASS);
+ cos.flush();
+ cos.close();
+ ps.close();
+ return baos.toByteArray();
+ }
+
+ /**
+ * The arguments are: filename_to_create length
+ * @param args
+ * @throws java.lang.Exception
+ */
+ public static void main(String...args) throws Exception {
+ FileOutputStream fos = new FileOutputStream(args[0]);
+ ZipOutputStream zos = new ZipOutputStream(fos);
+ byte[] manifest = getManifestAsBytes(Integer.parseInt(args[1]));
+ ZipEntry ze = new ZipEntry("META-INF/MANIFEST.MF");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(manifest.length);
+ ze.setCompressedSize(manifest.length);
+ ze.setCrc(crc.getValue());
+ ze.setTime(System.currentTimeMillis());
+ zos.putNextEntry(ze);
+ zos.write(manifest);
+ zos.flush();
+
+ // add a zero length class
+ ze = new ZipEntry(SOME_KLASS + ".class");
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(0);
+ ze.setCompressedSize(0);
+ ze.setCrc(0);
+ ze.setTime(System.currentTimeMillis());
+ zos.putNextEntry(ze);
+ zos.flush();
+ zos.closeEntry();
+ zos.close();
+ System.exit(0);
+ }
+}