8201247: Various cleanups in the attach framework

Reviewed-by: goetz, cjplummer
This commit is contained in:
Christoph Langer 2018-04-11 09:47:41 +02:00
parent 9fb40e61cb
commit 024d4eb8f4
15 changed files with 149 additions and 293 deletions

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
* Copyright (c) 2012, 2018 SAP SE. 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,12 +30,12 @@
#include "services/attachListener.hpp"
#include "services/dtraceAttacher.hpp"
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path)
@ -145,10 +145,10 @@ class ArgumentIterator : public StackObj {
}
char* next() {
if (*_pos == '\0') {
// advance the iterator if possible (null arguments)
if (_pos < _end) {
_pos += 1;
}
return NULL;
}
char* res = _pos;
@ -233,10 +233,10 @@ int AixAttachListener::init() {
// put in listen mode, set permissions, and rename into place
res = ::listen(listener, 5);
if (res == 0) {
RESTARTABLE(::chmod(initial_path, (S_IREAD|S_IWRITE) & ~(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)), res);
if (res == 0) {
res = ::rename(initial_path, path);
}
RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res);
if (res == 0) {
res = ::rename(initial_path, path);
}
}
if (res == -1) {
::close(listener);
@ -284,10 +284,12 @@ AixAttachOperation* AixAttachListener::read_request(int s) {
// Don't block on interrupts because this will
// hang in the clean-up when shutting down.
n = read(s, buf+off, left);
assert(n <= left, "buffer was too small, impossible!");
buf[max_len - 1] = '\0';
if (n == -1) {
return NULL; // reset by peer or other error
}
if (n == 0) { // end of file reached
if (n == 0) {
break;
}
for (int i=0; i<n; i++) {
@ -362,7 +364,7 @@ AixAttachOperation* AixAttachListener::dequeue() {
socklen_t len = sizeof(addr);
memset(&addr, 0, len);
// We must prevent accept blocking on the socket if it has been shut down.
// Therefore we allow interrups and check whether we have been shut down already.
// Therefore we allow interrupts and check whether we have been shut down already.
if (AixAttachListener::is_shutdown()) {
return NULL;
}
@ -371,19 +373,11 @@ AixAttachOperation* AixAttachListener::dequeue() {
return NULL; // log a warning?
}
// Added timeouts for read and write. If we get no request within the
// next AttachListenerTimeout milliseconds we just finish the connection.
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = AttachListenerTimeout * 1000;
::setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
::setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
// get the credentials of the peer and check the effective uid/guid
// - check with jeff on this.
struct peercred_struct cred_info;
socklen_t optlen = sizeof(cred_info);
if (::getsockopt(s, SOL_SOCKET, SO_PEERID, (void*)&cred_info, &optlen) == -1) {
log_debug(attach)("Failed to get socket option SO_PEERID");
::close(s);
continue;
}
@ -391,6 +385,7 @@ AixAttachOperation* AixAttachListener::dequeue() {
gid_t egid = getegid();
if (cred_info.euid != euid || cred_info.egid != egid) {
log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", cred_info.euid, cred_info.egid, euid, egid);
::close(s);
continue;
}
@ -532,10 +527,10 @@ bool AttachListener::is_init_trigger() {
if (init_at_startup() || is_initialized()) {
return false; // initialized at startup or already initialized
}
char fn[PATH_MAX+1];
sprintf(fn, ".attach_pid%d", os::current_process_id());
char fn[PATH_MAX + 1];
int ret;
struct stat64 st;
sprintf(fn, ".attach_pid%d", os::current_process_id());
RESTARTABLE(::stat64(fn, &st), ret);
if (ret == -1) {
log_trace(attach)("Failed to find attach file: %s, trying alternate", fn);
@ -551,7 +546,7 @@ bool AttachListener::is_init_trigger() {
// a bogus user creates the file
if (st.st_uid == geteuid()) {
init();
log_trace(attach)("Attach trigerred by %s", fn);
log_trace(attach)("Attach triggered by %s", fn);
return true;
} else {
log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 SAP SE. 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
@ -51,10 +51,6 @@
product(bool, AllowExtshm, false, \
"Allow VM to run with EXTSHM=ON.") \
\
product(intx, AttachListenerTimeout, 1000, \
"Timeout in ms the attach listener waits for a request") \
range(0, 2147483) \
\
/* Maximum expected size of the data segment. That correlates with the */ \
/* to the maximum C Heap consumption we expect. */ \
/* We need to know this because we need to leave "breathing space" for the */ \

View File

@ -137,6 +137,10 @@ class ArgumentIterator : public StackObj {
}
char* next() {
if (*_pos == '\0') {
// advance the iterator if possible (null arguments)
if (_pos < _end) {
_pos += 1;
}
return NULL;
}
char* res = _pos;
@ -195,6 +199,7 @@ int BsdAttachListener::init() {
// bind socket
struct sockaddr_un addr;
memset((void *)&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, initial_path);
::unlink(initial_path);
@ -260,6 +265,8 @@ BsdAttachOperation* BsdAttachListener::read_request(int s) {
do {
int n;
RESTARTABLE(read(s, buf+off, left), n);
assert(n <= left, "buffer was too small, impossible!");
buf[max_len - 1] = '\0';
if (n == -1) {
return NULL; // reset by peer or other error
}
@ -342,10 +349,10 @@ BsdAttachOperation* BsdAttachListener::dequeue() {
}
// get the credentials of the peer and check the effective uid/guid
// - check with jeff on this.
uid_t puid;
gid_t pgid;
if (::getpeereid(s, &puid, &pgid) != 0) {
log_debug(attach)("Failed to get peer id");
::close(s);
continue;
}
@ -353,6 +360,7 @@ BsdAttachOperation* BsdAttachListener::dequeue() {
gid_t egid = getegid();
if (puid != euid || pgid != egid) {
log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", puid, pgid, euid, egid);
::close(s);
continue;
}
@ -438,7 +446,6 @@ AttachOperation* AttachListener::dequeue() {
return op;
}
// Performs initialization at vm startup
// For BSD we remove any stale .java_pid file which could cause
// an attaching process to think we are ready to receive on the
@ -497,7 +504,6 @@ bool AttachListener::is_init_trigger() {
char fn[PATH_MAX + 1];
int ret;
struct stat st;
snprintf(fn, PATH_MAX + 1, "%s/.attach_pid%d",
os::get_temp_directory(), os::current_process_id());
RESTARTABLE(::stat(fn, &st), ret);
@ -509,7 +515,7 @@ bool AttachListener::is_init_trigger() {
// a bogus user creates the file
if (st.st_uid == geteuid()) {
init();
log_trace(attach)("Attach trigerred by %s", fn);
log_trace(attach)("Attach triggered by %s", fn);
return true;
} else {
log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());

View File

@ -138,6 +138,10 @@ class ArgumentIterator : public StackObj {
}
char* next() {
if (*_pos == '\0') {
// advance the iterator if possible (null arguments)
if (_pos < _end) {
_pos += 1;
}
return NULL;
}
char* res = _pos;
@ -196,6 +200,7 @@ int LinuxAttachListener::init() {
// bind socket
struct sockaddr_un addr;
memset((void *)&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, initial_path);
::unlink(initial_path);
@ -208,10 +213,10 @@ int LinuxAttachListener::init() {
// put in listen mode, set permissions, and rename into place
res = ::listen(listener, 5);
if (res == 0) {
RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res);
if (res == 0) {
res = ::rename(initial_path, path);
}
RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res);
if (res == 0) {
res = ::rename(initial_path, path);
}
}
if (res == -1) {
::close(listener);
@ -340,10 +345,10 @@ LinuxAttachOperation* LinuxAttachListener::dequeue() {
}
// get the credentials of the peer and check the effective uid/guid
// - check with jeff on this.
struct ucred cred_info;
socklen_t optlen = sizeof(cred_info);
if (::getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void*)&cred_info, &optlen) == -1) {
log_debug(attach)("Failed to get socket option SO_PEERCRED");
::close(s);
continue;
}
@ -351,6 +356,7 @@ LinuxAttachOperation* LinuxAttachListener::dequeue() {
gid_t egid = getegid();
if (cred_info.uid != euid || cred_info.gid != egid) {
log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", cred_info.uid, cred_info.gid, euid, egid);
::close(s);
continue;
}
@ -436,7 +442,6 @@ AttachOperation* AttachListener::dequeue() {
return op;
}
// Performs initialization at vm startup
// For Linux we remove any stale .java_pid file which could cause
// an attaching process to think we are ready to receive on the
@ -492,10 +497,10 @@ bool AttachListener::is_init_trigger() {
if (init_at_startup() || is_initialized()) {
return false; // initialized at startup or already initialized
}
char fn[PATH_MAX+1];
sprintf(fn, ".attach_pid%d", os::current_process_id());
char fn[PATH_MAX + 1];
int ret;
struct stat64 st;
sprintf(fn, ".attach_pid%d", os::current_process_id());
RESTARTABLE(::stat64(fn, &st), ret);
if (ret == -1) {
log_trace(attach)("Failed to find attach file: %s, trying alternate", fn);
@ -511,10 +516,10 @@ bool AttachListener::is_init_trigger() {
// a bogus user creates the file
if (st.st_uid == geteuid()) {
init();
log_trace(attach)("Attach trigerred by %s", fn);
log_trace(attach)("Attach triggered by %s", fn);
return true;
} else {
log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not trigerred", fn, st.st_uid, geteuid());
log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());
}
}
return false;

View File

@ -186,6 +186,10 @@ class ArgumentIterator : public StackObj {
}
char* next() {
if (*_pos == '\0') {
// advance the iterator if possible (null arguments)
if (_pos < _end) {
_pos += 1;
}
return NULL;
}
char* res = _pos;
@ -644,10 +648,10 @@ bool AttachListener::is_init_trigger() {
if (init_at_startup() || is_initialized()) {
return false; // initialized at startup or already initialized
}
char fn[PATH_MAX+1];
sprintf(fn, ".attach_pid%d", os::current_process_id());
char fn[PATH_MAX + 1];
int ret;
struct stat64 st;
sprintf(fn, ".attach_pid%d", os::current_process_id());
RESTARTABLE(::stat64(fn, &st), ret);
if (ret == -1) {
log_trace(attach)("Failed to find attach file: %s, trying alternate", fn);
@ -663,7 +667,10 @@ bool AttachListener::is_init_trigger() {
// a bogus user creates the file
if (st.st_uid == geteuid()) {
init();
log_trace(attach)("Attach triggered by %s", fn);
return true;
} else {
log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());
}
}
return false;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -131,12 +131,12 @@ class Win32AttachOperation: public AttachOperation {
pipe_name_max = 256 // maximum pipe name
};
char _pipe[pipe_name_max+1];
char _pipe[pipe_name_max + 1];
const char* pipe() const { return _pipe; }
void set_pipe(const char* pipe) {
assert(strlen(pipe) <= pipe_name_max, "execeds maximum length of pipe name");
strcpy(_pipe, pipe);
assert(strlen(pipe) <= pipe_name_max, "exceeds maximum length of pipe name");
os::snprintf(_pipe, sizeof(_pipe), "%s", pipe);
}
HANDLE open_pipe();
@ -329,12 +329,20 @@ void Win32AttachOperation::complete(jint result, bufferedStream* result_stream)
fSuccess = write_pipe(hPipe, msg, (int)strlen(msg));
if (fSuccess) {
write_pipe(hPipe, (char*) result_stream->base(), (int)(result_stream->size()));
fSuccess = write_pipe(hPipe, (char*)result_stream->base(), (int)(result_stream->size()));
}
// Need to flush buffers
FlushFileBuffers(hPipe);
CloseHandle(hPipe);
if (fSuccess) {
log_debug(attach)("wrote result of attach operation %s to pipe %s", name(), pipe());
} else {
log_error(attach)("failure writing result of operation %s to pipe %s", name(), pipe());
}
} else {
log_error(attach)("could not open pipe %s to send result of operation %s", pipe(), name());
}
DWORD res = ::WaitForSingleObject(Win32AttachListener::mutex(), INFINITE);

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015 SAP SE. All rights reserved.
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, SAP SE. 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
@ -34,8 +34,6 @@ import java.io.InputStream;
import java.io.IOException;
import java.io.File;
// Based on linux/classes/sun/tools/attach/VirtualMachineImpl.java.
/*
* Aix implementation of HotSpotVirtualMachine
*/
@ -140,7 +138,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
* Execute the given command in the target VM.
*/
InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
assert args.length <= 3; // includes null
assert args.length <= 3; // includes null
// did we detach?
synchronized (this) {
@ -261,7 +259,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
}
}
// On Solaris/Linux/Aix a simple handshake is used to start the attach mechanism
// On Aix a simple handshake is used to start the attach mechanism
// if not already started. The client creates a .attach_pid<pid> file in the
// target VM's working directory (or temp directory), and the SIGQUIT handler
// checks for the file.

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015 SAP SE. All rights reserved.
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, SAP SE. 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
@ -24,27 +24,18 @@
* questions.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <dirent.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
/*
* Based on 'LinuxVirtualMachine.c'. Non-relevant code has been removed and all
* occurrences of the string "Linux" have been replaced by "Aix".
*/
#include "sun_tools_attach_VirtualMachineImpl.h"
@ -67,15 +58,6 @@ JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_socket
if (fd == -1) {
JNU_ThrowIOExceptionWithLastError(env, "socket");
}
/* added time out values */
else {
struct timeval tv;
tv.tv_sec = 2 * 60;
tv.tv_usec = 0;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
}
return (jint)fd;
}
@ -125,23 +107,6 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connect
}
}
/*
* Structure and callback function used to send a QUIT signal to all
* children of a given process
*/
typedef struct {
pid_t ppid;
} SendQuitContext;
static void SendQuitCallback(const pid_t pid, void* user_data) {
SendQuitContext* context = (SendQuitContext*)user_data;
pid_t parent = getParent(pid);
if (parent == context->ppid) {
kill(pid, SIGQUIT);
}
}
/*
* Class: sun_tools_attach_VirtualMachineImpl
* Method: sendQuitTo
@ -169,7 +134,7 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
struct stat64 sb;
uid_t uid, gid;
int res;
/* added missing initialization of the stat64 buffer */
memset(&sb, 0, sizeof(struct stat64));
/*
@ -189,21 +154,21 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
char msg[100];
jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE;
} else if (sb.st_gid != gid) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE;
} else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);
isError = JNI_TRUE;
}
if (isError) {
char buf[256];
jio_snprintf(buf, sizeof(buf)-1, "well-known file %s is not secure: %s", p, msg);
snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg);
JNU_ThrowIOException(env, buf);
}
} else {
@ -229,11 +194,7 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close
(JNIEnv *env, jclass cls, jint fd)
{
int res;
/* Fixed deadlock when this call of close by the client is not seen by the attach server
* which has accepted the (very short) connection already and is waiting for the request. But read don't get a byte,
* because the close is lost without shutdown.
*/
shutdown(fd, 2);
shutdown(fd, SHUT_RDWR);
RESTARTABLE(close(fd), res);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -105,7 +105,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
} finally {
f.delete();
}
}
}
// Check that the file owner/permission to avoid attaching to
// bogus process
@ -274,7 +274,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
return new File(root, ".java_pid" + ns_pid);
}
// On Solaris/Linux a simple handshake is used to start the attach mechanism
// On Linux a simple handshake is used to start the attach mechanism
// if not already started. The client creates a .attach_pid<pid> file in the
// target VM's working directory (or temp directory), and the SIGQUIT handler
// checks for the file.
@ -356,8 +356,6 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
//-- native methods
static native void sendQuitToChildrenOf(int pid) throws IOException;
static native void sendQuitTo(int pid) throws IOException;
static native void checkPermissions(String path) throws IOException;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -23,23 +23,18 @@
* questions.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <dirent.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include "sun_tools_attach_VirtualMachineImpl.h"
@ -54,85 +49,6 @@
*/
DEF_STATIC_JNI_OnLoad
/*
* Defines a callback that is invoked for each process
*/
typedef void (*ProcessCallback)(const pid_t pid, void* user_data);
/*
* Invokes the callback function for each process
*/
static void forEachProcess(ProcessCallback f, void* user_data) {
DIR* dir;
struct dirent* ptr;
/*
* To locate the children we scan /proc looking for files that have a
* position integer as a filename.
*/
if ((dir = opendir("/proc")) == NULL) {
return;
}
while ((ptr = readdir(dir)) != NULL) {
pid_t pid;
/* skip current/parent directories */
if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
continue;
}
/* skip files that aren't numbers */
pid = (pid_t)atoi(ptr->d_name);
if ((int)pid <= 0) {
continue;
}
/* invoke the callback */
(*f)(pid, user_data);
}
closedir(dir);
}
/*
* Returns the parent pid of a given pid, or -1 if not found
*/
static pid_t getParent(pid_t pid) {
char state;
FILE* fp;
char stat[2048];
int statlen;
char fn[32];
int i, p;
char* s;
/*
* try to open /proc/%d/stat
*/
sprintf(fn, "/proc/%d/stat", pid);
fp = fopen(fn, "r");
if (fp == NULL) {
return -1;
}
/*
* The format is: pid (command) state ppid ...
* As the command could be anything we must find the right most
* ")" and then skip the white spaces that follow it.
*/
statlen = fread(stat, 1, 2047, fp);
stat[statlen] = '\0';
fclose(fp);
s = strrchr(stat, ')');
if (s == NULL) {
return -1;
}
do s++; while (isspace(*s));
i = sscanf(s, "%c %d", &state, &p);
return (pid_t)p;
}
/*
* Class: sun_tools_attach_VirtualMachineImpl
* Method: socket
@ -194,39 +110,6 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connect
}
}
/*
* Structure and callback function used to send a QUIT signal to all
* children of a given process
*/
typedef struct {
pid_t ppid;
} SendQuitContext;
static void SendQuitCallback(const pid_t pid, void* user_data) {
SendQuitContext* context = (SendQuitContext*)user_data;
pid_t parent = getParent(pid);
if (parent == context->ppid) {
kill(pid, SIGQUIT);
}
}
/*
* Class: sun_tools_attach_VirtualMachineImpl
* Method: sendQuitToChildrenOf
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sendQuitToChildrenOf
(JNIEnv *env, jclass cls, jint pid)
{
SendQuitContext context;
context.ppid = (pid_t)pid;
/*
* Iterate over all children of 'pid' and send a QUIT signal to each.
*/
forEachProcess(SendQuitCallback, (void*)&context);
}
/*
* Class: sun_tools_attach_VirtualMachineImpl
* Method: sendQuitTo
@ -255,6 +138,8 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
uid_t uid, gid;
int res;
memset(&sb, 0, sizeof(struct stat64));
/*
* Check that the path is owned by the effective uid/gid of this
* process. Also check that group/other access is not allowed.
@ -272,21 +157,21 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
char msg[100];
jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE;
} else if (sb.st_gid != gid) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE;
} else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);
isError = JNI_TRUE;
}
if (isError) {
char buf[256];
jio_snprintf(buf, sizeof(buf)-1, "well-known file %s is not secure: %s", p, msg);
snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg);
JNU_ThrowIOException(env, buf);
}
} else {
@ -312,6 +197,7 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close
(JNIEnv *env, jclass cls, jint fd)
{
int res;
shutdown(fd, SHUT_RDWR);
RESTARTABLE(close(fd), res);
}
@ -366,8 +252,8 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_write
RESTARTABLE(write(fd, buf, len), n);
if (n > 0) {
off += n;
remaining -= n;
off += n;
remaining -= n;
} else {
JNU_ThrowIOExceptionWithLastError(env, "write");
return;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -281,8 +281,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
}
private File createAttachFile(int pid) throws IOException {
String fn = ".attach_pid" + pid;
File f = new File(tmpdir, fn);
File f = new File(tmpdir, ".attach_pid" + pid);
createAttachFile0(f.getPath());
return f;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -23,24 +23,20 @@
* questions.
*/
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <dirent.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syslimits.h>
#include <sys/types.h>
#include <sys/un.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "sun_tools_attach_VirtualMachineImpl.h"
@ -144,6 +140,8 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
uid_t uid, gid;
int res;
memset(&sb, 0, sizeof(struct stat));
/*
* Check that the path is owned by the effective uid/gid of this
* process. Also check that group/other access is not allowed.
@ -161,21 +159,21 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
char msg[100];
jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE;
} else if (sb.st_gid != gid) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE;
} else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);
isError = JNI_TRUE;
}
if (isError) {
char buf[256];
jio_snprintf(buf, sizeof(buf)-1, "well-known file %s is not secure: %s", p, msg);
snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg);
JNU_ThrowIOException(env, buf);
}
} else {
@ -201,6 +199,7 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close
(JNIEnv *env, jclass cls, jint fd)
{
int res;
shutdown(fd, SHUT_RDWR);
RESTARTABLE(close(fd), res);
}
@ -255,8 +254,8 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_write
RESTARTABLE(write(fd, buf, len), n);
if (n > 0) {
off += n;
remaining -= n;
off += n;
remaining -= n;
} else {
JNU_ThrowIOExceptionWithLastError(env, "write");
return;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -225,7 +225,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
return fd;
}
// On Solaris/Linux a simple handshake is used to start the attach mechanism
// On Solaris a simple handshake is used to start the attach mechanism
// if not already started. The client creates a .attach_pid<pid> file in the
// target VM's working directory (or temporary directory), and the SIGQUIT
// handler checks for the file.

View File

@ -22,20 +22,19 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <door.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <door.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "sun_tools_attach_VirtualMachineImpl.h"
@ -105,6 +104,8 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
uid_t uid, gid;
int res;
memset(&sb, 0, sizeof(struct stat64));
/*
* Check that the path is owned by the effective uid/gid of this
* process. Also check that group/other access is not allowed.
@ -122,21 +123,21 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
char msg[100];
jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE;
} else if (sb.st_gid != gid) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE;
} else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {
jio_snprintf(msg, sizeof(msg)-1,
snprintf(msg, sizeof(msg),
"file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);
isError = JNI_TRUE;
}
if (isError) {
char buf[256];
jio_snprintf(buf, sizeof(buf)-1, "well-known file %s is not secure: %s", p, msg);
snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg);
JNU_ThrowIOException(env, buf);
}
} else {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -22,16 +22,15 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "jni_util.h"
#include <windows.h>
#include <Sddl.h>
#include <string.h>
#include "jni.h"
#include "jni_util.h"
#include "sun_tools_attach_VirtualMachineImpl.h"
/* kernel32 */
typedef HINSTANCE (WINAPI* GetModuleHandleFunc) (LPCTSTR);
typedef FARPROC (WINAPI* GetProcAddressFunc)(HMODULE, LPCSTR);
@ -303,9 +302,7 @@ JNIEXPORT jlong JNICALL Java_sun_tools_attach_VirtualMachineImpl_createPipe
LocalFree(sa.lpSecurityDescriptor);
if (hPipe == INVALID_HANDLE_VALUE) {
char msg[256];
_snprintf(msg, sizeof(msg), "CreateNamedPipe failed: %d", GetLastError());
JNU_ThrowIOExceptionWithLastError(env, msg);
JNU_ThrowIOExceptionWithLastError(env, "CreateNamedPipe failed");
}
return (jlong)hPipe;
}
@ -318,7 +315,7 @@ JNIEXPORT jlong JNICALL Java_sun_tools_attach_VirtualMachineImpl_createPipe
JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_closePipe
(JNIEnv *env, jclass cls, jlong hPipe)
{
CloseHandle( (HANDLE)hPipe );
CloseHandle((HANDLE)hPipe);
}
/*
@ -430,7 +427,7 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue
if ((*env)->ExceptionOccurred(env)) return;
}
}
for (i=argsLen; i<MAX_ARGS; i++) {
for (i = argsLen; i < MAX_ARGS; i++) {
data.arg[i][0] = '\0';
}