8197387: jcmd started by "root" must be allowed to access all VM processes

Reviewed-by: sspitsyn, stuefe
This commit is contained in:
Daniil Titov 2018-05-31 14:09:04 -07:00
parent dd3d24341b
commit a2a5e85195
10 changed files with 58 additions and 33 deletions

View File

@ -386,11 +386,10 @@ AixAttachOperation* AixAttachListener::dequeue() {
::close(s); ::close(s);
continue; continue;
} }
uid_t euid = geteuid();
gid_t egid = getegid();
if (cred_info.euid != euid || cred_info.egid != egid) { if (!os::Posix::matches_effective_uid_and_gid_or_root(cred_info.euid, cred_info.egid)) {
log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", cred_info.euid, cred_info.egid, euid, egid); log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)",
cred_info.euid, cred_info.egid, geteuid(), getegid());
::close(s); ::close(s);
continue; continue;
} }
@ -548,8 +547,8 @@ bool AttachListener::is_init_trigger() {
} }
if (ret == 0) { if (ret == 0) {
// simple check to avoid starting the attach mechanism when // simple check to avoid starting the attach mechanism when
// a bogus user creates the file // a bogus non-root user creates the file
if (st.st_uid == geteuid()) { if (os::Posix::matches_effective_uid_or_root(st.st_uid)) {
init(); init();
log_trace(attach)("Attach triggered by %s", fn); log_trace(attach)("Attach triggered by %s", fn);
return true; return true;

View File

@ -357,11 +357,10 @@ BsdAttachOperation* BsdAttachListener::dequeue() {
::close(s); ::close(s);
continue; continue;
} }
uid_t euid = geteuid();
gid_t egid = getegid();
if (puid != euid || pgid != egid) { if (!os::Posix::matches_effective_uid_and_gid_or_root(puid, pgid)) {
log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", puid, pgid, euid, egid); log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", puid, pgid,
geteuid(), getegid());
::close(s); ::close(s);
continue; continue;
} }
@ -513,8 +512,8 @@ bool AttachListener::is_init_trigger() {
} }
if (ret == 0) { if (ret == 0) {
// simple check to avoid starting the attach mechanism when // simple check to avoid starting the attach mechanism when
// a bogus user creates the file // a bogus non-root user creates the file
if (st.st_uid == geteuid()) { if (os::Posix::matches_effective_uid_or_root(st.st_uid)) {
init(); init();
log_trace(attach)("Attach triggered by %s", fn); log_trace(attach)("Attach triggered by %s", fn);
return true; return true;

View File

@ -357,11 +357,10 @@ LinuxAttachOperation* LinuxAttachListener::dequeue() {
::close(s); ::close(s);
continue; continue;
} }
uid_t euid = geteuid();
gid_t egid = getegid();
if (cred_info.uid != euid || cred_info.gid != egid) { if (!os::Posix::matches_effective_uid_and_gid_or_root(cred_info.uid, cred_info.gid)) {
log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", cred_info.uid, cred_info.gid, euid, egid); log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)",
cred_info.uid, cred_info.gid, geteuid(), getegid());
::close(s); ::close(s);
continue; continue;
} }
@ -518,8 +517,8 @@ bool AttachListener::is_init_trigger() {
} }
if (ret == 0) { if (ret == 0) {
// simple check to avoid starting the attach mechanism when // simple check to avoid starting the attach mechanism when
// a bogus user creates the file // a bogus non-root user creates the file
if (st.st_uid == geteuid()) { if (os::Posix::matches_effective_uid_or_root(st.st_uid)) {
init(); init();
log_trace(attach)("Attach triggered by %s", fn); log_trace(attach)("Attach triggered by %s", fn);
return true; return true;

View File

@ -51,6 +51,8 @@
#endif #endif
#define IS_VALID_PID(p) (p > 0 && p < MAX_PID) #define IS_VALID_PID(p) (p > 0 && p < MAX_PID)
#define ROOT_UID 0
#ifndef MAP_ANONYMOUS #ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON #define MAP_ANONYMOUS MAP_ANON
#endif #endif
@ -1454,6 +1456,18 @@ size_t os::Posix::get_initial_stack_size(ThreadType thr_type, size_t req_stack_s
return stack_size; return stack_size;
} }
bool os::Posix::is_root(uid_t uid){
return ROOT_UID == uid;
}
bool os::Posix::matches_effective_uid_or_root(uid_t uid) {
return is_root(uid) || geteuid() == uid;
}
bool os::Posix::matches_effective_uid_and_gid_or_root(uid_t uid, gid_t gid) {
return is_root(uid) || (geteuid() == uid && getegid() == gid);
}
Thread* os::ThreadCrashProtection::_protected_thread = NULL; Thread* os::ThreadCrashProtection::_protected_thread = NULL;
os::ThreadCrashProtection* os::ThreadCrashProtection::_crash_protection = NULL; os::ThreadCrashProtection* os::ThreadCrashProtection::_crash_protection = NULL;
volatile intptr_t os::ThreadCrashProtection::_crash_mux = 0; volatile intptr_t os::ThreadCrashProtection::_crash_mux = 0;

View File

@ -106,6 +106,16 @@ public:
// On error, it will return NULL and set errno. The content of 'outbuf' is undefined. // On error, it will return NULL and set errno. The content of 'outbuf' is undefined.
// On truncation error ('outbuf' too small), it will return NULL and set errno to ENAMETOOLONG. // On truncation error ('outbuf' too small), it will return NULL and set errno to ENAMETOOLONG.
static char* realpath(const char* filename, char* outbuf, size_t outbuflen); static char* realpath(const char* filename, char* outbuf, size_t outbuflen);
// Returns true if given uid is root.
static bool is_root(uid_t uid);
// Returns true if given uid is effective or root uid.
static bool matches_effective_uid_or_root(uid_t uid);
// Returns true if either given uid is effective uid and given gid is
// effective gid, or if given uid is root.
static bool matches_effective_uid_and_gid_or_root(uid_t uid, gid_t gid);
}; };
// On POSIX platforms the signal handler is global so we just do the write. // On POSIX platforms the signal handler is global so we just do the write.

View File

@ -213,16 +213,12 @@ static int check_credentials() {
return -1; // unable to get them, deny return -1; // unable to get them, deny
} }
// get our euid/eguid (probably could cache these)
uid_t euid = geteuid();
gid_t egid = getegid();
// get euid/egid from ucred_free // get euid/egid from ucred_free
uid_t ucred_euid = ucred_geteuid(cred_info); uid_t ucred_euid = ucred_geteuid(cred_info);
gid_t ucred_egid = ucred_getegid(cred_info); gid_t ucred_egid = ucred_getegid(cred_info);
// check that the effective uid/gid matches // check that the effective uid/gid matches
if (ucred_euid == euid && ucred_egid == egid) { if (os::Posix::matches_effective_uid_and_gid_or_root(ucred_euid, ucred_egid)) {
ret = 0; // allow ret = 0; // allow
} }
@ -664,8 +660,8 @@ bool AttachListener::is_init_trigger() {
} }
if (ret == 0) { if (ret == 0) {
// simple check to avoid starting the attach mechanism when // simple check to avoid starting the attach mechanism when
// a bogus user creates the file // a bogus non-root user creates the file
if (st.st_uid == geteuid()) { if (os::Posix::matches_effective_uid_or_root(st.st_uid)) {
init(); init();
log_trace(attach)("Attach triggered by %s", fn); log_trace(attach)("Attach triggered by %s", fn);
return true; return true;

View File

@ -46,6 +46,8 @@
} while(0) } while(0)
#define ROOT_UID 0
/* /*
* Class: sun_tools_attach_VirtualMachineImpl * Class: sun_tools_attach_VirtualMachineImpl
* Method: socket * Method: socket
@ -153,11 +155,11 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
if (res == 0) { if (res == 0) {
char msg[100]; char msg[100];
jboolean isError = JNI_FALSE; jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) { if (sb.st_uid != uid && uid != ROOT_UID) {
snprintf(msg, sizeof(msg), snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid); "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE; isError = JNI_TRUE;
} else if (sb.st_gid != gid) { } else if (sb.st_gid != gid && uid != ROOT_UID) {
snprintf(msg, sizeof(msg), snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid); "file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE; isError = JNI_TRUE;

View File

@ -44,6 +44,8 @@
} while((_result == -1) && (errno == EINTR)); \ } while((_result == -1) && (errno == EINTR)); \
} while(0) } while(0)
#define ROOT_UID 0
/* /*
* Declare library specific JNI_Onload entry if static build * Declare library specific JNI_Onload entry if static build
*/ */
@ -156,11 +158,11 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
if (res == 0) { if (res == 0) {
char msg[100]; char msg[100];
jboolean isError = JNI_FALSE; jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) { if (sb.st_uid != uid && uid != ROOT_UID) {
snprintf(msg, sizeof(msg), snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid); "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE; isError = JNI_TRUE;
} else if (sb.st_gid != gid) { } else if (sb.st_gid != gid && uid != ROOT_UID) {
snprintf(msg, sizeof(msg), snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid); "file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE; isError = JNI_TRUE;

View File

@ -46,6 +46,8 @@
} while((_result == -1) && (errno == EINTR)); \ } while((_result == -1) && (errno == EINTR)); \
} while(0) } while(0)
#define ROOT_UID 0
/* /*
* Declare library specific JNI_Onload entry if static build * Declare library specific JNI_Onload entry if static build
*/ */
@ -158,11 +160,11 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
if (res == 0) { if (res == 0) {
char msg[100]; char msg[100];
jboolean isError = JNI_FALSE; jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) { if (sb.st_uid != uid && uid != ROOT_UID) {
snprintf(msg, sizeof(msg), snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid); "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE; isError = JNI_TRUE;
} else if (sb.st_gid != gid) { } else if (sb.st_gid != gid && uid != ROOT_UID) {
snprintf(msg, sizeof(msg), snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid); "file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE; isError = JNI_TRUE;

View File

@ -38,6 +38,8 @@
#include "sun_tools_attach_VirtualMachineImpl.h" #include "sun_tools_attach_VirtualMachineImpl.h"
#define ROOT_UID 0
#define RESTARTABLE(_cmd, _result) do { \ #define RESTARTABLE(_cmd, _result) do { \
do { \ do { \
_result = _cmd; \ _result = _cmd; \
@ -122,11 +124,11 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
if (res == 0) { if (res == 0) {
char msg[100]; char msg[100];
jboolean isError = JNI_FALSE; jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) { if (sb.st_uid != uid && uid != ROOT_UID) {
snprintf(msg, sizeof(msg), snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid); "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE; isError = JNI_TRUE;
} else if (sb.st_gid != gid) { } else if (sb.st_gid != gid && uid != ROOT_UID) {
snprintf(msg, sizeof(msg), snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid); "file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE; isError = JNI_TRUE;