1 /* 2 * Copyright (c) 2005, 2012, 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.h" 27 #include "jni_util.h" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <errno.h> 33 #include <unistd.h> 34 #include <signal.h> 35 #include <dirent.h> 36 #include <ctype.h> 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 #include <sys/stat.h> 40 #include <sys/syslimits.h> 41 #include <sys/un.h> 42 #include <fcntl.h> 43 44 #include "sun_tools_attach_BsdVirtualMachine.h" 45 46 #define RESTARTABLE(_cmd, _result) do { \ 47 do { \ 48 _result = _cmd; \ 49 } while((_result == -1) && (errno == EINTR)); \ 50 } while(0) 51 52 /* 53 * Class: sun_tools_attach_BsdVirtualMachine 54 * Method: socket 55 * Signature: ()I 56 */ 57 JNIEXPORT jint JNICALL Java_sun_tools_attach_BsdVirtualMachine_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_BsdVirtualMachine 69 * Method: connect 70 * Signature: (ILjava/lang/String;)I 71 */ 72 JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_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 addr.sun_family = AF_UNIX; 82 strcpy(addr.sun_path, p); 83 84 if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { 85 err = errno; 86 } 87 88 if (isCopy) { 89 JNU_ReleaseStringPlatformChars(env, path, p); 90 } 91 92 /* 93 * If the connect failed then we throw the appropriate exception 94 * here (can't throw it before releasing the string as can't call 95 * JNI with pending exception) 96 */ 97 if (err != 0) { 98 if (err == ENOENT) { 99 JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL); 100 } else { 101 char* msg = strdup(strerror(err)); 102 JNU_ThrowIOException(env, msg); 103 if (msg != NULL) { 104 free(msg); 105 } 106 } 107 } 108 } 109 } 110 111 /* 112 * Class: sun_tools_attach_BsdVirtualMachine 113 * Method: sendQuitTo 114 * Signature: (I)V 115 */ 116 JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_sendQuitTo 117 (JNIEnv *env, jclass cls, jint pid) 118 { 119 if (kill((pid_t)pid, SIGQUIT)) { 120 JNU_ThrowIOExceptionWithLastError(env, "kill"); 121 } 122 } 123 124 /* 125 * Class: sun_tools_attach_BsdVirtualMachine 126 * Method: checkPermissions 127 * Signature: (Ljava/lang/String;)V 128 */ 129 JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_checkPermissions 130 (JNIEnv *env, jclass cls, jstring path) 131 { 132 jboolean isCopy; 133 const char* p = GetStringPlatformChars(env, path, &isCopy); 134 if (p != NULL) { 135 struct stat sb; 136 uid_t uid, gid; 137 int res; 138 139 /* 140 * Check that the path is owned by the effective uid/gid of this 141 * process. Also check that group/other access is not allowed. 142 */ 143 uid = geteuid(); 144 gid = getegid(); 145 146 res = stat(p, &sb); 147 if (res != 0) { 148 /* save errno */ 149 res = errno; 150 } 151 152 /* release p here before we throw an I/O exception */ 153 if (isCopy) { 154 JNU_ReleaseStringPlatformChars(env, path, p); 155 } 156 157 if (res == 0) { 158 if ( (sb.st_uid != uid) || (sb.st_gid != gid) || 159 ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) { 160 JNU_ThrowIOException(env, "well-known file is not secure"); 161 } 162 } else { 163 char* msg = strdup(strerror(res)); 164 JNU_ThrowIOException(env, msg); 165 if (msg != NULL) { 166 free(msg); 167 } 168 } 169 } 170 } 171 172 /* 173 * Class: sun_tools_attach_BsdVirtualMachine 174 * Method: close 175 * Signature: (I)V 176 */ 177 JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_close 178 (JNIEnv *env, jclass cls, jint fd) 179 { 180 int res; 181 RESTARTABLE(close(fd), res); 182 } 183 184 /* 185 * Class: sun_tools_attach_BsdVirtualMachine 186 * Method: read 187 * Signature: (I[BI)I 188 */ 189 JNIEXPORT jint JNICALL Java_sun_tools_attach_BsdVirtualMachine_read 190 (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen) 191 { 192 unsigned char buf[128]; 193 size_t len = sizeof(buf); 194 ssize_t n; 195 196 size_t remaining = (size_t)(baLen - off); 197 if (len > remaining) { 198 len = remaining; 199 } 200 201 RESTARTABLE(read(fd, buf+off, len), n); 202 if (n == -1) { 203 JNU_ThrowIOExceptionWithLastError(env, "read"); 204 } else { 205 if (n == 0) { 206 n = -1; // EOF 207 } else { 208 (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf+off)); 209 } 210 } 211 return n; 212 } 213 214 /* 215 * Class: sun_tools_attach_BsdVirtualMachine 216 * Method: write 217 * Signature: (I[B)V 218 */ 219 JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_write 220 (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen) 221 { 222 size_t remaining = bufLen; 223 do { 224 unsigned char buf[128]; 225 size_t len = sizeof(buf); 226 int n; 227 228 if (len > remaining) { 229 len = remaining; 230 } 231 (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf); 232 233 RESTARTABLE(write(fd, buf, len), n); 234 if (n > 0) { 235 off += n; 236 remaining -= n; 237 } else { 238 JNU_ThrowIOExceptionWithLastError(env, "write"); 239 return; 240 } 241 242 } while (remaining > 0); 243 } 244 245 /* 246 * Class: sun_tools_attach_BSDVirtualMachine 247 * Method: createAttachFile 248 * Signature: (Ljava.lang.String;)V 249 */ 250 JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_createAttachFile(JNIEnv *env, jclass cls, jstring path) 251 { 252 const char* _path; 253 jboolean isCopy; 254 int fd, rc; 255 256 _path = GetStringPlatformChars(env, path, &isCopy); 257 if (_path == NULL) { 258 JNU_ThrowIOException(env, "Must specify a path"); 259 return; 260 } 261 262 RESTARTABLE(open(_path, O_CREAT | O_EXCL, S_IWUSR | S_IRUSR), fd); 263 if (fd == -1) { 264 /* release p here before we throw an I/O exception */ 265 if (isCopy) { 266 JNU_ReleaseStringPlatformChars(env, path, _path); 267 } 268 JNU_ThrowIOExceptionWithLastError(env, "open"); 269 return; 270 } 271 272 RESTARTABLE(chown(_path, geteuid(), getegid()), rc); 273 274 RESTARTABLE(close(fd), rc); 275 276 /* release p here */ 277 if (isCopy) { 278 JNU_ReleaseStringPlatformChars(env, path, _path); 279 } 280 } 281 282 /* 283 * Class: sun_tools_attach_BSDVirtualMachine 284 * Method: getTempDir 285 * Signature: (V)Ljava.lang.String; 286 */ 287 JNIEXPORT jstring JNICALL Java_sun_tools_attach_BsdVirtualMachine_getTempDir(JNIEnv *env, jclass cls) 288 { 289 // This must be hard coded because it's the system's temporary 290 // directory not the java application's temp directory, ala java.io.tmpdir. 291 292 #ifdef __APPLE__ 293 // macosx has a secure per-user temporary directory 294 static char *temp_path = NULL; 295 char temp_path_storage[PATH_MAX]; 296 if (temp_path == NULL) { 297 int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, temp_path_storage, PATH_MAX); 298 if (pathSize == 0 || pathSize > PATH_MAX) { 299 strlcpy(temp_path_storage, "/tmp", sizeof(temp_path_storage)); 300 } 301 temp_path = temp_path_storage; 302 } 303 return JNU_NewStringPlatform(env, temp_path); 304 #else /* __APPLE__ */ 305 return (*env)->NewStringUTF(env, "/tmp"); 306 #endif /* __APPLE__ */ 307 }