diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java index 9d5db356255..2741915e55d 100644 --- a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java @@ -65,9 +65,6 @@ class UnixPath // array of offsets of elements in path (created lazily) private volatile int[] offsets; - // file permissions (created lazily) - private volatile FilePermission[] perms; - UnixPath(UnixFileSystem fs, byte[] path) { this.fs = fs; this.path = path; @@ -768,45 +765,23 @@ class UnixPath } } - // create file permissions used for read and write checks - private void checkReadOrWrite(boolean checkRead) { - SecurityManager sm = System.getSecurityManager(); - if (sm == null) - return; - if (perms == null) { - synchronized (this) { - if (perms == null) { - FilePermission[] p = new FilePermission[2]; - String pathForPermCheck = getPathForPermissionCheck(); - p[0] = new FilePermission(pathForPermCheck, - SecurityConstants.FILE_READ_ACTION); - p[1] = new FilePermission(pathForPermCheck, - SecurityConstants.FILE_WRITE_ACTION); - perms = p; - } - } - } - if (checkRead) { - sm.checkPermission(perms[0]); - } else { - sm.checkPermission(perms[1]); - } - } void checkRead() { - checkReadOrWrite(true); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkRead(getPathForPermissionCheck()); } void checkWrite() { - checkReadOrWrite(false); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkWrite(getPathForPermissionCheck()); } void checkDelete() { SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - // permission not cached + if (sm != null) sm.checkDelete(getPathForPermissionCheck()); - } } @Override diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java index 5af9876f33c..44cdb276de2 100644 --- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java @@ -46,6 +46,7 @@ class WindowsFileAttributeViews { @Override public WindowsFileAttributes readAttributes() throws IOException { + file.checkRead(); try { return WindowsFileAttributes.get(file, followLinks); } catch (WindowsException x) { diff --git a/jdk/test/java/nio/file/Path/CheckPermissions.java b/jdk/test/java/nio/file/Path/CheckPermissions.java new file mode 100644 index 00000000000..a8aef0f91f2 --- /dev/null +++ b/jdk/test/java/nio/file/Path/CheckPermissions.java @@ -0,0 +1,695 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6866804 + * @summary Unit test for java.nio.file.Path + * @library .. + */ + +import java.nio.ByteBuffer; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.channels.SeekableByteChannel; +import java.security.Permission; +import java.io.*; +import java.util.*; + +/** + * Checks each method that accesses the file system does the right permission + * check when there is a security manager set. + */ + +public class CheckPermissions { + + static class Checks { + private List permissionsChecked = new ArrayList(); + private Set propertiesChecked = new HashSet(); + private List readsChecked = new ArrayList(); + private List writesChecked = new ArrayList(); + private List deletesChecked = new ArrayList(); + private List execsChecked = new ArrayList(); + + List permissionsChecked() { return permissionsChecked; } + Set propertiesChecked() { return propertiesChecked; } + List readsChecked() { return readsChecked; } + List writesChecked() { return writesChecked; } + List deletesChecked() { return deletesChecked; } + List execsChecked() { return execsChecked; } + } + + static ThreadLocal myChecks = + new ThreadLocal() { + @Override protected Checks initialValue() { + return null; + } + }; + + static void prepare() { + myChecks.set(new Checks()); + } + + static void assertCheckPermission(Class type, + String name) + { + for (Permission perm: myChecks.get().permissionsChecked()) { + if (type.isInstance(perm) && perm.getName().equals(name)) + return; + } + throw new RuntimeException(type.getName() + "\"" + name + "\") not checked"); + } + + static void assertCheckPropertyAccess(String key) { + if (!myChecks.get().propertiesChecked().contains(key)) + throw new RuntimeException("Property " + key + " not checked"); + } + + static void assertChecked(Path file, List list) { + String s = file.toString(); + for (String f: list) { + if (f.endsWith(s)) + return; + } + throw new RuntimeException("Access not checked"); + } + + static void assertCheckRead(Path file) { + assertChecked(file, myChecks.get().readsChecked()); + } + + static void assertCheckWrite(Path file) { + assertChecked(file, myChecks.get().writesChecked()); + } + + static void assertCheckDelete(Path file) { + assertChecked(file, myChecks.get().deletesChecked()); + } + + static void assertCheckExec(Path file) { + assertChecked(file, myChecks.get().execsChecked()); + } + + static class LoggingSecurityManager extends SecurityManager { + static void install() { + System.setSecurityManager(new LoggingSecurityManager()); + } + + @Override + public void checkPermission(Permission perm) { + Checks checks = myChecks.get(); + if (checks != null) + checks.permissionsChecked().add(perm); + } + + @Override + public void checkPropertyAccess(String key) { + Checks checks = myChecks.get(); + if (checks != null) + checks.propertiesChecked().add(key); + } + + @Override + public void checkRead(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.readsChecked().add(file); + } + + @Override + public void checkWrite(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.writesChecked().add(file); + } + + @Override + public void checkDelete(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.deletesChecked().add(file); + } + + @Override + public void checkExec(String file) { + Checks checks = myChecks.get(); + if (checks != null) + checks.execsChecked().add(file); + } + } + + static void testBasicFileAttributeView(BasicFileAttributeView view, Path file) + throws IOException + { + prepare(); + view.readAttributes(); + assertCheckRead(file); + + prepare(); + FileTime now = FileTime.fromMillis(System.currentTimeMillis()); + view.setTimes(null, now, now); + assertCheckWrite(file); + } + + static void testPosixFileAttributeView(PosixFileAttributeView view, Path file) + throws IOException + { + prepare(); + PosixFileAttributes attrs = view.readAttributes(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setPermissions(attrs.permissions()); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setOwner(attrs.owner()); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setOwner(attrs.owner()); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + } + + public static void main(String[] args) throws IOException { + Path dir = Paths.get(System.getProperty("test.src", ".")); + Path file = dir.resolve("file1234").createFile(); + try { + LoggingSecurityManager.install(); + + // -- checkAccess -- + + prepare(); + file.checkAccess(); + assertCheckRead(file); + + prepare(); + file.checkAccess(AccessMode.READ); + assertCheckRead(file); + + prepare(); + file.checkAccess(AccessMode.WRITE); + assertCheckWrite(file); + + prepare(); + try { + file.checkAccess(AccessMode.EXECUTE); + } catch (AccessDeniedException x) { } + assertCheckExec(file); + + prepare(); + try { + file.checkAccess(AccessMode.READ, AccessMode.WRITE, AccessMode.EXECUTE); + } catch (AccessDeniedException x) { } + assertCheckRead(file); + assertCheckWrite(file); + assertCheckExec(file); + + // -- copyTo -- + + Path target = dir.resolve("target1234"); + prepare(); + file.copyTo(target); + try { + assertCheckRead(file); + assertCheckWrite(target); + } finally { + target.delete(); + } + + if (TestUtil.supportsLinks(dir)) { + Path link = dir.resolve("link1234").createSymbolicLink(file); + try { + prepare(); + link.copyTo(target, LinkOption.NOFOLLOW_LINKS); + try { + assertCheckRead(link); + assertCheckWrite(target); + assertCheckPermission(LinkPermission.class, "symbolic"); + } finally { + target.delete(); + } + } finally { + link.delete(); + } + } + + // -- createDirectory -- + + Path subdir = dir.resolve("subdir1234"); + prepare(); + subdir.createDirectory(); + try { + assertCheckWrite(subdir); + } finally { + subdir.delete(); + } + + // -- createFile -- + + Path fileToCreate = dir.resolve("file7890"); + prepare(); + try { + fileToCreate.createFile(); + assertCheckWrite(fileToCreate); + } finally { + fileToCreate.delete(); + } + + // -- createSymbolicLink -- + + if (TestUtil.supportsLinks(dir)) { + prepare(); + Path link = dir.resolve("link1234").createSymbolicLink(file); + try { + assertCheckWrite(link); + assertCheckPermission(LinkPermission.class, "symbolic"); + } finally { + link.delete(); + } + } + + // -- delete/deleteIfExists -- + + Path fileToDelete = dir.resolve("file7890"); + + fileToDelete.createFile(); + prepare(); + fileToDelete.delete(); + assertCheckDelete(fileToDelete); + + fileToDelete.createFile(); + prepare(); + fileToDelete.deleteIfExists(); + assertCheckDelete(fileToDelete); + + // -- exists/notExists -- + + prepare(); + file.exists(); + assertCheckRead(file); + + prepare(); + file.notExists(); + assertCheckRead(file); + + // -- getFileStore -- + + prepare(); + file.getFileStore(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "getFileStoreAttributes"); + + // -- isSameFile -- + + prepare(); + file.isSameFile(dir); + assertCheckRead(file); + assertCheckRead(dir); + + // -- moveTo -- + + Path target2 = dir.resolve("target1234"); + prepare(); + file.moveTo(target2); + try { + assertCheckWrite(file); + assertCheckWrite(target2); + } finally { + // restore file + target2.moveTo(file); + } + + // -- newByteChannel -- + + SeekableByteChannel sbc; + + prepare(); + sbc = file.newByteChannel(); + try { + assertCheckRead(file); + } finally { + sbc.close(); + } + prepare(); + sbc = file.newByteChannel(StandardOpenOption.WRITE); + try { + assertCheckWrite(file); + } finally { + sbc.close(); + } + prepare(); + sbc = file.newByteChannel(StandardOpenOption.READ, StandardOpenOption.WRITE); + try { + assertCheckRead(file); + assertCheckWrite(file); + } finally { + sbc.close(); + } + + prepare(); + sbc = file.newByteChannel(StandardOpenOption.DELETE_ON_CLOSE); + try { + assertCheckRead(file); + assertCheckDelete(file); + } finally { + sbc.close(); + } + file.createFile(); // restore file + + + // -- newInputStream/newOutptuStream -- + + prepare(); + InputStream in = file.newInputStream(); + try { + assertCheckRead(file); + } finally { + in.close(); + } + prepare(); + OutputStream out = file.newOutputStream(); + try { + assertCheckWrite(file); + } finally { + out.close(); + } + + // -- newDirectoryStream -- + + prepare(); + DirectoryStream stream = dir.newDirectoryStream(); + try { + assertCheckRead(dir); + + if (stream instanceof SecureDirectoryStream) { + Path entry; + SecureDirectoryStream sds = + (SecureDirectoryStream)stream; + + // newByteChannel + entry = file.getName(); + prepare(); + sbc = sds.newByteChannel(entry, EnumSet.of(StandardOpenOption.READ)); + try { + assertCheckRead(file); + } finally { + sbc.close(); + } + prepare(); + sbc = sds.newByteChannel(entry, EnumSet.of(StandardOpenOption.WRITE)); + try { + assertCheckWrite(file); + } finally { + sbc.close(); + } + + // deleteFile + entry = file.getName(); + prepare(); + sds.deleteFile(entry); + assertCheckDelete(file); + dir.resolve(entry).createFile(); // restore file + + // deleteDirectory + entry = Paths.get("subdir1234"); + dir.resolve(entry).createDirectory(); + prepare(); + sds.deleteDirectory(entry); + assertCheckDelete(dir.resolve(entry)); + + // move + entry = Paths.get("tempname1234"); + prepare(); + sds.move(file.getName(), sds, entry); + assertCheckWrite(file); + assertCheckWrite(dir.resolve(entry)); + sds.move(entry, sds, file.getName()); // restore file + + // newDirectoryStream + entry = Paths.get("subdir1234"); + dir.resolve(entry).createDirectory(); + try { + prepare(); + sds.newDirectoryStream(entry).close(); + assertCheckRead(dir.resolve(entry)); + } finally { + dir.resolve(entry).delete(); + } + + // getFileAttributeView to access attributes of directory + testBasicFileAttributeView(sds + .getFileAttributeView(BasicFileAttributeView.class), dir); + testPosixFileAttributeView(sds + .getFileAttributeView(PosixFileAttributeView.class), dir); + + // getFileAttributeView to access attributes of entry + entry = file.getName(); + testBasicFileAttributeView(sds + .getFileAttributeView(entry, BasicFileAttributeView.class), file); + testPosixFileAttributeView(sds + .getFileAttributeView(entry, PosixFileAttributeView.class), file); + + } else { + System.out.println("SecureDirectoryStream not tested"); + } + + } finally { + stream.close(); + } + + // -- toAbsolutePath -- + + prepare(); + file.getName().toAbsolutePath(); + assertCheckPropertyAccess("user.dir"); + + // -- toRealPath -- + + prepare(); + file.toRealPath(true); + assertCheckRead(file); + + prepare(); + file.toRealPath(false); + assertCheckRead(file); + + prepare(); + Paths.get(".").toRealPath(true); + assertCheckPropertyAccess("user.dir"); + + prepare(); + Paths.get(".").toRealPath(false); + assertCheckPropertyAccess("user.dir"); + + // -- register -- + + WatchService watcher = FileSystems.getDefault().newWatchService(); + try { + prepare(); + dir.register(watcher, StandardWatchEventKind.ENTRY_DELETE); + assertCheckRead(dir); + } finally { + watcher.close(); + } + + // -- getAttribute/setAttribute/readAttributes -- + + prepare(); + file.getAttribute("size"); + assertCheckRead(file); + + prepare(); + file.setAttribute("lastModifiedTime", + FileTime.fromMillis(System.currentTimeMillis())); + assertCheckWrite(file); + + prepare(); + file.readAttributes("*"); + assertCheckRead(file); + + // -- BasicFileAttributeView -- + testBasicFileAttributeView(file + .getFileAttributeView(BasicFileAttributeView.class), file); + + // -- PosixFileAttributeView -- + + { + PosixFileAttributeView view = + file.getFileAttributeView(PosixFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(PosixFileAttributeView.class)) + { + testPosixFileAttributeView(view, file); + } else { + System.out.println("PosixFileAttributeView not tested"); + } + } + + // -- DosFileAttributeView -- + + { + DosFileAttributeView view = + file.getFileAttributeView(DosFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(DosFileAttributeView.class)) + { + prepare(); + view.readAttributes(); + assertCheckRead(file); + + prepare(); + view.setArchive(false); + assertCheckWrite(file); + + prepare(); + view.setHidden(false); + assertCheckWrite(file); + + prepare(); + view.setReadOnly(false); + assertCheckWrite(file); + + prepare(); + view.setSystem(false); + assertCheckWrite(file); + } else { + System.out.println("DosFileAttributeView not tested"); + } + } + + // -- FileOwnerAttributeView -- + + { + FileOwnerAttributeView view = + file.getFileAttributeView(FileOwnerAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(FileOwnerAttributeView.class)) + { + prepare(); + UserPrincipal owner = view.getOwner(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + prepare(); + view.setOwner(owner); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + + } else { + System.out.println("FileOwnerAttributeView not tested"); + } + } + + // -- UserDefinedFileAttributeView -- + + { + UserDefinedFileAttributeView view = + file.getFileAttributeView(UserDefinedFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(UserDefinedFileAttributeView.class)) + { + prepare(); + view.write("test", ByteBuffer.wrap(new byte[100])); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.read("test", ByteBuffer.allocate(100)); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.size("test"); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.list(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + + prepare(); + view.delete("test"); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, + "accessUserDefinedAttributes"); + } else { + System.out.println("UserDefinedFileAttributeView not tested"); + } + } + + // -- AclFileAttributeView -- + { + AclFileAttributeView view = + file.getFileAttributeView(AclFileAttributeView.class); + if (view != null && + file.getFileStore().supportsFileAttributeView(AclFileAttributeView.class)) + { + prepare(); + List acl = view.getAcl(); + assertCheckRead(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + prepare(); + view.setAcl(acl); + assertCheckWrite(file); + assertCheckPermission(RuntimePermission.class, "accessUserInformation"); + } else { + System.out.println("AclFileAttributeView not tested"); + } + } + + // -- UserPrincipalLookupService + + UserPrincipalLookupService lookupService = + FileSystems.getDefault().getUserPrincipalLookupService(); + UserPrincipal owner = Attributes.getOwner(file); + + prepare(); + lookupService.lookupPrincipalByName(owner.getName()); + assertCheckPermission(RuntimePermission.class, + "lookupUserInformation"); + + try { + UserPrincipal group = Attributes.readPosixFileAttributes(file).group(); + prepare(); + lookupService.lookupPrincipalByGroupName(group.getName()); + assertCheckPermission(RuntimePermission.class, + "lookupUserInformation"); + } catch (UnsupportedOperationException ignore) { + System.out.println("lookupPrincipalByGroupName not tested"); + } + + + } finally { + file.deleteIfExists(); + } + } +} diff --git a/jdk/test/java/nio/file/Path/Misc.java b/jdk/test/java/nio/file/Path/Misc.java index 07418844fd8..9e5452c8988 100644 --- a/jdk/test/java/nio/file/Path/Misc.java +++ b/jdk/test/java/nio/file/Path/Misc.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 6866804 + * @bug 4313887 6838333 6867101 * @summary Unit test for java.nio.file.Path for miscellenous methods not * covered by other tests * @library ..