8344337: SecurityManager cleanup in java.prefs module

Reviewed-by: lancea, bpb, rriggs, iris
This commit is contained in:
Brent Christian 2024-11-26 01:17:37 +00:00
parent 1c7f34d3dd
commit 4d4cef800a
6 changed files with 181 additions and 344 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2024, 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
@ -28,8 +28,6 @@ package java.util.prefs;
import java.util.Objects;
class MacOSXPreferences extends AbstractPreferences {
// fixme need security checks?
// CF preferences file name for Java nodes with short names
// This value is also in MacOSXPreferencesFile.c
private static final String defaultAppName = "com.apple.java.util.prefs";

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2024, 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
@ -82,15 +82,9 @@ class MacOSXPreferencesFile {
loadPrefsLib();
}
@SuppressWarnings({"removal", "restricted"})
@SuppressWarnings("restricted")
private static void loadPrefsLib() {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("prefs");
return null;
}
});
System.loadLibrary("prefs");
}
private static class FlushTask extends TimerTask {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, 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
@ -27,8 +27,6 @@ package java.util.prefs;
import java.util.*;
import java.io.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* This class provides a skeletal implementation of the {@link Preferences}
@ -1058,14 +1056,8 @@ public abstract class AbstractPreferences extends Preferences {
* preference tree, {@code false} if it's in the system
* preference tree.
*/
@SuppressWarnings("removal")
public boolean isUserNode() {
return AccessController.doPrivileged(
new PrivilegedAction<Boolean>() {
public Boolean run() {
return root == Preferences.userRoot();
}
}).booleanValue();
return root == Preferences.userRoot();
}
public void addPreferenceChangeListener(PreferenceChangeListener pcl) {

View File

@ -30,20 +30,10 @@ import jdk.internal.util.OperatingSystem;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.ServiceConfigurationError;
// These imports needed only as a workaround for a JavaDoc bug
import java.lang.RuntimePermission;
import java.lang.Integer;
import java.lang.Long;
import java.lang.Float;
import java.lang.Double;
/**
* A node in a hierarchical collection of preference data. This class
* allows applications to store and retrieve user and system
@ -227,19 +217,10 @@ public abstract class Preferences {
private static final PreferencesFactory factory = factory();
@SuppressWarnings("removal")
private static PreferencesFactory factory() {
// 1. Try user-specified system property
String factoryName = AccessController.doPrivileged(
new PrivilegedAction<String>() {
public String run() {
return System.getProperty(
"java.util.prefs.PreferencesFactory");}});
String factoryName = System.getProperty("java.util.prefs.PreferencesFactory");
if (factoryName != null) {
// FIXME: This code should be run in a doPrivileged and
// not use the context classloader, to avoid being
// dependent on the invoking thread.
// Checking AllPermission also seems wrong.
try {
@SuppressWarnings("deprecation")
Object result =Class.forName(factoryName, false,
@ -250,10 +231,6 @@ public abstract class Preferences {
try {
// workaround for javaws, plugin,
// load factory class using non-system classloader
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new java.security.AllPermission());
}
@SuppressWarnings("deprecation")
Object result = Class.forName(factoryName, false,
Thread.currentThread()
@ -267,14 +244,6 @@ public abstract class Preferences {
}
}
}
return AccessController.doPrivileged(
new PrivilegedAction<PreferencesFactory>() {
public PreferencesFactory run() {
return factory1();}});
}
private static PreferencesFactory factory1() {
// 2. Try service provider interface
Iterator<PreferencesFactory> itr = ServiceLoader
.load(PreferencesFactory.class, ClassLoader.getSystemClassLoader())
@ -427,24 +396,12 @@ public abstract class Preferences {
return "/" + packageName.replace('.', '/');
}
/**
* This permission object represents the permission required to get
* access to the user or system root (which in turn allows for all
* other operations).
*/
private static Permission prefsPerm = new RuntimePermission("preferences");
/**
* Returns the root preference node for the calling user.
*
* @return the root preference node for the calling user.
*/
public static Preferences userRoot() {
@SuppressWarnings("removal")
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkPermission(prefsPerm);
return factory.userRoot();
}
@ -454,11 +411,6 @@ public abstract class Preferences {
* @return the root preference node for the system.
*/
public static Preferences systemRoot() {
@SuppressWarnings("removal")
SecurityManager security = System.getSecurityManager();
if (security != null)
security.checkPermission(prefsPerm);
return factory.systemRoot();
}

View File

@ -27,9 +27,6 @@ package java.util.prefs;
import java.util.*;
import java.io.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import sun.util.logging.PlatformLogger;
@ -53,13 +50,9 @@ class FileSystemPreferences extends AbstractPreferences {
loadPrefsLib();
}
@SuppressWarnings({"removal", "restricted"})
@SuppressWarnings("restricted")
private static void loadPrefsLib() {
PrivilegedAction<Void> load = () -> {
System.loadLibrary("prefs");
return null;
};
AccessController.doPrivileged(load);
System.loadLibrary("prefs");
}
/**
@ -67,8 +60,7 @@ class FileSystemPreferences extends AbstractPreferences {
*/
@SuppressWarnings("removal")
private static final int SYNC_INTERVAL = Math.max(1,
AccessController.doPrivileged((PrivilegedAction<Integer>) () ->
Integer.getInteger("java.util.prefs.syncInterval", 30)));
Integer.getInteger("java.util.prefs.syncInterval", 30));
/**
* Returns logger for error messages. Backing store exceptions are logged at
@ -117,52 +109,47 @@ class FileSystemPreferences extends AbstractPreferences {
return root;
}
@SuppressWarnings("removal")
private static void setupUserRoot() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
userRootDir =
new File(System.getProperty("java.util.prefs.userRoot",
userRootDir =
new File(System.getProperty("java.util.prefs.userRoot",
System.getProperty("user.home")), ".java/.userPrefs");
// Attempt to create root dir if it does not yet exist.
if (!userRootDir.exists()) {
if (userRootDir.mkdirs()) {
try {
chmod(userRootDir.getCanonicalPath(), USER_RWX);
} catch (IOException e) {
getLogger().warning("Could not change permissions" +
" on userRoot directory. ");
}
getLogger().info("Created user preferences directory.");
}
else
getLogger().warning("Couldn't create user preferences" +
" directory. User preferences are unusable.");
}
isUserRootWritable = userRootDir.canWrite();
String USER_NAME = System.getProperty("user.name");
userLockFile = new File (userRootDir,".user.lock." + USER_NAME);
userRootModFile = new File (userRootDir,
".userRootModFile." + USER_NAME);
if (!userRootModFile.exists())
// Attempt to create root dir if it does not yet exist.
if (!userRootDir.exists()) {
if (userRootDir.mkdirs()) {
try {
// create if does not exist.
userRootModFile.createNewFile();
// Only user can read/write userRootModFile.
int result = chmod(userRootModFile.getCanonicalPath(),
USER_READ_WRITE);
if (result !=0)
getLogger().warning("Problem creating userRoot " +
"mod file. Chmod failed on " +
userRootModFile.getCanonicalPath() +
" Unix error code " + result);
chmod(userRootDir.getCanonicalPath(), USER_RWX);
} catch (IOException e) {
getLogger().warning(e.toString());
getLogger().warning("Could not change permissions" +
" on userRoot directory. ");
}
userRootModTime = userRootModFile.lastModified();
return null;
getLogger().info("Created user preferences directory.");
} else {
getLogger().warning("Couldn't create user preferences" +
" directory. User preferences are unusable.");
}
});
}
isUserRootWritable = userRootDir.canWrite();
String USER_NAME = System.getProperty("user.name");
userLockFile = new File(userRootDir,".user.lock." + USER_NAME);
userRootModFile = new File (userRootDir,
".userRootModFile." + USER_NAME);
if (!userRootModFile.exists()) {
try {
// create if does not exist.
userRootModFile.createNewFile();
// Only user can read/write userRootModFile.
int result = chmod(userRootModFile.getCanonicalPath(),
USER_READ_WRITE);
if (result != 0)
getLogger().warning("Problem creating userRoot " +
"mod file. Chmod failed on " +
userRootModFile.getCanonicalPath() +
" Unix error code " + result);
} catch (IOException e) {
getLogger().warning(e.toString());
}
}
userRootModTime = userRootModFile.lastModified();
}
@ -185,58 +172,54 @@ class FileSystemPreferences extends AbstractPreferences {
return root;
}
@SuppressWarnings("removal")
private static void setupSystemRoot() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
String systemPrefsDirName =
System.getProperty("java.util.prefs.systemRoot","/etc/.java");
systemRootDir =
new File(systemPrefsDirName, ".systemPrefs");
// Attempt to create root dir if it does not yet exist.
if (!systemRootDir.exists()) {
// system root does not exist in /etc/.java
// Switching to java.home
systemRootDir =
new File(System.getProperty("java.home"),
".systemPrefs");
if (!systemRootDir.exists()) {
if (systemRootDir.mkdirs()) {
getLogger().info(
"Created system preferences directory "
+ "in java.home.");
try {
chmod(systemRootDir.getCanonicalPath(),
USER_RWX_ALL_RX);
} catch (IOException e) {
}
} else {
getLogger().warning("Could not create "
+ "system preferences directory. System "
+ "preferences are unusable.");
}
String systemPrefsDirName =
System.getProperty("java.util.prefs.systemRoot", "/etc/.java");
systemRootDir =
new File(systemPrefsDirName, ".systemPrefs");
// Attempt to create root dir if it does not yet exist.
if (!systemRootDir.exists()) {
// system root does not exist in /etc/.java
// Switching to java.home
systemRootDir =
new File(System.getProperty("java.home"),
".systemPrefs");
if (!systemRootDir.exists()) {
if (systemRootDir.mkdirs()) {
getLogger().info(
"Created system preferences directory "
+ "in java.home.");
try {
chmod(systemRootDir.getCanonicalPath(),
USER_RWX_ALL_RX);
} catch (IOException e) {
}
} else {
getLogger().warning("Could not create "
+ "system preferences directory. System "
+ "preferences are unusable.");
}
isSystemRootWritable = systemRootDir.canWrite();
systemLockFile = new File(systemRootDir, ".system.lock");
systemRootModFile =
new File (systemRootDir,".systemRootModFile");
if (!systemRootModFile.exists() && isSystemRootWritable)
try {
// create if does not exist.
systemRootModFile.createNewFile();
int result = chmod(systemRootModFile.getCanonicalPath(),
USER_RW_ALL_READ);
if (result !=0)
getLogger().warning("Chmod failed on " +
systemRootModFile.getCanonicalPath() +
" Unix error code " + result);
} catch (IOException e) { getLogger().warning(e.toString());
}
systemRootModTime = systemRootModFile.lastModified();
return null;
}
});
}
isSystemRootWritable = systemRootDir.canWrite();
systemLockFile = new File(systemRootDir, ".system.lock");
systemRootModFile = new File (systemRootDir, ".systemRootModFile");
if (!systemRootModFile.exists() && isSystemRootWritable) {
try {
// create if does not exist.
systemRootModFile.createNewFile();
int result = chmod(systemRootModFile.getCanonicalPath(),
USER_RW_ALL_READ);
if (result != 0) {
getLogger().warning("Chmod failed on " +
systemRootModFile.getCanonicalPath() +
" Unix error code " + result);
}
} catch (IOException e) {
getLogger().warning(e.toString());
}
}
systemRootModTime = systemRootModFile.lastModified();
}
@ -456,7 +439,6 @@ class FileSystemPreferences extends AbstractPreferences {
addShutdownHook();
}
@SuppressWarnings("removal")
private static void addShutdownHook() {
// Add periodic timer task to periodically sync cached prefs
syncTimer.schedule(new TimerTask() {
@ -466,16 +448,11 @@ class FileSystemPreferences extends AbstractPreferences {
}, SYNC_INTERVAL*1000, SYNC_INTERVAL*1000);
// Add shutdown hook to flush cached prefs on normal termination
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
Runtime.getRuntime().addShutdownHook(
new Thread(null, null, "Sync Timer Thread", 0, false) {
public void run() {
syncTimer.cancel();
syncWorld();
}
});
return null;
Runtime.getRuntime().addShutdownHook(
new Thread(null, null, "Sync Timer Thread", 0, false) {
public void run() {
syncTimer.cancel();
syncWorld();
}
});
}
@ -526,19 +503,13 @@ class FileSystemPreferences extends AbstractPreferences {
* parent node and name. This constructor, called from childSpi,
* is used to make every node except for the two //roots.
*/
@SuppressWarnings("removal")
private FileSystemPreferences(FileSystemPreferences parent, String name) {
super(parent, name);
isUserNode = parent.isUserNode;
dir = new File(parent.dir, dirName(name));
prefsFile = new File(dir, "prefs.xml");
tmpFile = new File(dir, "prefs.tmp");
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
newNode = !dir.exists();
return null;
}
});
newNode = !dir.exists();
if (newNode) {
// These 2 things guarantee node will get written at next flush/sync
prefsCache = new TreeMap<>();
@ -596,43 +567,32 @@ class FileSystemPreferences extends AbstractPreferences {
* fails, a BackingStoreException is thrown and both prefsCache and
* lastSyncTime are unaffected by the call.
*/
@SuppressWarnings("removal")
private void loadCache() throws BackingStoreException {
Map<String, String> m = new TreeMap<>();
long newLastSyncTime = 0;
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>() {
public Void run() throws BackingStoreException {
Map<String, String> m = new TreeMap<>();
long newLastSyncTime = 0;
try {
newLastSyncTime = prefsFile.lastModified();
try (FileInputStream fis = new FileInputStream(prefsFile)) {
XmlSupport.importMap(fis, m);
}
} catch(Exception e) {
if (e instanceof InvalidPreferencesFormatException) {
getLogger().warning("Invalid preferences format in "
+ prefsFile.getPath());
prefsFile.renameTo( new File(
prefsFile.getParentFile(),
"IncorrectFormatPrefs.xml"));
m = new TreeMap<>();
} else if (e instanceof FileNotFoundException) {
getLogger().warning("Prefs file removed in background "
+ prefsFile.getPath());
} else {
throw new BackingStoreException(e);
}
}
// Attempt succeeded; update state
prefsCache = m;
lastSyncTime = newLastSyncTime;
return null;
}
});
} catch (PrivilegedActionException e) {
throw (BackingStoreException) e.getException();
newLastSyncTime = prefsFile.lastModified();
try (FileInputStream fis = new FileInputStream(prefsFile)) {
XmlSupport.importMap(fis, m);
}
} catch(Exception e) {
if (e instanceof InvalidPreferencesFormatException) {
getLogger().warning("Invalid preferences format in "
+ prefsFile.getPath());
prefsFile.renameTo( new File(
prefsFile.getParentFile(),
"IncorrectFormatPrefs.xml"));
m = new TreeMap<>();
} else if (e instanceof FileNotFoundException) {
getLogger().warning("Prefs file removed in background "
+ prefsFile.getPath());
} else {
throw new BackingStoreException(e);
}
}
// Attempt succeeded; update state
prefsCache = m;
lastSyncTime = newLastSyncTime;
}
/**
@ -644,32 +604,21 @@ class FileSystemPreferences extends AbstractPreferences {
* and lastSyncTime will be unaffected by this call. This call will
* NEVER leave prefsFile in a corrupt state.
*/
@SuppressWarnings("removal")
private void writeBackCache() throws BackingStoreException {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>() {
public Void run() throws BackingStoreException {
try {
if (!dir.exists() && !dir.mkdirs())
throw new BackingStoreException(dir +
" create failed.");
try (FileOutputStream fos = new FileOutputStream(tmpFile)) {
XmlSupport.exportMap(fos, prefsCache);
}
if (!tmpFile.renameTo(prefsFile))
throw new BackingStoreException("Can't rename " +
tmpFile + " to " + prefsFile);
} catch(Exception e) {
if (e instanceof BackingStoreException)
throw (BackingStoreException)e;
throw new BackingStoreException(e);
}
return null;
}
});
} catch (PrivilegedActionException e) {
throw (BackingStoreException) e.getException();
if (!dir.exists() && !dir.mkdirs())
throw new BackingStoreException(dir +
" create failed.");
try (FileOutputStream fos = new FileOutputStream(tmpFile)) {
XmlSupport.exportMap(fos, prefsCache);
}
if (!tmpFile.renameTo(prefsFile))
throw new BackingStoreException("Can't rename " +
tmpFile + " to " + prefsFile);
} catch(BackingStoreException e) {
throw e;
} catch(Exception e) {
throw new BackingStoreException(e);
}
}
@ -678,21 +627,15 @@ class FileSystemPreferences extends AbstractPreferences {
return prefsCache.keySet().toArray(new String[prefsCache.size()]);
}
@SuppressWarnings("removal")
protected String[] childrenNamesSpi() {
return AccessController.doPrivileged(
new PrivilegedAction<String[]>() {
public String[] run() {
List<String> result = new ArrayList<>();
File[] dirContents = dir.listFiles();
if (dirContents != null) {
for (int i = 0; i < dirContents.length; i++)
if (dirContents[i].isDirectory())
result.add(nodeName(dirContents[i].getName()));
}
return result.toArray(EMPTY_STRING_ARRAY);
}
});
List<String> result = new ArrayList<>();
File[] dirContents = dir.listFiles();
if (dirContents != null) {
for (int i = 0; i < dirContents.length; i++)
if (dirContents[i].isDirectory())
result.add(nodeName(dirContents[i].getName()));
}
return result.toArray(EMPTY_STRING_ARRAY);
}
private static final String[] EMPTY_STRING_ARRAY = new String[0];
@ -717,42 +660,30 @@ class FileSystemPreferences extends AbstractPreferences {
/**
* Called with file lock held (in addition to node locks).
*/
@SuppressWarnings("removal")
protected void removeNodeSpi() throws BackingStoreException {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>() {
public Void run() throws BackingStoreException {
if (changeLog.contains(nodeCreate)) {
changeLog.remove(nodeCreate);
nodeCreate = null;
return null;
}
if (!dir.exists())
return null;
prefsFile.delete();
tmpFile.delete();
// dir should be empty now. If it's not, empty it
File[] junk = dir.listFiles();
if (junk.length != 0) {
getLogger().warning(
"Found extraneous files when removing node: "
+ Arrays.asList(junk));
for (int i=0; i<junk.length; i++)
junk[i].delete();
}
if (!dir.delete())
throw new BackingStoreException("Couldn't delete dir: "
+ dir);
return null;
}
});
} catch (PrivilegedActionException e) {
throw (BackingStoreException) e.getException();
if (changeLog.contains(nodeCreate)) {
changeLog.remove(nodeCreate);
nodeCreate = null;
return;
}
if (!dir.exists())
return;
prefsFile.delete();
tmpFile.delete();
// dir should be empty now. If it's not, empty it
File[] junk = dir.listFiles();
if (junk.length != 0) {
getLogger().warning(
"Found extraneous files when removing node: "
+ Arrays.asList(junk));
for (int i=0; i<junk.length; i++)
junk[i].delete();
}
if (!dir.delete())
throw new BackingStoreException("Couldn't delete dir: "
+ dir);
}
@SuppressWarnings("removal")
public synchronized void sync() throws BackingStoreException {
boolean userNode = isUserNode();
boolean shared;
@ -765,58 +696,34 @@ class FileSystemPreferences extends AbstractPreferences {
shared = !isSystemRootWritable;
}
synchronized (isUserNode()? userLockFile:systemLockFile) {
if (!lockFile(shared))
throw(new BackingStoreException("Couldn't get file lock."));
final Long newModTime =
AccessController.doPrivileged(
new PrivilegedAction<Long>() {
public Long run() {
long nmt;
if (isUserNode()) {
nmt = userRootModFile.lastModified();
isUserRootModified = userRootModTime == nmt;
} else {
nmt = systemRootModFile.lastModified();
isSystemRootModified = systemRootModTime == nmt;
}
return nmt;
}
});
if (!lockFile(shared)) {
throw (new BackingStoreException("Couldn't get file lock."));
}
long nmt;
if (isUserNode()) {
nmt = userRootModFile.lastModified();
isUserRootModified = userRootModTime == nmt;
} else {
nmt = systemRootModFile.lastModified();
isSystemRootModified = systemRootModTime == nmt;
}
final long newModTime = nmt;
try {
super.sync();
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
if (isUserNode()) {
userRootModTime = newModTime.longValue() + 1000;
userRootModFile.setLastModified(userRootModTime);
} else {
systemRootModTime = newModTime.longValue() + 1000;
systemRootModFile.setLastModified(systemRootModTime);
}
return null;
}
});
if (isUserNode()) {
userRootModTime = newModTime + 1000;
userRootModFile.setLastModified(userRootModTime);
} else {
systemRootModTime = newModTime + 1000;
systemRootModFile.setLastModified(systemRootModTime);
}
} finally {
unlockFile();
}
}
}
@SuppressWarnings("removal")
protected void syncSpi() throws BackingStoreException {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>() {
public Void run() throws BackingStoreException {
syncSpiPrivileged();
return null;
}
});
} catch (PrivilegedActionException e) {
throw (BackingStoreException) e.getException();
}
}
private void syncSpiPrivileged() throws BackingStoreException {
if (isRemoved())
throw new IllegalStateException("Node has been removed");
if (prefsCache == null)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, 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
@ -27,8 +27,6 @@ package java.util.prefs;
import java.util.StringTokenizer;
import java.io.ByteArrayOutputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.util.logging.PlatformLogger;
@ -50,13 +48,9 @@ class WindowsPreferences extends AbstractPreferences {
loadPrefsLib();
}
@SuppressWarnings({"removal", "restricted"})
@SuppressWarnings("restricted")
private static void loadPrefsLib() {
PrivilegedAction<Void> load = () -> {
System.loadLibrary("prefs");
return null;
};
AccessController.doPrivileged(load);
System.loadLibrary("prefs");
}
/**