src/os/solaris/vm/perfMemory_solaris.cpp

changeset 7707
60a992c821f8
parent 6349
7d28f4e15b61
child 7709
5ca2ea5eeff0
     1.1 --- a/src/os/solaris/vm/perfMemory_solaris.cpp	Mon Oct 20 23:02:07 2014 -0700
     1.2 +++ b/src/os/solaris/vm/perfMemory_solaris.cpp	Fri Oct 24 15:02:37 2014 -0400
     1.3 @@ -199,7 +199,38 @@
     1.4  }
     1.5  
     1.6  
     1.7 -// check if the given path is considered a secure directory for
     1.8 +// Check if the given statbuf is considered a secure directory for
     1.9 +// the backing store files. Returns true if the directory is considered
    1.10 +// a secure location. Returns false if the statbuf is a symbolic link or
    1.11 +// if an error occurred.
    1.12 +//
    1.13 +static bool is_statbuf_secure(struct stat *statp) {
    1.14 +  if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) {
    1.15 +    // The path represents a link or some non-directory file type,
    1.16 +    // which is not what we expected. Declare it insecure.
    1.17 +    //
    1.18 +    return false;
    1.19 +  }
    1.20 +  // We have an existing directory, check if the permissions are safe.
    1.21 +  //
    1.22 +  if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) {
    1.23 +    // The directory is open for writing and could be subjected
    1.24 +    // to a symlink or a hard link attack. Declare it insecure.
    1.25 +    //
    1.26 +    return false;
    1.27 +  }
    1.28 +  // See if the uid of the directory matches the effective uid of the process.
    1.29 +  //
    1.30 +  if (statp->st_uid != geteuid()) {
    1.31 +    // The directory was not created by this user, declare it insecure.
    1.32 +    //
    1.33 +    return false;
    1.34 +  }
    1.35 +  return true;
    1.36 +}
    1.37 +
    1.38 +
    1.39 +// Check if the given path is considered a secure directory for
    1.40  // the backing store files. Returns true if the directory exists
    1.41  // and is considered a secure location. Returns false if the path
    1.42  // is a symbolic link or if an error occurred.
    1.43 @@ -213,27 +244,185 @@
    1.44      return false;
    1.45    }
    1.46  
    1.47 -  // the path exists, now check it's mode
    1.48 -  if (S_ISLNK(statbuf.st_mode) || !S_ISDIR(statbuf.st_mode)) {
    1.49 -    // the path represents a link or some non-directory file type,
    1.50 -    // which is not what we expected. declare it insecure.
    1.51 -    //
    1.52 +  // The path exists, see if it is secure.
    1.53 +  return is_statbuf_secure(&statbuf);
    1.54 +}
    1.55 +
    1.56 +
    1.57 +// Check if the given directory file descriptor is considered a secure
    1.58 +// directory for the backing store files. Returns true if the directory
    1.59 +// exists and is considered a secure location. Returns false if the path
    1.60 +// is a symbolic link or if an error occurred.
    1.61 +//
    1.62 +static bool is_dirfd_secure(int dir_fd) {
    1.63 +  struct stat statbuf;
    1.64 +  int result = 0;
    1.65 +
    1.66 +  RESTARTABLE(::fstat(dir_fd, &statbuf), result);
    1.67 +  if (result == OS_ERR) {
    1.68      return false;
    1.69    }
    1.70 -  else {
    1.71 -    // we have an existing directory, check if the permissions are safe.
    1.72 -    //
    1.73 -    if ((statbuf.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
    1.74 -      // the directory is open for writing and could be subjected
    1.75 -      // to a symlnk attack. declare it insecure.
    1.76 -      //
    1.77 -      return false;
    1.78 +
    1.79 +  // The path exists, now check its mode.
    1.80 +  return is_statbuf_secure(&statbuf);
    1.81 +}
    1.82 +
    1.83 +
    1.84 +// Check to make sure fd1 and fd2 are referencing the same file system object.
    1.85 +//
    1.86 +static bool is_same_fsobject(int fd1, int fd2) {
    1.87 +  struct stat statbuf1;
    1.88 +  struct stat statbuf2;
    1.89 +  int result = 0;
    1.90 +
    1.91 +  RESTARTABLE(::fstat(fd1, &statbuf1), result);
    1.92 +  if (result == OS_ERR) {
    1.93 +    return false;
    1.94 +  }
    1.95 +  RESTARTABLE(::fstat(fd2, &statbuf2), result);
    1.96 +  if (result == OS_ERR) {
    1.97 +    return false;
    1.98 +  }
    1.99 +
   1.100 +  if ((statbuf1.st_ino == statbuf2.st_ino) &&
   1.101 +      (statbuf1.st_dev == statbuf2.st_dev)) {
   1.102 +    return true;
   1.103 +  } else {
   1.104 +    return false;
   1.105 +  }
   1.106 +}
   1.107 +
   1.108 +
   1.109 +// Open the directory of the given path and validate it.
   1.110 +// Return a DIR * of the open directory.
   1.111 +//
   1.112 +static DIR *open_directory_secure(const char* dirname) {
   1.113 +  // Open the directory using open() so that it can be verified
   1.114 +  // to be secure by calling is_dirfd_secure(), opendir() and then check
   1.115 +  // to see if they are the same file system object.  This method does not
   1.116 +  // introduce a window of opportunity for the directory to be attacked that
   1.117 +  // calling opendir() and is_directory_secure() does.
   1.118 +  int result;
   1.119 +  DIR *dirp = NULL;
   1.120 +  RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result);
   1.121 +  if (result == OS_ERR) {
   1.122 +    // Directory doesn't exist or is a symlink, so there is nothing to cleanup.
   1.123 +    if (PrintMiscellaneous && Verbose) {
   1.124 +      if (errno == ELOOP) {
   1.125 +        warning("directory %s is a symlink and is not secure\n", dirname);
   1.126 +      } else {
   1.127 +        warning("could not open directory %s: %s\n", dirname, strerror(errno));
   1.128 +      }
   1.129      }
   1.130 +    return dirp;
   1.131 +  }
   1.132 +  int fd = result;
   1.133 +
   1.134 +  // Determine if the open directory is secure.
   1.135 +  if (!is_dirfd_secure(fd)) {
   1.136 +    // The directory is not a secure directory.
   1.137 +    os::close(fd);
   1.138 +    return dirp;
   1.139 +  }
   1.140 +
   1.141 +  // Open the directory.
   1.142 +  dirp = ::opendir(dirname);
   1.143 +  if (dirp == NULL) {
   1.144 +    // The directory doesn't exist, close fd and return.
   1.145 +    os::close(fd);
   1.146 +    return dirp;
   1.147 +  }
   1.148 +
   1.149 +  // Check to make sure fd and dirp are referencing the same file system object.
   1.150 +  if (!is_same_fsobject(fd, dirp->dd_fd)) {
   1.151 +    // The directory is not secure.
   1.152 +    os::close(fd);
   1.153 +    os::closedir(dirp);
   1.154 +    dirp = NULL;
   1.155 +    return dirp;
   1.156 +  }
   1.157 +
   1.158 +  // Close initial open now that we know directory is secure
   1.159 +  os::close(fd);
   1.160 +
   1.161 +  return dirp;
   1.162 +}
   1.163 +
   1.164 +// NOTE: The code below uses fchdir(), open() and unlink() because
   1.165 +// fdopendir(), openat() and unlinkat() are not supported on all
   1.166 +// versions.  Once the support for fdopendir(), openat() and unlinkat()
   1.167 +// is available on all supported versions the code can be changed
   1.168 +// to use these functions.
   1.169 +
   1.170 +// Open the directory of the given path, validate it and set the
   1.171 +// current working directory to it.
   1.172 +// Return a DIR * of the open directory and the saved cwd fd.
   1.173 +//
   1.174 +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) {
   1.175 +
   1.176 +  // Open the directory.
   1.177 +  DIR* dirp = open_directory_secure(dirname);
   1.178 +  if (dirp == NULL) {
   1.179 +    // Directory doesn't exist or is insecure, so there is nothing to cleanup.
   1.180 +    return dirp;
   1.181 +  }
   1.182 +  int fd = dirp->dd_fd;
   1.183 +
   1.184 +  // Open a fd to the cwd and save it off.
   1.185 +  int result;
   1.186 +  RESTARTABLE(::open(".", O_RDONLY), result);
   1.187 +  if (result == OS_ERR) {
   1.188 +    *saved_cwd_fd = -1;
   1.189 +  } else {
   1.190 +    *saved_cwd_fd = result;
   1.191 +  }
   1.192 +
   1.193 +  // Set the current directory to dirname by using the fd of the directory.
   1.194 +  result = fchdir(fd);
   1.195 +
   1.196 +  return dirp;
   1.197 +}
   1.198 +
   1.199 +// Close the directory and restore the current working directory.
   1.200 +//
   1.201 +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) {
   1.202 +
   1.203 +  int result;
   1.204 +  // If we have a saved cwd change back to it and close the fd.
   1.205 +  if (saved_cwd_fd != -1) {
   1.206 +    result = fchdir(saved_cwd_fd);
   1.207 +    ::close(saved_cwd_fd);
   1.208 +  }
   1.209 +
   1.210 +  // Close the directory.
   1.211 +  os::closedir(dirp);
   1.212 +}
   1.213 +
   1.214 +// Check if the given file descriptor is considered a secure.
   1.215 +//
   1.216 +static bool is_file_secure(int fd, const char *filename) {
   1.217 +
   1.218 +  int result;
   1.219 +  struct stat statbuf;
   1.220 +
   1.221 +  // Determine if the file is secure.
   1.222 +  RESTARTABLE(::fstat(fd, &statbuf), result);
   1.223 +  if (result == OS_ERR) {
   1.224 +    if (PrintMiscellaneous && Verbose) {
   1.225 +      warning("fstat failed on %s: %s\n", filename, strerror(errno));
   1.226 +    }
   1.227 +    return false;
   1.228 +  }
   1.229 +  if (statbuf.st_nlink > 1) {
   1.230 +    // A file with multiple links is not expected.
   1.231 +    if (PrintMiscellaneous && Verbose) {
   1.232 +      warning("file %s has multiple links\n", filename);
   1.233 +    }
   1.234 +    return false;
   1.235    }
   1.236    return true;
   1.237  }
   1.238  
   1.239 -
   1.240  // return the user name for the given user id
   1.241  //
   1.242  // the caller is expected to free the allocated memory.
   1.243 @@ -308,9 +497,10 @@
   1.244  
   1.245    const char* tmpdirname = os::get_temp_directory();
   1.246  
   1.247 -  DIR* tmpdirp = os::opendir(tmpdirname);
   1.248 -
   1.249 +  // open the temp directory
   1.250 +  DIR* tmpdirp = open_directory_secure(tmpdirname);
   1.251    if (tmpdirp == NULL) {
   1.252 +    // Cannot open the directory to get the user name, return.
   1.253      return NULL;
   1.254    }
   1.255  
   1.256 @@ -335,7 +525,8 @@
   1.257      strcat(usrdir_name, "/");
   1.258      strcat(usrdir_name, dentry->d_name);
   1.259  
   1.260 -    DIR* subdirp = os::opendir(usrdir_name);
   1.261 +    // open the user directory
   1.262 +    DIR* subdirp = open_directory_secure(usrdir_name);
   1.263  
   1.264      if (subdirp == NULL) {
   1.265        FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal);
   1.266 @@ -504,26 +695,6 @@
   1.267  }
   1.268  
   1.269  
   1.270 -// remove file
   1.271 -//
   1.272 -// this method removes the file with the given file name in the
   1.273 -// named directory.
   1.274 -//
   1.275 -static void remove_file(const char* dirname, const char* filename) {
   1.276 -
   1.277 -  size_t nbytes = strlen(dirname) + strlen(filename) + 2;
   1.278 -  char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
   1.279 -
   1.280 -  strcpy(path, dirname);
   1.281 -  strcat(path, "/");
   1.282 -  strcat(path, filename);
   1.283 -
   1.284 -  remove_file(path);
   1.285 -
   1.286 -  FREE_C_HEAP_ARRAY(char, path, mtInternal);
   1.287 -}
   1.288 -
   1.289 -
   1.290  // cleanup stale shared memory resources
   1.291  //
   1.292  // This method attempts to remove all stale shared memory files in
   1.293 @@ -535,16 +706,11 @@
   1.294  //
   1.295  static void cleanup_sharedmem_resources(const char* dirname) {
   1.296  
   1.297 -  // open the user temp directory
   1.298 -  DIR* dirp = os::opendir(dirname);
   1.299 -
   1.300 +  int saved_cwd_fd;
   1.301 +  // open the directory
   1.302 +  DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
   1.303    if (dirp == NULL) {
   1.304 -    // directory doesn't exist, so there is nothing to cleanup
   1.305 -    return;
   1.306 -  }
   1.307 -
   1.308 -  if (!is_directory_secure(dirname)) {
   1.309 -    // the directory is not a secure directory
   1.310 +     // directory doesn't exist or is insecure, so there is nothing to cleanup
   1.311      return;
   1.312    }
   1.313  
   1.314 @@ -558,6 +724,7 @@
   1.315    //
   1.316    struct dirent* entry;
   1.317    char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
   1.318 +
   1.319    errno = 0;
   1.320    while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
   1.321  
   1.322 @@ -568,7 +735,7 @@
   1.323        if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
   1.324  
   1.325          // attempt to remove all unexpected files, except "." and ".."
   1.326 -        remove_file(dirname, entry->d_name);
   1.327 +        unlink(entry->d_name);
   1.328        }
   1.329  
   1.330        errno = 0;
   1.331 @@ -591,11 +758,14 @@
   1.332      if ((pid == os::current_process_id()) ||
   1.333          (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
   1.334  
   1.335 -        remove_file(dirname, entry->d_name);
   1.336 +        unlink(entry->d_name);
   1.337      }
   1.338      errno = 0;
   1.339    }
   1.340 -  os::closedir(dirp);
   1.341 +
   1.342 +  // close the directory and reset the current working directory
   1.343 +  close_directory_secure_cwd(dirp, saved_cwd_fd);
   1.344 +
   1.345    FREE_C_HEAP_ARRAY(char, dbuf, mtInternal);
   1.346  }
   1.347  
   1.348 @@ -652,19 +822,54 @@
   1.349      return -1;
   1.350    }
   1.351  
   1.352 +  int saved_cwd_fd;
   1.353 +  // open the directory and set the current working directory to it
   1.354 +  DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
   1.355 +  if (dirp == NULL) {
   1.356 +    // Directory doesn't exist or is insecure, so cannot create shared
   1.357 +    // memory file.
   1.358 +    return -1;
   1.359 +  }
   1.360 +
   1.361 +  // Open the filename in the current directory.
   1.362 +  // Cannot use O_TRUNC here; truncation of an existing file has to happen
   1.363 +  // after the is_file_secure() check below.
   1.364    int result;
   1.365 -
   1.366 -  RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result);
   1.367 +  RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result);
   1.368    if (result == OS_ERR) {
   1.369      if (PrintMiscellaneous && Verbose) {
   1.370 -      warning("could not create file %s: %s\n", filename, strerror(errno));
   1.371 +      if (errno == ELOOP) {
   1.372 +        warning("file %s is a symlink and is not secure\n", filename);
   1.373 +      } else {
   1.374 +        warning("could not create file %s: %s\n", filename, strerror(errno));
   1.375 +      }
   1.376      }
   1.377 +    // close the directory and reset the current working directory
   1.378 +    close_directory_secure_cwd(dirp, saved_cwd_fd);
   1.379 +
   1.380      return -1;
   1.381    }
   1.382 +  // close the directory and reset the current working directory
   1.383 +  close_directory_secure_cwd(dirp, saved_cwd_fd);
   1.384  
   1.385    // save the file descriptor
   1.386    int fd = result;
   1.387  
   1.388 +  // check to see if the file is secure
   1.389 +  if (!is_file_secure(fd, filename)) {
   1.390 +    ::close(fd);
   1.391 +    return -1;
   1.392 +  }
   1.393 +
   1.394 +  // truncate the file to get rid of any existing data
   1.395 +  RESTARTABLE(::ftruncate(fd, (off_t)0), result);
   1.396 +  if (result == OS_ERR) {
   1.397 +    if (PrintMiscellaneous && Verbose) {
   1.398 +      warning("could not truncate shared memory file: %s\n", strerror(errno));
   1.399 +    }
   1.400 +    ::close(fd);
   1.401 +    return -1;
   1.402 +  }
   1.403    // set the file size
   1.404    RESTARTABLE(::ftruncate(fd, (off_t)size), result);
   1.405    if (result == OS_ERR) {
   1.406 @@ -700,8 +905,15 @@
   1.407        THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
   1.408      }
   1.409    }
   1.410 +  int fd = result;
   1.411  
   1.412 -  return result;
   1.413 +  // check to see if the file is secure
   1.414 +  if (!is_file_secure(fd, filename)) {
   1.415 +    ::close(fd);
   1.416 +    return -1;
   1.417 +  }
   1.418 +
   1.419 +  return fd;
   1.420  }
   1.421  
   1.422  // create a named shared memory region. returns the address of the
   1.423 @@ -733,13 +945,21 @@
   1.424    char* dirname = get_user_tmp_dir(user_name);
   1.425    char* filename = get_sharedmem_filename(dirname, vmid);
   1.426  
   1.427 +  // get the short filename
   1.428 +  char* short_filename = strrchr(filename, '/');
   1.429 +  if (short_filename == NULL) {
   1.430 +    short_filename = filename;
   1.431 +  } else {
   1.432 +    short_filename++;
   1.433 +  }
   1.434 +
   1.435    // cleanup any stale shared memory files
   1.436    cleanup_sharedmem_resources(dirname);
   1.437  
   1.438    assert(((size > 0) && (size % os::vm_page_size() == 0)),
   1.439           "unexpected PerfMemory region size");
   1.440  
   1.441 -  fd = create_sharedmem_resources(dirname, filename, size);
   1.442 +  fd = create_sharedmem_resources(dirname, short_filename, size);
   1.443  
   1.444    FREE_C_HEAP_ARRAY(char, user_name, mtInternal);
   1.445    FREE_C_HEAP_ARRAY(char, dirname, mtInternal);
   1.446 @@ -854,12 +1074,12 @@
   1.447    // constructs for the file and the shared memory mapping.
   1.448    if (mode == PerfMemory::PERF_MODE_RO) {
   1.449      mmap_prot = PROT_READ;
   1.450 -    file_flags = O_RDONLY;
   1.451 +    file_flags = O_RDONLY | O_NOFOLLOW;
   1.452    }
   1.453    else if (mode == PerfMemory::PERF_MODE_RW) {
   1.454  #ifdef LATER
   1.455      mmap_prot = PROT_READ | PROT_WRITE;
   1.456 -    file_flags = O_RDWR;
   1.457 +    file_flags = O_RDWR | O_NOFOLLOW;
   1.458  #else
   1.459      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
   1.460                "Unsupported access mode");

mercurial