8209901: Canonical file handling
authorweijun
Mon, 22 Apr 2019 13:01:57 +0800
changeset 58612 32aff2b7585b
parent 58611 53ddf218eddd
child 58613 eb09ad30eccb
8209901: Canonical file handling Reviewed-by: mullan, alanb, ahgross
src/java.base/share/classes/java/io/FilePermission.java
src/java.base/share/classes/sun/security/util/FilePermCompat.java
src/java.base/share/conf/security/java.security
test/jdk/java/security/testlibrary/Proc.java
test/jdk/sun/security/util/FilePermCompat/Flag.java
--- a/src/java.base/share/classes/java/io/FilePermission.java	Fri Apr 19 10:22:20 2019 +0800
+++ b/src/java.base/share/classes/java/io/FilePermission.java	Mon Apr 22 13:01:57 2019 +0800
@@ -463,6 +463,9 @@
      * <P>
      * The default value of the {@code jdk.io.permissionsUseCanonicalPath}
      * system property is {@code false} in this implementation.
+     * <p>
+     * The value can also be set with a security property using the same name,
+     * but setting a system property will override the security property value.
      *
      * @param path the pathname of the file/directory.
      * @param actions the action string.
--- a/src/java.base/share/classes/sun/security/util/FilePermCompat.java	Fri Apr 19 10:22:20 2019 +0800
+++ b/src/java.base/share/classes/sun/security/util/FilePermCompat.java	Mon Apr 22 13:01:57 2019 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,8 +42,11 @@
     public static final boolean compat;
 
     static {
-        String flag = GetPropertyAction.privilegedGetProperty(
-                "jdk.io.permissionsUseCanonicalPath", "false");
+        String flag = SecurityProperties.privilegedGetOverridable(
+                "jdk.io.permissionsUseCanonicalPath");
+        if (flag == null) {
+            flag = "false";
+        }
         switch (flag) {
             case "true":
                 nb = false;
--- a/src/java.base/share/conf/security/java.security	Fri Apr 19 10:22:20 2019 +0800
+++ b/src/java.base/share/conf/security/java.security	Mon Apr 22 13:01:57 2019 +0800
@@ -1215,6 +1215,25 @@
 jdk.security.caDistrustPolicies=SYMANTEC_TLS
 
 #
+# FilePermission path canonicalization
+#
+# This security property dictates how the path argument is processed and stored
+# while constructing a FilePermission object. If the value is set to true, the
+# path argument is canonicalized and FilePermission methods (such as implies,
+# equals, and hashCode) are implemented based on this canonicalized result.
+# Otherwise, the path argument is not canonicalized and FilePermission methods are
+# implemented based on the original input. See the implementation note of the
+# FilePermission class for more details.
+#
+# If a system property of the same name is also specified, it supersedes the
+# security property value defined here.
+#
+# The default value for this property is false.
+#
+jdk.io.permissionsUseCanonicalPath=false
+
+
+#
 # Policies for the proxy_impersonator Kerberos ccache configuration entry
 #
 # The proxy_impersonator ccache configuration entry indicates that the ccache
--- a/test/jdk/java/security/testlibrary/Proc.java	Fri Apr 19 10:22:20 2019 +0800
+++ b/test/jdk/java/security/testlibrary/Proc.java	Mon Apr 22 13:01:57 2019 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,9 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UncheckedIOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -110,6 +113,7 @@
     private List<String> args = new ArrayList<>();
     private Map<String,String> env = new HashMap<>();
     private Map<String,String> prop = new HashMap();
+    private Map<String,String> secprop = new HashMap();
     private boolean inheritIO = false;
     private boolean noDump = false;
 
@@ -176,6 +180,11 @@
         prop.put(a, b);
         return this;
     }
+    // Specifies a security property. Can be called multiple times.
+    public Proc secprop(String a, String b) {
+        secprop.put(a, b);
+        return this;
+    }
     // Inherit the value of a system property
     public Proc inheritProp(String k) {
         String v = System.getProperty(k);
@@ -282,6 +291,17 @@
             cmd.add(cp.stream().collect(Collectors.joining(File.pathSeparator)));
         }
 
+        if (!secprop.isEmpty()) {
+            Path p = Path.of(getId("security"));
+            try (OutputStream fos = Files.newOutputStream(p);
+                 PrintStream ps = new PrintStream(fos)) {
+                secprop.forEach((k,v) -> ps.println(k + "=" + v));
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+            prop.put("java.security.properties", p.toString());
+        }
+
         for (Entry<String,String> e: prop.entrySet()) {
             cmd.add("-D" + e.getKey() + "=" + e.getValue());
         }
@@ -380,6 +400,12 @@
         }
         return p.waitFor();
     }
