src/os/linux/vm/perfMemory_linux.cpp

changeset 7493
d7b6bdd51abe
parent 6680
78bbf4d43a14
child 7495
42f27b59c550
     1.1 --- a/src/os/linux/vm/perfMemory_linux.cpp	Mon Nov 24 09:18:13 2014 -0800
     1.2 +++ b/src/os/linux/vm/perfMemory_linux.cpp	Mon Nov 17 15:51:46 2014 -0500
     1.3 @@ -197,7 +197,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 @@ -211,22 +242,180 @@
    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 +    if (PrintMiscellaneous && Verbose) {
   1.123 +      if (errno == ELOOP) {
   1.124 +        warning("directory %s is a symlink and is not secure\n", dirname);
   1.125 +      } else {
   1.126 +        warning("could not open directory %s: %s\n", dirname, strerror(errno));
   1.127 +      }
   1.128      }
   1.129 +    return dirp;
   1.130 +  }
   1.131 +  int fd = result;
   1.132 +
   1.133 +  // Determine if the open directory is secure.
   1.134 +  if (!is_dirfd_secure(fd)) {
   1.135 +    // The directory is not a secure directory.
   1.136 +    os::close(fd);
   1.137 +    return dirp;
   1.138 +  }
   1.139 +
   1.140 +  // Open the directory.
   1.141 +  dirp = ::opendir(dirname);
   1.142 +  if (dirp == NULL) {
   1.143 +    // The directory doesn't exist, close fd and return.
   1.144 +    os::close(fd);
   1.145 +    return dirp;
   1.146 +  }
   1.147 +
   1.148 +  // Check to make sure fd and dirp are referencing the same file system object.
   1.149 +  if (!is_same_fsobject(fd, dirfd(dirp))) {
   1.150 +    // The directory is not secure.
   1.151 +    os::close(fd);
   1.152 +    os::closedir(dirp);
   1.153 +    dirp = NULL;
   1.154 +    return dirp;
   1.155 +  }
   1.156 +
   1.157 +  // Close initial open now that we know directory is secure
   1.158 +  os::close(fd);
   1.159 +
   1.160 +  return dirp;
   1.161 +}
   1.162 +
   1.163 +// NOTE: The code below uses fchdir(), open() and unlink() because
   1.164 +// fdopendir(), openat() and unlinkat() are not supported on all
   1.165 +// versions.  Once the support for fdopendir(), openat() and unlinkat()
   1.166 +// is available on all supported versions the code can be changed
   1.167 +// to use these functions.
   1.168 +
   1.169 +// Open the directory of the given path, validate it and set the
   1.170 +// current working directory to it.
   1.171 +// Return a DIR * of the open directory and the saved cwd fd.
   1.172 +//
   1.173 +static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) {
   1.174 +
   1.175 +  // Open the directory.
   1.176 +  DIR* dirp = open_directory_secure(dirname);
   1.177 +  if (dirp == NULL) {
   1.178 +    // Directory doesn't exist or is insecure, so there is nothing to cleanup.
   1.179 +    return dirp;
   1.180 +  }
   1.181 +  int fd = dirfd(dirp);
   1.182 +
   1.183 +  // Open a fd to the cwd and save it off.
   1.184 +  int result;
   1.185 +  RESTARTABLE(::open(".", O_RDONLY), result);
   1.186 +  if (result == OS_ERR) {
   1.187 +    *saved_cwd_fd = -1;
   1.188 +  } else {
   1.189 +    *saved_cwd_fd = result;
   1.190 +  }
   1.191 +
   1.192 +  // Set the current directory to dirname by using the fd of the directory.
   1.193 +  result = fchdir(fd);
   1.194 +
   1.195 +  return dirp;
   1.196 +}
   1.197 +
   1.198 +// Close the directory and restore the current working directory.
   1.199 +//
   1.200 +static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) {
   1.201 +
   1.202 +  int result;
   1.203 +  // If we have a saved cwd change back to it and close the fd.
   1.204 +  if (saved_cwd_fd != -1) {
   1.205 +    result = fchdir(saved_cwd_fd);
   1.206 +    ::close(saved_cwd_fd);
   1.207 +  }
   1.208 +
   1.209 +  // Close the directory.
   1.210 +  os::closedir(dirp);
   1.211 +}
   1.212 +
   1.213 +// Check if the given file descriptor is considered a secure.
   1.214 +//
   1.215 +static bool is_file_secure(int fd, const char *filename) {
   1.216 +
   1.217 +  int result;
   1.218 +  struct stat statbuf;
   1.219 +
   1.220 +  // Determine if the file is secure.
   1.221 +  RESTARTABLE(::fstat(fd, &statbuf), result);
   1.222 +  if (result == OS_ERR) {
   1.223 +    if (PrintMiscellaneous && Verbose) {
   1.224 +      warning("fstat failed on %s: %s\n", filename, strerror(errno));
   1.225 +    }
   1.226 +    return false;
   1.227 +  }
   1.228 +  if (statbuf.st_nlink > 1) {
   1.229 +    // A file with multiple links is not expected.
   1.230 +    if (PrintMiscellaneous && Verbose) {
   1.231 +      warning("file %s has multiple links\n", filename);
   1.232 +    }
   1.233 +    return false;
   1.234    }
   1.235    return true;
   1.236  }
   1.237 @@ -317,9 +506,11 @@
   1.238  
   1.239    const char* tmpdirname = os::get_temp_directory();
   1.240  
   1.241 +  // open the temp directory
   1.242    DIR* tmpdirp = os::opendir(tmpdirname);
   1.243  
   1.244    if (tmpdirp == NULL) {
   1.245 +    // Cannot open the directory to get the user name, return.
   1.246      return NULL;
   1.247    }
   1.248  
   1.249 @@ -344,7 +535,8 @@
   1.250      strcat(usrdir_name, "/");
   1.251      strcat(usrdir_name, dentry->d_name);
   1.252  
   1.253 -    DIR* subdirp = os::opendir(usrdir_name);
   1.254 +    // open the user directory
   1.255 +    DIR* subdirp = open_directory_secure(usrdir_name);
   1.256  
   1.257      if (subdirp == NULL) {
   1.258        FREE_C_HEAP_ARRAY(char, usrdir_name, mtInternal);
   1.259 @@ -465,26 +657,6 @@
   1.260  }
   1.261  
   1.262  
   1.263 -// remove file
   1.264 -//
   1.265 -// this method removes the file with the given file name in the
   1.266 -// named directory.
   1.267 -//
   1.268 -static void remove_file(const char* dirname, const char* filename) {
   1.269 -
   1.270 -  size_t nbytes = strlen(dirname) + strlen(filename) + 2;
   1.271 -  char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
   1.272 -
   1.273 -  strcpy(path, dirname);
   1.274 -  strcat(path, "/");
   1.275 -  strcat(path, filename);
   1.276 -
   1.277 -  remove_file(path);
   1.278 -
   1.279 -  FREE_C_HEAP_ARRAY(char, path, mtInternal);
   1.280 -}
   1.281 -
   1.282 -
   1.283  // cleanup stale shared memory resources
   1.284  //
   1.285  // This method attempts to remove all stale shared memory files in
   1.286 @@ -496,16 +668,11 @@
   1.287  //
   1.288  static void cleanup_sharedmem_resources(const char* dirname) {
   1.289  
   1.290 -  // open the user temp directory
   1.291 -  DIR* dirp = os::opendir(dirname);
   1.292 -
   1.293 +  int saved_cwd_fd;
   1.294 +  // open the directory
   1.295 +  DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
   1.296    if (dirp == NULL) {
   1.297 -    // directory doesn't exist, so there is nothing to cleanup
   1.298 -    return;
   1.299 -  }
   1.300 -
   1.301 -  if (!is_directory_secure(dirname)) {
   1.302 -    // the directory is not a secure directory
   1.303 +    // directory doesn't exist or is insecure, so there is nothing to cleanup
   1.304      return;
   1.305    }
   1.306  
   1.307 @@ -519,6 +686,7 @@
   1.308    //
   1.309    struct dirent* entry;
   1.310    char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
   1.311 +
   1.312    errno = 0;
   1.313    while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
   1.314  
   1.315 @@ -527,9 +695,8 @@
   1.316      if (pid == 0) {
   1.317  
   1.318        if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
   1.319 -
   1.320          // attempt to remove all unexpected files, except "." and ".."
   1.321 -        remove_file(dirname, entry->d_name);
   1.322 +        unlink(entry->d_name);
   1.323        }
   1.324  
   1.325        errno = 0;
   1.326 @@ -551,12 +718,14 @@
   1.327      //
   1.328      if ((pid == os::current_process_id()) ||
   1.329          (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) {
   1.330 -
   1.331 -        remove_file(dirname, entry->d_name);
   1.332 +        unlink(entry->d_name);
   1.333      }
   1.334      errno = 0;
   1.335    }
   1.336 -  os::closedir(dirp);
   1.337 +
   1.338 +  // close the directory and reset the current working directory
   1.339 +  close_directory_secure_cwd(dirp, saved_cwd_fd);
   1.340 +
   1.341    FREE_C_HEAP_ARRAY(char, dbuf, mtInternal);
   1.342  }
   1.343  
   1.344 @@ -613,19 +782,54 @@
   1.345      return -1;
   1.346    }
   1.347  
   1.348 +  int saved_cwd_fd;
   1.349 +  // open the directory and set the current working directory to it
   1.350 +  DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd);
   1.351 +  if (dirp == NULL) {
   1.352 +    // Directory doesn't exist or is insecure, so cannot create shared
   1.353 +    // memory file.
   1.354 +    return -1;
   1.355 +  }
   1.356 +
   1.357 +  // Open the filename in the current directory.
   1.358 +  // Cannot use O_TRUNC here; truncation of an existing file has to happen
   1.359 +  // after the is_file_secure() check below.
   1.360    int result;
   1.361 -
   1.362 -  RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE), result);
   1.363 +  RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result);
   1.364    if (result == OS_ERR) {
   1.365      if (PrintMiscellaneous && Verbose) {
   1.366 -      warning("could not create file %s: %s\n", filename, strerror(errno));
   1.367 +      if (errno == ELOOP) {
   1.368 +        warning("file %s is a symlink and is not secure\n", filename);
   1.369 +      } else {
   1.370 +        warning("could not create file %s: %s\n", filename, strerror(errno));
   1.371 +      }
   1.372      }
   1.373 +    // close the directory and reset the current working directory
   1.374 +    close_directory_secure_cwd(dirp, saved_cwd_fd);
   1.375 +
   1.376      return -1;
   1.377    }
   1.378 +  // close the directory and reset the current working directory
   1.379 +  close_directory_secure_cwd(dirp, saved_cwd_fd);
   1.380  
   1.381    // save the file descriptor
   1.382    int fd = result;
   1.383  
   1.384 +  // check to see if the file is secure
   1.385 +  if (!is_file_secure(fd, filename)) {
   1.386 +    ::close(fd);
   1.387 +    return -1;
   1.388 +  }
   1.389 +
   1.390 +  // truncate the file to get rid of any existing data
   1.391 +  RESTARTABLE(::ftruncate(fd, (off_t)0), result);
   1.392 +  if (result == OS_ERR) {
   1.393 +    if (PrintMiscellaneous && Verbose) {
   1.394 +      warning("could not truncate shared memory file: %s\n", strerror(errno));
   1.395 +    }
   1.396 +    ::close(fd);
   1.397 +    return -1;
   1.398 +  }
   1.399    // set the file size
   1.400    RESTARTABLE(::ftruncate(fd, (off_t)size), result);
   1.401    if (result == OS_ERR) {
   1.402 @@ -683,8 +887,15 @@
   1.403        THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
   1.404      }
   1.405    }
   1.406 +  int fd = result;
   1.407  
   1.408 -  return result;
   1.409 +  // check to see if the file is secure
   1.410 +  if (!is_file_secure(fd, filename)) {
   1.411 +    ::close(fd);
   1.412 +    return -1;
   1.413 +  }
   1.414 +
   1.415 +  return fd;
   1.416  }
   1.417  
   1.418  // create a named shared memory region. returns the address of the
   1.419 @@ -715,6 +926,13 @@
   1.420  
   1.421    char* dirname = get_user_tmp_dir(user_name);
   1.422    char* filename = get_sharedmem_filename(dirname, vmid);
   1.423 +  // get the short filename
   1.424 +  char* short_filename = strrchr(filename, '/');
   1.425 +  if (short_filename == NULL) {
   1.426 +    short_filename = filename;
   1.427 +  } else {
   1.428 +    short_filename++;
   1.429 +  }
   1.430  
   1.431    // cleanup any stale shared memory files
   1.432    cleanup_sharedmem_resources(dirname);
   1.433 @@ -722,7 +940,7 @@
   1.434    assert(((size > 0) && (size % os::vm_page_size() == 0)),
   1.435           "unexpected PerfMemory region size");
   1.436  
   1.437 -  fd = create_sharedmem_resources(dirname, filename, size);
   1.438 +  fd = create_sharedmem_resources(dirname, short_filename, size);
   1.439  
   1.440    FREE_C_HEAP_ARRAY(char, user_name, mtInternal);
   1.441    FREE_C_HEAP_ARRAY(char, dirname, mtInternal);
   1.442 @@ -837,12 +1055,12 @@
   1.443    // constructs for the file and the shared memory mapping.
   1.444    if (mode == PerfMemory::PERF_MODE_RO) {
   1.445      mmap_prot = PROT_READ;
   1.446 -    file_flags = O_RDONLY;
   1.447 +    file_flags = O_RDONLY | O_NOFOLLOW;
   1.448    }
   1.449    else if (mode == PerfMemory::PERF_MODE_RW) {
   1.450  #ifdef LATER
   1.451      mmap_prot = PROT_READ | PROT_WRITE;
   1.452 -    file_flags = O_RDWR;
   1.453 +    file_flags = O_RDWR | O_NOFOLLOW;
   1.454  #else
   1.455      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
   1.456                "Unsupported access mode");

mercurial