You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by ja...@apache.org on 2022/12/11 08:15:49 UTC

[ant] branch master updated: 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 [...]

This is an automated email from the ASF dual-hosted git repository.

jaikiran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ant.git


The following commit(s) were added to refs/heads/master by this push:
     new 82c70f320 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 th [...]
82c70f320 is described below

commit 82c70f3202d5aec4d99fa3b6314ba4a6c338cd94
Author: Jaikiran Pai <ja...@apache.org>
AuthorDate: Sun Dec 11 08:16:41 2022 +0530

    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
---
 build.xml           |   5 +-
 src/main/allow.java | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/script/ant      |  15 +---
 src/script/ant.bat  |  21 ++---
 4 files changed, 258 insertions(+), 30 deletions(-)

diff --git a/build.xml b/build.xml
index 48378b078..10edf9de9 100644
--- a/build.xml
+++ b/build.xml
@@ -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