diff options
author | Jaikiran Pai <jaikiran@apache.org> | 2022-12-11 08:16:41 +0530 |
---|---|---|
committer | Jaikiran Pai <jaikiran@apache.org> | 2022-12-11 13:43:58 +0530 |
commit | 82c70f3202d5aec4d99fa3b6314ba4a6c338cd94 (patch) | |
tree | 2cfb83174fb7255f7b16bd3419f1f892bc8eac55 | |
parent | 7601bf1767a0c191ff22f661c8fde97302d0cd3a (diff) | |
download | ant-82c70f3202d5aec4d99fa3b6314ba4a6c338cd94.tar.gz |
redo security manager setting to allow calling System.setSecurityManager at runtime
- Reverts the changes done to launch scripts which were checking for the Java runtime version to decide whether or not to set java.security.manager=allow
- Introduces a new "allow" Java class (in unnamed package) as a workaround to allow setting java.security.manager=allow on (older) versions of Java which don't
recognize "allow" as a predefined text for that property
- Packages the "allow" Java class into ant-launcher.jar, which is the same jar file containing the org.apache.tools.ant.launch.Launcher class that gets launched
from the Ant startup scripts
- Sets java.security.manager=allow explicitly in Ant launch scripts, irrespective of which Java runtime version is being used
-rw-r--r-- | build.xml | 5 | ||||
-rw-r--r-- | src/main/allow.java | 247 | ||||
-rw-r--r-- | src/script/ant | 15 | ||||
-rwxr-xr-x | src/script/ant.bat | 21 |
4 files changed, 258 insertions, 30 deletions
@@ -347,7 +347,10 @@ </selector> <selector id="ant.launcher"> - <filename name="${ant.package}/launch/"/> + <or> + <filename name="${ant.package}/launch/"/> + <filename name="allow.*"/> + </or> </selector> <selector id="ant.core"> diff --git a/src/main/allow.java b/src/main/allow.java new file mode 100644 index 000000000..3e88cd1b9 --- /dev/null +++ b/src/main/allow.java @@ -0,0 +1,247 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +// +// THIS CLASS IS INTENTIONALLY IN AN UNNAMED PACKAGE +// (see the class level javadoc of this class for more details) +// + +import java.io.FileDescriptor; +import java.net.InetAddress; +import java.security.Permission; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * This class is only here to allow setting the {@code java.security.manager} system property + * to a value of {@code allow}. + * <p> + * Certain versions of Java (like Java 8) do not recognize {@code allow} + * as a valid textual value for the {@code java.security.manager}, but some higher versions of + * Java do recognize this value. While launching Ant (from scripts for example), it isn't straightforward + * to identify which runtime version of Java is used to launch Ant. That then causes additional and + * complex scripting logic (that works across all supported OS platforms) to first identify the Java + * runtime version being used and then deciding whether or not to set {@code allow} as a value for + * that system property. + * </p> + * <p> + * The system property value for this {@code java.security.manager} is considered some predefined + * text or if it doesn't match that predefined text then is considered a fully qualified classname + * of a class which extends the {@link SecurityManager} class. We use that knowledge to workaround + * the problem we have with setting {@code allow} as the value for Java runtime which don't understand + * that value. This {@code allow} class belongs to an unnamed package and is packaged within a jar + * file {@code ant-launcher.jar} which Ant always adds to the classpath for launching Ant. That + * way, this class is available in the classpath and any Java versions that don't recognize + * {@code allow} as a predefined value will end up instantiating this class. + * </p> + * <p> + * The implementation in this class doesn't really provide any {@code SecurityManager} expected + * semantics. So this really isn't a {@code SecurityManager} implementation and shouldn't be used + * as one. If/when this class gets instantiated and is set as a {@code SecurityManager}, it will + * uninstall itself, on first use, by calling + * {@link System#setSecurityManager(SecurityManager) System.setSecurityManager(null)}. First use is + * defined as any call on a public method of this instance. + * This class intentionally uninstalls itself on first use to preserve the semantics of {@code allow} + * which merely implies that setting a security manager instance by the application code through the + * use of {@link System#setSecurityManager(SecurityManager)} is allowed. + * </p> + * + * @deprecated This isn't for public consumption and is an internal detail of Ant + */ +// This class has been copied over from the Apache NetBeans project +@Deprecated +public class allow extends SecurityManager { + + private final AtomicBoolean uninstalling = new AtomicBoolean(); + + private void uninstall() { + if (uninstalling.compareAndSet(false, true)) { + // we set the security manager to null only when we ascertain that this class + // instance is the current installed security manager. We do this to avoid any race + // conditions where some other thread/caller had concurrently called + // System.setSecurityManager and we end up "null"ing that set instance. + // We rely on the (internal) detail that System.setSecurityManager is synchronized + // on the System.class + synchronized (System.class) { + final SecurityManager currentSecManager = System.getSecurityManager(); + if (currentSecManager != this) { + return; + } + System.setSecurityManager(null); + } + } + } + + @Override + public void checkAccept(String host, int port) { + uninstall(); + } + + @Override + public void checkAccess(Thread t) { + uninstall(); + } + + @Override + public void checkAccess(ThreadGroup g) { + uninstall(); + } + + @Override + public void checkAwtEventQueueAccess() { + uninstall(); + } + + @Override + public void checkConnect(String host, int port) { + uninstall(); + } + + @Override + public void checkConnect(String host, int port, Object context) { + uninstall(); + } + + @Override + public void checkCreateClassLoader() { + uninstall(); + } + + @Override + public void checkDelete(String file) { + uninstall(); + } + + @Override + public void checkExec(String cmd) { + uninstall(); + } + + @Override + public void checkExit(int status) { + uninstall(); + } + + @Override + public void checkLink(String lib) { + uninstall(); + } + + @Override + public void checkListen(int port) { + uninstall(); + } + + @Override + public void checkMemberAccess(Class<?> clazz, int which) { + uninstall(); + } + + @Override + public void checkMulticast(InetAddress maddr) { + uninstall(); + } + + @Override + public void checkMulticast(InetAddress maddr, byte ttl) { + uninstall(); + } + + @Override + public void checkPackageAccess(String pkg) { + uninstall(); + } + + @Override + public void checkPackageDefinition(String pkg) { + uninstall(); + } + + @Override + public void checkPermission(Permission perm) { + uninstall(); + } + + @Override + public void checkPermission(Permission perm, Object context) { + uninstall(); + } + + @Override + public void checkPrintJobAccess() { + uninstall(); + } + + @Override + public void checkPropertiesAccess() { + uninstall(); + } + + @Override + public void checkPropertyAccess(String key) { + uninstall(); + } + + @Override + public void checkRead(FileDescriptor fd) { + uninstall(); + } + + @Override + public void checkRead(String file) { + uninstall(); + } + + @Override + public void checkRead(String file, Object context) { + uninstall(); + } + + @Override + public void checkSecurityAccess(String target) { + uninstall(); + } + + @Override + public void checkSetFactory() { + uninstall(); + } + + @Override + public void checkSystemClipboardAccess() { + uninstall(); + } + + @Override + public boolean checkTopLevelWindow(Object window) { + uninstall(); + // we return false because we don't know what thread would be calling this permission + // check method + return false; + } + + @Override + public void checkWrite(FileDescriptor fd) { + uninstall(); + } + + @Override + public void checkWrite(String file) { + uninstall(); + } +} + diff --git a/src/script/ant b/src/script/ant index ebc5e95ef..0507ff166 100644 --- a/src/script/ant +++ b/src/script/ant @@ -368,19 +368,8 @@ else ant_sys_opts="-Djikes.class.path=\"$JIKESPATH\"" fi fi -# Run "java -XshowSettings:properties" and check the output for "java.specification.version" value -JAVA_SPEC_VERSION=$("$JAVACMD" -XshowSettings:properties 2>&1 | sed -n -e 's/[[:space:]]//g' -e 's/^java\.specification\.version=//p') -case "$JAVA_SPEC_VERSION" in - 1.*) - # Up to and including Java 8, versions are reported as 1.N. - ;; - *) - if [ "$JAVA_SPEC_VERSION" -ge 18 ]; then - # set security manager property to allow calls to System.setSecurityManager() at runtime - ANT_OPTS="$ANT_OPTS -Djava.security.manager=allow" - fi - ;; -esac +# allow calling System.setSecurityManager at runtime +ant_sys_opts="$ant_sys_opts -Djava.security.manager=allow" ant_exec_command="exec \"\$JAVACMD\" $ANT_OPTS -classpath \"\$LOCALCLASSPATH\" -Dant.home=\"\$ANT_HOME\" -Dant.library.dir=\"\$ANT_LIB\" $ant_sys_opts org.apache.tools.ant.launch.Launcher $ANT_ARGS -cp \"\$CLASSPATH\"" if $ant_exec_debug; then # using printf to avoid echo line continuation and escape interpretation confusion diff --git a/src/script/ant.bat b/src/script/ant.bat index 58dc3db86..574d8813d 100755 --- a/src/script/ant.bat +++ b/src/script/ant.bat @@ -57,6 +57,10 @@ rem CLASSPATH must not be used if it is equal to "" if "%CLASSPATH%"=="""" set _USE_CLASSPATH=no if "%CLASSPATH%"=="" set _USE_CLASSPATH=no +rem allow calling System.setSecurityManager at runtime +set "ANT_OPTS=%ANT_OPTS% -Djava.security.manager=allow" +echo ANT_OPTS is set to %ANT_OPTS% + rem Slurp the command line arguments. This loop allows for an unlimited number rem of arguments (up to the command line limit, anyway). set ANT_CMD_LINE_ARGS= @@ -117,26 +121,11 @@ set _JAVACMD=%JAVACMD% if "%JAVA_HOME%" == "" goto noJavaHome if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome if "%_JAVACMD%" == "" set _JAVACMD=%JAVA_HOME%\bin\java.exe -goto setSecurityManagerOpt +goto checkJikes :noJavaHome if "%_JAVACMD%" == "" set _JAVACMD=java.exe -:setSecurityManagerOpt -setlocal EnableDelayedExpansion -"!_JAVACMD!" -XshowSettings:properties 2>&1 | find "java.specification.version = 18" >nul 2>&1 -if !errorlevel! EQU 0 ( - rem This is Java 18, so set -Djava.security.manager=allow - set JAVA_SECMGR_OPT=-Djava.security.manager=allow -) else ( - "!_JAVACMD!" -XshowSettings:properties 2>&1 | find "java.specification.version = 19" >nul 2>&1 - if !errorlevel! EQU 0 ( - rem This is Java 19, so set -Djava.security.manager=allow - set JAVA_SECMGR_OPT=-Djava.security.manager=allow - ) -) -endlocal & set "ANT_OPTS=%ANT_OPTS% %JAVA_SECMGR_OPT%" - :checkJikes if not "%JIKESPATH%"=="" goto runAntWithJikes |