8364322: (fs) fchmodat support for AT_SYMLINK_NOFOLLOW flag too pessimistic on Linux

Reviewed-by: alanb
This commit is contained in:
Benjamin Peterson 2026-07-02 05:35:46 +00:00 committed by Alan Bateman
parent a301709aba
commit e1a3967870
3 changed files with 31 additions and 20 deletions

View File

@ -555,9 +555,10 @@ class UnixNativeDispatcher {
/**
* Capabilities
*/
private static final int SUPPORTS_OPENAT = 1 << 1; // syscalls
private static final int SUPPORTS_XATTR = 1 << 3;
private static final int SUPPORTS_BIRTHTIME = 1 << 16; // other features
private static final int SUPPORTS_OPENAT = 1 << 1; // syscalls
private static final int SUPPORTS_FCHMODAT_NOFOLLOW = 1 << 2;
private static final int SUPPORTS_XATTR = 1 << 3;
private static final int SUPPORTS_BIRTHTIME = 1 << 16; // other features
private static final int capabilities;
/**
@ -585,9 +586,8 @@ class UnixNativeDispatcher {
* Supports fchmodat with AT_SYMLINK_NOFOLLOW flag
*/
static boolean fchmodatNoFollowSupported() {
return fchmodatNoFollowSupported0();
return (capabilities & SUPPORTS_FCHMODAT_NOFOLLOW) != 0;
}
private static native boolean fchmodatNoFollowSupported0();
private static native int init();
static {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2026, 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
@ -388,17 +388,16 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_XATTR;
#endif
return capabilities;
}
JNIEXPORT jboolean JNICALL
Java_sun_nio_fs_UnixNativeDispatcher_fchmodatNoFollowSupported0(JNIEnv* env, jclass this) {
#if defined(__linux__)
// Linux recognizes but does not support the AT_SYMLINK_NOFOLLOW flag
return JNI_FALSE;
// Linux 6.6+ supports AT_SYMLINK_NOFOLLOW. glibc 2.32+ also provides emulation for older kernels.
if (fchmodat(AT_FDCWD, "", 0, AT_SYMLINK_NOFOLLOW) == 0 || errno != ENOTSUP) {
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FCHMODAT_NOFOLLOW;
}
#else
return JNI_TRUE;
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FCHMODAT_NOFOLLOW;
#endif
return capabilities;
}
JNIEXPORT jbyteArray JNICALL

View File

@ -212,6 +212,13 @@ public class SecureDS {
Path link = createSymbolicLink(aDir.resolve(linkEntry), fileEntry);
Set<PosixFilePermission> permsLink = getPosixFilePermissions(link, NOFOLLOW_LINKS);
// Test setting permissions on a regular file through the no-follow view
view = stream.getFileAttributeView(fileEntry, PosixFileAttributeView.class, NOFOLLOW_LINKS);
view.setPermissions(noperms);
assertEquals(noperms, getPosixFilePermissions(file));
view.setPermissions(permsFile);
assertEquals(permsFile, getPosixFilePermissions(file));
// Test following link to file
view = stream.getFileAttributeView(link, PosixFileAttributeView.class);
view.setPermissions(noperms);
@ -220,14 +227,19 @@ public class SecureDS {
view.setPermissions(permsFile);
assertEquals(permsFile, getPosixFilePermissions(file));
assertEquals(permsLink, getPosixFilePermissions(link, NOFOLLOW_LINKS));
// Symbolic link permissions do not apply on Linux
if (!Platform.isLinux()) {
// Test not following link to file
view = stream.getFileAttributeView(link, PosixFileAttributeView.class, NOFOLLOW_LINKS);
view.setPermissions(noperms);
// Test not following link to file
var linkView = stream.getFileAttributeView(link, PosixFileAttributeView.class, NOFOLLOW_LINKS);
if (Platform.isLinux()) {
// Symbolic link permissions do not apply on Linux
assertThrows(IOException.class, () -> linkView.setPermissions(noperms));
assertEquals(permsFile, getPosixFilePermissions(file));
assertThrows(IOException.class, () -> linkView.setPermissions(permsLink));
} else {
linkView.setPermissions(noperms);
assertEquals(permsFile, getPosixFilePermissions(file));
assertEquals(noperms, getPosixFilePermissions(link, NOFOLLOW_LINKS));
view.setPermissions(permsLink);
linkView.setPermissions(permsLink);
assertEquals(permsFile, getPosixFilePermissions(file));
assertEquals(permsLink, getPosixFilePermissions(link, NOFOLLOW_LINKS));
}