undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
48
test/jdk/com/sun/tools/attach/warnings/Application.java
Normal file
48
test/jdk/com/sun/tools/attach/warnings/Application.java
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* The "application" launched by DyamicLoadWarningTest.
|
||||
*
|
||||
* The application phones home, sends its pid to the test, waits for a reply, then exits.
|
||||
*/
|
||||
public class Application {
|
||||
public static void main(String[] args) throws Exception {
|
||||
InetAddress lh = InetAddress.getLoopbackAddress();
|
||||
int port = Integer.parseInt(args[0]);
|
||||
try (Socket s = new Socket(lh, port);
|
||||
DataOutputStream out = new DataOutputStream(s.getOutputStream())) {
|
||||
|
||||
// send pid
|
||||
long pid = ProcessHandle.current().pid();
|
||||
out.writeLong(pid);
|
||||
|
||||
// wait for shutdown
|
||||
s.getInputStream().read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8307478
|
||||
* @summary Test that a warning is printed when an agent is dynamically loaded
|
||||
* @requires vm.jvmti
|
||||
* @modules jdk.attach jdk.jcmd
|
||||
* @library /test/lib /test/jdk
|
||||
* @build Application JavaAgent
|
||||
* @run junit/othervm/native DynamicLoadWarningTest
|
||||
*/
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
|
||||
import jdk.test.lib.JDKToolLauncher;
|
||||
import jdk.test.lib.Platform;
|
||||
import jdk.test.lib.Utils;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.util.JarUtils;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class DynamicLoadWarningTest {
|
||||
private static final String JVMTI_AGENT_WARNING = "WARNING: A JVM TI agent has been loaded dynamically";
|
||||
private static final String JAVA_AGENT_WARNING = "WARNING: A Java agent has been loaded dynamically";
|
||||
|
||||
// JVM TI agents
|
||||
private static final String JVMTI_AGENT1_LIB = "JvmtiAgent1";
|
||||
private static final String JVMTI_AGENT2_LIB = "JvmtiAgent2";
|
||||
private static String jvmtiAgentPath1;
|
||||
private static String jvmtiAgentPath2;
|
||||
|
||||
// Java agent
|
||||
private static final String TEST_CLASSES = System.getProperty("test.classes");
|
||||
private static String javaAgent;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() throws Exception {
|
||||
// get absolute path to JVM TI agents
|
||||
String libname1 = Platform.buildSharedLibraryName(JVMTI_AGENT1_LIB);
|
||||
String libname2 = Platform.buildSharedLibraryName(JVMTI_AGENT2_LIB);
|
||||
jvmtiAgentPath1 = Path.of(Utils.TEST_NATIVE_PATH, libname1).toAbsolutePath().toString();
|
||||
jvmtiAgentPath2 = Path.of(Utils.TEST_NATIVE_PATH, libname2).toAbsolutePath().toString();
|
||||
|
||||
// create JAR file with Java agent
|
||||
Manifest man = new Manifest();
|
||||
Attributes attrs = man.getMainAttributes();
|
||||
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
|
||||
attrs.put(new Attributes.Name("Agent-Class"), "JavaAgent");
|
||||
Path jarfile = Path.of("javaagent.jar");
|
||||
Path classes = Path.of(TEST_CLASSES);
|
||||
JarUtils.createJarFile(jarfile, man, classes, Path.of("JavaAgent.class"));
|
||||
javaAgent = jarfile.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions to load JvmtiAgent1 into a running VM.
|
||||
*/
|
||||
private static Stream<OnAttachAction> loadJvmtiAgent1() {
|
||||
// load agent with the attach API
|
||||
OnAttachAction loadJvmtiAgent = (pid, vm) -> vm.loadAgentLibrary(JVMTI_AGENT1_LIB);
|
||||
|
||||
// jcmd <pid> JVMTI.agent_load <agent>
|
||||
OnAttachAction jcmdAgentLoad = jcmdAgentLoad(jvmtiAgentPath1);
|
||||
|
||||
return Stream.of(loadJvmtiAgent, jcmdAgentLoad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test loading JvmtiAgent1 into a running VM.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("loadJvmtiAgent1")
|
||||
void testLoadOneJvmtiAgent(OnAttachAction loadJvmtiAgent1) throws Exception {
|
||||
// dynamically load loadJvmtiAgent1
|
||||
test().whenRunning(loadJvmtiAgent1)
|
||||
.stderrShouldContain(JVMTI_AGENT_WARNING);
|
||||
|
||||
// opt-in via command line option to allow dynamic loading of agents
|
||||
test().withOpts("-XX:+EnableDynamicAgentLoading")
|
||||
.whenRunning(loadJvmtiAgent1)
|
||||
.stderrShouldNotContain(JVMTI_AGENT_WARNING);
|
||||
|
||||
// start loadJvmtiAgent1 via the command line, then dynamically load loadJvmtiAgent1
|
||||
test().withOpts("-agentpath:" + jvmtiAgentPath1)
|
||||
.whenRunning(loadJvmtiAgent1)
|
||||
.stderrShouldNotContain(JVMTI_AGENT_WARNING);
|
||||
|
||||
// dynamically load loadJvmtiAgent1 twice, should be one warning
|
||||
test().whenRunning(loadJvmtiAgent1)
|
||||
.whenRunning(loadJvmtiAgent1)
|
||||
.stderrShouldContain(JVMTI_AGENT_WARNING, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test loading JvmtiAgent1 and JvmtiAgent2 into a running VM.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("loadJvmtiAgent1")
|
||||
void testLoadTwoJvmtiAgents(OnAttachAction loadJvmtiAgent1) throws Exception {
|
||||
OnAttachAction loadJvmtiAgent2 = (pid, vm) -> vm.loadAgentLibrary(JVMTI_AGENT2_LIB);
|
||||
OnAttachAction jcmdAgentLoad2 = jcmdAgentLoad(jvmtiAgentPath2);
|
||||
|
||||
// dynamically load loadJvmtiAgent1, then dynamically load loadJvmtiAgent2 with attach API
|
||||
test().whenRunning(loadJvmtiAgent1)
|
||||
.whenRunning(loadJvmtiAgent2)
|
||||
.stderrShouldContain(JVMTI_AGENT_WARNING, 2);
|
||||
|
||||
// dynamically load loadJvmtiAgent1, then dynamically load loadJvmtiAgent2 with jcmd
|
||||
test().whenRunning(loadJvmtiAgent1)
|
||||
.whenRunning(jcmdAgentLoad2)
|
||||
.stderrShouldContain(JVMTI_AGENT_WARNING, 2);
|
||||
|
||||
// start loadJvmtiAgent2 via the command line, then dynamically load loadJvmtiAgent1
|
||||
test().withOpts("-agentpath:" + jvmtiAgentPath2)
|
||||
.whenRunning(loadJvmtiAgent1)
|
||||
.stderrShouldContain(JVMTI_AGENT_WARNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test loading Java agent into a running VM.
|
||||
*/
|
||||
@Test
|
||||
void testLoadJavaAgent() throws Exception {
|
||||
OnAttachAction loadJavaAgent = (pid, vm) -> vm.loadAgent(javaAgent);
|
||||
|
||||
// agent dynamically loaded
|
||||
test().whenRunning(loadJavaAgent)
|
||||
.stderrShouldContain(JAVA_AGENT_WARNING);
|
||||
|
||||
// opt-in via command line option to allow dynamic loading of agents
|
||||
test().withOpts("-XX:+EnableDynamicAgentLoading")
|
||||
.whenRunning(loadJavaAgent)
|
||||
.stderrShouldNotContain(JAVA_AGENT_WARNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an operation that accepts a process identifier and a VirtualMachine
|
||||
* that the current JVM is attached to.
|
||||
*/
|
||||
private interface OnAttachAction {
|
||||
void accept(long pid, VirtualMachine vm) throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an operation that invokes "jcmd <pid> JVMTI.agent_load <agentpath>" to
|
||||
* load the given agent library into the JVM that the current JVM is attached to.
|
||||
*/
|
||||
private static OnAttachAction jcmdAgentLoad(String agentPath) {
|
||||
return (pid, vm) -> {
|
||||
String[] jcmd = JDKToolLauncher.createUsingTestJDK("jcmd")
|
||||
.addToolArg(Long.toString(pid))
|
||||
.addToolArg("JVMTI.agent_load")
|
||||
.addToolArg(agentPath)
|
||||
.getCommand();
|
||||
System.out.println(Arrays.stream(jcmd).collect(Collectors.joining(" ")));
|
||||
Process p = new ProcessBuilder(jcmd).inheritIO().start();
|
||||
assertEquals(0, p.waitFor());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new app runner.
|
||||
*/
|
||||
private static AppRunner test() {
|
||||
return new AppRunner();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an application in its own VM. Once started, it attachs to the VM, runs a set
|
||||
* of actions, then checks that the output contains, or does not contain, a string.
|
||||
*/
|
||||
private static class AppRunner {
|
||||
private String[] vmopts = new String[0];
|
||||
private List<OnAttachAction> actions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Specifies VM options to run the application.
|
||||
*/
|
||||
AppRunner withOpts(String... vmopts) {
|
||||
this.vmopts = vmopts;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies an action to run when the attached to the running application.
|
||||
*/
|
||||
AppRunner whenRunning(OnAttachAction action) {
|
||||
actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
OutputAnalyzer run() throws Exception {
|
||||
// start a listener socket that the application will connect to
|
||||
try (ServerSocket listener = new ServerSocket()) {
|
||||
InetAddress lh = InetAddress.getLoopbackAddress();
|
||||
listener.bind(new InetSocketAddress(lh, 0));
|
||||
|
||||
var done = new AtomicBoolean();
|
||||
|
||||
// start a thread to wait for the application to phone home
|
||||
Thread.ofPlatform().daemon().start(() -> {
|
||||
try (Socket s = listener.accept();
|
||||
DataInputStream in = new DataInputStream(s.getInputStream())) {
|
||||
|
||||
// read pid
|
||||
long pid = in.readLong();
|
||||
|
||||
// attach and run the actions with the vm object
|
||||
VirtualMachine vm = VirtualMachine.attach(Long.toString(pid));
|
||||
try {
|
||||
for (OnAttachAction action : actions) {
|
||||
action.accept(pid, vm);
|
||||
}
|
||||
} finally {
|
||||
vm.detach();
|
||||
}
|
||||
done.set(true);
|
||||
|
||||
// shutdown
|
||||
s.getOutputStream().write(0);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
// launch application with the given VM options, waiting for it to terminate
|
||||
Stream<String> s1 = Stream.of(vmopts);
|
||||
Stream<String> s2 = Stream.of("Application", Integer.toString(listener.getLocalPort()));
|
||||
String[] opts = Stream.concat(s1, s2).toArray(String[]::new);
|
||||
OutputAnalyzer outputAnalyzer = ProcessTools
|
||||
.executeTestJava(opts)
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out);
|
||||
assertEquals(0, outputAnalyzer.getExitValue());
|
||||
assertTrue(done.get(), "Attach or action failed, see log for details");
|
||||
return outputAnalyzer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the application, checking that standard error contains a string.
|
||||
*/
|
||||
void stderrShouldContain(String s) throws Exception {
|
||||
run().stderrShouldContain(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the application, checking that standard error contains the given number of
|
||||
* occurrences of a string.
|
||||
*/
|
||||
void stderrShouldContain(String s, int occurrences) throws Exception {
|
||||
List<String> lines = run().asLines();
|
||||
int count = (int) lines.stream().filter(line -> line.indexOf(s) >= 0).count();
|
||||
assertEquals(occurrences, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the application, checking that standard error does not contain a string.
|
||||
*/
|
||||
void stderrShouldNotContain(String s) throws Exception {
|
||||
run().stderrShouldNotContain(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
30
test/jdk/com/sun/tools/attach/warnings/JavaAgent.java
Normal file
30
test/jdk/com/sun/tools/attach/warnings/JavaAgent.java
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A no-op Java agent.
|
||||
*/
|
||||
public class JavaAgent {
|
||||
public static void agentmain(String args) {
|
||||
}
|
||||
}
|
||||
40
test/jdk/com/sun/tools/attach/warnings/libJvmtiAgent1.cpp
Normal file
40
test/jdk/com/sun/tools/attach/warnings/libJvmtiAgent1.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
#include "jvmti.h"
|
||||
|
||||
/**
|
||||
* A no-op JVM TI agent.
|
||||
*/
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
|
||||
jvmtiEnv* jvmti;
|
||||
return vm->GetEnv((void**)&jvmti, JVMTI_VERSION);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnAttach(JavaVM *vm, char *options, void *reserved) {
|
||||
jvmtiEnv* jvmti;
|
||||
return vm->GetEnv((void**)&jvmti, JVMTI_VERSION);
|
||||
}
|
||||
40
test/jdk/com/sun/tools/attach/warnings/libJvmtiAgent2.cpp
Normal file
40
test/jdk/com/sun/tools/attach/warnings/libJvmtiAgent2.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
#include "jvmti.h"
|
||||
|
||||
/**
|
||||
* A no-op JVM TI agent.
|
||||
*/
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
|
||||
jvmtiEnv* jvmti;
|
||||
return vm->GetEnv((void**)&jvmti, JVMTI_VERSION);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnAttach(JavaVM *vm, char *options, void *reserved) {
|
||||
jvmtiEnv* jvmti;
|
||||
return vm->GetEnv((void**)&jvmti, JVMTI_VERSION);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue