Quelle JdwpAllowTest.java
Sprache: JAVA
/*
* Copyright ( c ) 2017 , 2021 , 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
* @ summary Smoke test for JDWP hardening
* @ library / test / lib
* @ run driver JdwpAllowTest
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import jdk.test.lib.JDWP;
import jdk.test.lib.Utils;
import jdk.test.lib.apps.LingeredApp;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
public class JdwpAllowTest {
public static int handshake(int port) throws IOException {
// Connect to the debuggee and handshake
int res = -1 ;
Socket s = null ;
try {
s = new Socket(localAddr, port);
s.getOutputStream().write("JDWP-Handshake" .getBytes("UTF-8" ));
byte [] buffer = new byte [24 ];
res = s.getInputStream().read(buffer);
}
catch (SocketException ex) {
ex.printStackTrace();
// pass
} finally {
if (s != null ) {
s.close();
}
}
return res;
}
public static String[] prepareCmd(String allowOpt) {
String jdwpArgs = "-agentlib:jdwp=transport=dt_socket,server=y," +
"suspend=n,address=*:0"
+ (allowOpt == null ? "" : ",allow=" + allowOpt);
return new String[] { jdwpArgs };
}
private static int detectPort(LingeredApp app) {
long maxWaitTime = System.currentTimeMillis()
+ Utils.adjustTimeout(10000 ); // 10 seconds adjusted for TIMEOUT_FACTOR
while (true ) {
String s = app.getProcessStdout();
JDWP.ListenAddress addr = JDWP.parseListenAddress(s);
if (addr != null ) {
return Integer.parseInt(addr.address());
}
if (System.currentTimeMillis() > maxWaitTime) {
throw new RuntimeException("Could not detect port from '" + s + "' (timeout)" );
}
try {
if (app.getProcess().waitFor(500 , TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Could not detect port from '" + s + "' (debuggee is terminated)" );
}
} catch (InterruptedException e) {
// ignore
}
}
}
public static void positiveTest(String testName, String allowOpt)
throws InterruptedException, IOException {
System.err.println("\nStarting " + testName);
String[] cmd = prepareCmd(allowOpt);
LingeredApp a = LingeredApp.startApp(cmd);
int res;
try {
res = handshake(detectPort(a));
} finally {
a.stopApp();
}
if (res < 0 ) {
throw new RuntimeException(testName + " FAILED" );
}
System.err.println(testName + " PASSED" );
}
public static void negativeTest(String testName, String allowOpt)
throws InterruptedException, IOException {
System.err.println("\nStarting " + testName);
String[] cmd = prepareCmd(allowOpt);
LingeredApp a = LingeredApp.startApp(cmd);
int res;
try {
res = handshake(detectPort(a));
} finally {
a.stopApp();
}
if (res > 0 ) {
System.err.println(testName + ": res=" + res);
throw new RuntimeException(testName + " FAILED" );
}
System.err.println(testName + ": returned a negative code as expected: " + res);
System.err.println(testName + " PASSED" );
}
public static void badAllowOptionTest(String testName, String allowOpt)
throws InterruptedException, IOException {
System.err.println("\nStarting " + testName);
String[] cmd = prepareCmd(allowOpt);
LingeredApp a;
try {
a = LingeredApp.startApp(cmd);
} catch (IOException ex) {
System.err.println(testName + ": caught expected IOException" );
System.err.println(testName + " PASSED" );
return ;
}
// LingeredApp.startApp is expected to fail, but if not, terminate the app
a.stopApp();
throw new RuntimeException(testName + " FAILED" );
}
/*
* Generate allow address by changing random bit in the local address
* and calculate 2 masks ( prefix length ) - one is matches original local address
* and another doesn ' t .
*/
private static class MaskTest {
public final String localAddress;
public final String allowAddress;
public final int prefixLengthGood;
public final int prefixLengthBad;
public MaskTest(InetAddress addr) throws Exception {
localAddress = addr.getHostAddress();
byte [] bytes = addr.getAddress();
Random r = new Random();
// prefix length must be >= 1, so bitToChange must be >= 2
int bitToChange = r.nextInt(bytes.length * 8 - 3 ) + 2 ;
setBit(bytes, bitToChange, !getBit(bytes, bitToChange));
// clear rest of the bits for mask address
for (int i = bitToChange + 1 ; i < bytes.length * 8 ; i++) {
setBit(bytes, i, false );
}
allowAddress = InetAddress.getByAddress(bytes).getHostAddress();
prefixLengthBad = bitToChange;
prefixLengthGood = bitToChange - 1 ;
}
private static boolean getBit(byte [] bytes, int pos) {
return (bytes[pos / 8 ] & (1 << (7 - (pos % 8 )))) != 0 ;
}
private static void setBit(byte [] bytes, int pos, boolean value) {
byte byteValue = (byte )(1 << (7 - (pos % 8 )));
if (value) {
bytes[pos / 8 ] = (byte )(bytes[pos / 8 ] | byteValue);
} else {
bytes[pos / 8 ] &= (~byteValue);
}
}
}
private static String localAddr;
private static List<MaskTest> maskTests = new LinkedList<>();
private static void init() throws Exception {
InetAddress addrs[] = InetAddress.getAllByName("localhost" );
if (addrs.length == 0 ) {
throw new RuntimeException("No addresses is returned for 'localhost'" );
}
localAddr = addrs[0 ].getHostAddress();
System.err.println("localhost address: " + localAddr);
for (int i = 0 ; i < addrs.length; i++) {
maskTests.add(new MaskTest(addrs[i]));
}
}
public static void main(String[] args) throws Exception {
init();
// No allow option is the same as the allow option ',allow=*' is passed
positiveTest("DefaultTest" , null );
// Explicit permission for connections from everywhere
positiveTest("ExplicitDefaultTest" , "*" );
positiveTest("AllowTest" , localAddr);
positiveTest("MultiAllowTest" , localAddr + "+10.0.0.0/8+172.16.0.0/12+192.168.0.0/24" );
// Bad allow address
negativeTest("DenyTest" , "0.0.0.0" );
// Wrong separator ';' is used for allow option
badAllowOptionTest("MultiDenyTest" , localAddr + ";192.168.0.0/24" );
// Empty allow option
badAllowOptionTest("EmptyAllowOptionTest" , "" );
// Bad mix of allow option '*' with address value
badAllowOptionTest("ExplicitMultiDefault1Test" , "*+" + localAddr);
// Bad mix of allow address value with '*'
badAllowOptionTest("ExplicitMultiDefault2Test" , localAddr + "+*" );
for (MaskTest test: maskTests) {
// override localAddr (to connect to required IPv4 or IPv6 address)
localAddr = test.localAddress;
positiveTest("PositiveMaskTest(" + test.localAddress + ")" ,
test.allowAddress + "/" + test.prefixLengthGood);
positiveTest("NegativeMaskTest(" + test.localAddress + ")" ,
test.allowAddress + "/" + test.prefixLengthBad);
}
System.err.println("\nTest PASSED" );
}
}
Messung V0.5 in Prozent C=95 H=98 G=96
¤ Dauer der Verarbeitung: 0.6 Sekunden
¤
*© Formatika GbR, Deutschland
2026-10-11
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1127926
#Domains=2039723