Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8292177: InitialSecurityProperty JFR event #2827

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/java.base/share/classes/java/security/Security.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

import jdk.internal.event.EventHelper;
import jdk.internal.event.SecurityPropertyModificationEvent;
import jdk.internal.misc.JavaSecurityPropertiesAccess;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.util.StaticProperty;
import sun.security.util.Debug;
Expand Down Expand Up @@ -63,6 +64,9 @@ public final class Security {
/* The java.security properties */
private static Properties props;

/* cache a copy for recording purposes */
private static Properties initialSecurityProperties;

// An element in the cache
private static class ProviderProperty {
String className;
Expand All @@ -80,6 +84,13 @@ public Void run() {
return null;
}
});
// Set up JavaSecurityPropertiesAccess in SharedSecrets
SharedSecrets.setJavaSecurityPropertiesAccess(new JavaSecurityPropertiesAccess() {
@Override
public Properties getInitialProperties() {
return initialSecurityProperties;
}
});
}

private static void initialize() {
Expand All @@ -105,6 +116,14 @@ private static void initialize() {
}
loadProps(null, extraPropFile, overrideAll);
}
initialSecurityProperties = (Properties) props.clone();
if (sdebug != null) {
for (String key : props.stringPropertyNames()) {
sdebug.println("Initial security property: " + key + "=" +
props.getProperty(key));
}
}

}

private static boolean loadProps(File masterFile, String extraPropFile, boolean overrideAll) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2022, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package jdk.internal.misc;

import java.util.Properties;

public interface JavaSecurityPropertiesAccess {
Properties getInitialProperties();
}
15 changes: 15 additions & 0 deletions src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.io.ObjectInputStream;
import java.io.RandomAccessFile;
import java.security.ProtectionDomain;
import java.security.Security;
import java.security.Signature;

