/* * Class: sun_tools_attach_BSDVirtualMachine * Method: createAttachFile * Signature: (Ljava.lang.String;)V */ JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_createAttachFile(JNIEnv *env, jclass cls, jstring path) { const char* _path; jboolean isCopy; int fd, rc; _path = GetStringPlatformChars(env, path, &isCopy); if (_path == NULL) { JNU_ThrowIOException(env, "Must specify a path"); return; } RESTARTABLE(open(_path, O_CREAT | O_EXCL, S_IWUSR | S_IRUSR), fd); if (fd == -1) { /* release p here before we throw an I/O exception */ if (isCopy) { JNU_ReleaseStringPlatformChars(env, path, _path); } JNU_ThrowIOExceptionWithLastError(env, "open"); return; } RESTARTABLE(chown(_path, geteuid(), getegid()), rc); RESTARTABLE(close(fd), rc); /* release p here */ if (isCopy) { JNU_ReleaseStringPlatformChars(env, path, _path); } }
// Open the directory of the given path and validate it. // Return a DIR * of the open directory. static DIR *open_directory_secure(const char* dirname) { // Open the directory using open() so that it can be verified // to be secure by calling is_dirfd_secure(), opendir() and then check // to see if they are the same file system object. This method does not // introduce a window of opportunity for the directory to be attacked that // calling opendir() and is_directory_secure() does. int result; DIR *dirp = NULL; // No O_NOFOLLOW defined at buildtime, and it is not documented for open; // so provide a workaround in this case. #ifdef O_NOFOLLOW RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); #else // workaround (jdk6 coding) RESTARTABLE(::open_o_nofollow(dirname, O_RDONLY), result); #endif if (result == OS_ERR) { // Directory doesn't exist or is a symlink, so there is nothing to cleanup. if (PrintMiscellaneous && Verbose) { if (errno == ELOOP) { warning("directory %s is a symlink and is not secure\n", dirname); } else { warning("could not open directory %s: %s\n", dirname, strerror(errno)); } } return dirp; } int fd = result; // Determine if the open directory is secure. if (!is_dirfd_secure(fd)) { // The directory is not a secure directory. os::close(fd); return dirp; } // Open the directory. dirp = ::opendir(dirname); if (dirp == NULL) { // The directory doesn't exist, close fd and return. os::close(fd); return dirp; } // Check to make sure fd and dirp are referencing the same file system object. if (!is_same_fsobject(fd, dirp->dd_fd)) { // The directory is not secure. os::close(fd); os::closedir(dirp); dirp = NULL; return dirp; } // Close initial open now that we know directory is secure os::close(fd); return dirp; }
JNIEXPORT void JNICALL Java_sun_net_spi_SdpProvider_convert(JNIEnv *env, jclass cls, jint fd) { #ifdef PROTO_SDP int domain = ipv6_available() ? AF_INET6 : AF_INET; int s = socket(domain, SOCK_STREAM, PROTO_SDP); if (s < 0) { JNU_ThrowIOExceptionWithLastError(env, "socket"); } else { int arg, len, res; struct linger linger; /* copy socket options that are relevant to SDP */ len = sizeof(arg); if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, &len) == 0) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, len); len = sizeof(arg); if (getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, &len) == 0) setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, len); len = sizeof(linger); if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (void*)&linger, &len) == 0) setsockopt(s, SOL_SOCKET, SO_LINGER, (char*)&linger, len); RESTARTABLE(dup2(s, fd), res); if (res < 0) JNU_ThrowIOExceptionWithLastError(env, "dup2"); RESTARTABLE(close(s), res); } #else JNU_ThrowInternalError(env, "should not reach here"); #endif }
/** * Converts an existing file descriptor, that references an unbound TCP socket, * to SDP. */ JNIEXPORT void JNICALL Java_sun_net_sdp_SdpSupport_convert0(JNIEnv *env, jclass cls, int fd) { int s = create(env); if (s >= 0) { socklen_t len; int arg, res; struct linger linger; /* copy socket options that are relevant to SDP */ len = sizeof(arg); if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, &len) == 0) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, len); len = sizeof(arg); if (getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, &len) == 0) setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, len); len = sizeof(linger); if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (void*)&linger, &len) == 0) setsockopt(s, SOL_SOCKET, SO_LINGER, (char*)&linger, len); RESTARTABLE(dup2(s, fd), res); if (res < 0) JNU_ThrowIOExceptionWithLastError(env, "dup2"); RESTARTABLE(close(s), res); } }
int BsdAttachListener::init() { char path[UNIX_PATH_MAX]; // socket file char initial_path[UNIX_PATH_MAX]; // socket file during setup int listener; // listener socket (file descriptor) // register function to cleanup ::atexit(listener_cleanup); int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", os::get_temp_directory(), os::current_process_id()); if (n < (int)UNIX_PATH_MAX) { n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); } if (n >= (int)UNIX_PATH_MAX) { return -1; } // create the listener socket listener = ::socket(PF_UNIX, SOCK_STREAM, 0); if (listener == -1) { return -1; } // bind socket struct sockaddr_un addr; addr.sun_family = AF_UNIX; strcpy(addr.sun_path, initial_path); ::unlink(initial_path); int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); if (res == -1) { ::close(listener); return -1; } // put in listen mode, set permissions, and rename into place res = ::listen(listener, 5); if (res == 0) { RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res); if (res == 0) { // make sure the file is owned by the effective user and effective group // (this is the default on linux, but not on mac os) RESTARTABLE(::chown(initial_path, geteuid(), getegid()), res); if (res == 0) { res = ::rename(initial_path, path); } } } if (res == -1) { ::close(listener); ::unlink(initial_path); return -1; } set_path(path); set_listener(listener); return 0; }
// check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. // static bool is_directory_secure(const char* path) { struct stat statbuf; int result = 0; RESTARTABLE(::lstat(path, &statbuf), result); if (result == OS_ERR) { return false; } // the path exists, now check it's mode if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) { // the path represents a link or some non-directory file type, // which is not what we expected. declare it insecure. // return false; } else { // we have an existing directory, check if the permissions are safe. // if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) { // the directory is open for writing and could be subjected // to a symlnk attack. declare it insecure. // return false; } } return true; }
/* * Class: sun_tools_attach_LinuxVirtualMachine * Method: write * Signature: (I[B)V */ JNIEXPORT void JNICALL Java_sun_tools_attach_LinuxVirtualMachine_write (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen) { size_t remaining = bufLen; do { unsigned char buf[128]; size_t len = sizeof(buf); int n; if (len > remaining) { len = remaining; } (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf); RESTARTABLE(write(fd, buf, len), n); if (n > 0) { off += n; remaining -= n; } else { JNU_ThrowIOExceptionWithLastError(env, "write"); return; } } while (remaining > 0); }
// Create the door int SolarisAttachListener::create_door() { char door_path[PATH_MAX+1]; char initial_path[PATH_MAX+1]; int fd, res; // register exit function ::atexit(listener_cleanup); // create the door descriptor int dd = ::door_create(enqueue_proc, NULL, 0); if (dd < 0) { return -1; } // create initial file to attach door descriptor snprintf(door_path, sizeof(door_path), "%s/.java_pid%d", os::get_temp_directory(), os::current_process_id()); snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path); RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd); if (fd == -1) { debug_only(warning("attempt to create %s failed", initial_path)); ::door_revoke(dd); return -1; } assert(fd >= 0, "bad file descriptor"); ::close(fd); // attach the door descriptor to the file if ((res = ::fattach(dd, initial_path)) == -1) { // if busy then detach and try again if (errno == EBUSY) { ::fdetach(initial_path); res = ::fattach(dd, initial_path); } if (res == -1) { ::door_revoke(dd); dd = -1; } } // rename file so that clients can attach if (dd >= 0) { if (::rename(initial_path, door_path) == -1) { ::close(dd); ::fdetach(initial_path); dd = -1; } } if (dd >= 0) { set_door_descriptor(dd); set_door_path(door_path); } else { // unable to create door, attach it to file, or rename file into place ::unlink(initial_path); return -1; } return 0; }
/* attach to given JVM */ jvm_t* jvm_attach(pid_t pid) { jvm_t* jvm; int door_fd, attach_fd, i; jvm = (jvm_t*) calloc(1, sizeof(jvm_t)); if (jvm == NULL) { set_jvm_error(JVM_ERR_OUT_OF_MEMORY); print_debug("calloc failed in %s at %d\n", __FILE__, __LINE__); return NULL; } jvm->pid = pid; attach_fd = -1; door_fd = open_door(pid); if (door_fd < 0) { print_debug("trying to create attach file\n"); if ((attach_fd = create_attach_file(pid)) < 0) { goto quit; } /* send QUIT signal to the target so that it will * check for the attach file. */ if (send_sigquit(pid) != 0) { set_jvm_error(JVM_ERR_CANT_SIGNAL); print_debug("sending SIGQUIT failed\n"); goto quit; } /* give the target VM time to start the attach mechanism */ do { int res; RESTARTABLE(poll(0, 0, 200), res); door_fd = open_door(pid); i++; } while (i <= 50 && door_fd == -1); if (door_fd < 0) { print_debug("Unable to open door to process %d\n", pid); goto quit; } } quit: if (attach_fd >= 0) { file_close(attach_fd); delete_attach_file(jvm->pid); } if (door_fd >= 0) { jvm->door_fd = door_fd; clear_jvm_error(); } else { free(jvm); jvm = NULL; } return jvm; }
// save the specified memory region to the given file // // Note: this function might be called from signal handler (by os::abort()), // don't allocate heap memory. // static void save_memory_to_file(char* addr, size_t size) { const char* destfile = PerfMemory::get_perfdata_file_path(); assert(destfile[0] != '\0', "invalid PerfData file path"); int result; RESTARTABLE(::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE), result);; if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not create Perfdata save file: %s: %s\n", destfile, strerror(errno)); } } else { int fd = result; for (size_t remaining = size; remaining > 0;) { RESTARTABLE(::write(fd, addr, remaining), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("Could not write Perfdata save file: %s: %s\n", destfile, strerror(errno)); } break; } remaining -= (size_t)result; addr += result; } RESTARTABLE(::close(fd), result); if (PrintMiscellaneous && Verbose) { if (result == OS_ERR) { warning("Could not close %s: %s\n", destfile, strerror(errno)); } } } FREE_C_HEAP_ARRAY(char, destfile, mtInternal); }
// Check to make sure fd1 and fd2 are referencing the same file system object. static bool is_same_fsobject(int fd1, int fd2) { struct stat statbuf1; struct stat statbuf2; int result = 0; RESTARTABLE(::fstat(fd1, &statbuf1), result); if (result == OS_ERR) { return false; } RESTARTABLE(::fstat(fd2, &statbuf2), result); if (result == OS_ERR) { return false; } if ((statbuf1.st_ino == statbuf2.st_ino) && (statbuf1.st_dev == statbuf2.st_dev)) { return true; } else { return false; } }
FD handleOpen(const char *path, int oflag, int mode) { FD fd; RESTARTABLE(open64(path, oflag, mode), fd); if (fd != -1) { struct stat64 buf64; int result; RESTARTABLE(fstat64(fd, &buf64), result); if (result != -1) { if (S_ISDIR(buf64.st_mode)) { close(fd); errno = EISDIR; fd = -1; } } else { close(fd); fd = -1; } } return fd; }
// (Taken over from Solaris to support the O_NOFOLLOW case on AIX.) // Check if the given directory file descriptor is considered a secure // directory for the backing store files. Returns true if the directory // exists and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. static bool is_dirfd_secure(int dir_fd) { struct stat statbuf; int result = 0; RESTARTABLE(::fstat(dir_fd, &statbuf), result); if (result == OS_ERR) { return false; } // The path exists, now check its mode. return is_statbuf_secure(&statbuf); }
// Check if the given path is considered a secure directory for // the backing store files. Returns true if the directory exists // and is considered a secure location. Returns false if the path // is a symbolic link or if an error occurred. static bool is_directory_secure(const char* path) { struct stat statbuf; int result = 0; RESTARTABLE(::lstat(path, &statbuf), result); if (result == OS_ERR) { return false; } // The path exists, see if it is secure. return is_statbuf_secure(&statbuf); }
inline int hpi::socket_available(int fd, long *pbytes) { if (fd < 0) return OS_OK; int ret; RESTARTABLE(::ioctl(fd, FIONREAD, pbytes), ret); //%% note ioctl can return 0 when successful, JVM_SocketAvailable // is expected to return 0 on failure and 1 on success to the jdk. return (ret == OS_ERR) ? 0 : 1; }
// If the file .attach_pid<pid> exists in the working directory // or /tmp then this is the trigger to start the attach mechanism bool AttachListener::is_init_trigger() { if (init_at_startup() || is_initialized()) { return false; // initialized at startup or already initialized } char fn[32]; sprintf(fn, ".attach_pid%d", os::current_process_id()); int ret; struct stat st; RESTARTABLE(::stat(fn,&st),ret); if (ret == -1) { sprintf(fn,"%s/.attach_pid%d",os::get_temp_directory(),os::current_process_id()); RESTARTABLE(::stat(fn,&st),ret); } if (ret == 0) { // simple check to avoid starting the attach mechanism when // a bogus user creates the file if (st.st_uid == geteuid()) { init(); return true; } } return false; }
JNIEXPORT jint JNICALL Java_jdk_internal_jimage_concurrent_ConcurrentPReader_pread(JNIEnv *env, jclass clazz, jobject fdo, jlong address, jint len, jlong offset) { jint fd = (*env)->GetIntField(env, fdo, fd_fdID); void *buf = (void *)jlong_to_ptr(address); int res; RESTARTABLE(pread64(fd, buf, len, offset), res); if (res == -1) { JNU_ThrowIOExceptionWithLastError(env, "pread failed"); } return res; }
// Dequeue an operation // // In the Linux implementation there is only a single operation and clients // cannot queue commands (except at the socket level). // LinuxAttachOperation* LinuxAttachListener::dequeue() { for (;;) { int s; // wait for client to connect #ifdef AZ_PROXIED RESTARTABLE(proxy_invoke_remote_VMAttachAccept(listener()), s); #else // !AZ_PROXIED struct sockaddr addr; socklen_t len = sizeof(addr); RESTARTABLE(::accept(listener(), &addr, &len), s); #endif // !AZ_PROXIED if (s == -1) { return NULL; // log a warning? } #ifdef AZ_PROXIED if (proxy_invoke_remote_VMAttachCheckCredentials(s) == -1) { int res; RESTARTABLE(VM_ATTACH_CLOSE(s), res); continue; } #else // !AZ_PROXIED // get the credentials of the peer and check the effective uid/guid // - check with jeff on this. struct ucred cred_info; socklen_t optlen = sizeof(cred_info); if (::getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void*)&cred_info, &optlen) == -1) { int res; RESTARTABLE(VM_ATTACH_CLOSE(s),res); continue; } uid_t euid = geteuid(); gid_t egid = getegid(); if (cred_info.uid != euid || cred_info.gid != egid) { int res; RESTARTABLE(VM_ATTACH_CLOSE(s),res); continue; } #endif // !AZ_PROXIED // peer credential look okay so we read the request LinuxAttachOperation* op = read_request(s); if (op == NULL) { int res; RESTARTABLE(VM_ATTACH_CLOSE(s),res); continue; } else { return op; } } }
void AttachListener::vm_start() { char fn[PATH_MAX+1]; struct stat64 st; int ret; int n = snprintf(fn, sizeof(fn), "%s/.java_pid%d", os::get_temp_directory(), os::current_process_id()); assert(n < sizeof(fn), "java_pid file name buffer overflow"); RESTARTABLE(::stat64(fn, &st), ret); if (ret == 0) { ret = ::unlink(fn); if (ret == -1) { debug_only(warning("failed to remove stale attach pid file at %s", fn)); } } }
void LinuxAttachOperation::complete(jint result, bufferedStream* st) { JavaThread* thread = JavaThread::current(); ThreadBlockInVM tbivm(thread,"complete attach operation"); // write operation result char msg[32]; sprintf(msg, "%d\n", result); int rc = LinuxAttachListener::write_fully(this->socket(), msg, strlen(msg)); // write any result data if (rc == 0) { LinuxAttachListener::write_fully(this->socket(), (char*) st->base(), st->size()); VM_ATTACH_SHUTDOWN(this->socket(),2); } // done RESTARTABLE(VM_ATTACH_CLOSE(this->socket()),rc); delete this; }
// Enqueue an operation void SolarisAttachListener::enqueue(SolarisAttachOperation* op) { // lock list int res = os::Solaris::mutex_lock(mutex()); assert(res == 0, "mutex_lock failed"); // enqueue at tail op->set_next(NULL); if (head() == NULL) { set_head(op); } else { tail()->set_next(op); } set_tail(op); // wakeup the attach listener RESTARTABLE(::sema_post(wakeup()), res); assert(res == 0, "sema_post failed"); // unlock os::Solaris::mutex_unlock(mutex()); }
// Check if the given file descriptor is considered a secure. static bool is_file_secure(int fd, const char *filename) { int result; struct stat statbuf; // Determine if the file is secure. RESTARTABLE(::fstat(fd, &statbuf), result); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("fstat failed on %s: %s\n", filename, strerror(errno)); } return false; } if (statbuf.st_nlink > 1) { // A file with multiple links is not expected. if (PrintMiscellaneous && Verbose) { warning("file %s has multiple links\n", filename); } return false; } return true; }
// Dequeue an operation // // In the Bsd implementation there is only a single operation and clients // cannot queue commands (except at the socket level). // BsdAttachOperation* BsdAttachListener::dequeue() { for (;;) { int s; // wait for client to connect struct sockaddr addr; socklen_t len = sizeof(addr); RESTARTABLE(::accept(listener(), &addr, &len), s); if (s == -1) { return NULL; // log a warning? } // get the credentials of the peer and check the effective uid/guid // - check with jeff on this. uid_t puid; gid_t pgid; if (::getpeereid(s, &puid, &pgid) != 0) { ::close(s); continue; } uid_t euid = geteuid(); gid_t egid = getegid(); if (puid != euid || pgid != egid) { ::close(s); continue; } // peer credential look okay so we read the request BsdAttachOperation* op = read_request(s); if (op == NULL) { ::close(s); continue; } else { return op; } } }
// Dequeue an operation // // In the Linux implementation there is only a single operation and clients // cannot queue commands (except at the socket level). // LinuxAttachOperation* LinuxAttachListener::dequeue() { for (;;) { int s; // wait for client to connect struct sockaddr addr; socklen_t len = sizeof(addr); RESTARTABLE(::accept(listener(), &addr, &len), s); if (s == -1) { return NULL; // log a warning? } // get the credentials of the peer and check the effective uid/guid // - check with jeff on this. struct ucred cred_info; socklen_t optlen = sizeof(cred_info); if (::getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void*)&cred_info, &optlen) == -1) { ::close(s); continue; } uid_t euid = geteuid(); gid_t egid = getegid(); if (cred_info.uid != euid || cred_info.gid != egid) { ::close(s); continue; } // peer credential look okay so we read the request LinuxAttachOperation* op = read_request(s); if (op == NULL) { ::close(s); continue; } else { return op; } } }
// Open the directory of the given path, validate it and set the // current working directory to it. // Return a DIR * of the open directory and the saved cwd fd. // static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { // Open the directory. DIR* dirp = open_directory_secure(dirname); if (dirp == NULL) { // Directory doesn't exist or is insecure, so there is nothing to cleanup. return dirp; } int fd = dirfd(dirp); // Open a fd to the cwd and save it off. int result; RESTARTABLE(::open(".", O_RDONLY), result); if (result == OS_ERR) { *saved_cwd_fd = -1; } else { *saved_cwd_fd = result; } // Set the current directory to dirname by using the fd of the directory and // handle errors, otherwise shared memory files will be created in cwd. result = fchdir(fd); if (result == OS_ERR) { if (PrintMiscellaneous && Verbose) { warning("could not change to directory %s", dirname); } if (*saved_cwd_fd != -1) { ::close(*saved_cwd_fd); *saved_cwd_fd = -1; } // Close the directory. os::closedir(dirp); return NULL; } else { return dirp; } }
/* * Class: sun_tools_attach_LinuxVirtualMachine * Method: read * Signature: (I[BI)I */ JNIEXPORT jint JNICALL Java_sun_tools_attach_LinuxVirtualMachine_read (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen) { unsigned char buf[128]; size_t len = sizeof(buf); ssize_t n; size_t remaining = (size_t)(baLen - off); if (len > remaining) { len = remaining; } RESTARTABLE(read(fd, buf+off, len), n); if (n == -1) { JNU_ThrowIOExceptionWithLastError(env, "read"); } else { if (n == 0) { n = -1; // EOF } else { (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf+off)); } } return n; }
// Open the directory of the given path, validate it and set the // current working directory to it. // Return a DIR * of the open directory and the saved cwd fd. // static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { // Open the directory. DIR* dirp = open_directory_secure(dirname); if (dirp == NULL) { // Directory doesn't exist or is insecure, so there is nothing to cleanup. return dirp; } int fd = dirp->dd_fd; // Open a fd to the cwd and save it off. int result; RESTARTABLE(::open(".", O_RDONLY), result); if (result == OS_ERR) { *saved_cwd_fd = -1; } else { *saved_cwd_fd = result; } // Set the current directory to dirname by using the fd of the directory. result = fchdir(fd); return dirp; }
inline size_t os::write(int fd, const void *buf, unsigned int nBytes) { size_t res; RESTARTABLE((size_t) ::write(fd, buf, (size_t) nBytes), res); return res; }
inline size_t os::restartable_read(int fd, void *buf, unsigned int nBytes) { size_t res; RESTARTABLE( (size_t) ::read(fd, buf, (size_t) nBytes), res); return res; }
// return the name of the user that owns the process identified by vmid. // // This method uses a slow directory search algorithm to find the backing // store file for the specified vmid and returns the user name, as determined // by the user name suffix of the hsperfdata_<username> directory name. // // the caller is expected to free the allocated memory. // static char* get_user_name_slow(int vmid, TRAPS) { // short circuit the directory search if the process doesn't even exist. if (kill(vmid, 0) == OS_ERR) { if (errno == ESRCH) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); } else /* EPERM */ { THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno)); } } // directory search char* oldest_user = NULL; time_t oldest_ctime = 0; const char* tmpdirname = os::get_temp_directory(); DIR* tmpdirp = os::opendir(tmpdirname); if (tmpdirp == NULL) { return NULL; } // for each entry in the directory that matches the pattern hsperfdata_*, // open the directory and check if the file for the given vmid exists. // The file with the expected name and the latest creation date is used // to determine the user name for the process id. // struct dirent* dentry; char* tdbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(tmpdirname), mtInternal); errno = 0; while ((dentry = os::readdir(tmpdirp, (struct dirent *)tdbuf)) != NULL) { // check if the directory entry is a hsperfdata file if (strncmp(dentry->d_name, PERFDATA_NAME, strlen(PERFDATA_NAME)) != 0) { continue; } char* usrdir_name = NEW_C_HEAP_ARRAY(char, strlen(tmpdirname) + strlen(dentry->d_name) + 2, mtInternal); strcpy(usrdir_name, tmpdirname); strcat(usrdir_name, "/"); strcat(usrdir_name, dentry->d_name); // Open the user directory. DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == NULL) { FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); continue; } // Since we don't create the backing store files in directories // pointed to by symbolic links, we also don't follow them when // looking for the files. We check for a symbolic link after the // call to opendir in order to eliminate a small window where the // symlink can be exploited. // if (!is_directory_secure(usrdir_name)) { FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); os::closedir(subdirp); continue; } struct dirent* udentry; char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name), mtInternal); errno = 0; while ((udentry = os::readdir(subdirp, (struct dirent *)udbuf)) != NULL) { if (filename_to_pid(udentry->d_name) == vmid) { struct stat statbuf; int result; char* filename = NEW_C_HEAP_ARRAY(char, strlen(usrdir_name) + strlen(udentry->d_name) + 2, mtInternal); strcpy(filename, usrdir_name); strcat(filename, "/"); strcat(filename, udentry->d_name); // don't follow symbolic links for the file RESTARTABLE(::lstat(filename, &statbuf), result); if (result == OS_ERR) { FREE_C_HEAP_ARRAY(char, filename, mtInternal); continue; } // skip over files that are not regular files. if (!S_ISREG(statbuf.st_mode)) { FREE_C_HEAP_ARRAY(char, filename, mtInternal); continue; } // compare and save filename with latest creation time if (statbuf.st_size > 0 && statbuf.st_ctime > oldest_ctime) { if (statbuf.st_ctime > oldest_ctime) { char* user = strchr(dentry->d_name, '_') + 1; if (oldest_user != NULL) FREE_C_HEAP_ARRAY(char, oldest_user, mtInternal); oldest_user = NEW_C_HEAP_ARRAY(char, strlen(user)+1, mtInternal); strcpy(oldest_user, user); oldest_ctime = statbuf.st_ctime; } } FREE_C_HEAP_ARRAY(char, filename, mtInternal); } } os::closedir(subdirp); FREE_C_HEAP_ARRAY(char, udbuf, mtInternal); FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal); }