8069590: AIX port of "8050807: Better performing performance data handling"
Co-authored-by: Martin Doerr <martin.doerr@sap.com> Reviewed-by: simonis, goetz
This commit is contained in:
parent
4775e0767d
commit
21cd501d27
@ -74,6 +74,12 @@ CFLAGS += -D_REENTRANT
|
|||||||
# no xlc counterpart for -fcheck-new
|
# no xlc counterpart for -fcheck-new
|
||||||
# CFLAGS += -fcheck-new
|
# CFLAGS += -fcheck-new
|
||||||
|
|
||||||
|
# We need to define this on the command line if we want to use the the
|
||||||
|
# predefined format specifiers from "inttypes.h". Otherwise system headrs
|
||||||
|
# can indirectly include inttypes.h before we define __STDC_FORMAT_MACROS
|
||||||
|
# in globalDefinitions.hpp
|
||||||
|
CFLAGS += -D__STDC_FORMAT_MACROS
|
||||||
|
|
||||||
ARCHFLAG = -q64
|
ARCHFLAG = -q64
|
||||||
|
|
||||||
CFLAGS += $(ARCHFLAG)
|
CFLAGS += $(ARCHFLAG)
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "os_aix.inline.hpp"
|
#include "os_aix.inline.hpp"
|
||||||
#include "runtime/handles.inline.hpp"
|
#include "runtime/handles.inline.hpp"
|
||||||
#include "runtime/perfMemory.hpp"
|
#include "runtime/perfMemory.hpp"
|
||||||
|
#include "services/memTracker.hpp"
|
||||||
#include "utilities/exceptions.hpp"
|
#include "utilities/exceptions.hpp"
|
||||||
|
|
||||||
// put OS-includes here
|
// put OS-includes here
|
||||||
@ -196,12 +197,37 @@ static pid_t filename_to_pid(const char* filename) {
|
|||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the given statbuf is considered a secure directory for
|
||||||
|
// the backing store files. Returns true if the directory is considered
|
||||||
|
// a secure location. Returns false if the statbuf is a symbolic link or
|
||||||
|
// if an error occurred.
|
||||||
|
static bool is_statbuf_secure(struct stat *statp) {
|
||||||
|
if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) {
|
||||||
|
// The path represents a link or some non-directory file type,
|
||||||
|
// which is not what we expected. Declare it insecure.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// We have an existing directory, check if the permissions are safe.
|
||||||
|
if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) {
|
||||||
|
// The directory is open for writing and could be subjected
|
||||||
|
// to a symlink or a hard link attack. Declare it insecure.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// See if the uid of the directory matches the effective uid of the process.
|
||||||
|
//
|
||||||
|
if (statp->st_uid != geteuid()) {
|
||||||
|
// The directory was not created by this user, declare it insecure.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// check if the given path is considered a secure directory for
|
|
||||||
|
// Check if the given path is considered a secure directory for
|
||||||
// the backing store files. Returns true if the directory exists
|
// the backing store files. Returns true if the directory exists
|
||||||
// and is considered a secure location. Returns false if the path
|
// and is considered a secure location. Returns false if the path
|
||||||
// is a symbolic link or if an error occurred.
|
// is a symbolic link or if an error occurred.
|
||||||
//
|
|
||||||
static bool is_directory_secure(const char* path) {
|
static bool is_directory_secure(const char* path) {
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
@ -211,38 +237,276 @@ static bool is_directory_secure(const char* path) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the path exists, now check it's mode
|
// The path exists, see if it is secure.
|
||||||
if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) {
|
return is_statbuf_secure(&statbuf);
|
||||||
// the path represents a link or some non-directory file type,
|
}
|
||||||
// which is not what we expected. declare it insecure.
|
|
||||||
//
|
// (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;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// we have an existing directory, check if the permissions are safe.
|
// The path exists, now check its mode.
|
||||||
//
|
return is_statbuf_secure(&statbuf);
|
||||||
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.
|
|
||||||
//
|
// 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;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions for open without O_NOFOLLOW which is not present on AIX 5.3/6.1.
|
||||||
|
// We use the jdk6 implementation here.
|
||||||
|
#ifndef O_NOFOLLOW
|
||||||
|
// The O_NOFOLLOW oflag doesn't exist before solaris 5.10, this is to simulate that behaviour
|
||||||
|
// was done in jdk 5/6 hotspot by Oracle this way
|
||||||
|
static int open_o_nofollow_impl(const char* path, int oflag, mode_t mode, bool use_mode) {
|
||||||
|
struct stat orig_st;
|
||||||
|
struct stat new_st;
|
||||||
|
bool create;
|
||||||
|
int error;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
create = false;
|
||||||
|
|
||||||
|
if (lstat(path, &orig_st) != 0) {
|
||||||
|
if (errno == ENOENT && (oflag & O_CREAT) != 0) {
|
||||||
|
// File doesn't exist, but_we want to create it, add O_EXCL flag
|
||||||
|
// to make sure no-one creates it (or a symlink) before us
|
||||||
|
// This works as we expect with symlinks, from posix man page:
|
||||||
|
// 'If O_EXCL and O_CREAT are set, and path names a symbolic
|
||||||
|
// link, open() shall fail and set errno to [EEXIST]'.
|
||||||
|
oflag |= O_EXCL;
|
||||||
|
create = true;
|
||||||
|
} else {
|
||||||
|
// File doesn't exist, and we are not creating it.
|
||||||
|
return OS_ERR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Lstat success, check if existing file is a link.
|
||||||
|
if ((orig_st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
|
// File is a symlink.
|
||||||
|
errno = ELOOP;
|
||||||
|
return OS_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_mode == true) {
|
||||||
|
fd = open(path, oflag, mode);
|
||||||
|
} else {
|
||||||
|
fd = open(path, oflag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd == OS_ERR) {
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't do inode checks on before/after if we created the file.
|
||||||
|
if (create == false) {
|
||||||
|
if (fstat(fd, &new_st) != 0) {
|
||||||
|
// Keep errno from fstat, in case close also fails.
|
||||||
|
error = errno;
|
||||||
|
::close(fd);
|
||||||
|
errno = error;
|
||||||
|
return OS_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orig_st.st_dev != new_st.st_dev || orig_st.st_ino != new_st.st_ino) {
|
||||||
|
// File was tampered with during race window.
|
||||||
|
::close(fd);
|
||||||
|
errno = EEXIST;
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("possible file tampering attempt detected when opening %s", path);
|
||||||
|
}
|
||||||
|
return OS_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_o_nofollow(const char* path, int oflag, mode_t mode) {
|
||||||
|
return open_o_nofollow_impl(path, oflag, mode, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_o_nofollow(const char* path, int oflag) {
|
||||||
|
return open_o_nofollow_impl(path, oflag, 0, false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: The code below uses fchdir(), open() and unlink() because
|
||||||
|
// fdopendir(), openat() and unlinkat() are not supported on all
|
||||||
|
// versions. Once the support for fdopendir(), openat() and unlinkat()
|
||||||
|
// is available on all supported versions the code can be changed
|
||||||
|
// to use these functions.
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the directory and restore the current working directory.
|
||||||
|
static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) {
|
||||||
|
|
||||||
|
int result;
|
||||||
|
// If we have a saved cwd change back to it and close the fd.
|
||||||
|
if (saved_cwd_fd != -1) {
|
||||||
|
result = fchdir(saved_cwd_fd);
|
||||||
|
::close(saved_cwd_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the directory.
|
||||||
|
os::closedir(dirp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the user name for the given user id.
|
||||||
// return the user name for the given user id
|
|
||||||
//
|
|
||||||
// the caller is expected to free the allocated memory.
|
|
||||||
//
|
//
|
||||||
|
// The caller is expected to free the allocated memory.
|
||||||
static char* get_user_name(uid_t uid) {
|
static char* get_user_name(uid_t uid) {
|
||||||
|
|
||||||
struct passwd pwent;
|
struct passwd pwent;
|
||||||
|
|
||||||
// determine the max pwbuf size from sysconf, and hardcode
|
// Determine the max pwbuf size from sysconf, and hardcode
|
||||||
// a default if this not available through sysconf.
|
// a default if this not available through sysconf.
|
||||||
//
|
|
||||||
long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
|
long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||||
if (bufsize == -1)
|
if (bufsize == -1)
|
||||||
bufsize = 1024;
|
bufsize = 1024;
|
||||||
@ -344,7 +608,8 @@ static char* get_user_name_slow(int vmid, TRAPS) {
|
|||||||
strcat(usrdir_name, "/");
|
strcat(usrdir_name, "/");
|
||||||
strcat(usrdir_name, dentry->d_name);
|
strcat(usrdir_name, dentry->d_name);
|
||||||
|
|
||||||
DIR* subdirp = os::opendir(usrdir_name);
|
// Open the user directory.
|
||||||
|
DIR* subdirp = open_directory_secure(usrdir_name);
|
||||||
|
|
||||||
if (subdirp == NULL) {
|
if (subdirp == NULL) {
|
||||||
FREE_C_HEAP_ARRAY(char, usrdir_name);
|
FREE_C_HEAP_ARRAY(char, usrdir_name);
|
||||||
@ -464,28 +729,7 @@ static void remove_file(const char* path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cleanup stale shared memory resources
|
||||||
// remove file
|
|
||||||
//
|
|
||||||
// this method removes the file with the given file name in the
|
|
||||||
// named directory.
|
|
||||||
//
|
|
||||||
static void remove_file(const char* dirname, const char* filename) {
|
|
||||||
|
|
||||||
size_t nbytes = strlen(dirname) + strlen(filename) + 2;
|
|
||||||
char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
|
|
||||||
|
|
||||||
strcpy(path, dirname);
|
|
||||||
strcat(path, "/");
|
|
||||||
strcat(path, filename);
|
|
||||||
|
|
||||||
remove_file(path);
|
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// cleanup stale shared memory resources
|
|
||||||
//
|
//
|
||||||
// This method attempts to remove all stale shared memory files in
|
// This method attempts to remove all stale shared memory files in
|
||||||
// the named user temporary directory. It scans the named directory
|
// the named user temporary directory. It scans the named directory
|
||||||
@ -493,33 +737,26 @@ static void remove_file(const char* dirname, const char* filename) {
|
|||||||
// process id is extracted from the file name and a test is run to
|
// process id is extracted from the file name and a test is run to
|
||||||
// determine if the process is alive. If the process is not alive,
|
// determine if the process is alive. If the process is not alive,
|
||||||
// any stale file resources are removed.
|
// any stale file resources are removed.
|
||||||
//
|
|
||||||
static void cleanup_sharedmem_resources(const char* dirname) {
|
static void cleanup_sharedmem_resources(const char* dirname) {
|
||||||
|
|
||||||
// open the user temp directory
|
int saved_cwd_fd;
|
||||||
DIR* dirp = os::opendir(dirname);
|
// Open the directory.
|
||||||
|
DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
|
||||||
if (dirp == NULL) {
|
if (dirp == NULL) {
|
||||||
// directory doesn't exist, so there is nothing to cleanup
|
// Directory doesn't exist or is insecure, so there is nothing to cleanup.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_directory_secure(dirname)) {
|
// For each entry in the directory that matches the expected file
|
||||||
// the directory is not a secure directory
|
|
||||||
os::closedir(dirp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each entry in the directory that matches the expected file
|
|
||||||
// name pattern, determine if the file resources are stale and if
|
// name pattern, determine if the file resources are stale and if
|
||||||
// so, remove the file resources. Note, instrumented HotSpot processes
|
// so, remove the file resources. Note, instrumented HotSpot processes
|
||||||
// for this user may start and/or terminate during this search and
|
// for this user may start and/or terminate during this search and
|
||||||
// remove or create new files in this directory. The behavior of this
|
// remove or create new files in this directory. The behavior of this
|
||||||
// loop under these conditions is dependent upon the implementation of
|
// loop under these conditions is dependent upon the implementation of
|
||||||
// opendir/readdir.
|
// opendir/readdir.
|
||||||
//
|
|
||||||
struct dirent* entry;
|
struct dirent* entry;
|
||||||
char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
|
char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
|
while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
|
||||||
|
|
||||||
@ -529,56 +766,55 @@ static void cleanup_sharedmem_resources(const char* dirname) {
|
|||||||
|
|
||||||
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
|
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
|
||||||
|
|
||||||
// attempt to remove all unexpected files, except "." and ".."
|
// Attempt to remove all unexpected files, except "." and "..".
|
||||||
remove_file(dirname, entry->d_name);
|
unlink(entry->d_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we now have a file name that converts to a valid integer
|
// We now have a file name that converts to a valid integer
|
||||||
// that could represent a process id . if this process id
|
// that could represent a process id . if this process id
|
||||||
// matches the current process id or the process is not running,
|
// matches the current process id or the process is not running,
|
||||||
// then remove the stale file resources.
|
// then remove the stale file resources.
|
||||||
//
|
//
|
||||||
// process liveness is detected by sending signal number 0 to
|
// Process liveness is detected by sending signal number 0 to
|
||||||
// the process id (see kill(2)). if kill determines that the
|
// the process id (see kill(2)). if kill determines that the
|
||||||
// process does not exist, then the file resources are removed.
|
// process does not exist, then the file resources are removed.
|
||||||
// if kill determines that that we don't have permission to
|
// if kill determines that that we don't have permission to
|
||||||
// signal the process, then the file resources are assumed to
|
// signal the process, then the file resources are assumed to
|
||||||
// be stale and are removed because the resources for such a
|
// be stale and are removed because the resources for such a
|
||||||
// process should be in a different user specific directory.
|
// process should be in a different user specific directory.
|
||||||
//
|
|
||||||
if ((pid == os::current_process_id()) ||
|
if ((pid == os::current_process_id()) ||
|
||||||
(kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
|
(kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
|
||||||
|
|
||||||
remove_file(dirname, entry->d_name);
|
unlink(entry->d_name);
|
||||||
}
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
}
|
}
|
||||||
os::closedir(dirp);
|
|
||||||
FREE_C_HEAP_ARRAY(char, dbuf);
|
// Close the directory and reset the current working directory.
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
|
FREE_C_HEAP_ARRAY(char, dbuf, mtInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make the user specific temporary directory. Returns true if
|
// Make the user specific temporary directory. Returns true if
|
||||||
// the directory exists and is secure upon return. Returns false
|
// the directory exists and is secure upon return. Returns false
|
||||||
// if the directory exists but is either a symlink, is otherwise
|
// if the directory exists but is either a symlink, is otherwise
|
||||||
// insecure, or if an error occurred.
|
// insecure, or if an error occurred.
|
||||||
//
|
|
||||||
static bool make_user_tmp_dir(const char* dirname) {
|
static bool make_user_tmp_dir(const char* dirname) {
|
||||||
|
|
||||||
// create the directory with 0755 permissions. note that the directory
|
// Create the directory with 0755 permissions. note that the directory
|
||||||
// will be owned by euid::egid, which may not be the same as uid::gid.
|
// will be owned by euid::egid, which may not be the same as uid::gid.
|
||||||
//
|
|
||||||
if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == OS_ERR) {
|
if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == OS_ERR) {
|
||||||
if (errno == EEXIST) {
|
if (errno == EEXIST) {
|
||||||
// The directory already exists and was probably created by another
|
// The directory already exists and was probably created by another
|
||||||
// JVM instance. However, this could also be the result of a
|
// JVM instance. However, this could also be the result of a
|
||||||
// deliberate symlink. Verify that the existing directory is safe.
|
// deliberate symlink. Verify that the existing directory is safe.
|
||||||
//
|
|
||||||
if (!is_directory_secure(dirname)) {
|
if (!is_directory_secure(dirname)) {
|
||||||
// directory is not secure
|
// Directory is not secure.
|
||||||
if (PrintMiscellaneous && Verbose) {
|
if (PrintMiscellaneous && Verbose) {
|
||||||
warning("%s directory is insecure\n", dirname);
|
warning("%s directory is insecure\n", dirname);
|
||||||
}
|
}
|
||||||
@ -614,19 +850,63 @@ static int create_sharedmem_resources(const char* dirname, const char* filename,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result;
|
int saved_cwd_fd;
|
||||||
|
// Open the directory and set the current working directory to it.
|
||||||
RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result);
|
DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
|
||||||
if (result == OS_ERR) {
|
if (dirp == NULL) {
|
||||||
if (PrintMiscellaneous && Verbose) {
|
// Directory doesn't exist or is insecure, so cannot create shared
|
||||||
warning("could not create file %s: %s\n", filename, strerror(errno));
|
// memory file.
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open the filename in the current directory.
|
||||||
|
// Cannot use O_TRUNC here; truncation of an existing file has to happen
|
||||||
|
// after the is_file_secure() check below.
|
||||||
|
int result;
|
||||||
|
|
||||||
|
// 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(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result);
|
||||||
|
#else
|
||||||
|
// workaround function (jdk6 code)
|
||||||
|
RESTARTABLE(::open_o_nofollow(filename, O_RDWR|O_CREAT, S_IREAD|S_IWRITE), result);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
if (errno == ELOOP) {
|
||||||
|
warning("file %s is a symlink and is not secure\n", filename);
|
||||||
|
} else {
|
||||||
|
warning("could not create file %s: %s\n", filename, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Close the directory and reset the current working directory.
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Close the directory and reset the current working directory.
|
||||||
|
close_directory_secure_cwd(dirp, saved_cwd_fd);
|
||||||
|
|
||||||
// save the file descriptor
|
// save the file descriptor
|
||||||
int fd = result;
|
int fd = result;
|
||||||
|
|
||||||
|
// Check to see if the file is secure.
|
||||||
|
if (!is_file_secure(fd, filename)) {
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate the file to get rid of any existing data.
|
||||||
|
RESTARTABLE(::ftruncate(fd, (off_t)0), result);
|
||||||
|
if (result == OS_ERR) {
|
||||||
|
if (PrintMiscellaneous && Verbose) {
|
||||||
|
warning("could not truncate shared memory file: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
// set the file size
|
// set the file size
|
||||||
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
|
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
|
||||||
if (result == OS_ERR) {
|
if (result == OS_ERR) {
|
||||||
@ -648,7 +928,14 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) {
|
|||||||
|
|
||||||
// open the file
|
// open the file
|
||||||
int result;
|
int result;
|
||||||
|
// 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(filename, oflags), result);
|
RESTARTABLE(::open(filename, oflags), result);
|
||||||
|
#else
|
||||||
|
RESTARTABLE(::open_o_nofollow(filename, oflags), result);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (result == OS_ERR) {
|
if (result == OS_ERR) {
|
||||||
if (errno == ENOENT) {
|
if (errno == ENOENT) {
|
||||||
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
|
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
|
||||||
@ -662,8 +949,15 @@ static int open_sharedmem_file(const char* filename, int oflags, TRAPS) {
|
|||||||
THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno));
|
THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int fd = result;
|
||||||
|
|
||||||
return result;
|
// Check to see if the file is secure.
|
||||||
|
if (!is_file_secure(fd, filename)) {
|
||||||
|
::close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a named shared memory region. returns the address of the
|
// create a named shared memory region. returns the address of the
|
||||||
@ -695,13 +989,21 @@ static char* mmap_create_shared(size_t size) {
|
|||||||
char* dirname = get_user_tmp_dir(user_name);
|
char* dirname = get_user_tmp_dir(user_name);
|
||||||
char* filename = get_sharedmem_filename(dirname, vmid);
|
char* filename = get_sharedmem_filename(dirname, vmid);
|
||||||
|
|
||||||
|
// Get the short filename.
|
||||||
|
char* short_filename = strrchr(filename, '/');
|
||||||
|
if (short_filename == NULL) {
|
||||||
|
short_filename = filename;
|
||||||
|
} else {
|
||||||
|
short_filename++;
|
||||||
|
}
|
||||||
|
|
||||||
// cleanup any stale shared memory files
|
// cleanup any stale shared memory files
|
||||||
cleanup_sharedmem_resources(dirname);
|
cleanup_sharedmem_resources(dirname);
|
||||||
|
|
||||||
assert(((size > 0) && (size % os::vm_page_size() == 0)),
|
assert(((size > 0) && (size % os::vm_page_size() == 0)),
|
||||||
"unexpected PerfMemory region size");
|
"unexpected PerfMemory region size");
|
||||||
|
|
||||||
fd = create_sharedmem_resources(dirname, filename, size);
|
fd = create_sharedmem_resources(dirname, short_filename, size);
|
||||||
|
|
||||||
FREE_C_HEAP_ARRAY(char, user_name);
|
FREE_C_HEAP_ARRAY(char, user_name);
|
||||||
FREE_C_HEAP_ARRAY(char, dirname);
|
FREE_C_HEAP_ARRAY(char, dirname);
|
||||||
@ -733,6 +1035,9 @@ static char* mmap_create_shared(size_t size) {
|
|||||||
// clear the shared memory region
|
// clear the shared memory region
|
||||||
(void)::memset((void*) mapAddress, 0, size);
|
(void)::memset((void*) mapAddress, 0, size);
|
||||||
|
|
||||||
|
// It does not go through os api, the operation has to record from here.
|
||||||
|
MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC, mtInternal);
|
||||||
|
|
||||||
return mapAddress;
|
return mapAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,7 +1112,7 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor
|
|||||||
char* mapAddress;
|
char* mapAddress;
|
||||||
int result;
|
int result;
|
||||||
int fd;
|
int fd;
|
||||||
size_t size;
|
size_t size = 0;
|
||||||
const char* luser = NULL;
|
const char* luser = NULL;
|
||||||
|
|
||||||
int mmap_prot;
|
int mmap_prot;
|
||||||
@ -819,12 +1124,18 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor
|
|||||||
// constructs for the file and the shared memory mapping.
|
// constructs for the file and the shared memory mapping.
|
||||||
if (mode == PerfMemory::PERF_MODE_RO) {
|
if (mode == PerfMemory::PERF_MODE_RO) {
|
||||||
mmap_prot = PROT_READ;
|
mmap_prot = PROT_READ;
|
||||||
|
|
||||||
|
// No O_NOFOLLOW defined at buildtime, and it is not documented for open.
|
||||||
|
#ifdef O_NOFOLLOW
|
||||||
|
file_flags = O_RDONLY | O_NOFOLLOW;
|
||||||
|
#else
|
||||||
file_flags = O_RDONLY;
|
file_flags = O_RDONLY;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else if (mode == PerfMemory::PERF_MODE_RW) {
|
else if (mode == PerfMemory::PERF_MODE_RW) {
|
||||||
#ifdef LATER
|
#ifdef LATER
|
||||||
mmap_prot = PROT_READ | PROT_WRITE;
|
mmap_prot = PROT_READ | PROT_WRITE;
|
||||||
file_flags = O_RDWR;
|
file_flags = O_RDWR | O_NOFOLLOW;
|
||||||
#else
|
#else
|
||||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||||
"Unsupported access mode");
|
"Unsupported access mode");
|
||||||
@ -853,9 +1164,9 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor
|
|||||||
// store file, we don't follow them when attaching either.
|
// store file, we don't follow them when attaching either.
|
||||||
//
|
//
|
||||||
if (!is_directory_secure(dirname)) {
|
if (!is_directory_secure(dirname)) {
|
||||||
FREE_C_HEAP_ARRAY(char, dirname);
|
FREE_C_HEAP_ARRAY(char, dirname, mtInternal);
|
||||||
if (luser != user) {
|
if (luser != user) {
|
||||||
FREE_C_HEAP_ARRAY(char, luser);
|
FREE_C_HEAP_ARRAY(char, luser, mtInternal);
|
||||||
}
|
}
|
||||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||||
"Process not found");
|
"Process not found");
|
||||||
@ -901,6 +1212,9 @@ static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemor
|
|||||||
"Could not map PerfMemory");
|
"Could not map PerfMemory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It does not go through os api, the operation has to record from here.
|
||||||
|
MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC, mtInternal);
|
||||||
|
|
||||||
*addr = mapAddress;
|
*addr = mapAddress;
|
||||||
*sizep = size;
|
*sizep = size;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user