/** A repository of "shared secrets", which are a mechanism for
Expand Down Expand Up @@ -74,6 +75,7 @@ public class SharedSecrets {
private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
private static JavaObjectInputFilterAccess javaObjectInputFilterAccess;
private static JavaIORandomAccessFileAccess javaIORandomAccessFileAccess;
private static JavaSecurityPropertiesAccess javaSecurityPropertiesAccess;
private static JavaSecuritySignatureAccess javaSecuritySignatureAccess;
private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess;

Expand Down Expand Up @@ -248,6 +250,19 @@ public static JavaSecurityAccess getJavaSecurityAccess() {
return javaSecurityAccess;
}

public static void setJavaSecurityPropertiesAccess(JavaSecurityPropertiesAccess jspa) {
javaSecurityPropertiesAccess = jspa;
}

public static JavaSecurityPropertiesAccess getJavaSecurityPropertiesAccess() {
var access = javaSecurityPropertiesAccess;
if (access == null) {
unsafe.ensureClassInitialized(Security.class);
access = javaSecurityPropertiesAccess;
}
return access;
}

public static JavaUtilZipFileAccess getJavaUtilZipFileAccess() {
if (javaUtilZipFileAccess == null)
unsafe.ensureClassInitialized(java.util.zip.ZipFile.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2022, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package jdk.jfr.events;

import jdk.jfr.Category;
import jdk.jfr.Description;
import jdk.jfr.Label;
import jdk.jfr.Name;

@Category({"Java Development Kit", "Security"})
@Label("Initial Security Property")
@Name("jdk.InitialSecurityProperty")
@Description("Initial Security Properties")
public final class InitialSecurityPropertyEvent extends AbstractJDKEvent {
@Label("Key")
public String key;

@Label("Value")
public String value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import jdk.internal.misc.SharedSecrets;
import jdk.jfr.Event;
import jdk.jfr.events.ActiveRecordingEvent;
import jdk.jfr.events.ActiveSettingEvent;
Expand All @@ -38,6 +40,7 @@
import jdk.jfr.events.FileReadEvent;
import jdk.jfr.events.FileWriteEvent;
import jdk.jfr.events.DeserializationEvent;
import jdk.jfr.events.InitialSecurityPropertyEvent;
import jdk.jfr.events.SecurityPropertyModificationEvent;
import jdk.jfr.events.SecurityProviderServiceEvent;
import jdk.jfr.events.SocketReadEvent;
Expand Down Expand Up @@ -80,7 +83,9 @@ public final class JDKEvents {
jdk.internal.event.SecurityProviderServiceEvent.class,
jdk.internal.event.TLSHandshakeEvent.class,
jdk.internal.event.X509CertificateEvent.class,
jdk.internal.event.X509ValidationEvent.class
jdk.internal.event.X509ValidationEvent.class,

InitialSecurityPropertyEvent.class,
};

// This is a list of the classes with instrumentation code that should be applied.
Expand All @@ -97,6 +102,7 @@ public final class JDKEvents {
private static final Class<?>[] targetClasses = new Class<?>[instrumentationClasses.length];
private static final JVM jvm = JVM.getJVM();
private static final Runnable emitExceptionStatistics = JDKEvents::emitExceptionStatistics;
private static final Runnable emitInitialSecurityProperties = JDKEvents::emitInitialSecurityProperties;
private static boolean initializationTriggered;

@SuppressWarnings("unchecked")
Expand All @@ -111,6 +117,7 @@ public synchronized static void initialize() {
}
initializationTriggered = true;
RequestEngine.addTrustedJDKHook(ExceptionStatisticsEvent.class, emitExceptionStatistics);
RequestEngine.addTrustedJDKHook(InitialSecurityPropertyEvent.class, emitInitialSecurityProperties);
}
} catch (Exception e) {
Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Could not initialize JDK events. " + e.getMessage());
Expand Down Expand Up @@ -167,5 +174,18 @@ public static byte[] retransformCallback(Class<?> klass, byte[] oldBytes) throws

public static void remove() {
RequestEngine.removeHook(JDKEvents::emitExceptionStatistics);
RequestEngine.removeHook(JDKEvents::emitInitialSecurityProperties);
}

private static void emitInitialSecurityProperties() {
Properties p = SharedSecrets.getJavaSecurityPropertiesAccess().getInitialProperties();
if (p != null) {
for (String key : p.stringPropertyNames()) {
InitialSecurityPropertyEvent e = new InitialSecurityPropertyEvent();
e.key = key;
e.value = p.getProperty(key);
e.commit();
}
}
}
}
5 changes: 5 additions & 0 deletions src/jdk.jfr/share/conf/jfr/default.jfc
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,11 @@
<setting name="stackTrace">true</setting>
</event>

<event name="jdk.InitialSecurityProperty">
<setting name="enabled">true</setting>
<setting name="period">beginChunk</setting>
</event>

<event name="jdk.SecurityPropertyModification">
<setting name="enabled">false</setting>
<setting name="stackTrace">true</setting>
Expand Down
5 changes: 5 additions & 0 deletions src/jdk.jfr/share/conf/jfr/profile.jfc
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,11 @@
<setting name="stackTrace">true</setting>
</event>

<event name="jdk.InitialSecurityProperty">
<setting name="enabled">true</setting>
<setting name="period">beginChunk</setting>
</event>

<event name="jdk.SecurityPropertyModification">
<setting name="enabled">false</setting>
<setting name="stackTrace">true</setting>
Expand Down
32 changes: 30 additions & 2 deletions test/jdk/java/security/Security/ConfigFileTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,20 @@
/*
* @test
* @summary Throw error if default java.security file is missing
* @bug 8155246 8292297
* @bug 8155246 8292297 8292177
* @library /test/lib
* @run main ConfigFileTest
*/
public class ConfigFileTest {

private static final String EXPECTED_DEBUG_OUTPUT =
"Initial security property: crypto.policy=unlimited";

private static final String UNEXPECTED_DEBUG_OUTPUT =
"Initial security property: postInitTest=shouldNotRecord";

private static boolean overrideDetected = false;

public static void main(String[] args) throws Exception {
Path copyJdkDir = Path.of("./jdk-8155246-tmpdir");
Path copiedJava = Optional.of(
Expand All @@ -52,6 +60,7 @@ public static void main(String[] args) throws Exception {
if (args.length == 1) {
// set up is complete. Run code to exercise loading of java.security
Provider[] provs = Security.getProviders();
Security.setProperty("postInitTest", "shouldNotRecord");
System.out.println(Arrays.toString(provs) + "NumProviders: " + provs.length);
} else {
Files.createDirectory(copyJdkDir);
Expand Down Expand Up @@ -99,13 +108,32 @@ public static void main(String[] args) throws Exception {
copiedJava.toString(), "-cp", System.getProperty("test.classes"),
"-Djava.security.debug=all", "-Djavax.net.debug=all",
"-Djava.security.properties==file:///" + extraPropsFile, "ConfigFileTest", "runner");

if (!overrideDetected) {
throw new RuntimeException("Override scenario not seen");
}
}
}

private static void exerciseSecurity(int exitCode, String output, String... args) throws Exception {
ProcessBuilder process = new ProcessBuilder(args);
OutputAnalyzer oa = ProcessTools.executeProcess(process);
oa.shouldHaveExitValue(exitCode).shouldContain(output);
oa.shouldHaveExitValue(exitCode)
.shouldContain(output);

// extra checks on debug output
if (exitCode != 1) {
if (oa.getStderr().contains("overriding other security properties files!")) {
overrideDetected = true;
// master file is not in use - only provider properties are set in custom file
oa.shouldContain("security.provider.2=SunRsaSign")
.shouldNotContain(EXPECTED_DEBUG_OUTPUT)
.shouldNotContain(UNEXPECTED_DEBUG_OUTPUT);
} else {
oa.shouldContain(EXPECTED_DEBUG_OUTPUT)
.shouldNotContain(UNEXPECTED_DEBUG_OUTPUT);
}
}
}

private static void copyJDK(Path src, Path dst) throws Exception {
Expand Down
1 change: 1 addition & 0 deletions test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ private static void testSettingConfiguration(String configurationName) throws Ex
settingValues.put(EventNames.ActiveSetting + "#threshold", "0 ns");
settingValues.put(EventNames.ActiveRecording + "#stackTrace", "false");
settingValues.put(EventNames.ActiveRecording + "#threshold", "0 ns");
settingValues.put(EventNames.InitialSecurityProperty + "#threshold", "0 ns");
settingValues.put(EventNames.JavaExceptionThrow + "#threshold", "0 ns");
settingValues.put(EventNames.JavaErrorThrow + "#threshold", "0 ns");
settingValues.put(EventNames.SecurityProperty + "#threshold", "0 ns");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2022, 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
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package jdk.jfr.event.security;

import jdk.internal.misc.SharedSecrets;
import jdk.jfr.Recording;
import jdk.jfr.consumer.RecordedEvent;
import jdk.test.lib.Asserts;
import jdk.test.lib.jfr.EventNames;
import jdk.test.lib.jfr.Events;

import java.security.Security;
import java.util.List;
import java.util.Properties;

/*
* @test
* @bug 8292177
* @summary InitialSecurityProperty JFR event
* @key jfr
* @requires vm.hasJFR
* @library /test/lib
* @modules java.base/jdk.internal.misc
* @run main/othervm jdk.jfr.event.security.TestInitialSecurityPropertyEvent
*/
public class TestInitialSecurityPropertyEvent {

private static final String SEC_KEY = "security.overridePropertiesFile";
public static void main(String[] args) throws Exception {
try (Recording recording = new Recording()) {
recording.enable(EventNames.InitialSecurityProperty)
.with("period", "beginChunk");
recording.start();
// this property edit should not be recorded
Security.setProperty(SEC_KEY, "false");
recording.stop();

Properties p = SharedSecrets.getJavaSecurityPropertiesAccess().getInitialProperties();
List<RecordedEvent> events = Events.fromRecording(recording);
if (events.size() == 0) {
throw new Exception("No security properties - Security class may not have loaded ?");
}
Asserts.assertEquals(events.size(), p.size(), "Incorrect number of events");
assertEvent(events, SEC_KEY, "true");
}
}

private static void assertEvent(List<RecordedEvent> events, String key, String origValue) throws Exception {
for (RecordedEvent e : events) {
if (e.getString("key").equals(key)) {
Events.assertField(e, "value").equal(origValue);
return;
}
}
System.out.println(events);
throw new Exception("Incorrect value for " + key + " property recorded");
}
}
Loading