test/jdk/com/sun/jdi/BasicJDWPConnectionTest.java
author iignatyev
Mon, 17 Sep 2018 11:50:39 -0700
changeset 51769 0ae80830256e
parent 51754 594919232b8f
child 52110 65efb9c57fef
permissions -rw-r--r--
8210779: 8182404 and 8210732 haven't updated copyright years Reviewed-by: bchristi

/*
 * Copyright (c) 2017, 2018, 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 BasicJDWPConnectionTest
 */

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

import java.net.Socket;
import java.net.SocketException;

import jdk.test.lib.apps.LingeredApp;
import jdk.test.lib.Utils;

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


public class BasicJDWPConnectionTest {

    public static int handshake(int port) throws IOException {
        // Connect to the debuggee and handshake
        int res = -1;
        Socket s = null;
        try {
            s = new Socket("localhost", port);
            s.getOutputStream().write("JDWP-Handshake".getBytes("UTF-8"));
            byte[] buffer = new byte[24];
            res = s.getInputStream().read(buffer);
        }
        catch (SocketException ex) {
            // pass
        } finally {
            if (s != null) {
                s.close();
            }
        }
        return res;
    }

    public static ArrayList<String> prepareCmd(int port, String allowOpt) {
         String address = "*:" + String.valueOf(port);
         ArrayList<String> cmd = new ArrayList<>();

         String jdwpArgs = "-agentlib:jdwp=transport=dt_socket,server=y," +
                           "suspend=n,address=" + address + allowOpt;
         cmd.add(jdwpArgs);
         return cmd;
    }

    public static void positiveTest(String testName, String allowOpt)
        throws InterruptedException, IOException {
        System.err.println("\nStarting " + testName);
        int port = Utils.getFreePort();
        ArrayList<String> cmd = prepareCmd(port, allowOpt);

        LingeredApp a = LingeredApp.startApp(cmd);
        int res = handshake(port);
        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);
        int port = Utils.getFreePort();
        ArrayList<String> cmd = prepareCmd(port, allowOpt);

        LingeredApp a = LingeredApp.startApp(cmd);
        int res = handshake(port);
        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);
        int port = Utils.getFreePort();
        ArrayList<String> cmd = prepareCmd(port, allowOpt);

        try {
            LingeredApp a = LingeredApp.startApp(cmd);
        } catch (IOException ex) {
            System.err.println(testName + ": caught expected IOException");
            System.err.println(testName + " PASSED");
            return;
        }
        throw new RuntimeException(testName + " FAILED");
    }

    public static void DefaultTest() throws InterruptedException, IOException {
        // No allow option is the same as the allow option ',allow=*' is passed
        String allowOpt = "";
        positiveTest("DefaultTest", allowOpt);
    }

    static void ExplicitDefaultTest() throws InterruptedException, IOException {
        // Explicit permission for connections from everywhere
        String allowOpt = ",allow=*";
        positiveTest("ExplicitDefaultTest" ,allowOpt);
    }

    public static void AllowTest() throws InterruptedException, IOException {
        String allowOpt = ",allow=127.0.0.1";
        positiveTest("AllowTest", allowOpt);
    }

    public static void MultiAllowTest() throws InterruptedException, IOException {
        String allowOpt = ",allow=127.0.0.1+10.0.0.0/8+172.16.0.0/12+192.168.0.0/24";
        positiveTest("MultiAllowTest", allowOpt);
    }

    public static void DenyTest() throws InterruptedException, IOException {
        // Bad allow address
        String allowOpt = ",allow=0.0.0.0";
        negativeTest("DenyTest", allowOpt);
    }

    public static void MultiDenyTest() throws InterruptedException, IOException {
        // Wrong separator ';' is used for allow option
        String allowOpt = ",allow=127.0.0.1;192.168.0.0/24";
        badAllowOptionTest("MultiDenyTest", allowOpt);
    }

    public static void EmptyAllowOptionTest() throws InterruptedException, IOException {
        // Empty allow option
        String allowOpt = ",allow=";
        badAllowOptionTest("EmptyAllowOptionTest", allowOpt);
    }

    public static void ExplicitMultiDefault1Test() throws InterruptedException, IOException {
        // Bad mix of allow option '*' with address value
        String allowOpt = ",allow=*+allow=127.0.0.1";
        badAllowOptionTest("ExplicitMultiDefault1Test", allowOpt);
    }

    public static void ExplicitMultiDefault2Test() throws InterruptedException, IOException {
        // Bad mix of allow address value with '*'
        String allowOpt = ",allow=allow=127.0.0.1+*";
        badAllowOptionTest("ExplicitMultiDefault2Test", allowOpt);
    }

    public static void main(String[] args) {
        try {
            DefaultTest();
            ExplicitDefaultTest();
            AllowTest();
            MultiAllowTest();
            DenyTest();
            MultiDenyTest();
            EmptyAllowOptionTest();
            ExplicitMultiDefault1Test();
            ExplicitMultiDefault2Test();
            System.err.println("\nTest PASSED");
        } catch (InterruptedException ex) {
            System.err.println("\nTest ERROR, getFreePort");
            ex.printStackTrace();
            System.exit(3);
        } catch (IOException ex) {
            System.err.println("\nTest ERROR");
            ex.printStackTrace();
            System.exit(3);
        }
    }
}