Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/native/sun/tools/attach/SolarisVirtualMachine.c
32288 views
/*1* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24#include <sys/types.h>25#include <sys/stat.h>26#include <door.h>27#include <stdlib.h>28#include <unistd.h>29#include <signal.h>30#include <string.h>31#include <fcntl.h>32#include <errno.h>33#include <limits.h>3435#include "jni.h"36#include "jni_util.h"37#include "jvm.h"3839#include "sun_tools_attach_SolarisVirtualMachine.h"4041#define RESTARTABLE(_cmd, _result) do { \42do { \43_result = _cmd; \44} while((_result == -1) && (errno == EINTR)); \45} while(0)4647/*48* Class: sun_tools_attach_SolarisVirtualMachine49* Method: open50* Signature: (Ljava/lang/String;)I51*/52JNIEXPORT jint JNICALL Java_sun_tools_attach_SolarisVirtualMachine_open53(JNIEnv *env, jclass cls, jstring path)54{55jboolean isCopy;56const char* p = GetStringPlatformChars(env, path, &isCopy);57if (p == NULL) {58return 0;59} else {60int fd;61int err = 0;6263fd = open(p, O_RDWR);64if (fd == -1) {65err = errno;66}6768if (isCopy) {69JNU_ReleaseStringPlatformChars(env, path, p);70}7172if (fd == -1) {73if (err == ENOENT) {74JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);75} else {76char* msg = strdup(strerror(err));77JNU_ThrowIOException(env, msg);78if (msg != NULL) {79free(msg);80}81}82}83return fd;84}85}8687/*88* Class: sun_tools_attach_SolarisVirtualMachine89* Method: checkPermissions90* Signature: (Ljava/lang/String;)V91*/92JNIEXPORT void JNICALL Java_sun_tools_attach_SolarisVirtualMachine_checkPermissions93(JNIEnv *env, jclass cls, jstring path)94{95jboolean isCopy;96const char* p = GetStringPlatformChars(env, path, &isCopy);97if (p != NULL) {98struct stat64 sb;99uid_t uid, gid;100int res;101102/*103* Check that the path is owned by the effective uid/gid of this104* process. Also check that group/other access is not allowed.105*/106uid = geteuid();107gid = getegid();108109res = stat64(p, &sb);110if (res != 0) {111/* save errno */112res = errno;113}114115if (res == 0) {116char msg[100];117jboolean isError = JNI_FALSE;118if (sb.st_uid != uid) {119jio_snprintf(msg, sizeof(msg)-1,120"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);121isError = JNI_TRUE;122} else if (sb.st_gid != gid) {123jio_snprintf(msg, sizeof(msg)-1,124"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);125isError = JNI_TRUE;126} else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {127jio_snprintf(msg, sizeof(msg)-1,128"file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);129isError = JNI_TRUE;130}131if (isError) {132char buf[256];133jio_snprintf(buf, sizeof(buf)-1, "well-known file %s is not secure: %s", p, msg);134JNU_ThrowIOException(env, buf);135}136} else {137char* msg = strdup(strerror(res));138JNU_ThrowIOException(env, msg);139if (msg != NULL) {140free(msg);141}142}143144if (isCopy) {145JNU_ReleaseStringPlatformChars(env, path, p);146}147}148}149150/*151* Class: sun_tools_attach_SolarisVirtualMachine152* Method: close153* Signature: (I)V154*/155JNIEXPORT void JNICALL Java_sun_tools_attach_SolarisVirtualMachine_close156(JNIEnv *env, jclass cls, jint fd)157{158int ret;159RESTARTABLE(close(fd), ret);160}161162/*163* Class: sun_tools_attach_SolarisVirtualMachine164* Method: read165* Signature: (I[BI)I166*/167JNIEXPORT jint JNICALL Java_sun_tools_attach_SolarisVirtualMachine_read168(JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)169{170unsigned char buf[128];171size_t len = sizeof(buf);172ssize_t n;173174size_t remaining = (size_t)(baLen - off);175if (len > remaining) {176len = remaining;177}178179RESTARTABLE(read(fd, buf, len), n);180if (n == -1) {181JNU_ThrowIOExceptionWithLastError(env, "read");182} else {183if (n == 0) {184n = -1; // EOF185} else {186(*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf));187}188}189return n;190}191192/*193* Class: sun_tools_attach_SolarisVirtualMachine194* Method: sigquit195* Signature: (I)V196*/197JNIEXPORT void JNICALL Java_sun_tools_attach_SolarisVirtualMachine_sigquit198(JNIEnv *env, jclass cls, jint pid)199{200if (kill((pid_t)pid, SIGQUIT) == -1) {201JNU_ThrowIOExceptionWithLastError(env, "kill");202}203}204205/*206* A simple table to translate some known errors into reasonable207* error messages208*/209static struct {210jint err;211const char* msg;212} const error_messages[] = {213{ 100, "Bad request" },214{ 101, "Protocol mismatch" },215{ 102, "Resource failure" },216{ 103, "Internal error" },217{ 104, "Permission denied" },218};219220/*221* Lookup the given error code and return the appropriate222* message. If not found return NULL.223*/224static const char* translate_error(jint err) {225int table_size = sizeof(error_messages) / sizeof(error_messages[0]);226int i;227228for (i=0; i<table_size; i++) {229if (err == error_messages[i].err) {230return error_messages[i].msg;231}232}233return NULL;234}235236/*237* Current protocol version238*/239static const char* PROTOCOL_VERSION = "1";240241/*242* Class: sun_tools_attach_SolarisVirtualMachine243* Method: enqueue244* Signature: (JILjava/lang/String;[Ljava/lang/Object;)V245*/246JNIEXPORT jint JNICALL Java_sun_tools_attach_SolarisVirtualMachine_enqueue247(JNIEnv *env, jclass cls, jint fd, jstring cmd, jobjectArray args)248{249jint arg_count, i;250size_t size;251jboolean isCopy;252door_arg_t door_args;253char res_buffer[128];254jint result = -1;255int rc;256const char* cstr;257char* buf;258259/*260* First we get the command string and create the start of the261* argument string to send to the target VM:262* <ver>\0<cmd>\0263*/264cstr = JNU_GetStringPlatformChars(env, cmd, &isCopy);265if (cstr == NULL) {266return -1; /* pending exception */267}268size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2;269buf = (char*)malloc(size);270if (buf != NULL) {271char* pos = buf;272strcpy(buf, PROTOCOL_VERSION);273pos += strlen(PROTOCOL_VERSION)+1;274strcpy(pos, cstr);275}276if (isCopy) {277JNU_ReleaseStringPlatformChars(env, cmd, cstr);278}279if (buf == NULL) {280JNU_ThrowOutOfMemoryError(env, "malloc failed");281return -1;282}283284/*285* Next we iterate over the arguments and extend the buffer286* to include them.287*/288arg_count = (*env)->GetArrayLength(env, args);289290for (i=0; i<arg_count; i++) {291jobject obj = (*env)->GetObjectArrayElement(env, args, i);292if (obj != NULL) {293cstr = JNU_GetStringPlatformChars(env, obj, &isCopy);294if (cstr != NULL) {295size_t len = strlen(cstr);296char* newbuf = (char*)realloc(buf, size+len+1);297if (newbuf != NULL) {298buf = newbuf;299strcpy(buf+size, cstr);300size += len+1;301}302if (isCopy) {303JNU_ReleaseStringPlatformChars(env, obj, cstr);304}305if (newbuf == NULL) {306free(buf);307JNU_ThrowOutOfMemoryError(env, "realloc failed");308return -1;309}310}311}312if ((*env)->ExceptionOccurred(env)) {313free(buf);314return -1;315}316}317318/*319* The arguments to the door function are in 'buf' so we now320* do the door call321*/322door_args.data_ptr = buf;323door_args.data_size = size;324door_args.desc_ptr = NULL;325door_args.desc_num = 0;326door_args.rbuf = (char*)&res_buffer;327door_args.rsize = sizeof(res_buffer);328329RESTARTABLE(door_call(fd, &door_args), rc);330331/*332* door_call failed333*/334if (rc == -1) {335JNU_ThrowIOExceptionWithLastError(env, "door_call");336} else {337/*338* door_call succeeded but the call didn't return the the expected jint.339*/340if (door_args.data_size < sizeof(jint)) {341JNU_ThrowIOException(env, "Enqueue error - reason unknown as result is truncated!");342} else {343jint* res = (jint*)(door_args.data_ptr);344if (*res != JNI_OK) {345const char* msg = translate_error(*res);346char buf[255];347if (msg == NULL) {348sprintf(buf, "Unable to enqueue command to target VM: %d", *res);349} else {350sprintf(buf, "Unable to enqueue command to target VM: %s", msg);351}352JNU_ThrowIOException(env, buf);353} else {354/*355* The door call should return a file descriptor to one end of356* a socket pair357*/358if ((door_args.desc_ptr != NULL) &&359(door_args.desc_num == 1) &&360(door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) {361result = door_args.desc_ptr->d_data.d_desc.d_descriptor;362} else {363JNU_ThrowIOException(env, "Reply from enqueue missing descriptor!");364}365}366}367}368369free(buf);370return result;371}372373374