1 /* 2 * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @summary Smoke test for JDWP hardening 27 * @library /test/lib 28 * @run driver BasicJDWPConnectionTest 29 */ 30 31 import java.io.IOException; 32 33 import java.net.Socket; 34 import java.net.SocketException; 35 36 import jdk.test.lib.apps.LingeredApp; 37 38 import java.util.ArrayList; 39 import java.util.regex.Matcher; 40 import java.util.regex.Pattern; 41 42 43 public class BasicJDWPConnectionTest { 44 45 public static int handshake(int port) throws IOException { 46 // Connect to the debuggee and handshake 47 int res = -1; 48 Socket s = null; 49 try { 50 s = new Socket("localhost", port); 51 s.getOutputStream().write("JDWP-Handshake".getBytes("UTF-8")); 52 byte[] buffer = new byte[24]; 53 res = s.getInputStream().read(buffer); 54 } 55 catch (SocketException ex) { 56 // pass 57 } finally { 58 if (s != null) { 59 s.close(); 60 } 61 } 62 return res; 63 } 64 65 public static ArrayList<String> prepareCmd(String allowOpt) { 66 ArrayList<String> cmd = new ArrayList<>(); 67 68 String jdwpArgs = "-agentlib:jdwp=transport=dt_socket,server=y," + 69 "suspend=n,address=*:0" + allowOpt; 70 cmd.add(jdwpArgs); 71 return cmd; 72 } 73 74 private static Pattern listenRegexp = Pattern.compile("Listening for transport \\b(.+)\\b at address: \\b(\\d+)\\b"); 75 private static int detectPort(String s) { 76 Matcher m = listenRegexp.matcher(s); 77 if (!m.find()) { 78 throw new RuntimeException("Could not detect port from '" + s + "'"); 79 } 80 // m.group(1) is transport, m.group(2) is port 81 return Integer.parseInt(m.group(2)); 82 } 83 84 public static void positiveTest(String testName, String allowOpt) 85 throws InterruptedException, IOException { 86 System.err.println("\nStarting " + testName); 87 ArrayList<String> cmd = prepareCmd(allowOpt); 88 89 LingeredApp a = LingeredApp.startApp(cmd); 90 int res; 91 try { 92 res = handshake(detectPort(a.getProcessStdout())); 93 } finally { 94 a.stopApp(); 95 } 96 if (res < 0) { 97 throw new RuntimeException(testName + " FAILED"); 98 } 99 System.err.println(testName + " PASSED"); 100 } 101 102 public static void negativeTest(String testName, String allowOpt) 103 throws InterruptedException, IOException { 104 System.err.println("\nStarting " + testName); 105 ArrayList<String> cmd = prepareCmd(allowOpt); 106 107 LingeredApp a = LingeredApp.startApp(cmd); 108 int res; 109 try { 110 res = handshake(detectPort(a.getProcessStdout())); 111 } finally { 112 a.stopApp(); 113 } 114 if (res > 0) { 115 System.err.println(testName + ": res=" + res); 116 throw new RuntimeException(testName + " FAILED"); 117 } 118 System.err.println(testName + ": returned a negative code as expected: " + res); 119 System.err.println(testName + " PASSED"); 120 } 121 122 public static void badAllowOptionTest(String testName, String allowOpt) 123 throws InterruptedException, IOException { 124 System.err.println("\nStarting " + testName); 125 ArrayList<String> cmd = prepareCmd(allowOpt); 126 127 LingeredApp a; 128 try { 129 a = LingeredApp.startApp(cmd); 130 } catch (IOException ex) { 131 System.err.println(testName + ": caught expected IOException"); 132 System.err.println(testName + " PASSED"); 133 return; 134 } 135 // LingeredApp.startApp is expected to fail, but if not, terminate the app 136 a.stopApp(); 137 throw new RuntimeException(testName + " FAILED"); 138 } 139 140 public static void DefaultTest() throws InterruptedException, IOException { 141 // No allow option is the same as the allow option ',allow=*' is passed 142 String allowOpt = ""; 143 positiveTest("DefaultTest", allowOpt); 144 } 145 146 static void ExplicitDefaultTest() throws InterruptedException, IOException { 147 // Explicit permission for connections from everywhere 148 String allowOpt = ",allow=*"; 149 positiveTest("ExplicitDefaultTest" ,allowOpt); 150 } 151 152 public static void AllowTest() throws InterruptedException, IOException { 153 String allowOpt = ",allow=127.0.0.1"; 154 positiveTest("AllowTest", allowOpt); 155 } 156 157 public static void MultiAllowTest() throws InterruptedException, IOException { 158 String allowOpt = ",allow=127.0.0.1+10.0.0.0/8+172.16.0.0/12+192.168.0.0/24"; 159 positiveTest("MultiAllowTest", allowOpt); 160 } 161 162 public static void DenyTest() throws InterruptedException, IOException { 163 // Bad allow address 164 String allowOpt = ",allow=0.0.0.0"; 165 negativeTest("DenyTest", allowOpt); 166 } 167 168 public static void MultiDenyTest() throws InterruptedException, IOException { 169 // Wrong separator ';' is used for allow option 170 String allowOpt = ",allow=127.0.0.1;192.168.0.0/24"; 171 badAllowOptionTest("MultiDenyTest", allowOpt); 172 } 173 174 public static void EmptyAllowOptionTest() throws InterruptedException, IOException { 175 // Empty allow option 176 String allowOpt = ",allow="; 177 badAllowOptionTest("EmptyAllowOptionTest", allowOpt); 178 } 179 180 public static void ExplicitMultiDefault1Test() throws InterruptedException, IOException { 181 // Bad mix of allow option '*' with address value 182 String allowOpt = ",allow=*+allow=127.0.0.1"; 183 badAllowOptionTest("ExplicitMultiDefault1Test", allowOpt); 184 } 185 186 public static void ExplicitMultiDefault2Test() throws InterruptedException, IOException { 187 // Bad mix of allow address value with '*' 188 String allowOpt = ",allow=allow=127.0.0.1+*"; 189 badAllowOptionTest("ExplicitMultiDefault2Test", allowOpt); 190 } 191 192 public static void main(String[] args) throws Exception { 193 DefaultTest(); 194 ExplicitDefaultTest(); 195 AllowTest(); 196 MultiAllowTest(); 197 DenyTest(); 198 MultiDenyTest(); 199 EmptyAllowOptionTest(); 200 ExplicitMultiDefault1Test(); 201 ExplicitMultiDefault2Test(); 202 System.err.println("\nTest PASSED"); 203 } 204 }