--- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties Fri Sep 01 11:54:58 2017 -0700
+++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties Sun Sep 03 14:19:45 2017 +0200
@@ -137,7 +137,6 @@
\ -Xms<size> set initial Java heap size\n\
\ -Xmx<size> set maximum Java heap size\n\
\ -Xnoclassgc disable class garbage collection\n\
-\ -Xprof output cpu profiling data (deprecated)\n\
\ -Xrs reduce use of OS signals by Java/VM (see documentation)\n\
\ -Xshare:auto use shared class data if possible (default)\n\
\ -Xshare:off do not attempt to use shared class data\n\
--- a/jdk/src/jdk.jdwp.agent/share/native/include/jdwpTransport.h Fri Sep 01 11:54:58 2017 -0700
+++ b/jdk/src/jdk.jdwp.agent/share/native/include/jdwpTransport.h Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -33,7 +33,8 @@
#include "jni.h"
enum {
- JDWPTRANSPORT_VERSION_1_0 = 0x00010000
+ JDWPTRANSPORT_VERSION_1_0 = 0x00010000,
+ JDWPTRANSPORT_VERSION_1_1 = 0x00010001
};
#ifdef __cplusplus
@@ -142,6 +143,13 @@
jint version,
jdwpTransportEnv** env);
+/*
+ * JDWP transport configuration from the agent.
+ */
+typedef struct jdwpTransportConfiguration {
+ /* Field added in JDWPTRANSPORT_VERSION_1_1: */
+ const char* allowed_peers; /* Peers allowed for connection */
+} jdwpTransportConfiguration;
/* Function Interface */
@@ -191,6 +199,9 @@
jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env,
char** error);
+ /* 12: SetTransportConfiguration added in JDWPTRANSPORT_VERSION_1_1 */
+ jdwpTransportError (JNICALL *SetTransportConfiguration)(jdwpTransportEnv* env,
+ jdwpTransportConfiguration *config);
};
@@ -248,6 +259,10 @@
return functions->GetLastError(this, error);
}
+ /* SetTransportConfiguration added in JDWPTRANSPORT_VERSION_1_1 */
+ jdwpTransportError SetTransportConfiguration(jdwpTransportEnv* env,
+ return functions->SetTransportConfiguration(this, config);
+ }
#endif /* __cplusplus */
};
--- a/jdk/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c Fri Sep 01 11:54:58 2017 -0700
+++ b/jdk/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c Sun Sep 03 14:19:45 2017 +0200
@@ -34,6 +34,9 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
+#else
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
#endif
/*
@@ -73,6 +76,19 @@
static jint recv_fully(int, char *, int);
static jint send_fully(int, char *, int);
+/* version >= JDWPTRANSPORT_VERSION_1_1 */
+typedef struct {
+ uint32_t subnet;
+ uint32_t netmask;
+} AllowedPeerInfo;
+
+#define STR(x) #x
+#define MAX_PEER_ENTRIES 32
+#define MAX_PEERS_STR STR(MAX_PEER_ENTRIES)
+static AllowedPeerInfo _peers[MAX_PEER_ENTRIES];
+static int _peers_cnt = 0;
+
+
/*
* Record the last error for this thread.
*/
@@ -260,7 +276,7 @@
char *colon;
int port;
- memset((void *)sa,0,sizeof(struct sockaddr_in));
+ memset((void *)sa, 0, sizeof(struct sockaddr_in));
sa->sin_family = AF_INET;
/* check for host:port or port */
@@ -274,7 +290,7 @@
if (colon == NULL) {
// bind to localhost only if no address specified
sa->sin_addr.s_addr = getLocalHostAddress();
- } else if (strncmp(address,"localhost:",10) == 0) {
+ } else if (strncmp(address, "localhost:", 10) == 0) {
// optimize for common case
sa->sin_addr.s_addr = getLocalHostAddress();
} else if (*address == '*' && *(address+1) == ':') {
@@ -286,7 +302,7 @@
char *hostname;
uint32_t addr;
- buf = (*callback->alloc)((int)strlen(address)+1);
+ buf = (*callback->alloc)((int)strlen(address) + 1);
if (buf == NULL) {
RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory");
}
@@ -320,6 +336,131 @@
return JDWPTRANSPORT_ERROR_NONE;
}
+static const char *
+ip_s2u(const char *instr, uint32_t *ip) {
+ // Convert string representation of ip to integer
+ // in network byte order (big-endian)
+ char t[4] = { 0, 0, 0, 0 };
+ const char *s = instr;
+ int i = 0;
+
+ while (1) {
+ if (*s == '.') {
+ ++i;
+ ++s;
+ continue;
+ }
+ if (*s == 0 || *s == '+' || *s == '/') {
+ break;
+ }
+ if (*s < '0' || *s > '9') {
+ return instr;
+ }
+ t[i] = (t[i] * 10) + (*s - '0');
+ ++s;
+ }
+
+ *ip = *(uint32_t*)(t);
+ return s;
+}
+
+static const char *
+mask_s2u(const char *instr, uint32_t *mask) {
+ // Convert the number of bits to a netmask
+ // in network byte order (big-endian)
+ unsigned char m = 0;
+ const char *s = instr;
+
+ while (1) {
+ if (*s == 0 || *s == '+') {
+ break;
+ }
+ if (*s < '0' || *s > '9') {
+ return instr;
+ }
+ m = (m * 10) + (*s - '0');
+ ++s;
+ }
+
+ if (m == 0 || m > 32) {
+ // Drop invalid input
+ return instr;
+ }
+
+ *mask = htonl(-1 << (32 - m));
+ return s;
+}
+
+static int
+ip_in_subnet(uint32_t subnet, uint32_t mask, uint32_t ipaddr) {
+ return (ipaddr & mask) == subnet;
+}
+
+static jdwpTransportError
+parseAllowedPeers(const char *allowed_peers) {
+ // Build a list of allowed peers from char string
+ // of format 192.168.0.10+192.168.0.0/24
+ const char *s = NULL;
+ const char *p = allowed_peers;
+ uint32_t ip = 0;
+ uint32_t mask = 0xFFFFFFFF;
+
+ while (1) {
+ s = ip_s2u(p, &ip);
+ if (s == p) {
+ _peers_cnt = 0;
+ fprintf(stderr, "Error in allow option: '%s'\n", s);
+ RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
+ "invalid IP address in allow option");
+ }
+
+ if (*s == '/') {
+ // netmask specified
+ s = mask_s2u(s + 1, &mask);
+ if (*(s - 1) == '/') {
+ // Input is not consumed, something bad happened
+ _peers_cnt = 0;
+ fprintf(stderr, "Error in allow option: '%s'\n", s);
+ RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
+ "invalid netmask in allow option");
+ }
+ } else {
+ // reset netmask
+ mask = 0xFFFFFFFF;
+ }
+
+ if (*s == '+' || *s == 0) {
+ if (_peers_cnt >= MAX_PEER_ENTRIES) {
+ fprintf(stderr, "Error in allow option: '%s'\n", allowed_peers);
+ RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
+ "exceeded max number of allowed peers: " MAX_PEERS_STR);
+ }
+ _peers[_peers_cnt].subnet = ip;
+ _peers[_peers_cnt].netmask = mask;
+ _peers_cnt++;
+ if (*s == 0) {
+ // end of options
+ break;
+ }
+ // advance to next IP block
+ p = s + 1;
+ }
+ }
+ return JDWPTRANSPORT_ERROR_NONE;
+}
+
+static int
+isPeerAllowed(struct sockaddr_in *peer) {
+ int i;
+ for (i = 0; i < _peers_cnt; ++i) {
+ int peer_ip = peer->sin_addr.s_addr;
+ if (ip_in_subnet(_peers[i].subnet, _peers[i].netmask, peer_ip)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
static jdwpTransportError JNICALL
socketTransport_getCapabilities(jdwpTransportEnv* env,
@@ -412,7 +553,7 @@
socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout)
{
socklen_t socketLen;
- int err;
+ int err = JDWPTRANSPORT_ERROR_NONE;
struct sockaddr_in socket;
jlong startTime = (jlong)0;
@@ -474,14 +615,34 @@
return JDWPTRANSPORT_ERROR_IO_ERROR;
}
- /* handshake with the debugger */
- err = handshake(socketFD, handshakeTimeout);
+ /*
+ * version >= JDWPTRANSPORT_VERSION_1_1:
+ * Verify that peer is allowed to connect.
+ */
+ if (_peers_cnt > 0) {
+ if (!isPeerAllowed(&socket)) {
+ char ebuf[64] = { 0 };
+ char buf[INET_ADDRSTRLEN] = { 0 };
+ const char* addr_str = inet_ntop(AF_INET, &(socket.sin_addr), buf, INET_ADDRSTRLEN);
+ sprintf(ebuf, "ERROR: Peer not allowed to connect: %s\n",
+ (addr_str == NULL) ? "<bad address>" : addr_str);
+ dbgsysSocketClose(socketFD);
+ socketFD = -1;
+ err = JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT;
+ setLastError(err, ebuf);
+ }
+ }
+
+ if (socketFD > 0) {
+ /* handshake with the debugger */
+ err = handshake(socketFD, handshakeTimeout);
+ }
/*
* If the handshake fails then close the connection. If there if an accept
* timeout then we must adjust the timeout for the next poll.
*/
- if (err) {
+ if (err != JDWPTRANSPORT_ERROR_NONE) {
fprintf(stderr, "Debugger failed to attach: %s\n", getLastError());
dbgsysSocketClose(socketFD);
socketFD = -1;
@@ -743,20 +904,20 @@
packet->type.cmd.len = length;
- n = recv_fully(socketFD,(char *)&(packet->type.cmd.id),sizeof(jint));
+ n = recv_fully(socketFD,(char *)&(packet->type.cmd.id), sizeof(jint));
if (n < (int)sizeof(jint)) {
RETURN_RECV_ERROR(n);
}
packet->type.cmd.id = (jint)dbgsysNetworkToHostLong(packet->type.cmd.id);
- n = recv_fully(socketFD,(char *)&(packet->type.cmd.flags),sizeof(jbyte));
+ n = recv_fully(socketFD,(char *)&(packet->type.cmd.flags), sizeof(jbyte));
if (n < (int)sizeof(jbyte)) {
RETURN_RECV_ERROR(n);
}
if (packet->type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
- n = recv_fully(socketFD,(char *)&(packet->type.reply.errorCode),sizeof(jbyte));
+ n = recv_fully(socketFD,(char *)&(packet->type.reply.errorCode), sizeof(jbyte));
if (n < (int)sizeof(jshort)) {
RETURN_RECV_ERROR(n);
}
@@ -765,12 +926,12 @@
} else {
- n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmdSet),sizeof(jbyte));
+ n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmdSet), sizeof(jbyte));
if (n < (int)sizeof(jbyte)) {
RETURN_RECV_ERROR(n);
}
- n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmd),sizeof(jbyte));
+ n = recv_fully(socketFD,(char *)&(packet->type.cmd.cmd), sizeof(jbyte));
if (n < (int)sizeof(jbyte)) {
RETURN_RECV_ERROR(n);
}
@@ -814,11 +975,44 @@
return JDWPTRANSPORT_ERROR_NONE;
}
+static jdwpTransportError JNICALL
+socketTransport_setConfiguration(jdwpTransportEnv* env, jdwpTransportConfiguration* cfg) {
+ const char* allowed_peers = NULL;
+
+ if (cfg == NULL) {
+ RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
+ "NULL pointer to transport configuration is invalid");
+ }
+ allowed_peers = cfg->allowed_peers;
+ _peers_cnt = 0;
+ if (allowed_peers != NULL) {
+ size_t len = strlen(allowed_peers);
+ if (len == 0) { /* Impossible: parseOptions() would reject it */
+ fprintf(stderr, "Error in allow option: '%s'\n", allowed_peers);
+ RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
+ "allow option should not be empty");
+ } else if (*allowed_peers == '*') {
+ if (len != 1) {
+ fprintf(stderr, "Error in allow option: '%s'\n", allowed_peers);
+ RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT,
+ "allow option '*' cannot be expanded");
+ }
+ } else {
+ int err = parseAllowedPeers(allowed_peers);
+ if (err != JDWPTRANSPORT_ERROR_NONE) {
+ return err;
+ }
+ }
+ }
+ return JDWPTRANSPORT_ERROR_NONE;
+}
+
jint JNICALL
jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
- jint version, jdwpTransportEnv** result)
+ jint version, jdwpTransportEnv** env)
{
- if (version != JDWPTRANSPORT_VERSION_1_0) {
+ if (version < JDWPTRANSPORT_VERSION_1_0 ||
+ version > JDWPTRANSPORT_VERSION_1_1) {
return JNI_EVERSION;
}
if (initialized) {
@@ -842,7 +1036,10 @@
interface.ReadPacket = &socketTransport_readPacket;
interface.WritePacket = &socketTransport_writePacket;
interface.GetLastError = &socketTransport_getLastError;
- *result = &single_env;
+ if (version >= JDWPTRANSPORT_VERSION_1_1) {
+ interface.SetTransportConfiguration = &socketTransport_setConfiguration;
+ }
+ *env = &single_env;
/* initialized TLS */
tlsIndex = dbgsysTlsAlloc();
--- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c Fri Sep 01 11:54:58 2017 -0700
+++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, 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
@@ -89,6 +89,7 @@
char *name;
char *address;
long timeout;
+ char *allow;
} TransportSpec;
/*
@@ -564,7 +565,8 @@
LOG_MISC(("Begin startTransport"));
serror = transport_startTransport(enumArg->isServer, transport->name,
- transport->address, transport->timeout);
+ transport->address, transport->timeout,
+ transport->allow);
if (serror != JDWP_ERROR(NONE)) {
ERROR_MESSAGE(("JDWP Transport %s failed to initialize, %s(%d)",
transport->name, jdwpErrorText(serror), serror));
@@ -1060,7 +1062,6 @@
if (transports == NULL) {
EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"transports");
}
-
}
current = names;
@@ -1080,6 +1081,9 @@
goto syntax_error;
}
currentTransport->name = current;
+ currentTransport->address = NULL;
+ currentTransport->allow = NULL;
+ currentTransport->timeout = 0L;
current += strlen(current) + 1;
} else if (strcmp(buf, "address") == 0) {
if (currentTransport == NULL) {
@@ -1092,7 +1096,18 @@
}
currentTransport->address = current;
current += strlen(current) + 1;
- } else if (strcmp(buf, "timeout") == 0) {
+ } else if (strcmp(buf, "allow") == 0) {
+ if (currentTransport == NULL) {
+ errmsg = "allow specified without transport";
+ goto bad_option_with_errmsg;
+ }
+ /*LINTED*/
+ if (!get_tok(&str, current, (int)(end - current), ',')) {
+ goto syntax_error;
+ }
+ currentTransport->allow = current;
+ current += strlen(current) + 1;
+ } else if (strcmp(buf, "timeout") == 0) {
if (currentTransport == NULL) {
errmsg = "timeout specified without transport";
goto bad_option_with_errmsg;
--- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/transport.c Fri Sep 01 11:54:58 2017 -0700
+++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/transport.c Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, 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
@@ -29,7 +29,9 @@
#include "debugLoop.h"
#include "sys.h"
-static jdwpTransportEnv *transport;
+static jdwpTransportEnv *transport = NULL;
+static unsigned transportVersion = JDWPTRANSPORT_VERSION_1_0;
+
static jrawMonitorID listenerLock;
static jrawMonitorID sendLock;
@@ -41,6 +43,8 @@
jdwpTransportEnv *transport;
char *address;
long timeout;
+ char *allowed_peers;
+ unsigned transportVersion;
} TransportInfo;
static struct jdwpTransportCallback callback = {jvmtiAllocate, jvmtiDeallocate};
@@ -135,7 +139,7 @@
* JDK 1.2 javai.c v1.61
*/
static jdwpError
-loadTransport(const char *name, jdwpTransportEnv **transportPtr)
+loadTransport(const char *name, TransportInfo *info)
{
JNIEnv *env;
jdwpTransport_OnLoad_t onLoad;
@@ -147,6 +151,10 @@
ERROR_MESSAGE(("library name is empty"));
return JDWP_ERROR(TRANSPORT_LOAD);
}
+ if (info == NULL) {
+ ERROR_MESSAGE(("internal error: info should not be NULL"));
+ return JDWP_ERROR(TRANSPORT_LOAD);
+ }
/* First, look in sun.boot.library.path. This should find the standard
* dt_socket and dt_shmem transport libraries, or any library
@@ -192,22 +200,34 @@
/* Get transport interface */
env = getEnv();
- if ( env != NULL ) {
- jdwpTransportEnv *t;
- JavaVM *jvm;
- jint ver;
+ if (env != NULL) {
+ jdwpTransportEnv *t = NULL;
+ JavaVM *jvm = NULL;
+ jint rc;
+ size_t i;
+ /* If a new version is added here, update 'case JNI_EVERSION' below. */
+ jint supported_versions[2] = {JDWPTRANSPORT_VERSION_1_1, JDWPTRANSPORT_VERSION_1_0};
JNI_FUNC_PTR(env,GetJavaVM)(env, &jvm);
- ver = (*onLoad)(jvm, &callback, JDWPTRANSPORT_VERSION_1_0, &t);
- if (ver != JNI_OK) {
- switch (ver) {
+
+ /* Try version 1.1 first, fallback to 1.0 on error */
+ for (i = 0; i < sizeof(supported_versions); ++i) {
+ rc = (*onLoad)(jvm, &callback, supported_versions[i], &t);
+ if (rc != JNI_EVERSION) {
+ info->transportVersion = supported_versions[i];
+ break;
+ }
+ }
+
+ if (rc != JNI_OK) {
+ switch (rc) {
case JNI_ENOMEM :
ERROR_MESSAGE(("insufficient memory to complete initialization"));
break;
case JNI_EVERSION :
- ERROR_MESSAGE(("transport doesn't recognize version %x",
- JDWPTRANSPORT_VERSION_1_0));
+ ERROR_MESSAGE(("transport doesn't recognize all supported versions: "
+ "{ 1_1, 1_0 }"));
break;
case JNI_EEXIST :
@@ -215,13 +235,19 @@
break;
default:
- ERROR_MESSAGE(("unrecognized error %d from transport", ver));
+ ERROR_MESSAGE(("unrecognized error %d from transport", rc));
break;
}
return JDWP_ERROR(TRANSPORT_INIT);
}
- *transportPtr = t;
+
+ /* Store transport version to global variable to be able to
+ * set correct transport version for subsequent connect,
+ * even if info is already deallocated.
+ */
+ transportVersion = info->transportVersion;
+ info->transport = t;
} else {
return JDWP_ERROR(TRANSPORT_LOAD);
}
@@ -314,7 +340,6 @@
info = (TransportInfo*)(void*)arg;
t = info->transport;
-
rc = (*t)->Accept(t, info->timeout, 0);
/* System property no longer needed */
@@ -339,8 +364,10 @@
static void JNICALL
attachThread(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
{
+ TransportInfo *info = (TransportInfo*)(void*)arg;
+
LOG_MISC(("Begin attach thread"));
- connectionInitiated((jdwpTransportEnv *)(void*)arg);
+ connectionInitiated(info->transport);
LOG_MISC(("End attach thread"));
}
@@ -418,13 +445,26 @@
jdwpError
transport_startTransport(jboolean isServer, char *name, char *address,
- long timeout)
+ long timeout, char *allowed_peers)
{
jvmtiStartFunction func;
- jdwpTransportEnv *trans;
char threadName[MAXPATHLEN + 100];
jint err;
jdwpError serror;
+ jdwpTransportConfiguration cfg = {0};
+ TransportInfo *info;
+ jdwpTransportEnv *trans;
+
+ info = jvmtiAllocate(sizeof(*info));
+ if (info == NULL) {
+ return JDWP_ERROR(OUT_OF_MEMORY);
+ }
+
+ info->transport = transport;
+ info->transportVersion = transportVersion;
+ info->name = NULL;
+ info->address = NULL;
+ info->allowed_peers = NULL;
/*
* If the transport is already loaded then use it
@@ -434,28 +474,24 @@
* That probably means we have a bag a transport environments
* to correspond to the transports bag.
*/
- if (transport != NULL) {
- trans = transport;
- } else {
- serror = loadTransport(name, &trans);
+ if (info->transport == NULL) {
+ serror = loadTransport(name, info);
if (serror != JDWP_ERROR(NONE)) {
+ jvmtiDeallocate(info);
return serror;
}
}
+ // Cache the value
+ trans = info->transport;
+
if (isServer) {
-
char *retAddress;
char *launchCommand;
- TransportInfo *info;
jvmtiError error;
int len;
char* prop_value;
- info = jvmtiAllocate(sizeof(*info));
- if (info == NULL) {
- return JDWP_ERROR(OUT_OF_MEMORY);
- }
info->timeout = timeout;
info->name = jvmtiAllocate((int)strlen(name)+1);
@@ -465,7 +501,6 @@
}
(void)strcpy(info->name, name);
- info->address = NULL;
if (address != NULL) {
info->address = jvmtiAllocate((int)strlen(address)+1);
if (info->address == NULL) {
@@ -475,7 +510,32 @@
(void)strcpy(info->address, address);
}
- info->transport = trans;
+ if (info->transportVersion == JDWPTRANSPORT_VERSION_1_0) {
+ if (allowed_peers != NULL) {
+ ERROR_MESSAGE(("Allow parameter is specified but transport doesn't support it"));
+ serror = JDWP_ERROR(TRANSPORT_INIT);
+ goto handleError;
+ }
+ } else {
+ /* Memory is allocated only for transport versions > 1.0
+ * as the version 1.0 does not support the 'allow' option.
+ */
+ if (allowed_peers != NULL) {
+ info->allowed_peers = jvmtiAllocate((int)strlen(allowed_peers) + 1);
+ if (info->allowed_peers == NULL) {
+ serror = JDWP_ERROR(OUT_OF_MEMORY);
+ goto handleError;
+ }
+ (void)strcpy(info->allowed_peers, allowed_peers);
+ }
+ cfg.allowed_peers = info->allowed_peers;
+ err = (*trans)->SetTransportConfiguration(trans, &cfg);
+ if (err != JDWPTRANSPORT_ERROR_NONE) {
+ printLastError(trans, err);
+ serror = JDWP_ERROR(TRANSPORT_INIT);
+ goto handleError;
+ }
+ }
err = (*trans)->StartListening(trans, address, &retAddress);
if (err != JDWPTRANSPORT_ERROR_NONE) {
@@ -527,6 +587,7 @@
handleError:
jvmtiDeallocate(info->name);
jvmtiDeallocate(info->address);
+ jvmtiDeallocate(info->allowed_peers);
jvmtiDeallocate(info);
} else {
/*
@@ -543,6 +604,10 @@
if (err != JDWPTRANSPORT_ERROR_NONE) {
printLastError(trans, err);
serror = JDWP_ERROR(TRANSPORT_INIT);
+ /* The name, address and allowed_peers fields in 'info'
+ * are not allocated in the non-server case so
+ * they do not need to be freed. */
+ jvmtiDeallocate(info);
return serror;
}
@@ -553,7 +618,7 @@
(void)strcat(threadName, name);
func = &attachThread;
- err = spawnNewThread(func, (void*)trans, threadName);
+ err = spawnNewThread(func, (void*)info, threadName);
serror = map2jdwpError(err);
}
return serror;
--- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/transport.h Fri Sep 01 11:54:58 2017 -0700
+++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/transport.h Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, 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
@@ -30,7 +30,8 @@
void transport_initialize(void);
void transport_reset(void);
-jdwpError transport_startTransport(jboolean isServer, char *name, char *address, long timeout);
+jdwpError transport_startTransport(jboolean isServer, char *name, char *address,
+ long timeout, char *allowed_peers);
jint transport_receivePacket(jdwpPacket *);
jint transport_sendPacket(jdwpPacket *);
--- a/jdk/src/linux/doc/man/java.1 Fri Sep 01 11:54:58 2017 -0700
+++ b/jdk/src/linux/doc/man/java.1 Sun Sep 03 14:19:45 2017 +0200
@@ -921,11 +921,6 @@
at startup, the class objects in the application will be left untouched during GC and will always be considered live\&. This can result in more memory being permanently occupied which, if not used carefully, will throw an out of memory exception\&.
.RE
.PP
-\-Xprof
-.RS 4
-Profiles the running program and sends profiling data to standard output\&. This option is provided as a utility that is useful in program development and is not intended to be used in production systems\&.
-.RE
-.PP
\-Xrs
.RS 4
Reduces the use of operating system signals by the JVM\&.
--- a/jdk/src/solaris/doc/sun/man/man1/java.1 Fri Sep 01 11:54:58 2017 -0700
+++ b/jdk/src/solaris/doc/sun/man/man1/java.1 Sun Sep 03 14:19:45 2017 +0200
@@ -921,11 +921,6 @@
at startup, the class objects in the application will be left untouched during GC and will always be considered live\&. This can result in more memory being permanently occupied which, if not used carefully, will throw an out of memory exception\&.
.RE
.PP
-\-Xprof
-.RS 4
-Profiles the running program and sends profiling data to standard output\&. This option is provided as a utility that is useful in program development and is not intended to be used in production systems\&.
-.RE
-.PP
\-Xrs
.RS 4
Reduces the use of operating system signals by the JVM\&.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jdi/BasicJDWPConnectionTest.java Sun Sep 03 14:19:45 2017 +0200
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2017, 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 /lib/testlibrary
+ * @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.testlibrary.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);
+ }
+ }
+}