1 /*
   2  * Copyright (c) 2016, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  *
  26  * @test
  27  * @bug 8164705
  28  * @modules java.base/java.io:open
  29  * @summary Remove pathname canonicalization from FilePermission
  30  */
  31 
  32 import java.io.FilePermission;
  33 import java.lang.reflect.Method;
  34 import java.nio.file.Path;
  35 import java.nio.file.Paths;
  36 
  37 public class Correctness {
  38 
  39     static boolean err = false;
  40     static Method containsMethod;
  41     static boolean isWindows =
  42             System.getProperty("os.name").contains("Windows");
  43     public static void main(String args[]) throws Exception {
  44         check("/", "/");
  45         checkNo("/", "/x");
  46         checkNo("/", "/../x");
  47 
  48         checkNo("/", "x");
  49 
  50         check("/-", "/*");
  51         checkNo("/*", "/-");
  52 
  53         check("/*", "/x");
  54         check("/-", "/x");
  55         check("/-", "/x/*");
  56         check("/-", "/x/-");
  57         check("/-", "/x/y");
  58         checkNo("/*", "/x/y");
  59         check("/x/*", "/x/x");
  60         checkNo("/x/-", "/x");
  61         checkNo("/x/*", "/x");
  62         check("/x/-", "/x/x");
  63         check("/x/-", "/x/x/y");
  64         checkNo("/x/*", "/x/x/y");
  65         checkNo("/x/*", "/x");
  66 
  67         check("*", "x");
  68         checkNo("", "x");
  69         check("-", "x");
  70         check("-", "*");
  71         check("-", "a/-");
  72         check("-", "a/*");
  73         checkNo("*", "a/b");
  74         check("a/*", "a/b");
  75         check("a/-", "a/*");
  76         check("a/-", "a/b/c");
  77         checkNo("a/*", "a/b/c");
  78 
  79         check("../", "../");
  80         check("../-", "../*");
  81         check("../../*", "../../a");
  82 
  83         // If we allow .. and abs/rel checks
  84         check("../-", "a");
  85         check("../../-", "-");
  86         checkNo("../../*", "a");
  87         //check("/-", "a");
  88         //checkNo("/*", "a");
  89         //check("/-", "-");
  90 
  91         try {
  92             // containsPath is broken on Windows.
  93             containsMethod = FilePermission.class.getDeclaredMethod(
  94                     "containsPath", Path.class, Path.class);
  95             containsMethod.setAccessible(true);
  96             System.out.println();
  97 
  98             contains("x", "x", 0);
  99             contains("x", "x/y", 1);
 100             contains("x", "x/y/z", 2);
 101             contains("x", "y", -1);
 102             contains("x", "", -1);
 103             contains("", "", 0);
 104             contains("", "x", 1);
 105             contains("", "x/y", 2);
 106             contains("/", "/", 0);
 107             contains("/", "/x", 1);
 108             contains("/", "/x/y", 2);
 109             contains("/x", "/x/y", 1);
 110             contains("/x", "/y", -1);
 111             //contains("/", "..", Integer.MAX_VALUE);
 112             //contains("/", "x", Integer.MAX_VALUE);
 113             //contains("/", "x/y", Integer.MAX_VALUE);
 114             //contains("/", "../x", Integer.MAX_VALUE);
 115             contains("/x", "y", -1);
 116             contains("x", "/y", -1);
 117 
 118             contains("", "..", -1);
 119             contains("", "../x", -1);
 120             contains("..", "", 1);
 121             contains("..", "x", 2);
 122             contains("..", "x/y", 3);
 123             contains("../x", "x", -1);
 124             contains("../x", "y", -1);
 125             contains("../x", "../x/y", 1);
 126             contains("../../x", "../../x/y", 1);
 127             contains("../../../x", "../../../x/y", 1);
 128             contains("../x", "../y", -1);
 129         } catch (NoSuchMethodException e) {
 130             // Ignored
 131         }
 132         if (err) throw new Exception("Failed.");
 133     }
 134 
 135     // Checks if s2 is inside s1 and depth is expected.
 136     static void contains(String s1, String s2, int expected) throws Exception {
 137         contains0(s1, s2, expected);
 138         if (isWindows) {
 139             contains0("C:" + s1, s2, -1);
 140             contains0(s1, "C:" + s2, -1);
 141             contains0("C:" + s1, "D:" + s2, -1);
 142             contains0("C:" + s1, "C:" + s2, expected);
 143         }
 144     }
 145 
 146     static void contains0(String s1, String s2, int expected) throws Exception {
 147         Path p1 = Paths.get(s1);
 148         Path p2 = Paths.get(s2);
 149         int d = (int)containsMethod.invoke(null, p1, p2);
 150         Path p;
 151         try {
 152             p = p2.relativize(p1);
 153         } catch (Exception e) {
 154             p = null;
 155         }
 156         System.out.printf("%-20s -> %-20s: %20s %5d %5d %s\n", s1, s2, p,
 157                 d, expected, d==expected?"":" WRONG");
 158         if (d != expected) {
 159             err = true;
 160         }
 161     }
 162 
 163     static void check(String s1, String s2, boolean expected) {
 164         FilePermission fp1 = new FilePermission(s1, "read");
 165         FilePermission fp2 = new FilePermission(s2, "read");
 166         boolean b = fp1.implies(fp2);
 167         System.out.printf("%-30s -> %-30s: %5b %s\n",
 168                 s1, s2, b, b==expected?"":" WRONG");
 169         if (b != expected) {
 170             err = true;
 171             System.out.println(fp1);
 172             System.out.println(fp2);
 173         }
 174     }
 175 
 176     static void check(String s1, String s2) {
 177         check(s1, s2, true);
 178     }
 179 
 180     static void checkNo(String s1, String s2) {
 181         check(s1, s2, false);
 182     }
 183 }