Browse Source

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
master
Jaikiran Pai 2 years ago
parent
commit
82c70f3202
4 changed files with 258 additions and 30 deletions
  1. +4
    -1
      build.xml
  2. +247
    -0
      src/main/allow.java
  3. +2
    -13
      src/script/ant
  4. +5
    -16
      src/script/ant.bat

+ 4
- 1
build.xml View File

@@ -347,7 +347,10 @@
</selector> </selector>


<selector id="ant.launcher"> <selector id="ant.launcher">
<filename name="${ant.package}/launch/"/>
<or>
<filename name="${ant.package}/launch/"/>
<filename name="allow.*"/>
</or>
</selector> </selector>


<selector id="ant.core"> <selector id="ant.core">


+ 247
- 0
src/main/allow.java View File

@@ -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();
}
}


+ 2
- 13
src/script/ant View File

@@ -368,19 +368,8 @@ else
ant_sys_opts="-Djikes.class.path=\"$JIKESPATH\"" ant_sys_opts="-Djikes.class.path=\"$JIKESPATH\""
fi fi
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\"" 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 if $ant_exec_debug; then
# using printf to avoid echo line continuation and escape interpretation confusion # using printf to avoid echo line continuation and escape interpretation confusion


+ 5
- 16
src/script/ant.bat View File

@@ -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
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 Slurp the command line arguments. This loop allows for an unlimited number
rem of arguments (up to the command line limit, anyway). rem of arguments (up to the command line limit, anyway).
set ANT_CMD_LINE_ARGS= set ANT_CMD_LINE_ARGS=
@@ -117,26 +121,11 @@ set _JAVACMD=%JAVACMD%
if "%JAVA_HOME%" == "" goto noJavaHome if "%JAVA_HOME%" == "" goto noJavaHome
if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
if "%_JAVACMD%" == "" set _JAVACMD=%JAVA_HOME%\bin\java.exe if "%_JAVACMD%" == "" set _JAVACMD=%JAVA_HOME%\bin\java.exe
goto setSecurityManagerOpt
goto checkJikes


:noJavaHome :noJavaHome
if "%_JAVACMD%" == "" set _JAVACMD=java.exe 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 :checkJikes
if not "%JIKESPATH%"=="" goto runAntWithJikes if not "%JIKESPATH%"=="" goto runAntWithJikes




Loading…
Cancel
Save