1 /* 2 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. 3 * Copyright 2014 SAP AG. 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 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <unistd.h> 35 #include <signal.h> 36 #include <dirent.h> 37 #include <ctype.h> 38 #include <sys/types.h> 39 #include <sys/socket.h> 40 #include <sys/stat.h> 41 #include <sys/un.h> 42 43 /* 44 * Based on 'LinuxVirtualMachine.c'. Non-relevant code has been removed and all 45 * occurrences of the string "Linux" have been replaced by "Aix". 46 */ 47 48 #include "sun_tools_attach_AixVirtualMachine.h" 49 50 #define RESTARTABLE(_cmd, _result) do { \ 51 do { \ 52 _result = _cmd; \ 53 } while((_result == -1) && (errno == EINTR)); \ 54 } while(0) 55 56 57 /* 58 * Class: sun_tools_attach_AixVirtualMachine 59 * Method: socket 60 * Signature: ()I 61 */ 62 JNIEXPORT jint JNICALL Java_sun_tools_attach_AixVirtualMachine_socket 63 (JNIEnv *env, jclass cls) 64 { 65 int fd = socket(PF_UNIX, SOCK_STREAM, 0); 66 if (fd == -1) { 67 JNU_ThrowIOExceptionWithLastError(env, "socket"); 68 } 69 /* added time out values */ 70 else { 71 struct timeval tv; 72 tv.tv_sec = 2 * 60; 73 tv.tv_usec = 0; 74 75 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)); 76 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv)); 77 } 78 return (jint)fd; 79 } 80 81 /* 82 * Class: sun_tools_attach_AixVirtualMachine 83 * Method: connect 84 * Signature: (ILjava/lang/String;)I 85 */ 86 JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_connect 87 (JNIEnv *env, jclass cls, jint fd, jstring path) 88 { 89 jboolean isCopy; 90 const char* p = GetStringPlatformChars(env, path, &isCopy); 91 if (p != NULL) { 92 struct sockaddr_un addr; 93 int err = 0; 94 95 memset(&addr, 0, sizeof(addr)); 96 addr.sun_family = AF_UNIX; 97 /* strncpy is safe because addr.sun_path was zero-initialized before. */ 98 strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1); 99 /* We must call bind with the actual socketaddr length. This is obligatory for AS400. */ 100 if (connect(fd, (struct sockaddr*)&addr, SUN_LEN(&addr)) == -1) { 101 err = errno; 102 } 103 104 if (isCopy) { 105 JNU_ReleaseStringPlatformChars(env, path, p); 106 } 107 108 /* 109 * If the connect failed then we throw the appropriate exception 110 * here (can't throw it before releasing the string as can't call 111 * JNI with pending exception) 112 */ 113 if (err != 0) { 114 if (err == ENOENT) { 115 JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL); 116 } else { 117 char* msg = strdup(strerror(err)); 118 JNU_ThrowIOException(env, msg); 119 if (msg != NULL) { 120 free(msg); 121 } 122 } 123 } 124 } 125 } 126 127 128 /* 129 * Structure and callback function used to send a QUIT signal to all 130 * children of a given process 131 */ 132 typedef struct { 133 pid_t ppid; 134 } SendQuitContext; 135 136 static void SendQuitCallback(const pid_t pid, void* user_data) { 137 SendQuitContext* context = (SendQuitContext*)user_data; 138 pid_t parent = getParent(pid); 139 if (parent == context->ppid) { 140 kill(pid, SIGQUIT); 141 } 142 } 143 144 /* 145 * Class: sun_tools_attach_AixVirtualMachine 146 * Method: sendQuitTo 147 * Signature: (I)V 148 */ 149 JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_sendQuitTo 150 (JNIEnv *env, jclass cls, jint pid) 151 { 152 if (kill((pid_t)pid, SIGQUIT)) { 153 JNU_ThrowIOExceptionWithLastError(env, "kill"); 154 } 155 } 156 157 /* 158 * Class: sun_tools_attach_AixVirtualMachine 159 * Method: checkPermissions 160 * Signature: (Ljava/lang/String;)V 161 */ 162 JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_checkPermissions 163 (JNIEnv *env, jclass cls, jstring path) 164 { 165 jboolean isCopy; 166 const char* p = GetStringPlatformChars(env, path, &isCopy); 167 if (p != NULL) { 168 struct stat64 sb; 169 uid_t uid, gid; 170 int res; 171 /* added missing initialization of the stat64 buffer */ 172 memset(&sb, 0, sizeof(struct stat64)); 173 174 /* 175 * Check that the path is owned by the effective uid/gid of this 176 * process. Also check that group/other access is not allowed. 177 */ 178 uid = geteuid(); 179 gid = getegid(); 180 181 res = stat64(p, &sb); 182 if (res != 0) { 183 /* save errno */ 184 res = errno; 185 } 186 187 /* release p here before we throw an I/O exception */ 188 if (isCopy) { 189 JNU_ReleaseStringPlatformChars(env, path, p); 190 } 191 192 if (res == 0) { 193 if ( (sb.st_uid != uid) || (sb.st_gid != gid) || 194 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) { 195 JNU_ThrowIOException(env, "well-known file is not secure"); 196 } 197 } else { 198 char* msg = strdup(strerror(res)); 199 JNU_ThrowIOException(env, msg); 200 if (msg != NULL) { 201 free(msg); 202 } 203 } 204 } 205 } 206 207 /* 208 * Class: sun_tools_attach_AixVirtualMachine 209 * Method: close 210 * Signature: (I)V 211 */ 212 JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_close 213 (JNIEnv *env, jclass cls, jint fd) 214 { 215 int res; 216 /* Fixed deadlock when this call of close by the client is not seen by the attach server 217 * which has accepted the (very short) connection already and is waiting for the request. But read don't get a byte, 218 * because the close is lost without shutdown. 219 */ 220 shutdown(fd, 2); 221 RESTARTABLE(close(fd), res); 222 } 223 224 /* 225 * Class: sun_tools_attach_AixVirtualMachine 226 * Method: read 227 * Signature: (I[BI)I 228 */ 229 JNIEXPORT jint JNICALL Java_sun_tools_attach_AixVirtualMachine_read 230 (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen) 231 { 232 unsigned char buf[128]; 233 size_t len = sizeof(buf); 234 ssize_t n; 235 236 size_t remaining = (size_t)(baLen - off); 237 if (len > remaining) { 238 len = remaining; 239 } 240 241 RESTARTABLE(read(fd, buf+off, len), n); 242 if (n == -1) { 243 JNU_ThrowIOExceptionWithLastError(env, "read"); 244 } else { 245 if (n == 0) { 246 n = -1; // EOF 247 } else { 248 (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf+off)); 249 } 250 } 251 return n; 252 } 253 254 /* 255 * Class: sun_tools_attach_AixVirtualMachine 256 * Method: write 257 * Signature: (I[B)V 258 */ 259 JNIEXPORT void JNICALL Java_sun_tools_attach_AixVirtualMachine_write 260 (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen) 261 { 262 size_t remaining = bufLen; 263 do { 264 unsigned char buf[128]; 265 size_t len = sizeof(buf); 266 int n; 267 268 if (len > remaining) { 269 len = remaining; 270 } 271 (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf); 272 273 RESTARTABLE(write(fd, buf, len), n); 274 if (n > 0) { 275 off += n; 276 remaining -= n; 277 } else { 278 JNU_ThrowIOExceptionWithLastError(env, "write"); 279 return; 280 } 281 282 } while (remaining > 0); 283 }