+    // Wait for process end with expected exit code
+    public void waitFor(int expected) throws Exception {
+        if (p.waitFor() != expected) {
+            throw new RuntimeException("Exit code not " + expected);
+        }
+    }
 
     // The following methods are used inside a proc
 
--- a/test/jdk/sun/security/util/FilePermCompat/Flag.java	Fri Apr 19 10:22:20 2019 +0800
+++ b/test/jdk/sun/security/util/FilePermCompat/Flag.java	Mon Apr 22 13:01:57 2019 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,22 +23,84 @@
 
 /*
  * @test
- * @bug 8164705
+ * @bug 8164705 8209901
+ * @library /test/jdk/java/security/testlibrary
+ * @modules java.base/jdk.internal.misc
  * @summary check jdk.filepermission.canonicalize
- * @run main/othervm/policy=flag.policy
-  *     -Djdk.io.permissionsUseCanonicalPath=true Flag true true
- * @run main/othervm/policy=flag.policy
-  *     -Djdk.io.permissionsUseCanonicalPath=false Flag false true
- * @run main/othervm/policy=flag.policy Flag false true
  */
 
 import java.io.File;
 import java.io.FilePermission;
 import java.lang.*;
+import java.nio.file.Path;
 
 public class Flag {
     public static void main(String[] args) throws Exception {
 
+        if (args.length == 0) {
+            String policy = Path.of(
+                    System.getProperty("test.src"), "flag.policy").toString();
+
+            // effectively true
+            Proc.create("Flag")
+                    .prop("java.security.manager", "")
+                    .prop("java.security.policy", policy)
+                    .prop("jdk.io.permissionsUseCanonicalPath", "true")
+                    .args("run", "true", "true")
+                    .start()
+                    .waitFor(0);
+            Proc.create("Flag")
+                    .prop("java.security.manager", "")
+                    .prop("java.security.policy", policy)
+                    .secprop("jdk.io.permissionsUseCanonicalPath", "true")
+                    .args("run", "true", "true")
+                    .start()
+                    .waitFor(0);
+            Proc.create("Flag")
+                    .prop("java.security.manager", "")
+                    .prop("java.security.policy", policy)
+                    .secprop("jdk.io.permissionsUseCanonicalPath", "false")
+                    .prop("jdk.io.permissionsUseCanonicalPath", "true")
+                    .args("run", "true", "true")
+                    .start()
+                    .waitFor(0);
+
+            // effectively false
+            Proc.create("Flag")
+                    .prop("java.security.manager", "")
+                    .prop("java.security.policy", policy)
+                    .prop("jdk.io.permissionsUseCanonicalPath", "false")
+                    .args("run", "false", "true")
+                    .start()
+                    .waitFor(0);
+            Proc.create("Flag")
+                    .prop("java.security.manager", "")
+                    .prop("java.security.policy", policy)
+                    .secprop("jdk.io.permissionsUseCanonicalPath", "false")
+                    .args("run", "false", "true")
+                    .start()
+                    .waitFor(0);
+            Proc.create("Flag")
+                    .prop("java.security.manager", "")
+                    .prop("java.security.policy", policy)
+                    .secprop("jdk.io.permissionsUseCanonicalPath", "true")
+                    .prop("jdk.io.permissionsUseCanonicalPath", "false")
+                    .args("run", "false", "true")
+                    .start()
+                    .waitFor(0);
+            Proc.create("Flag")
+                    .prop("java.security.manager", "")
+                    .prop("java.security.policy", policy)
+                    .args("run", "false", "true")
+                    .start()
+                    .waitFor(0);
+        } else {
+            run(args);
+        }
+    }
+
+    static void run(String[] args) throws Exception {
+
         boolean test1;
         boolean test2;
 
@@ -55,8 +117,8 @@
             test2 = false;
         }
 
-        if (test1 != Boolean.parseBoolean(args[0]) ||
-                test2 != Boolean.parseBoolean(args[1])) {
+        if (test1 != Boolean.parseBoolean(args[1]) ||
+                test2 != Boolean.parseBoolean(args[2])) {
             throw new Exception("Test failed: " + test1 + " " + test2);
         }
     }