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