1 /* 2 * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "jni_util.h" 27 28 #include <sys/socket.h> 29 #include <sys/stat.h> 30 #include <sys/types.h> 31 #include <sys/un.h> 32 #include <errno.h> 33 #include <signal.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "sun_tools_attach_VirtualMachineImpl.h" 40 41 #define RESTARTABLE(_cmd, _result) do { \ 42 do { \ 43 _result = _cmd; \ 44 } while((_result == -1) && (errno == EINTR)); \ 45 } while(0) 46 47 /* 48 * Declare library specific JNI_Onload entry if static build 49 */ 50 DEF_STATIC_JNI_OnLoad 51 52 /* 53 * Class: sun_tools_attach_VirtualMachineImpl 54 * Method: socket 55 * Signature: ()I 56 */ 57 JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_socket 58 (JNIEnv *env, jclass cls) 59 { 60 int fd = socket(PF_UNIX, SOCK_STREAM, 0); 61 if (fd == -1) { 62 JNU_ThrowIOExceptionWithLastError(env, "socket"); 63 } 64 return (jint)fd; 65 } 66 67 /* 68 * Class: sun_tools_attach_VirtualMachineImpl 69 * Method: connect 70 * Signature: (ILjava/lang/String;)I 71 */ 72 JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connect 73 (JNIEnv *env, jclass cls, jint fd, jstring path) 74 { 75 jboolean isCopy; 76 const char* p = GetStringPlatformChars(env, path, &isCopy); 77 if (p != NULL) { 78 struct sockaddr_un addr; 79 int err = 0; 80 81 memset(&addr, 0, sizeof(addr)); 82 addr.sun_family = AF_UNIX; 83 /* strncpy is safe because addr.sun_path was zero-initialized before. */ 84 strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1); 85 86 if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { 87 err = errno; 88 } 89 90 if (isCopy) { 91 JNU_ReleaseStringPlatformChars(env, path, p); 92 } 93 94 /* 95 * If the connect failed then we throw the appropriate exception 96 * here (can't throw it before releasing the string as can't call 97 * JNI with pending exception) 98 */ 99 if (err != 0) { 100 if (err == ENOENT) { 101 JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL); 102 } else { 103 char* msg = strdup(strerror(err)); 104 JNU_ThrowIOException(env, msg); 105 if (msg != NULL) { 106 free(msg); 107 } 108 } 109 } 110 } 111 } 112 113 /* 114 * Class: sun_tools_attach_VirtualMachineImpl 115 * Method: sendQuitTo 116 * Signature: (I)V 117 */ 118 JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo 119 (JNIEnv *env, jclass cls, jint pid) 120 { 121 if (kill((pid_t)pid, SIGQUIT)) { 122 JNU_ThrowIOExceptionWithLastError(env, "kill"); 123 } 124 } 125 126 /* 127 * Class: sun_tools_attach_VirtualMachineImpl 128 * Method: checkPermissions 129 * Signature: (Ljava/lang/String;)V 130 */ 131 JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions 132 (JNIEnv *env, jclass cls, jstring path) 133 { 134 jboolean isCopy; 135 const char* p = GetStringPlatformChars(env, path, &isCopy); 136 if (p != NULL) { 137 struct stat64 sb; 138 uid_t uid, gid; 139 int res; 140 141 memset(&sb, 0, sizeof(struct stat64)); 142 143 /* 144 * Check that the path is owned by the effective uid/gid of this 145 * process. Also check that group/other access is not allowed. 146 */ 147 uid = geteuid(); 148 gid = getegid(); 149 150 res = stat64(p, &sb); 151 if (res != 0) { 152 /* save errno */ 153 res = errno; 154 } 155 156 if (res == 0) { 157 char msg[100]; 158 jboolean isError = JNI_FALSE; 159 if (sb.st_uid != uid) { 160 snprintf(msg, sizeof(msg), 161 "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid); 162 isError = JNI_TRUE; 163 } else if (sb.st_gid != gid) { 164 snprintf(msg, sizeof(msg), 165 "file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid); 166 isError = JNI_TRUE; 167 } else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) { 168 snprintf(msg, sizeof(msg), 169 "file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777); 170 isError = JNI_TRUE; 171 } 172 if (isError) { 173 char buf[256]; 174 snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg); 175 JNU_ThrowIOException(env, buf); 176 } 177 } else { 178 char* msg = strdup(strerror(res)); 179 JNU_ThrowIOException(env, msg); 180 if (msg != NULL) { 181 free(msg); 182 } 183 } 184 185 if (isCopy) { 186 JNU_ReleaseStringPlatformChars(env, path, p); 187 } 188 } 189 } 190 191 /* 192 * Class: sun_tools_attach_VirtualMachineImpl 193 * Method: close 194 * Signature: (I)V 195 */ 196 JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close 197 (JNIEnv *env, jclass cls, jint fd) 198 { 199 int res; 200 shutdown(fd, SHUT_RDWR); 201 RESTARTABLE(close(fd), res); 202 } 203 204 /* 205 * Class: sun_tools_attach_VirtualMachineImpl 206 * Method: read 207 * Signature: (I[BI)I 208 */ 209 JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_read 210 (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen) 211 { 212 unsigned char buf[128]; 213 size_t len = sizeof(buf); 214 ssize_t n; 215 216 size_t remaining = (size_t)(baLen - off); 217 if (len > remaining) { 218 len = remaining; 219 } 220 221 RESTARTABLE(read(fd, buf, len), n); 222 if (n == -1) { 223 JNU_ThrowIOExceptionWithLastError(env, "read"); 224 } else { 225 if (n == 0) { 226 n = -1; // EOF 227 } else { 228 (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf)); 229 } 230 } 231 return n; 232 } 233 234 /* 235 * Class: sun_tools_attach_VirtualMachineImpl 236 * Method: write 237 * Signature: (I[B)V 238 */ 239 JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_write 240 (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen) 241 { 242 size_t remaining = bufLen; 243 do { 244 unsigned char buf[128]; 245 size_t len = sizeof(buf); 246 int n; 247 248 if (len > remaining) { 249 len = remaining; 250 } 251 (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf); 252 253 RESTARTABLE(write(fd, buf, len), n); 254 if (n > 0) { 255 off += n; 256 remaining -= n; 257 } else { 258 JNU_ThrowIOExceptionWithLastError(env, "write"); 259 return; 260 } 261 262 } while (remaining > 0); 263 }