Skip to content

Commit f87f491

Browse files
author
Christian Wimmer
committed
Avoid pulling File and URL code in image via CodeSource.location
1 parent 4175303 commit f87f491

File tree

3 files changed

+145
-29
lines changed

3 files changed

+145
-29
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727
//Checkstyle: allow reflection
2828

29-
import java.io.File;
3029
import java.io.InputStream;
3130
import java.io.Serializable;
3231
import java.lang.annotation.Annotation;
@@ -43,11 +42,8 @@
4342
import java.lang.reflect.Modifier;
4443
import java.lang.reflect.Type;
4544
import java.lang.reflect.TypeVariable;
46-
import java.net.MalformedURLException;
4745
import java.net.URL;
48-
import java.security.CodeSource;
4946
import java.security.ProtectionDomain;
50-
import java.security.cert.Certificate;
5147
import java.util.List;
5248
import java.util.Optional;
5349
import java.util.Set;
@@ -58,7 +54,6 @@
5854
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
5955
import org.graalvm.nativeimage.Platform;
6056
import org.graalvm.nativeimage.Platforms;
61-
import org.graalvm.nativeimage.ProcessProperties;
6257
import org.graalvm.nativeimage.c.function.CFunctionPointer;
6358
import org.graalvm.util.DirectAnnotationAccess;
6459

@@ -89,7 +84,6 @@
8984
import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError;
9085

9186
import jdk.vm.ci.meta.JavaKind;
92-
import sun.security.util.SecurityConstants;
9387

9488
@Hybrid(canHybridFieldsBeDuplicated = false)
9589
@Substitute
@@ -318,28 +312,6 @@ public void setModule(Object module) {
318312
this.module = module;
319313
}
320314

321-
/**
322-
* Final fields in subsituted classes are treated as implicitly RecomputeFieldValue even when
323-
* not annotated with @RecomputeFieldValue. Their name must not match a field in the original
324-
* class, i.e., allPermDomain.
325-
*/
326-
static final LazyFinalReference<java.security.ProtectionDomain> allPermDomainReference = new LazyFinalReference<>(() -> {
327-
java.security.Permissions perms = new java.security.Permissions();
328-
perms.add(SecurityConstants.ALL_PERMISSION);
329-
CodeSource cs;
330-
try {
331-
// Try to use executable image's name as code source for the class.
332-
// The file location can be used by Java code to determine its location on disk, similar
333-
// to argv[0].
334-
cs = new CodeSource(new File(ProcessProperties.getExecutableName()).toURI().toURL(), (Certificate[]) null);
335-
} catch (MalformedURLException ex) {
336-
// This should not really happen; the file is cannonicalized, absolute, so it should
337-
// always have file:// URL.
338-
cs = null;
339-
}
340-
return new java.security.ProtectionDomain(cs, perms);
341-
});
342-
343315
private final LazyFinalReference<DynamicHubCompanion> companion = new LazyFinalReference<>(() -> new DynamicHubCompanion(this));
344316

345317
@Platforms(Platform.HOSTED_ONLY.class)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHubCompanion.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.graalvm.nativeimage.ImageSingletons;
4242

