Path: blob/master/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c
40941 views
/*1* Copyright (c) 2005, 2021, 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*/2425#include "jni_util.h"2627#include <sys/socket.h>28#include <sys/stat.h>29#include <sys/syslimits.h>30#include <sys/types.h>31#include <sys/un.h>32#include <errno.h>33#include <fcntl.h>34#include <signal.h>35#include <stdio.h>36#include <stdlib.h>37#include <string.h>38#include <unistd.h>3940#include "sun_tools_attach_VirtualMachineImpl.h"4142#define RESTARTABLE(_cmd, _result) do { \43do { \44_result = _cmd; \45} while((_result == -1) && (errno == EINTR)); \46} while(0)4748#define ROOT_UID 04950/*51* Declare library specific JNI_Onload entry if static build52*/53DEF_STATIC_JNI_OnLoad5455/*56* Class: sun_tools_attach_VirtualMachineImpl57* Method: socket58* Signature: ()I59*/60JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_socket61(JNIEnv *env, jclass cls)62{63int fd = socket(PF_UNIX, SOCK_STREAM, 0);64if (fd == -1) {65JNU_ThrowIOExceptionWithLastError(env, "socket");66}67return (jint)fd;68}6970/*71* Class: sun_tools_attach_VirtualMachineImpl72* Method: connect73* Signature: (ILjava/lang/String;)I74*/75JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connect76(JNIEnv *env, jclass cls, jint fd, jstring path)77{78jboolean isCopy;79const char* p = GetStringPlatformChars(env, path, &isCopy);80if (p != NULL) {81struct sockaddr_un addr;82int err = 0;8384memset(&addr, 0, sizeof(addr));85addr.sun_family = AF_UNIX;86/* strncpy is safe because addr.sun_path was zero-initialized before. */87strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1);8889if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {90err = errno;91}9293if (isCopy) {94JNU_ReleaseStringPlatformChars(env, path, p);95}9697/*98* If the connect failed then we throw the appropriate exception99* here (can't throw it before releasing the string as can't call100* JNI with pending exception)101*/102if (err != 0) {103if (err == ENOENT) {104JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);105} else {106char* msg = strdup(strerror(err));107JNU_ThrowIOException(env, msg);108if (msg != NULL) {109free(msg);110}111}112}113}114}115116/*117* Class: sun_tools_attach_VirtualMachineImpl118* Method: sendQuitTo119* Signature: (I)V120*/121JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo122(JNIEnv *env, jclass cls, jint pid)123{124if (kill((pid_t)pid, SIGQUIT)) {125JNU_ThrowIOExceptionWithLastError(env, "kill");126}127}128129/*130* Class: sun_tools_attach_VirtualMachineImpl131* Method: checkPermissions132* Signature: (Ljava/lang/String;)V133*/134JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions135(JNIEnv *env, jclass cls, jstring path)136{137jboolean isCopy;138const char* p = GetStringPlatformChars(env, path, &isCopy);139if (p != NULL) {140struct stat sb;141uid_t uid, gid;142int res;143144memset(&sb, 0, sizeof(struct stat));145146/*147* Check that the path is owned by the effective uid/gid of this148* process. Also check that group/other access is not allowed.149*/150uid = geteuid();151gid = getegid();152153res = stat(p, &sb);154if (res != 0) {155/* save errno */156res = errno;157}158159if (res == 0) {160char msg[100];161jboolean isError = JNI_FALSE;162if (sb.st_uid != uid && uid != ROOT_UID) {163snprintf(msg, sizeof(msg),164"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);165isError = JNI_TRUE;166} else if (sb.st_gid != gid && uid != ROOT_UID) {167snprintf(msg, sizeof(msg),168"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);169isError = JNI_TRUE;170} else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {171snprintf(msg, sizeof(msg),172"file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);173isError = JNI_TRUE;174}175if (isError) {176char buf[256];177snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg);178JNU_ThrowIOException(env, buf);179}180} else {181char* msg = strdup(strerror(res));182JNU_ThrowIOException(env, msg);183if (msg != NULL) {184free(msg);185}186}187188if (isCopy) {189JNU_ReleaseStringPlatformChars(env, path, p);190}191}192}193194/*195* Class: sun_tools_attach_VirtualMachineImpl196* Method: close197* Signature: (I)V198*/199JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close200(JNIEnv *env, jclass cls, jint fd)201{202int res;203shutdown(fd, SHUT_RDWR);204RESTARTABLE(close(fd), res);205}206207/*208* Class: sun_tools_attach_VirtualMachineImpl209* Method: read210* Signature: (I[BI)I211*/212JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_read213(JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)214{215unsigned char buf[128];216size_t len = sizeof(buf);217ssize_t n;218219size_t remaining = (size_t)(baLen - off);220if (len > remaining) {221len = remaining;222}223224RESTARTABLE(read(fd, buf, len), n);225if (n == -1) {226JNU_ThrowIOExceptionWithLastError(env, "read");227} else {228if (n == 0) {229n = -1; // EOF230} else {231(*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf));232}233}234return n;235}236237/*238* Class: sun_tools_attach_VirtualMachineImpl239* Method: write240* Signature: (I[B)V241*/242JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_write243(JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen)244{245size_t remaining = bufLen;246do {247unsigned char buf[128];248size_t len = sizeof(buf);249int n;250251if (len > remaining) {252len = remaining;253}254(*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf);255256RESTARTABLE(write(fd, buf, len), n);257if (n > 0) {258off += n;259remaining -= n;260} else {261JNU_ThrowIOExceptionWithLastError(env, "write");262return;263}264265} while (remaining > 0);266}267268/*269* Class: sun_tools_attach_BSDVirtualMachine270* Method: createAttachFile271* Signature: (Ljava.lang.String;)V272*/273JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_createAttachFile0(JNIEnv *env, jclass cls, jstring path)274{275const char* _path;276jboolean isCopy;277int fd, rc;278279_path = GetStringPlatformChars(env, path, &isCopy);280if (_path == NULL) {281JNU_ThrowIOException(env, "Must specify a path");282return;283}284285RESTARTABLE(open(_path, O_CREAT | O_EXCL, S_IWUSR | S_IRUSR), fd);286if (fd == -1) {287/* release p here before we throw an I/O exception */288if (isCopy) {289JNU_ReleaseStringPlatformChars(env, path, _path);290}291JNU_ThrowIOExceptionWithLastError(env, "open");292return;293}294295RESTARTABLE(chown(_path, geteuid(), getegid()), rc);296297RESTARTABLE(close(fd), rc);298299/* release p here */300if (isCopy) {301JNU_ReleaseStringPlatformChars(env, path, _path);302}303}304305/*306* Class: sun_tools_attach_BSDVirtualMachine307* Method: getTempDir308* Signature: (V)Ljava.lang.String;309*/310JNIEXPORT jstring JNICALL Java_sun_tools_attach_VirtualMachineImpl_getTempDir(JNIEnv *env, jclass cls)311{312// This must be hard coded because it's the system's temporary313// directory not the java application's temp directory, ala java.io.tmpdir.314315#ifdef __APPLE__316// macosx has a secure per-user temporary directory.317// Don't cache the result as this is only called once.318char path[PATH_MAX];319int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, path, PATH_MAX);320if (pathSize == 0 || pathSize > PATH_MAX) {321strlcpy(path, "/tmp", sizeof(path));322}323return JNU_NewStringPlatform(env, path);324#else /* __APPLE__ */325return (*env)->NewStringUTF(env, "/tmp");326#endif /* __APPLE__ */327}328329330