// 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; } }
// 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; }
// 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); }