Navigation Menu

Skip to content

Commit

Permalink
[JENKINS-49147] Tolerate unusual CodeSource.location format from old …
Browse files Browse the repository at this point in the history
…versions of Tomcat.
  • Loading branch information
jglick committed Jan 25, 2018
1 parent 0d1f80b commit 655be64
Showing 1 changed file with 39 additions and 6 deletions.
45 changes: 39 additions & 6 deletions core/src/main/java/jenkins/security/ClassFilterImpl.java
Expand Up @@ -28,6 +28,7 @@
import hudson.ExtensionList;
import hudson.Main;
import hudson.remoting.ClassFilter;
import hudson.remoting.Which;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
Expand All @@ -49,6 +50,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jenkins.model.Jenkins;
import jenkins.util.SystemProperties;
import org.apache.commons.io.IOUtils;
Expand All @@ -71,11 +74,14 @@ public class ClassFilterImpl extends ClassFilter {
private static /* not final */ boolean SUPPRESS_WHITELIST = SystemProperties.getBoolean("jenkins.security.ClassFilterImpl.SUPPRESS_WHITELIST");
private static /* not final */ boolean SUPPRESS_ALL = SystemProperties.getBoolean("jenkins.security.ClassFilterImpl.SUPPRESS_ALL");

private static final String JENKINS_LOC = codeSource(Jenkins.class);
private static final String REMOTING_LOC = codeSource(ClassFilter.class);

/**
* Register this implementation as the default in the system.
*/
public static void register() {
if (Main.isUnitTest && Jenkins.class.getProtectionDomain().getCodeSource().getLocation() == null) {
if (Main.isUnitTest && JENKINS_LOC == null) {
mockOff();
return;
}
Expand Down Expand Up @@ -146,10 +152,9 @@ public boolean isBlacklisted(Class _c) {
LOGGER.log(Level.FINE, "permitting {0} since it is an enum", name);
return false;
}
CodeSource codeSource = c.getProtectionDomain().getCodeSource();
URL location = codeSource != null ? codeSource.getLocation() : null;
String location = codeSource(c);
if (location != null) {
if (isLocationWhitelisted(location.toString())) {
if (isLocationWhitelisted(location)) {
LOGGER.log(Level.FINE, "permitting {0} due to its location in {1}", new Object[] {name, location});
return false;
}
Expand All @@ -176,11 +181,11 @@ public boolean isBlacklisted(Class _c) {
private static final Pattern CLASSES_JAR = Pattern.compile("(file:/.+/)WEB-INF/lib/classes[.]jar");
private boolean isLocationWhitelisted(String _loc) {
return codeSourceCache.computeIfAbsent(_loc, loc -> {
if (loc.equals(Jenkins.class.getProtectionDomain().getCodeSource().getLocation().toString())) {
if (loc.equals(JENKINS_LOC)) {
LOGGER.log(Level.FINE, "{0} seems to be the location of Jenkins core, OK", loc);
return true;
}
if (loc.equals(ClassFilter.class.getProtectionDomain().getCodeSource().getLocation().toString())) {
if (loc.equals(REMOTING_LOC)) {
LOGGER.log(Level.FINE, "{0} seems to be the location of Remoting, OK", loc);
return true;
}
Expand Down Expand Up @@ -241,6 +246,34 @@ private boolean isLocationWhitelisted(String _loc) {
});
}

/**
* Tries to determine what JAR file a given class was loaded from.
* The location is an opaque string suitable only for comparison to others.
* Similar to {@link Which#jarFile(Class)} but potentially faster, and more tolerant of unknown URL formats.
* @param c some class
* @return something typically like {@code file:/…/plugins/structs/WEB-INF/lib/structs-1.10.jar};
* or null for classes in the Java Platform, some generated classes, etc.
*/
private static @CheckForNull String codeSource(@Nonnull Class<?> c) {
CodeSource cs = c.getProtectionDomain().getCodeSource();
if (cs == null) {
return null;
}
URL loc = cs.getLocation();
if (loc == null) {
return null;
}
String r = loc.toString();
if (r.endsWith(".class")) {
// JENKINS-49147: Tomcat bug. Now do the more expensive check…
String suffix = c.getName().replace('.', '/') + ".class";
if (r.endsWith(suffix)) {
r = r.substring(0, r.length() - suffix.length());
}
}
return r;
}

private static boolean isPluginManifest(Manifest mf) {
Attributes attr = mf.getMainAttributes();
return attr.getValue("Short-Name") != null && (attr.getValue("Plugin-Version") != null || attr.getValue("Jenkins-Version") != null) ||
Expand Down

0 comments on commit 655be64

Please sign in to comment.