4343
import com.oracle.svm.core.hub.DynamicHub.ReflectionData;
44+
import com.oracle.svm.core.jdk.ProtectionDomainSupport;
4445
import com.oracle.svm.core.reflect.MethodMetadataDecoder;
4546
import com.oracle.svm.core.reflect.MethodMetadataDecoder.MethodDescriptor;
4647
import com.oracle.svm.core.util.VMError;
@@ -82,7 +83,7 @@ public void setClassLoader(ClassLoader loader) {
8283

8384
public ProtectionDomain getProtectionDomain() {
8485
if (protectionDomain == null) {
85-
protectionDomain = DynamicHub.allPermDomainReference.get();
86+
protectionDomain = ProtectionDomainSupport.allPermDomain();
8687
}
8788
return protectionDomain;
8889
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core.jdk;
26+
27+
// Checkstyle: allow reflection
28+
29+
import java.io.File;
30+
import java.net.MalformedURLException;
31+
import java.net.URL;
32+
import java.security.CodeSource;
33+
import java.security.ProtectionDomain;
34+
import java.security.cert.Certificate;
35+
import java.util.function.Supplier;
36+
37+
import org.graalvm.compiler.options.Option;
38+
import org.graalvm.nativeimage.ImageSingletons;
39+
import org.graalvm.nativeimage.Platform;
40+
import org.graalvm.nativeimage.Platforms;
41+
import org.graalvm.nativeimage.ProcessProperties;
42+
import org.graalvm.nativeimage.hosted.Feature;
43+
44+
import com.oracle.svm.core.annotate.AutomaticFeature;
45+
import com.oracle.svm.core.option.HostedOptionKey;
46+
import com.oracle.svm.core.util.LazyFinalReference;
47+
import com.oracle.svm.util.ReflectionUtil;
48+
49+
import sun.security.util.SecurityConstants;
50+
51+
/**
52+
* All classes that do not set a ProtectionDomain explicitly have a "default" ProtectionDomain. And
53+
* every ProtectionDomain has a CodeSource with a URL as its location.
54+
*
55+
* If an application invokes {@link CodeSource#getLocation()}, it can reasonably expect a non-null
56+
* URL. We use the executable image's name as the location, because that is the best value we can
57+
* provide.
58+
*
59+
* But computing the URL for the location pulls in a lot of JDK dependencies. For a simple
60+
* application like "Hello World", that would significantly increase the image size. So we only add
61+
* code to compute the URL if the application explicitly invokes {@link CodeSource#getLocation()}.
62+
* This is done using a reachability handler registered in
63+
* {@link ProtectionDomainFeature#beforeAnalysis}.
64+
*
65+
* Note that this still leads to observable differences in places where the location is used
66+
* implicitly, like {@link CodeSource#toString} and {@link CodeSource#implies}. We accept that
67+
* difference in behavior.
68+
*/
69+
public final class ProtectionDomainSupport {
70+
71+
public static class Options {
72+
@Option(help = "Return a the application path as the Class.getProtectionDomain().getCodeSource().getLocation() for all classes that have no explicit ProtectionDomain")//
73+
public static final HostedOptionKey<Boolean> UseApplicationCodeSourceLocation = new HostedOptionKey<>(null);
74+
}
75+
76+
private final LazyFinalReference<ProtectionDomain> allPermDomain = new LazyFinalReference<>(this::createAllPermDomain);
77+
78+
/** Remains null as long as the reachability handler has not triggered. */
79+
Supplier<URL> executableURLSupplier;
80+
81+
public static ProtectionDomain allPermDomain() {
82+
return ImageSingletons.lookup(ProtectionDomainSupport.class).allPermDomain.get();
83+
}
84+
85+
private ProtectionDomain createAllPermDomain() {
86+
java.security.Permissions perms = new java.security.Permissions();
87+
perms.add(SecurityConstants.ALL_PERMISSION);
88+
URL executableURL = executableURLSupplier != null ? executableURLSupplier.get() : null;
89+
CodeSource cs = new CodeSource(executableURL, (Certificate[]) null);
90+
return new java.security.ProtectionDomain(cs, perms);
91+
}
92+
93+
private static URL createExecutableURL() {
94+
/*
95+
* Try to use executable image's name as code source for the class. The file location can be
96+
* used by Java code to determine its location on disk, similar to argv[0].
97+
*/
98+
String executableName = ProcessProperties.getExecutableName();
99+
if (executableName != null) {
100+
try {
101+
return new File(executableName).toURI().toURL();
102+
} catch (MalformedURLException ex) {
103+
/*
104+
* This should not really happen; the file is canonicalized, absolute, so it should
105+
* always have a file:// URL. But if it happens, it is OK to just ignore.
106+
*/
107+
}
108+
}
109+
return null;
110+
}
111+
112+
@Platforms(Platform.HOSTED_ONLY.class)
113+
static void enableCodeSource(Feature.DuringAnalysisAccess access) {
114+
ImageSingletons.lookup(ProtectionDomainSupport.class).executableURLSupplier = ProtectionDomainSupport::createExecutableURL;
115+
if (access != null) {
116+
access.requireAnalysisIteration();
117+
}
118+
}
119+
}
120+
121+
@AutomaticFeature
122+
final class ProtectionDomainFeature implements Feature {
123+
124+
@Override
125+
public void afterRegistration(AfterRegistrationAccess access) {
126+
ImageSingletons.add(ProtectionDomainSupport.class, new ProtectionDomainSupport());
127+
}
128+
129+
@Override
130+
public void beforeAnalysis(BeforeAnalysisAccess access) {
131+
Boolean useApplicationCodeSourceLocation = ProtectionDomainSupport.Options.UseApplicationCodeSourceLocation.getValue();
132+
if (useApplicationCodeSourceLocation == null) {
133+
/* Option not set explicitly, so use automatic behavior based on reachability. */
134+
access.registerReachabilityHandler(ProtectionDomainSupport::enableCodeSource,
135+
ReflectionUtil.lookupMethod(CodeSource.class, "getLocation"));
136+
} else if (useApplicationCodeSourceLocation) {
137+
/* Always enabled. */
138+
ProtectionDomainSupport.enableCodeSource(null);
139+
} else {
140+
/* Always disabled - nothing to do. */
141+
}
142+
}
143+
}

0 commit comments

Comments
 (0)