perfMemory_windows.cpp revision 10627:1537c752a7f5
1170754Sdelphij/*
2170754Sdelphij * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
3170754Sdelphij * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4170754Sdelphij *
5170754Sdelphij * This code is free software; you can redistribute it and/or modify it
6170754Sdelphij * under the terms of the GNU General Public License version 2 only, as
7170754Sdelphij * published by the Free Software Foundation.
8170754Sdelphij *
9170754Sdelphij * This code is distributed in the hope that it will be useful, but WITHOUT
10170754Sdelphij * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11170754Sdelphij * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12170754Sdelphij * version 2 for more details (a copy is included in the LICENSE file that
13170754Sdelphij * accompanied this code).
14170754Sdelphij *
15170754Sdelphij * You should have received a copy of the GNU General Public License version
16170754Sdelphij * 2 along with this work; if not, write to the Free Software Foundation,
17170754Sdelphij * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18170754Sdelphij *
19170754Sdelphij * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20170754Sdelphij * or visit www.oracle.com if you need additional information or have any
21170754Sdelphij * questions.
22170754Sdelphij *
23170754Sdelphij */
24170754Sdelphij
25170754Sdelphij#include "precompiled.hpp"
26170754Sdelphij#include "classfile/vmSymbols.hpp"
27170754Sdelphij#include "memory/allocation.inline.hpp"
28170754Sdelphij#include "memory/resourceArea.hpp"
29170754Sdelphij#include "oops/oop.inline.hpp"
30170754Sdelphij#include "os_windows.inline.hpp"
31170754Sdelphij#include "runtime/handles.inline.hpp"
32170754Sdelphij#include "runtime/os.hpp"
33170754Sdelphij#include "runtime/perfMemory.hpp"
34170754Sdelphij#include "services/memTracker.hpp"
35170754Sdelphij#include "utilities/exceptions.hpp"
36170754Sdelphij
37170754Sdelphij#include <windows.h>
38170754Sdelphij#include <sys/types.h>
39170754Sdelphij#include <sys/stat.h>
40170754Sdelphij#include <errno.h>
41170754Sdelphij#include <lmcons.h>
42170754Sdelphij
43170754Sdelphijtypedef BOOL (WINAPI *SetSecurityDescriptorControlFnPtr)(
44170754Sdelphij   IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
45170754Sdelphij   IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
46170754Sdelphij   IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet);
47170754Sdelphij
48170754Sdelphij// Standard Memory Implementation Details
49170754Sdelphij
50170754Sdelphij// create the PerfData memory region in standard memory.
51170754Sdelphij//
52170754Sdelphijstatic char* create_standard_memory(size_t size) {
53170754Sdelphij
54170754Sdelphij  // allocate an aligned chuck of memory
55170754Sdelphij  char* mapAddress = os::reserve_memory(size);
56170754Sdelphij
57170754Sdelphij  if (mapAddress == NULL) {
58170754Sdelphij    return NULL;
59170754Sdelphij  }
60170754Sdelphij
61170754Sdelphij  // commit memory
62170754Sdelphij  if (!os::commit_memory(mapAddress, size, !ExecMem)) {
63170754Sdelphij    if (PrintMiscellaneous && Verbose) {
64170754Sdelphij      warning("Could not commit PerfData memory\n");
65170754Sdelphij    }
66170754Sdelphij    os::release_memory(mapAddress, size);
67170754Sdelphij    return NULL;
68170754Sdelphij  }
69170754Sdelphij
70170754Sdelphij  return mapAddress;
71170754Sdelphij}
72170754Sdelphij
73170754Sdelphij// delete the PerfData memory region
74170754Sdelphij//
75170754Sdelphijstatic void delete_standard_memory(char* addr, size_t size) {
76170754Sdelphij
77170754Sdelphij  // there are no persistent external resources to cleanup for standard
78170754Sdelphij  // memory. since DestroyJavaVM does not support unloading of the JVM,
79170754Sdelphij  // cleanup of the memory resource is not performed. The memory will be
80170754Sdelphij  // reclaimed by the OS upon termination of the process.
81170754Sdelphij  //
82170754Sdelphij  return;
83170754Sdelphij
84170754Sdelphij}
85170754Sdelphij
86170754Sdelphij// save the specified memory region to the given file
87170754Sdelphij//
88170754Sdelphijstatic void save_memory_to_file(char* addr, size_t size) {
89170754Sdelphij
90170754Sdelphij  const char* destfile = PerfMemory::get_perfdata_file_path();
91170754Sdelphij  assert(destfile[0] != '\0', "invalid Perfdata file path");
92170754Sdelphij
93170754Sdelphij  int fd = ::_open(destfile, _O_BINARY|_O_CREAT|_O_WRONLY|_O_TRUNC,
94170754Sdelphij                   _S_IREAD|_S_IWRITE);
95170754Sdelphij
96170754Sdelphij  if (fd == OS_ERR) {
97170754Sdelphij    if (PrintMiscellaneous && Verbose) {
98170754Sdelphij      warning("Could not create Perfdata save file: %s: %s\n",
99170754Sdelphij              destfile, os::strerror(errno));
100170754Sdelphij    }
101170754Sdelphij  } else {
102170754Sdelphij    for (size_t remaining = size; remaining > 0;) {
103170754Sdelphij
104170754Sdelphij      int nbytes = ::_write(fd, addr, (unsigned int)remaining);
105170754Sdelphij      if (nbytes == OS_ERR) {
106170754Sdelphij        if (PrintMiscellaneous && Verbose) {
107170754Sdelphij          warning("Could not write Perfdata save file: %s: %s\n",
108170754Sdelphij                  destfile, os::strerror(errno));
109170754Sdelphij        }
110170754Sdelphij        break;
111170754Sdelphij      }
112170754Sdelphij
113170754Sdelphij      remaining -= (size_t)nbytes;
114170754Sdelphij      addr += nbytes;
115170754Sdelphij    }
116170754Sdelphij
117170754Sdelphij    int result = ::_close(fd);
118170754Sdelphij    if (PrintMiscellaneous && Verbose) {
119170754Sdelphij      if (result == OS_ERR) {
120170754Sdelphij        warning("Could not close %s: %s\n", destfile, os::strerror(errno));
121170754Sdelphij      }
122170754Sdelphij    }
123170754Sdelphij  }
124170754Sdelphij
125170754Sdelphij  FREE_C_HEAP_ARRAY(char, destfile);
126170754Sdelphij}
127170754Sdelphij
128170754Sdelphij// Shared Memory Implementation Details
129170754Sdelphij
130170754Sdelphij// Note: the win32 shared memory implementation uses two objects to represent
131170754Sdelphij// the shared memory: a windows kernel based file mapping object and a backing
132170754Sdelphij// store file. On windows, the name space for shared memory is a kernel
133170754Sdelphij// based name space that is disjoint from other win32 name spaces. Since Java
134170754Sdelphij// is unaware of this name space, a parallel file system based name space is
135170754Sdelphij// maintained, which provides a common file system based shared memory name
136170754Sdelphij// space across the supported platforms and one that Java apps can deal with
137170754Sdelphij// through simple file apis.
138170754Sdelphij//
139170754Sdelphij// For performance and resource cleanup reasons, it is recommended that the
140170754Sdelphij// user specific directory and the backing store file be stored in either a
141170754Sdelphij// RAM based file system or a local disk based file system. Network based
142170754Sdelphij// file systems are not recommended for performance reasons. In addition,
143170754Sdelphij// use of SMB network based file systems may result in unsuccesful cleanup
144170754Sdelphij// of the disk based resource on exit of the VM. The Windows TMP and TEMP
145170754Sdelphij// environement variables, as used by the GetTempPath() Win32 API (see
146170754Sdelphij// os::get_temp_directory() in os_win32.cpp), control the location of the
147170754Sdelphij// user specific directory and the shared memory backing store file.
148170754Sdelphij
149170754Sdelphijstatic HANDLE sharedmem_fileMapHandle = NULL;
150170754Sdelphijstatic HANDLE sharedmem_fileHandle = INVALID_HANDLE_VALUE;
151170754Sdelphijstatic char*  sharedmem_fileName = NULL;
152170754Sdelphij
153170754Sdelphij// return the user specific temporary directory name.
154170754Sdelphij//
155170754Sdelphij// the caller is expected to free the allocated memory.
156170754Sdelphij//
157170754Sdelphijstatic char* get_user_tmp_dir(const char* user) {
158170754Sdelphij
159170754Sdelphij  const char* tmpdir = os::get_temp_directory();
160170754Sdelphij  const char* perfdir = PERFDATA_NAME;
161170754Sdelphij  size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3;
162170754Sdelphij  char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
163170754Sdelphij
164170754Sdelphij  // construct the path name to user specific tmp directory
165170754Sdelphij  _snprintf(dirname, nbytes, "%s\\%s_%s", tmpdir, perfdir, user);
166170754Sdelphij
167170754Sdelphij  return dirname;
168170754Sdelphij}
169170754Sdelphij
170170754Sdelphij// convert the given file name into a process id. if the file
171170754Sdelphij// does not meet the file naming constraints, return 0.
172170754Sdelphij//
173170754Sdelphijstatic int filename_to_pid(const char* filename) {
174170754Sdelphij
175170754Sdelphij  // a filename that doesn't begin with a digit is not a
176170754Sdelphij  // candidate for conversion.
177170754Sdelphij  //
178170754Sdelphij  if (!isdigit(*filename)) {
179170754Sdelphij    return 0;
180170754Sdelphij  }
181170754Sdelphij
182170754Sdelphij  // check if file name can be converted to an integer without
183170754Sdelphij  // any leftover characters.
184170754Sdelphij  //
185170754Sdelphij  char* remainder = NULL;
186170754Sdelphij  errno = 0;
187170754Sdelphij  int pid = (int)strtol(filename, &remainder, 10);
188170754Sdelphij
189170754Sdelphij  if (errno != 0) {
190170754Sdelphij    return 0;
191170754Sdelphij  }
192170754Sdelphij
193170754Sdelphij  // check for left over characters. If any, then the filename is
194170754Sdelphij  // not a candidate for conversion.
195170754Sdelphij  //
196170754Sdelphij  if (remainder != NULL && *remainder != '\0') {
197170754Sdelphij    return 0;
198170754Sdelphij  }
199170754Sdelphij
200170754Sdelphij  // successful conversion, return the pid
201170754Sdelphij  return pid;
202170754Sdelphij}
203170754Sdelphij
204170754Sdelphij// check if the given path is considered a secure directory for
205170754Sdelphij// the backing store files. Returns true if the directory exists
206170754Sdelphij// and is considered a secure location. Returns false if the path
207170754Sdelphij// is a symbolic link or if an error occurred.
208170754Sdelphij//
209170754Sdelphijstatic bool is_directory_secure(const char* path) {
210170754Sdelphij
211170754Sdelphij  DWORD fa;
212170754Sdelphij
213170754Sdelphij  fa = GetFileAttributes(path);
214170754Sdelphij  if (fa == 0xFFFFFFFF) {
215170754Sdelphij    DWORD lasterror = GetLastError();
216170754Sdelphij    if (lasterror == ERROR_FILE_NOT_FOUND) {
217170754Sdelphij      return false;
218170754Sdelphij    }
219170754Sdelphij    else {
220170754Sdelphij      // unexpected error, declare the path insecure
221170754Sdelphij      if (PrintMiscellaneous && Verbose) {
222170754Sdelphij        warning("could not get attributes for file %s: ",
223170754Sdelphij                " lasterror = %d\n", path, lasterror);
224170754Sdelphij      }
225170754Sdelphij      return false;
226170754Sdelphij    }
227170754Sdelphij  }
228170754Sdelphij
229170754Sdelphij  if (fa & FILE_ATTRIBUTE_REPARSE_POINT) {
230170754Sdelphij    // we don't accept any redirection for the user specific directory
231170754Sdelphij    // so declare the path insecure. This may be too conservative,
232170754Sdelphij    // as some types of reparse points might be acceptable, but it
233170754Sdelphij    // is probably more secure to avoid these conditions.
234170754Sdelphij    //
235170754Sdelphij    if (PrintMiscellaneous && Verbose) {
236170754Sdelphij      warning("%s is a reparse point\n", path);
237170754Sdelphij    }
238170754Sdelphij    return false;
239170754Sdelphij  }
240170754Sdelphij
241170754Sdelphij  if (fa & FILE_ATTRIBUTE_DIRECTORY) {
242170754Sdelphij    // this is the expected case. Since windows supports symbolic
243170754Sdelphij    // links to directories only, not to files, there is no need
244170754Sdelphij    // to check for open write permissions on the directory. If the
245170754Sdelphij    // directory has open write permissions, any files deposited that
246170754Sdelphij    // are not expected will be removed by the cleanup code.
247170754Sdelphij    //
248170754Sdelphij    return true;
249170754Sdelphij  }
250170754Sdelphij  else {
251170754Sdelphij    // this is either a regular file or some other type of file,
252170754Sdelphij    // any of which are unexpected and therefore insecure.
253170754Sdelphij    //
254170754Sdelphij    if (PrintMiscellaneous && Verbose) {
255170754Sdelphij      warning("%s is not a directory, file attributes = "
256170754Sdelphij              INTPTR_FORMAT "\n", path, fa);
257170754Sdelphij    }
258170754Sdelphij    return false;
259170754Sdelphij  }
260170754Sdelphij}
261170754Sdelphij
262170754Sdelphij// return the user name for the owner of this process
263170754Sdelphij//
264170754Sdelphij// the caller is expected to free the allocated memory.
265170754Sdelphij//
266170754Sdelphijstatic char* get_user_name() {
267170754Sdelphij
268170754Sdelphij  /* get the user name. This code is adapted from code found in
269170754Sdelphij   * the jdk in src/windows/native/java/lang/java_props_md.c
270170754Sdelphij   * java_props_md.c  1.29 02/02/06. According to the original
271170754Sdelphij   * source, the call to GetUserName is avoided because of a resulting
272170754Sdelphij   * increase in footprint of 100K.
273170754Sdelphij   */
274170754Sdelphij  char* user = getenv("USERNAME");
275170754Sdelphij  char buf[UNLEN+1];
276170754Sdelphij  DWORD buflen = sizeof(buf);
277170754Sdelphij  if (user == NULL || strlen(user) == 0) {
278170754Sdelphij    if (GetUserName(buf, &buflen)) {
279170754Sdelphij      user = buf;
280170754Sdelphij    }
281170754Sdelphij    else {
282170754Sdelphij      return NULL;
283170754Sdelphij    }
284170754Sdelphij  }
285170754Sdelphij
286170754Sdelphij  char* user_name = NEW_C_HEAP_ARRAY(char, strlen(user)+1, mtInternal);
287170754Sdelphij  strcpy(user_name, user);
288170754Sdelphij
289170754Sdelphij  return user_name;
290170754Sdelphij}
291170754Sdelphij
292170754Sdelphij// return the name of the user that owns the process identified by vmid.
293170754Sdelphij//
294170754Sdelphij// This method uses a slow directory search algorithm to find the backing
295170754Sdelphij// store file for the specified vmid and returns the user name, as determined
296170754Sdelphij// by the user name suffix of the hsperfdata_<username> directory name.
297170754Sdelphij//
298170754Sdelphij// the caller is expected to free the allocated memory.
299170754Sdelphij//
300170754Sdelphijstatic char* get_user_name_slow(int vmid) {
301170754Sdelphij
302170754Sdelphij  // directory search
303170754Sdelphij  char* latest_user = NULL;
304170754Sdelphij  time_t latest_ctime = 0;
305170754Sdelphij
306170754Sdelphij  const char* tmpdirname = os::get_temp_directory();
307170754Sdelphij
308170754Sdelphij  DIR* tmpdirp = os::opendir(tmpdirname);
309170754Sdelphij
310170754Sdelphij  if (tmpdirp == NULL) {
311170754Sdelphij    return NULL;
312170754Sdelphij  }
313170754Sdelphij
314170754Sdelphij  // for each entry in the directory that matches the pattern hsperfdata_*,
315170754Sdelphij  // open the directory and check if the file for the given vmid exists.
316170754Sdelphij  // The file with the expected name and the latest creation date is used
317170754Sdelphij  // to determine the user name for the process id.
318170754Sdelphij  //
319170754Sdelphij  struct dirent* dentry;
320170754Sdelphij  char* tdbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(tmpdirname), mtInternal);
321170754Sdelphij  errno = 0;
322170754Sdelphij  while ((dentry = os::readdir(tmpdirp, (struct dirent *)tdbuf)) != NULL) {
323170754Sdelphij
324170754Sdelphij    // check if the directory entry is a hsperfdata file
325170754Sdelphij    if (strncmp(dentry->d_name, PERFDATA_NAME, strlen(PERFDATA_NAME)) != 0) {
326170754Sdelphij      continue;
327170754Sdelphij    }
328170754Sdelphij
329170754Sdelphij    char* usrdir_name = NEW_C_HEAP_ARRAY(char,
330170754Sdelphij        strlen(tmpdirname) + strlen(dentry->d_name) + 2, mtInternal);
331170754Sdelphij    strcpy(usrdir_name, tmpdirname);
332170754Sdelphij    strcat(usrdir_name, "\\");
333170754Sdelphij    strcat(usrdir_name, dentry->d_name);
334170754Sdelphij
335170754Sdelphij    DIR* subdirp = os::opendir(usrdir_name);
336170754Sdelphij
337170754Sdelphij    if (subdirp == NULL) {
338170754Sdelphij      FREE_C_HEAP_ARRAY(char, usrdir_name);
339170754Sdelphij      continue;
340170754Sdelphij    }
341170754Sdelphij
342170754Sdelphij    // Since we don't create the backing store files in directories
343170754Sdelphij    // pointed to by symbolic links, we also don't follow them when
344170754Sdelphij    // looking for the files. We check for a symbolic link after the
345170754Sdelphij    // call to opendir in order to eliminate a small window where the
346170754Sdelphij    // symlink can be exploited.
347170754Sdelphij    //
348170754Sdelphij    if (!is_directory_secure(usrdir_name)) {
349170754Sdelphij      FREE_C_HEAP_ARRAY(char, usrdir_name);
350170754Sdelphij      os::closedir(subdirp);
351170754Sdelphij      continue;
352170754Sdelphij    }
353170754Sdelphij
354170754Sdelphij    struct dirent* udentry;
355170754Sdelphij    char* udbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(usrdir_name), mtInternal);
356170754Sdelphij    errno = 0;
357170754Sdelphij    while ((udentry = os::readdir(subdirp, (struct dirent *)udbuf)) != NULL) {
358170754Sdelphij
359170754Sdelphij      if (filename_to_pid(udentry->d_name) == vmid) {
360170754Sdelphij        struct stat statbuf;
361170754Sdelphij
362170754Sdelphij        char* filename = NEW_C_HEAP_ARRAY(char,
363170754Sdelphij           strlen(usrdir_name) + strlen(udentry->d_name) + 2, mtInternal);
364170754Sdelphij
365170754Sdelphij        strcpy(filename, usrdir_name);
366170754Sdelphij        strcat(filename, "\\");
367170754Sdelphij        strcat(filename, udentry->d_name);
368170754Sdelphij
369170754Sdelphij        if (::stat(filename, &statbuf) == OS_ERR) {
370170754Sdelphij           FREE_C_HEAP_ARRAY(char, filename);
371170754Sdelphij           continue;
372170754Sdelphij        }
373170754Sdelphij
374170754Sdelphij        // skip over files that are not regular files.
375170754Sdelphij        if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
376170754Sdelphij          FREE_C_HEAP_ARRAY(char, filename);
377170754Sdelphij          continue;
378170754Sdelphij        }
379170754Sdelphij
380170754Sdelphij        // If we found a matching file with a newer creation time, then
381170754Sdelphij        // save the user name. The newer creation time indicates that
382170754Sdelphij        // we found a newer incarnation of the process associated with
383170754Sdelphij        // vmid. Due to the way that Windows recycles pids and the fact
384170754Sdelphij        // that we can't delete the file from the file system namespace
385170754Sdelphij        // until last close, it is possible for there to be more than
386170754Sdelphij        // one hsperfdata file with a name matching vmid (diff users).
387170754Sdelphij        //
388170754Sdelphij        // We no longer ignore hsperfdata files where (st_size == 0).
389170754Sdelphij        // In this function, all we're trying to do is determine the
390170754Sdelphij        // name of the user that owns the process associated with vmid
391170754Sdelphij        // so the size doesn't matter. Very rarely, we have observed
392170754Sdelphij        // hsperfdata files where (st_size == 0) and the st_size field
393170754Sdelphij        // later becomes the expected value.
394170754Sdelphij        //
395170754Sdelphij        if (statbuf.st_ctime > latest_ctime) {
396170754Sdelphij          char* user = strchr(dentry->d_name, '_') + 1;
397170754Sdelphij
398170754Sdelphij          if (latest_user != NULL) FREE_C_HEAP_ARRAY(char, latest_user);
399170754Sdelphij          latest_user = NEW_C_HEAP_ARRAY(char, strlen(user)+1, mtInternal);
400170754Sdelphij
401170754Sdelphij          strcpy(latest_user, user);
402170754Sdelphij          latest_ctime = statbuf.st_ctime;
403170754Sdelphij        }
404170754Sdelphij
405170754Sdelphij        FREE_C_HEAP_ARRAY(char, filename);
406170754Sdelphij      }
407170754Sdelphij    }
408170754Sdelphij    os::closedir(subdirp);
409170754Sdelphij    FREE_C_HEAP_ARRAY(char, udbuf);
410170754Sdelphij    FREE_C_HEAP_ARRAY(char, usrdir_name);
411170754Sdelphij  }
412170754Sdelphij  os::closedir(tmpdirp);
413170754Sdelphij  FREE_C_HEAP_ARRAY(char, tdbuf);
414170754Sdelphij
415170754Sdelphij  return(latest_user);
416170754Sdelphij}
417170754Sdelphij
418170754Sdelphij// return the name of the user that owns the process identified by vmid.
419170754Sdelphij//
420170754Sdelphij// note: this method should only be used via the Perf native methods.
421170754Sdelphij// There are various costs to this method and limiting its use to the
422170754Sdelphij// Perf native methods limits the impact to monitoring applications only.
423170754Sdelphij//
424170754Sdelphijstatic char* get_user_name(int vmid) {
425170754Sdelphij
426170754Sdelphij  // A fast implementation is not provided at this time. It's possible
427170754Sdelphij  // to provide a fast process id to user name mapping function using
428170754Sdelphij  // the win32 apis, but the default ACL for the process object only
429170754Sdelphij  // allows processes with the same owner SID to acquire the process
430170754Sdelphij  // handle (via OpenProcess(PROCESS_QUERY_INFORMATION)). It's possible
431170754Sdelphij  // to have the JVM change the ACL for the process object to allow arbitrary
432170754Sdelphij  // users to access the process handle and the process security token.
433170754Sdelphij  // The security ramifications need to be studied before providing this
434170754Sdelphij  // mechanism.
435170754Sdelphij  //
436170754Sdelphij  return get_user_name_slow(vmid);
437170754Sdelphij}
438170754Sdelphij
439170754Sdelphij// return the name of the shared memory file mapping object for the
440170754Sdelphij// named shared memory region for the given user name and vmid.
441170754Sdelphij//
442170754Sdelphij// The file mapping object's name is not the file name. It is a name
443170754Sdelphij// in a separate name space.
444170754Sdelphij//
445170754Sdelphij// the caller is expected to free the allocated memory.
446170754Sdelphij//
447170754Sdelphijstatic char *get_sharedmem_objectname(const char* user, int vmid) {
448170754Sdelphij
449170754Sdelphij  // construct file mapping object's name, add 3 for two '_' and a
450170754Sdelphij  // null terminator.
451170754Sdelphij  int nbytes = (int)strlen(PERFDATA_NAME) + (int)strlen(user) + 3;
452170754Sdelphij
453170754Sdelphij  // the id is converted to an unsigned value here because win32 allows
454170754Sdelphij  // negative process ids. However, OpenFileMapping API complains
455170754Sdelphij  // about a name containing a '-' characters.
456170754Sdelphij  //
457170754Sdelphij  nbytes += UINT_CHARS;
458170754Sdelphij  char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
459170754Sdelphij  _snprintf(name, nbytes, "%s_%s_%u", PERFDATA_NAME, user, vmid);
460170754Sdelphij
461170754Sdelphij  return name;
462170754Sdelphij}
463170754Sdelphij
464170754Sdelphij// return the file name of the backing store file for the named
465170754Sdelphij// shared memory region for the given user name and vmid.
466170754Sdelphij//
467170754Sdelphij// the caller is expected to free the allocated memory.
468170754Sdelphij//
469170754Sdelphijstatic char* get_sharedmem_filename(const char* dirname, int vmid) {
470170754Sdelphij
471170754Sdelphij  // add 2 for the file separator and a null terminator.
472170754Sdelphij  size_t nbytes = strlen(dirname) + UINT_CHARS + 2;
473170754Sdelphij
474170754Sdelphij  char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
475170754Sdelphij  _snprintf(name, nbytes, "%s\\%d", dirname, vmid);
476170754Sdelphij
477170754Sdelphij  return name;
478170754Sdelphij}
479170754Sdelphij
480170754Sdelphij// remove file
481170754Sdelphij//
482170754Sdelphij// this method removes the file with the given file name.
483170754Sdelphij//
484170754Sdelphij// Note: if the indicated file is on an SMB network file system, this
485170754Sdelphij// method may be unsuccessful in removing the file.
486170754Sdelphij//
487170754Sdelphijstatic void remove_file(const char* dirname, const char* filename) {
488170754Sdelphij
489170754Sdelphij  size_t nbytes = strlen(dirname) + strlen(filename) + 2;
490170754Sdelphij  char* path = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
491170754Sdelphij
492170754Sdelphij  strcpy(path, dirname);
493170754Sdelphij  strcat(path, "\\");
494170754Sdelphij  strcat(path, filename);
495170754Sdelphij
496170754Sdelphij  if (::unlink(path) == OS_ERR) {
497170754Sdelphij    if (PrintMiscellaneous && Verbose) {
498170754Sdelphij      if (errno != ENOENT) {
499170754Sdelphij        warning("Could not unlink shared memory backing"
500170754Sdelphij                " store file %s : %s\n", path, os::strerror(errno));
501170754Sdelphij      }
502170754Sdelphij    }
503170754Sdelphij  }
504170754Sdelphij
505170754Sdelphij  FREE_C_HEAP_ARRAY(char, path);
506170754Sdelphij}
507170754Sdelphij
508170754Sdelphij// returns true if the process represented by pid is alive, otherwise
509170754Sdelphij// returns false. the validity of the result is only accurate if the
510170754Sdelphij// target process is owned by the same principal that owns this process.
511170754Sdelphij// this method should not be used if to test the status of an otherwise
512170754Sdelphij// arbitrary process unless it is know that this process has the appropriate
513170754Sdelphij// privileges to guarantee a result valid.
514170754Sdelphij//
515170754Sdelphijstatic bool is_alive(int pid) {
516170754Sdelphij
517170754Sdelphij  HANDLE ph = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
518170754Sdelphij  if (ph == NULL) {
519170754Sdelphij    // the process does not exist.
520170754Sdelphij    if (PrintMiscellaneous && Verbose) {
521170754Sdelphij      DWORD lastError = GetLastError();
522170754Sdelphij      if (lastError != ERROR_INVALID_PARAMETER) {
523170754Sdelphij        warning("OpenProcess failed: %d\n", GetLastError());
524170754Sdelphij      }
525170754Sdelphij    }
526170754Sdelphij    return false;
527170754Sdelphij  }
528170754Sdelphij
529170754Sdelphij  DWORD exit_status;
530170754Sdelphij  if (!GetExitCodeProcess(ph, &exit_status)) {
531170754Sdelphij    if (PrintMiscellaneous && Verbose) {
532170754Sdelphij      warning("GetExitCodeProcess failed: %d\n", GetLastError());
533170754Sdelphij    }
534170754Sdelphij    CloseHandle(ph);
535170754Sdelphij    return false;
536170754Sdelphij  }
537170754Sdelphij
538170754Sdelphij  CloseHandle(ph);
539170754Sdelphij  return (exit_status == STILL_ACTIVE) ? true : false;
540170754Sdelphij}
541170754Sdelphij
542170754Sdelphij// check if the file system is considered secure for the backing store files
543170754Sdelphij//
544170754Sdelphijstatic bool is_filesystem_secure(const char* path) {
545170754Sdelphij
546170754Sdelphij  char root_path[MAX_PATH];
547170754Sdelphij  char fs_type[MAX_PATH];
548170754Sdelphij
549170754Sdelphij  if (PerfBypassFileSystemCheck) {
550170754Sdelphij    if (PrintMiscellaneous && Verbose) {
551170754Sdelphij      warning("bypassing file system criteria checks for %s\n", path);
552170754Sdelphij    }
553170754Sdelphij    return true;
554170754Sdelphij  }
555170754Sdelphij
556170754Sdelphij  char* first_colon = strchr((char *)path, ':');
557170754Sdelphij  if (first_colon == NULL) {
558170754Sdelphij    if (PrintMiscellaneous && Verbose) {
559170754Sdelphij      warning("expected device specifier in path: %s\n", path);
560170754Sdelphij    }
561170754Sdelphij    return false;
562170754Sdelphij  }
563170754Sdelphij
564170754Sdelphij  size_t len = (size_t)(first_colon - path);
565170754Sdelphij  assert(len + 2 <= MAX_PATH, "unexpected device specifier length");
566170754Sdelphij  strncpy(root_path, path, len + 1);
567170754Sdelphij  root_path[len + 1] = '\\';
568170754Sdelphij  root_path[len + 2] = '\0';
569170754Sdelphij
570170754Sdelphij  // check that we have something like "C:\" or "AA:\"
571170754Sdelphij  assert(strlen(root_path) >= 3, "device specifier too short");
572170754Sdelphij  assert(strchr(root_path, ':') != NULL, "bad device specifier format");
573170754Sdelphij  assert(strchr(root_path, '\\') != NULL, "bad device specifier format");
574170754Sdelphij
575170754Sdelphij  DWORD maxpath;
576170754Sdelphij  DWORD flags;
577170754Sdelphij
578170754Sdelphij  if (!GetVolumeInformation(root_path, NULL, 0, NULL, &maxpath,
579170754Sdelphij                            &flags, fs_type, MAX_PATH)) {
580170754Sdelphij    // we can't get information about the volume, so assume unsafe.
581170754Sdelphij    if (PrintMiscellaneous && Verbose) {
582170754Sdelphij      warning("could not get device information for %s: "
583170754Sdelphij              " path = %s: lasterror = %d\n",
584170754Sdelphij              root_path, path, GetLastError());
585170754Sdelphij    }
586170754Sdelphij    return false;
587170754Sdelphij  }
588170754Sdelphij
589170754Sdelphij  if ((flags & FS_PERSISTENT_ACLS) == 0) {
590170754Sdelphij    // file system doesn't support ACLs, declare file system unsafe
591170754Sdelphij    if (PrintMiscellaneous && Verbose) {
592170754Sdelphij      warning("file system type %s on device %s does not support"
593170754Sdelphij              " ACLs\n", fs_type, root_path);
594170754Sdelphij    }
595170754Sdelphij    return false;
596170754Sdelphij  }
597170754Sdelphij
598170754Sdelphij  if ((flags & FS_VOL_IS_COMPRESSED) != 0) {
599170754Sdelphij    // file system is compressed, declare file system unsafe
600170754Sdelphij    if (PrintMiscellaneous && Verbose) {
601170754Sdelphij      warning("file system type %s on device %s is compressed\n",
602170754Sdelphij              fs_type, root_path);
603170754Sdelphij    }
604170754Sdelphij    return false;
605170754Sdelphij  }
606170754Sdelphij
607170754Sdelphij  return true;
608170754Sdelphij}
609170754Sdelphij
610170754Sdelphij// cleanup stale shared memory resources
611170754Sdelphij//
612170754Sdelphij// This method attempts to remove all stale shared memory files in
613170754Sdelphij// the named user temporary directory. It scans the named directory
614170754Sdelphij// for files matching the pattern ^$[0-9]*$. For each file found, the
615170754Sdelphij// process id is extracted from the file name and a test is run to
616170754Sdelphij// determine if the process is alive. If the process is not alive,
617170754Sdelphij// any stale file resources are removed.
618170754Sdelphij//
619170754Sdelphijstatic void cleanup_sharedmem_resources(const char* dirname) {
620170754Sdelphij
621170754Sdelphij  // open the user temp directory
622170754Sdelphij  DIR* dirp = os::opendir(dirname);
623170754Sdelphij
624170754Sdelphij  if (dirp == NULL) {
625170754Sdelphij    // directory doesn't exist, so there is nothing to cleanup
626170754Sdelphij    return;
627170754Sdelphij  }
628170754Sdelphij
629170754Sdelphij  if (!is_directory_secure(dirname)) {
630170754Sdelphij    // the directory is not secure, don't attempt any cleanup
631170754Sdelphij    os::closedir(dirp);
632170754Sdelphij    return;
633170754Sdelphij  }
634170754Sdelphij
635170754Sdelphij  // for each entry in the directory that matches the expected file
636170754Sdelphij  // name pattern, determine if the file resources are stale and if
637170754Sdelphij  // so, remove the file resources. Note, instrumented HotSpot processes
638170754Sdelphij  // for this user may start and/or terminate during this search and
639170754Sdelphij  // remove or create new files in this directory. The behavior of this
640170754Sdelphij  // loop under these conditions is dependent upon the implementation of
641170754Sdelphij  // opendir/readdir.
642170754Sdelphij  //
643170754Sdelphij  struct dirent* entry;
644170754Sdelphij  char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(dirname), mtInternal);
645170754Sdelphij  errno = 0;
646170754Sdelphij  while ((entry = os::readdir(dirp, (struct dirent *)dbuf)) != NULL) {
647170754Sdelphij
648170754Sdelphij    int pid = filename_to_pid(entry->d_name);
649170754Sdelphij
650170754Sdelphij    if (pid == 0) {
651170754Sdelphij
652170754Sdelphij      if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
653170754Sdelphij
654170754Sdelphij        // attempt to remove all unexpected files, except "." and ".."
655170754Sdelphij        remove_file(dirname, entry->d_name);
656170754Sdelphij      }
657170754Sdelphij
658170754Sdelphij      errno = 0;
659170754Sdelphij      continue;
660170754Sdelphij    }
661170754Sdelphij
662170754Sdelphij    // we now have a file name that converts to a valid integer
663170754Sdelphij    // that could represent a process id . if this process id
664170754Sdelphij    // matches the current process id or the process is not running,
665170754Sdelphij    // then remove the stale file resources.
666170754Sdelphij    //
667170754Sdelphij    // process liveness is detected by checking the exit status
668170754Sdelphij    // of the process. if the process id is valid and the exit status
669170754Sdelphij    // indicates that it is still running, the file file resources
670170754Sdelphij    // are not removed. If the process id is invalid, or if we don't
671170754Sdelphij    // have permissions to check the process status, or if the process
672170754Sdelphij    // id is valid and the process has terminated, the the file resources
673170754Sdelphij    // are assumed to be stale and are removed.
674170754Sdelphij    //
675170754Sdelphij    if (pid == os::current_process_id() || !is_alive(pid)) {
676170754Sdelphij
677170754Sdelphij      // we can only remove the file resources. Any mapped views
678170754Sdelphij      // of the file can only be unmapped by the processes that
679170754Sdelphij      // opened those views and the file mapping object will not
680170754Sdelphij      // get removed until all views are unmapped.
681170754Sdelphij      //
682170754Sdelphij      remove_file(dirname, entry->d_name);
683170754Sdelphij    }
684170754Sdelphij    errno = 0;
685170754Sdelphij  }
686170754Sdelphij  os::closedir(dirp);
687170754Sdelphij  FREE_C_HEAP_ARRAY(char, dbuf);
688170754Sdelphij}
689170754Sdelphij
690170754Sdelphij// create a file mapping object with the requested name, and size
691170754Sdelphij// from the file represented by the given Handle object
692170754Sdelphij//
693170754Sdelphijstatic HANDLE create_file_mapping(const char* name, HANDLE fh, LPSECURITY_ATTRIBUTES fsa, size_t size) {
694170754Sdelphij
695170754Sdelphij  DWORD lowSize = (DWORD)size;
696170754Sdelphij  DWORD highSize = 0;
697170754Sdelphij  HANDLE fmh = NULL;
698170754Sdelphij
699170754Sdelphij  // Create a file mapping object with the given name. This function
700170754Sdelphij  // will grow the file to the specified size.
701170754Sdelphij  //
702170754Sdelphij  fmh = CreateFileMapping(
703170754Sdelphij               fh,                 /* HANDLE file handle for backing store */
704170754Sdelphij               fsa,                /* LPSECURITY_ATTRIBUTES Not inheritable */
705170754Sdelphij               PAGE_READWRITE,     /* DWORD protections */
706170754Sdelphij               highSize,           /* DWORD High word of max size */
707170754Sdelphij               lowSize,            /* DWORD Low word of max size */
708170754Sdelphij               name);              /* LPCTSTR name for object */
709170754Sdelphij
710170754Sdelphij  if (fmh == NULL) {
711170754Sdelphij    if (PrintMiscellaneous && Verbose) {
712170754Sdelphij      warning("CreateFileMapping failed, lasterror = %d\n", GetLastError());
713170754Sdelphij    }
714170754Sdelphij    return NULL;
715170754Sdelphij  }
716170754Sdelphij
717170754Sdelphij  if (GetLastError() == ERROR_ALREADY_EXISTS) {
718170754Sdelphij
719170754Sdelphij    // a stale file mapping object was encountered. This object may be
720170754Sdelphij    // owned by this or some other user and cannot be removed until
721170754Sdelphij    // the other processes either exit or close their mapping objects
722170754Sdelphij    // and/or mapped views of this mapping object.
723170754Sdelphij    //
724170754Sdelphij    if (PrintMiscellaneous && Verbose) {
725170754Sdelphij      warning("file mapping already exists, lasterror = %d\n", GetLastError());
726170754Sdelphij    }
727170754Sdelphij
728170754Sdelphij    CloseHandle(fmh);
729170754Sdelphij    return NULL;
730170754Sdelphij  }
731170754Sdelphij
732170754Sdelphij  return fmh;
733170754Sdelphij}
734170754Sdelphij
735170754Sdelphij
736170754Sdelphij// method to free the given security descriptor and the contained
737170754Sdelphij// access control list.
738170754Sdelphij//
739170754Sdelphijstatic void free_security_desc(PSECURITY_DESCRIPTOR pSD) {
740170754Sdelphij
741170754Sdelphij  BOOL success, exists, isdefault;
742170754Sdelphij  PACL pACL;
743170754Sdelphij
744170754Sdelphij  if (pSD != NULL) {
745170754Sdelphij
746170754Sdelphij    // get the access control list from the security descriptor
747170754Sdelphij    success = GetSecurityDescriptorDacl(pSD, &exists, &pACL, &isdefault);
748170754Sdelphij
749170754Sdelphij    // if an ACL existed and it was not a default acl, then it must
750170754Sdelphij    // be an ACL we enlisted. free the resources.
751170754Sdelphij    //
752170754Sdelphij    if (success && exists && pACL != NULL && !isdefault) {
753170754Sdelphij      FREE_C_HEAP_ARRAY(char, pACL);
754170754Sdelphij    }
755170754Sdelphij
756170754Sdelphij    // free the security descriptor
757170754Sdelphij    FREE_C_HEAP_ARRAY(char, pSD);
758170754Sdelphij  }
759170754Sdelphij}
760170754Sdelphij
761170754Sdelphij// method to free up a security attributes structure and any
762170754Sdelphij// contained security descriptors and ACL
763170754Sdelphij//
764170754Sdelphijstatic void free_security_attr(LPSECURITY_ATTRIBUTES lpSA) {
765170754Sdelphij
766170754Sdelphij  if (lpSA != NULL) {
767170754Sdelphij    // free the contained security descriptor and the ACL
768170754Sdelphij    free_security_desc(lpSA->lpSecurityDescriptor);
769170754Sdelphij    lpSA->lpSecurityDescriptor = NULL;
770170754Sdelphij
771170754Sdelphij    // free the security attributes structure
772170754Sdelphij    FREE_C_HEAP_ARRAY(char, lpSA);
773170754Sdelphij  }
774170754Sdelphij}
775170754Sdelphij
776170754Sdelphij// get the user SID for the process indicated by the process handle
777170754Sdelphij//
778170754Sdelphijstatic PSID get_user_sid(HANDLE hProcess) {
779170754Sdelphij
780170754Sdelphij  HANDLE hAccessToken;
781170754Sdelphij  PTOKEN_USER token_buf = NULL;
782170754Sdelphij  DWORD rsize = 0;
783170754Sdelphij
784170754Sdelphij  if (hProcess == NULL) {
785170754Sdelphij    return NULL;
786170754Sdelphij  }
787170754Sdelphij
788170754Sdelphij  // get the process token
789170754Sdelphij  if (!OpenProcessToken(hProcess, TOKEN_READ, &hAccessToken)) {
790170754Sdelphij    if (PrintMiscellaneous && Verbose) {
791170754Sdelphij      warning("OpenProcessToken failure: lasterror = %d \n", GetLastError());
792170754Sdelphij    }
793170754Sdelphij    return NULL;
794170754Sdelphij  }
795170754Sdelphij
796170754Sdelphij  // determine the size of the token structured needed to retrieve
797170754Sdelphij  // the user token information from the access token.
798170754Sdelphij  //
799170754Sdelphij  if (!GetTokenInformation(hAccessToken, TokenUser, NULL, rsize, &rsize)) {
800170754Sdelphij    DWORD lasterror = GetLastError();
801170754Sdelphij    if (lasterror != ERROR_INSUFFICIENT_BUFFER) {
802170754Sdelphij      if (PrintMiscellaneous && Verbose) {
803170754Sdelphij        warning("GetTokenInformation failure: lasterror = %d,"
804170754Sdelphij                " rsize = %d\n", lasterror, rsize);
805170754Sdelphij      }
806170754Sdelphij      CloseHandle(hAccessToken);
807170754Sdelphij      return NULL;
808170754Sdelphij    }
809170754Sdelphij  }
810170754Sdelphij
811170754Sdelphij  token_buf = (PTOKEN_USER) NEW_C_HEAP_ARRAY(char, rsize, mtInternal);
812170754Sdelphij
813170754Sdelphij  // get the user token information
814170754Sdelphij  if (!GetTokenInformation(hAccessToken, TokenUser, token_buf, rsize, &rsize)) {
815170754Sdelphij    if (PrintMiscellaneous && Verbose) {
816170754Sdelphij      warning("GetTokenInformation failure: lasterror = %d,"
817170754Sdelphij              " rsize = %d\n", GetLastError(), rsize);
818170754Sdelphij    }
819170754Sdelphij    FREE_C_HEAP_ARRAY(char, token_buf);
820170754Sdelphij    CloseHandle(hAccessToken);
821170754Sdelphij    return NULL;
822170754Sdelphij  }
823170754Sdelphij
824170754Sdelphij  DWORD nbytes = GetLengthSid(token_buf->User.Sid);
825170754Sdelphij  PSID pSID = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal);
826170754Sdelphij
827170754Sdelphij  if (!CopySid(nbytes, pSID, token_buf->User.Sid)) {
828170754Sdelphij    if (PrintMiscellaneous && Verbose) {
829170754Sdelphij      warning("GetTokenInformation failure: lasterror = %d,"
830170754Sdelphij              " rsize = %d\n", GetLastError(), rsize);
831170754Sdelphij    }
832170754Sdelphij    FREE_C_HEAP_ARRAY(char, token_buf);
833170754Sdelphij    FREE_C_HEAP_ARRAY(char, pSID);
834170754Sdelphij    CloseHandle(hAccessToken);
835170754Sdelphij    return NULL;
836170754Sdelphij  }
837170754Sdelphij
838170754Sdelphij  // close the access token.
839170754Sdelphij  CloseHandle(hAccessToken);
840170754Sdelphij  FREE_C_HEAP_ARRAY(char, token_buf);
841170754Sdelphij
842170754Sdelphij  return pSID;
843170754Sdelphij}
844170754Sdelphij
845170754Sdelphij// structure used to consolidate access control entry information
846170754Sdelphij//
847170754Sdelphijtypedef struct ace_data {
848170754Sdelphij  PSID pSid;      // SID of the ACE
849170754Sdelphij  DWORD mask;     // mask for the ACE
850170754Sdelphij} ace_data_t;
851170754Sdelphij
852170754Sdelphij
853170754Sdelphij// method to add an allow access control entry with the access rights
854170754Sdelphij// indicated in mask for the principal indicated in SID to the given
855170754Sdelphij// security descriptor. Much of the DACL handling was adapted from
856170754Sdelphij// the example provided here:
857170754Sdelphij//      http://support.microsoft.com/kb/102102/EN-US/
858170754Sdelphij//
859170754Sdelphij
860170764Sdelphijstatic bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
861170764Sdelphij                           ace_data_t aces[], int ace_count) {
862170764Sdelphij  PACL newACL = NULL;
863170764Sdelphij  PACL oldACL = NULL;
864170764Sdelphij
865170754Sdelphij  if (pSD == NULL) {
866170754Sdelphij    return false;
867170754Sdelphij  }
868170754Sdelphij
869170754Sdelphij  BOOL exists, isdefault;
870170754Sdelphij
871170754Sdelphij  // retrieve any existing access control list.
872170754Sdelphij  if (!GetSecurityDescriptorDacl(pSD, &exists, &oldACL, &isdefault)) {
873170754Sdelphij    if (PrintMiscellaneous && Verbose) {
874170754Sdelphij      warning("GetSecurityDescriptor failure: lasterror = %d \n",
875170754Sdelphij              GetLastError());
876170754Sdelphij    }
877170754Sdelphij    return false;
878170754Sdelphij  }
879170754Sdelphij
880170754Sdelphij  // get the size of the DACL
881170754Sdelphij  ACL_SIZE_INFORMATION aclinfo;
882170754Sdelphij
883170754Sdelphij  // GetSecurityDescriptorDacl may return true value for exists (lpbDaclPresent)
884170754Sdelphij  // while oldACL is NULL for some case.
885170754Sdelphij  if (oldACL == NULL) {
886170754Sdelphij    exists = FALSE;
887170754Sdelphij  }
888170754Sdelphij
889170754Sdelphij  if (exists) {
890170754Sdelphij    if (!GetAclInformation(oldACL, &aclinfo,
891170754Sdelphij                           sizeof(ACL_SIZE_INFORMATION),
892170754Sdelphij                           AclSizeInformation)) {
893170754Sdelphij      if (PrintMiscellaneous && Verbose) {
894170754Sdelphij        warning("GetAclInformation failure: lasterror = %d \n", GetLastError());
895170754Sdelphij        return false;
896170754Sdelphij      }
897170754Sdelphij    }
898170754Sdelphij  } else {
899170754Sdelphij    aclinfo.AceCount = 0; // assume NULL DACL
900170754Sdelphij    aclinfo.AclBytesFree = 0;
901170754Sdelphij    aclinfo.AclBytesInUse = sizeof(ACL);
902170754Sdelphij  }
903170754Sdelphij
904170754Sdelphij  // compute the size needed for the new ACL
905170754Sdelphij  // initial size of ACL is sum of the following:
906170754Sdelphij  //   * size of ACL structure.
907170754Sdelphij  //   * size of each ACE structure that ACL is to contain minus the sid
908170754Sdelphij  //     sidStart member (DWORD) of the ACE.
909170754Sdelphij  //   * length of the SID that each ACE is to contain.
910170754Sdelphij  DWORD newACLsize = aclinfo.AclBytesInUse +
911170754Sdelphij                        (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) * ace_count;
912170754Sdelphij  for (int i = 0; i < ace_count; i++) {
913170754Sdelphij     assert(aces[i].pSid != 0, "pSid should not be 0");
914170754Sdelphij     newACLsize += GetLengthSid(aces[i].pSid);
915170754Sdelphij  }
916170754Sdelphij
917170754Sdelphij  // create the new ACL
918170754Sdelphij  newACL = (PACL) NEW_C_HEAP_ARRAY(char, newACLsize, mtInternal);
919170754Sdelphij
920170764Sdelphij  if (!InitializeAcl(newACL, newACLsize, ACL_REVISION)) {
921170764Sdelphij    if (PrintMiscellaneous && Verbose) {
922170754Sdelphij      warning("InitializeAcl failure: lasterror = %d \n", GetLastError());
923170754Sdelphij    }
924170754Sdelphij    FREE_C_HEAP_ARRAY(char, newACL);
925170754Sdelphij    return false;
926170754Sdelphij  }
927170754Sdelphij
928170754Sdelphij  unsigned int ace_index = 0;
929170754Sdelphij  // copy any existing ACEs from the old ACL (if any) to the new ACL.
930170754Sdelphij  if (aclinfo.AceCount != 0) {
931170754Sdelphij    while (ace_index < aclinfo.AceCount) {
932170754Sdelphij      LPVOID ace;
933170754Sdelphij      if (!GetAce(oldACL, ace_index, &ace)) {
934170754Sdelphij        if (PrintMiscellaneous && Verbose) {
935170764Sdelphij          warning("InitializeAcl failure: lasterror = %d \n", GetLastError());
936170754Sdelphij        }
937170754Sdelphij        FREE_C_HEAP_ARRAY(char, newACL);
938170754Sdelphij        return false;
939170754Sdelphij      }
940170754Sdelphij      if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceFlags && INHERITED_ACE) {
941170754Sdelphij        // this is an inherited, allowed ACE; break from loop so we can
942170754Sdelphij        // add the new access allowed, non-inherited ACE in the correct
943170754Sdelphij        // position, immediately following all non-inherited ACEs.
944170754Sdelphij        break;
945170754Sdelphij      }
946170754Sdelphij
947170754Sdelphij      // determine if the SID of this ACE matches any of the SIDs
948170754Sdelphij      // for which we plan to set ACEs.
949170754Sdelphij      int matches = 0;
950170754Sdelphij      for (int i = 0; i < ace_count; i++) {
951170754Sdelphij        if (EqualSid(aces[i].pSid, &(((ACCESS_ALLOWED_ACE *)ace)->SidStart))) {
952170754Sdelphij          matches++;
953170754Sdelphij          break;
954170754Sdelphij        }
955170754Sdelphij      }
956170754Sdelphij
957170754Sdelphij      // if there are no SID matches, then add this existing ACE to the new ACL
958170754Sdelphij      if (matches == 0) {
959170754Sdelphij        if (!AddAce(newACL, ACL_REVISION, MAXDWORD, ace,
960170754Sdelphij                    ((PACE_HEADER)ace)->AceSize)) {
961170754Sdelphij          if (PrintMiscellaneous && Verbose) {
962170754Sdelphij            warning("AddAce failure: lasterror = %d \n", GetLastError());
963170754Sdelphij          }
964170754Sdelphij          FREE_C_HEAP_ARRAY(char, newACL);
965170754Sdelphij          return false;
966170754Sdelphij        }
967170754Sdelphij      }
968170754Sdelphij      ace_index++;
969170754Sdelphij    }
970170754Sdelphij  }
971170754Sdelphij
972170754Sdelphij  // add the passed-in access control entries to the new ACL
973170764Sdelphij  for (int i = 0; i < ace_count; i++) {
974170754Sdelphij    if (!AddAccessAllowedAce(newACL, ACL_REVISION,
975170754Sdelphij                             aces[i].mask, aces[i].pSid)) {
976170754Sdelphij      if (PrintMiscellaneous && Verbose) {
977170764Sdelphij        warning("AddAccessAllowedAce failure: lasterror = %d \n",
978170754Sdelphij                GetLastError());
979170754Sdelphij      }
980170754Sdelphij      FREE_C_HEAP_ARRAY(char, newACL);
981170754Sdelphij      return false;
982170754Sdelphij    }
983170754Sdelphij  }
984170754Sdelphij
985170754Sdelphij  // now copy the rest of the inherited ACEs from the old ACL
986170754Sdelphij  if (aclinfo.AceCount != 0) {
987170754Sdelphij    // picking up at ace_index, where we left off in the
988170754Sdelphij    // previous ace_index loop
989170754Sdelphij    while (ace_index < aclinfo.AceCount) {
990170754Sdelphij      LPVOID ace;
991170754Sdelphij      if (!GetAce(oldACL, ace_index, &ace)) {
992170754Sdelphij        if (PrintMiscellaneous && Verbose) {
993170754Sdelphij          warning("InitializeAcl failure: lasterror = %d \n", GetLastError());
994170754Sdelphij        }
995170754Sdelphij        FREE_C_HEAP_ARRAY(char, newACL);
996170754Sdelphij        return false;
997170754Sdelphij      }
998170754Sdelphij      if (!AddAce(newACL, ACL_REVISION, MAXDWORD, ace,
999170754Sdelphij                  ((PACE_HEADER)ace)->AceSize)) {
1000170754Sdelphij        if (PrintMiscellaneous && Verbose) {
1001170754Sdelphij          warning("AddAce failure: lasterror = %d \n", GetLastError());
1002170754Sdelphij        }
1003170754Sdelphij        FREE_C_HEAP_ARRAY(char, newACL);
1004170754Sdelphij        return false;
1005170754Sdelphij      }
1006170754Sdelphij      ace_index++;
1007170754Sdelphij    }
1008170754Sdelphij  }
1009170754Sdelphij
1010170754Sdelphij  // add the new ACL to the security descriptor.
1011170754Sdelphij  if (!SetSecurityDescriptorDacl(pSD, TRUE, newACL, FALSE)) {
1012170754Sdelphij    if (PrintMiscellaneous && Verbose) {
1013170754Sdelphij      warning("SetSecurityDescriptorDacl failure:"
1014170754Sdelphij              " lasterror = %d \n", GetLastError());
1015170754Sdelphij    }
1016170754Sdelphij    FREE_C_HEAP_ARRAY(char, newACL);
1017170754Sdelphij    return false;
1018170764Sdelphij  }
1019170754Sdelphij
1020170754Sdelphij  // if running on windows 2000 or later, set the automatic inheritance
1021170754Sdelphij  // control flags.
1022170754Sdelphij  SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl;
1023170754Sdelphij  _SetSecurityDescriptorControl = (SetSecurityDescriptorControlFnPtr)
1024170754Sdelphij       GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),
1025170754Sdelphij                      "SetSecurityDescriptorControl");
1026170754Sdelphij
1027170754Sdelphij  if (_SetSecurityDescriptorControl != NULL) {
1028170754Sdelphij    // We do not want to further propagate inherited DACLs, so making them
1029170754Sdelphij    // protected prevents that.
1030170754Sdelphij    if (!_SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED,
1031170754Sdelphij                                            SE_DACL_PROTECTED)) {
1032170754Sdelphij      if (PrintMiscellaneous && Verbose) {
1033170754Sdelphij        warning("SetSecurityDescriptorControl failure:"
1034170754Sdelphij                " lasterror = %d \n", GetLastError());
1035170754Sdelphij      }
1036170754Sdelphij      FREE_C_HEAP_ARRAY(char, newACL);
1037170754Sdelphij      return false;
1038170754Sdelphij    }
1039170754Sdelphij  }
1040170764Sdelphij   // Note, the security descriptor maintains a reference to the newACL, not
1041170754Sdelphij   // a copy of it. Therefore, the newACL is not freed here. It is freed when
1042170754Sdelphij   // the security descriptor containing its reference is freed.
1043170754Sdelphij   //
1044170754Sdelphij   return true;
1045170754Sdelphij}
1046170754Sdelphij
1047170754Sdelphij// method to create a security attributes structure, which contains a
1048170754Sdelphij// security descriptor and an access control list comprised of 0 or more
1049170754Sdelphij// access control entries. The method take an array of ace_data structures
1050170754Sdelphij// that indicate the ACE to be added to the security descriptor.
1051170754Sdelphij//
1052170754Sdelphij// the caller must free the resources associated with the security
1053170754Sdelphij// attributes structure created by this method by calling the
1054170754Sdelphij// free_security_attr() method.
1055170754Sdelphij//
1056170754Sdelphijstatic LPSECURITY_ATTRIBUTES make_security_attr(ace_data_t aces[], int count) {
1057170754Sdelphij
1058170754Sdelphij  // allocate space for a security descriptor
1059170754Sdelphij  PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)
1060170754Sdelphij     NEW_C_HEAP_ARRAY(char, SECURITY_DESCRIPTOR_MIN_LENGTH, mtInternal);
1061170754Sdelphij
1062170754Sdelphij  // initialize the security descriptor
1063170754Sdelphij  if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
1064170754Sdelphij    if (PrintMiscellaneous && Verbose) {
1065170754Sdelphij      warning("InitializeSecurityDescriptor failure: "
1066170754Sdelphij              "lasterror = %d \n", GetLastError());
1067170754Sdelphij    }
1068170754Sdelphij    free_security_desc(pSD);
1069170754Sdelphij    return NULL;
1070170754Sdelphij  }
1071170754Sdelphij
1072170754Sdelphij  // add the access control entries
1073170754Sdelphij  if (!add_allow_aces(pSD, aces, count)) {
1074170754Sdelphij    free_security_desc(pSD);
1075170754Sdelphij    return NULL;
1076170754Sdelphij  }
1077170754Sdelphij
1078170754Sdelphij  // allocate and initialize the security attributes structure and
1079170754Sdelphij  // return it to the caller.
1080170754Sdelphij  //
1081170754Sdelphij  LPSECURITY_ATTRIBUTES lpSA = (LPSECURITY_ATTRIBUTES)
1082170754Sdelphij    NEW_C_HEAP_ARRAY(char, sizeof(SECURITY_ATTRIBUTES), mtInternal);
1083170754Sdelphij  lpSA->nLength = sizeof(SECURITY_ATTRIBUTES);
1084170754Sdelphij  lpSA->lpSecurityDescriptor = pSD;
1085170754Sdelphij  lpSA->bInheritHandle = FALSE;
1086170754Sdelphij
1087170754Sdelphij  return(lpSA);
1088170754Sdelphij}
1089170754Sdelphij
1090170754Sdelphij// method to create a security attributes structure with a restrictive
1091170754Sdelphij// access control list that creates a set access rights for the user/owner
1092170754Sdelphij// of the securable object and a separate set access rights for everyone else.
1093170754Sdelphij// also provides for full access rights for the administrator group.
1094170754Sdelphij//
1095170754Sdelphij// the caller must free the resources associated with the security
1096170754Sdelphij// attributes structure created by this method by calling the
1097170754Sdelphij// free_security_attr() method.
1098170754Sdelphij//
1099170754Sdelphij
1100170754Sdelphijstatic LPSECURITY_ATTRIBUTES make_user_everybody_admin_security_attr(
1101170754Sdelphij                                DWORD umask, DWORD emask, DWORD amask) {
1102170754Sdelphij
1103170754Sdelphij  ace_data_t aces[3];
1104170754Sdelphij
1105170754Sdelphij  // initialize the user ace data
1106170754Sdelphij  aces[0].pSid = get_user_sid(GetCurrentProcess());
1107170754Sdelphij  aces[0].mask = umask;
1108170754Sdelphij
1109170754Sdelphij  if (aces[0].pSid == 0)
1110170754Sdelphij    return NULL;
1111170754Sdelphij
1112170754Sdelphij  // get the well known SID for BUILTIN\Administrators
1113170754Sdelphij  PSID administratorsSid = NULL;
1114170754Sdelphij  SID_IDENTIFIER_AUTHORITY SIDAuthAdministrators = SECURITY_NT_AUTHORITY;
1115170754Sdelphij
1116170754Sdelphij  if (!AllocateAndInitializeSid( &SIDAuthAdministrators, 2,
1117170754Sdelphij           SECURITY_BUILTIN_DOMAIN_RID,
1118170754Sdelphij           DOMAIN_ALIAS_RID_ADMINS,
1119170754Sdelphij           0, 0, 0, 0, 0, 0, &administratorsSid)) {
1120170754Sdelphij
1121170754Sdelphij    if (PrintMiscellaneous && Verbose) {
1122170754Sdelphij      warning("AllocateAndInitializeSid failure: "
1123170754Sdelphij              "lasterror = %d \n", GetLastError());
1124170754Sdelphij    }
1125170754Sdelphij    return NULL;
1126170754Sdelphij  }
1127170754Sdelphij
1128170754Sdelphij  // initialize the ace data for administrator group
1129170754Sdelphij  aces[1].pSid = administratorsSid;
1130170754Sdelphij  aces[1].mask = amask;
1131170754Sdelphij
1132170754Sdelphij  // get the well known SID for the universal Everybody
1133170754Sdelphij  PSID everybodySid = NULL;
1134170754Sdelphij  SID_IDENTIFIER_AUTHORITY SIDAuthEverybody = SECURITY_WORLD_SID_AUTHORITY;
1135170754Sdelphij
1136170754Sdelphij  if (!AllocateAndInitializeSid( &SIDAuthEverybody, 1, SECURITY_WORLD_RID,
1137170754Sdelphij           0, 0, 0, 0, 0, 0, 0, &everybodySid)) {
1138170754Sdelphij
1139170754Sdelphij    if (PrintMiscellaneous && Verbose) {
1140170754Sdelphij      warning("AllocateAndInitializeSid failure: "
1141170754Sdelphij              "lasterror = %d \n", GetLastError());
1142170754Sdelphij    }
1143170754Sdelphij    return NULL;
1144170754Sdelphij  }
1145170754Sdelphij
1146170754Sdelphij  // initialize the ace data for everybody else.
1147170754Sdelphij  aces[2].pSid = everybodySid;
1148170754Sdelphij  aces[2].mask = emask;
1149170754Sdelphij
1150170754Sdelphij  // create a security attributes structure with access control
1151170754Sdelphij  // entries as initialized above.
1152170754Sdelphij  LPSECURITY_ATTRIBUTES lpSA = make_security_attr(aces, 3);
1153170754Sdelphij  FREE_C_HEAP_ARRAY(char, aces[0].pSid);
1154170754Sdelphij  FreeSid(everybodySid);
1155170754Sdelphij  FreeSid(administratorsSid);
1156170754Sdelphij  return(lpSA);
1157170754Sdelphij}
1158170754Sdelphij
1159170754Sdelphij
1160170754Sdelphij// method to create the security attributes structure for restricting
1161170754Sdelphij// access to the user temporary directory.
1162170754Sdelphij//
1163170754Sdelphij// the caller must free the resources associated with the security
1164170754Sdelphij// attributes structure created by this method by calling the
1165170754Sdelphij// free_security_attr() method.
1166170754Sdelphij//
1167170754Sdelphijstatic LPSECURITY_ATTRIBUTES make_tmpdir_security_attr() {
1168170754Sdelphij
1169170754Sdelphij  // create full access rights for the user/owner of the directory
1170170754Sdelphij  // and read-only access rights for everybody else. This is
1171170754Sdelphij  // effectively equivalent to UNIX 755 permissions on a directory.
1172170754Sdelphij  //
1173170754Sdelphij  DWORD umask = STANDARD_RIGHTS_REQUIRED | FILE_ALL_ACCESS;
1174170754Sdelphij  DWORD emask = GENERIC_READ | FILE_LIST_DIRECTORY | FILE_TRAVERSE;
1175170754Sdelphij  DWORD amask = STANDARD_RIGHTS_ALL | FILE_ALL_ACCESS;
1176170754Sdelphij
1177170754Sdelphij  return make_user_everybody_admin_security_attr(umask, emask, amask);
1178170754Sdelphij}
1179170754Sdelphij
1180170754Sdelphij// method to create the security attributes structure for restricting
1181170754Sdelphij// access to the shared memory backing store file.
1182170754Sdelphij//
1183170754Sdelphij// the caller must free the resources associated with the security
1184170754Sdelphij// attributes structure created by this method by calling the
1185170754Sdelphij// free_security_attr() method.
1186170754Sdelphij//
1187170754Sdelphijstatic LPSECURITY_ATTRIBUTES make_file_security_attr() {
1188170754Sdelphij
1189170754Sdelphij  // create extensive access rights for the user/owner of the file
1190170754Sdelphij  // and attribute read-only access rights for everybody else. This
1191170754Sdelphij  // is effectively equivalent to UNIX 600 permissions on a file.
1192170754Sdelphij  //
1193170754Sdelphij  DWORD umask = STANDARD_RIGHTS_ALL | FILE_ALL_ACCESS;
1194170754Sdelphij  DWORD emask = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES |
1195170754Sdelphij                 FILE_READ_EA | FILE_LIST_DIRECTORY | FILE_TRAVERSE;
1196170754Sdelphij  DWORD amask = STANDARD_RIGHTS_ALL | FILE_ALL_ACCESS;
1197170754Sdelphij
1198170754Sdelphij  return make_user_everybody_admin_security_attr(umask, emask, amask);
1199170754Sdelphij}
1200170754Sdelphij
1201170754Sdelphij// method to create the security attributes structure for restricting
1202170754Sdelphij// access to the name shared memory file mapping object.
1203170754Sdelphij//
1204170754Sdelphij// the caller must free the resources associated with the security
1205170754Sdelphij// attributes structure created by this method by calling the
1206170754Sdelphij// free_security_attr() method.
1207170754Sdelphij//
1208170754Sdelphijstatic LPSECURITY_ATTRIBUTES make_smo_security_attr() {
1209170754Sdelphij
1210170754Sdelphij  // create extensive access rights for the user/owner of the shared
1211170754Sdelphij  // memory object and attribute read-only access rights for everybody
1212170754Sdelphij  // else. This is effectively equivalent to UNIX 600 permissions on
1213170754Sdelphij  // on the shared memory object.
1214170754Sdelphij  //
1215170754Sdelphij  DWORD umask = STANDARD_RIGHTS_REQUIRED | FILE_MAP_ALL_ACCESS;
1216170754Sdelphij  DWORD emask = STANDARD_RIGHTS_READ; // attributes only
1217170754Sdelphij  DWORD amask = STANDARD_RIGHTS_ALL | FILE_MAP_ALL_ACCESS;
1218170754Sdelphij
1219170754Sdelphij  return make_user_everybody_admin_security_attr(umask, emask, amask);
1220170754Sdelphij}
1221170754Sdelphij
1222170754Sdelphij// make the user specific temporary directory
1223170754Sdelphij//
1224170754Sdelphijstatic bool make_user_tmp_dir(const char* dirname) {
1225170754Sdelphij
1226170754Sdelphij
1227  LPSECURITY_ATTRIBUTES pDirSA = make_tmpdir_security_attr();
1228  if (pDirSA == NULL) {
1229    return false;
1230  }
1231
1232
1233  // create the directory with the given security attributes
1234  if (!CreateDirectory(dirname, pDirSA)) {
1235    DWORD lasterror = GetLastError();
1236    if (lasterror == ERROR_ALREADY_EXISTS) {
1237      // The directory already exists and was probably created by another
1238      // JVM instance. However, this could also be the result of a
1239      // deliberate symlink. Verify that the existing directory is safe.
1240      //
1241      if (!is_directory_secure(dirname)) {
1242        // directory is not secure
1243        if (PrintMiscellaneous && Verbose) {
1244          warning("%s directory is insecure\n", dirname);
1245        }
1246        return false;
1247      }
1248      // The administrator should be able to delete this directory.
1249      // But the directory created by previous version of JVM may not
1250      // have permission for administrators to delete this directory.
1251      // So add full permission to the administrator. Also setting new
1252      // DACLs might fix the corrupted the DACLs.
1253      SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
1254      if (!SetFileSecurity(dirname, secInfo, pDirSA->lpSecurityDescriptor)) {
1255        if (PrintMiscellaneous && Verbose) {
1256          lasterror = GetLastError();
1257          warning("SetFileSecurity failed for %s directory.  lasterror %d \n",
1258                                                        dirname, lasterror);
1259        }
1260      }
1261    }
1262    else {
1263      if (PrintMiscellaneous && Verbose) {
1264        warning("CreateDirectory failed: %d\n", GetLastError());
1265      }
1266      return false;
1267    }
1268  }
1269
1270  // free the security attributes structure
1271  free_security_attr(pDirSA);
1272
1273  return true;
1274}
1275
1276// create the shared memory resources
1277//
1278// This function creates the shared memory resources. This includes
1279// the backing store file and the file mapping shared memory object.
1280//
1281static HANDLE create_sharedmem_resources(const char* dirname, const char* filename, const char* objectname, size_t size) {
1282
1283  HANDLE fh = INVALID_HANDLE_VALUE;
1284  HANDLE fmh = NULL;
1285
1286
1287  // create the security attributes for the backing store file
1288  LPSECURITY_ATTRIBUTES lpFileSA = make_file_security_attr();
1289  if (lpFileSA == NULL) {
1290    return NULL;
1291  }
1292
1293  // create the security attributes for the shared memory object
1294  LPSECURITY_ATTRIBUTES lpSmoSA = make_smo_security_attr();
1295  if (lpSmoSA == NULL) {
1296    free_security_attr(lpFileSA);
1297    return NULL;
1298  }
1299
1300  // create the user temporary directory
1301  if (!make_user_tmp_dir(dirname)) {
1302    // could not make/find the directory or the found directory
1303    // was not secure
1304    return NULL;
1305  }
1306
1307  // Create the file - the FILE_FLAG_DELETE_ON_CLOSE flag allows the
1308  // file to be deleted by the last process that closes its handle to
1309  // the file. This is important as the apis do not allow a terminating
1310  // JVM being monitored by another process to remove the file name.
1311  //
1312  fh = CreateFile(
1313             filename,                          /* LPCTSTR file name */
1314
1315             GENERIC_READ|GENERIC_WRITE,        /* DWORD desired access */
1316             FILE_SHARE_DELETE|FILE_SHARE_READ, /* DWORD share mode, future READONLY
1317                                                 * open operations allowed
1318                                                 */
1319             lpFileSA,                          /* LPSECURITY security attributes */
1320             CREATE_ALWAYS,                     /* DWORD creation disposition
1321                                                 * create file, if it already
1322                                                 * exists, overwrite it.
1323                                                 */
1324             FILE_FLAG_DELETE_ON_CLOSE,         /* DWORD flags and attributes */
1325
1326             NULL);                             /* HANDLE template file access */
1327
1328  free_security_attr(lpFileSA);
1329
1330  if (fh == INVALID_HANDLE_VALUE) {
1331    DWORD lasterror = GetLastError();
1332    if (PrintMiscellaneous && Verbose) {
1333      warning("could not create file %s: %d\n", filename, lasterror);
1334    }
1335    return NULL;
1336  }
1337
1338  // try to create the file mapping
1339  fmh = create_file_mapping(objectname, fh, lpSmoSA, size);
1340
1341  free_security_attr(lpSmoSA);
1342
1343  if (fmh == NULL) {
1344    // closing the file handle here will decrement the reference count
1345    // on the file. When all processes accessing the file close their
1346    // handle to it, the reference count will decrement to 0 and the
1347    // OS will delete the file. These semantics are requested by the
1348    // FILE_FLAG_DELETE_ON_CLOSE flag in CreateFile call above.
1349    CloseHandle(fh);
1350    fh = NULL;
1351    return NULL;
1352  } else {
1353    // We created the file mapping, but rarely the size of the
1354    // backing store file is reported as zero (0) which can cause
1355    // failures when trying to use the hsperfdata file.
1356    struct stat statbuf;
1357    int ret_code = ::stat(filename, &statbuf);
1358    if (ret_code == OS_ERR) {
1359      if (PrintMiscellaneous && Verbose) {
1360        warning("Could not get status information from file %s: %s\n",
1361            filename, os::strerror(errno));
1362      }
1363      CloseHandle(fmh);
1364      CloseHandle(fh);
1365      fh = NULL;
1366      fmh = NULL;
1367      return NULL;
1368    }
1369
1370    // We could always call FlushFileBuffers() but the Microsoft
1371    // docs indicate that it is considered expensive so we only
1372    // call it when we observe the size as zero (0).
1373    if (statbuf.st_size == 0 && FlushFileBuffers(fh) != TRUE) {
1374      DWORD lasterror = GetLastError();
1375      if (PrintMiscellaneous && Verbose) {
1376        warning("could not flush file %s: %d\n", filename, lasterror);
1377      }
1378      CloseHandle(fmh);
1379      CloseHandle(fh);
1380      fh = NULL;
1381      fmh = NULL;
1382      return NULL;
1383    }
1384  }
1385
1386  // the file has been successfully created and the file mapping
1387  // object has been created.
1388  sharedmem_fileHandle = fh;
1389  sharedmem_fileName = os::strdup(filename);
1390
1391  return fmh;
1392}
1393
1394// open the shared memory object for the given vmid.
1395//
1396static HANDLE open_sharedmem_object(const char* objectname, DWORD ofm_access, TRAPS) {
1397
1398  HANDLE fmh;
1399
1400  // open the file mapping with the requested mode
1401  fmh = OpenFileMapping(
1402               ofm_access,       /* DWORD access mode */
1403               FALSE,            /* BOOL inherit flag - Do not allow inherit */
1404               objectname);      /* name for object */
1405
1406  if (fmh == NULL) {
1407    if (PrintMiscellaneous && Verbose) {
1408      warning("OpenFileMapping failed for shared memory object %s:"
1409              " lasterror = %d\n", objectname, GetLastError());
1410    }
1411    THROW_MSG_(vmSymbols::java_lang_Exception(),
1412               "Could not open PerfMemory", INVALID_HANDLE_VALUE);
1413  }
1414
1415  return fmh;;
1416}
1417
1418// create a named shared memory region
1419//
1420// On Win32, a named shared memory object has a name space that
1421// is independent of the file system name space. Shared memory object,
1422// or more precisely, file mapping objects, provide no mechanism to
1423// inquire the size of the memory region. There is also no api to
1424// enumerate the memory regions for various processes.
1425//
1426// This implementation utilizes the shared memory name space in parallel
1427// with the file system name space. This allows us to determine the
1428// size of the shared memory region from the size of the file and it
1429// allows us to provide a common, file system based name space for
1430// shared memory across platforms.
1431//
1432static char* mapping_create_shared(size_t size) {
1433
1434  void *mapAddress;
1435  int vmid = os::current_process_id();
1436
1437  // get the name of the user associated with this process
1438  char* user = get_user_name();
1439
1440  if (user == NULL) {
1441    return NULL;
1442  }
1443
1444  // construct the name of the user specific temporary directory
1445  char* dirname = get_user_tmp_dir(user);
1446
1447  // check that the file system is secure - i.e. it supports ACLs.
1448  if (!is_filesystem_secure(dirname)) {
1449    FREE_C_HEAP_ARRAY(char, dirname);
1450    FREE_C_HEAP_ARRAY(char, user);
1451    return NULL;
1452  }
1453
1454  // create the names of the backing store files and for the
1455  // share memory object.
1456  //
1457  char* filename = get_sharedmem_filename(dirname, vmid);
1458  char* objectname = get_sharedmem_objectname(user, vmid);
1459
1460  // cleanup any stale shared memory resources
1461  cleanup_sharedmem_resources(dirname);
1462
1463  assert(((size != 0) && (size % os::vm_page_size() == 0)),
1464         "unexpected PerfMemry region size");
1465
1466  FREE_C_HEAP_ARRAY(char, user);
1467
1468  // create the shared memory resources
1469  sharedmem_fileMapHandle =
1470               create_sharedmem_resources(dirname, filename, objectname, size);
1471
1472  FREE_C_HEAP_ARRAY(char, filename);
1473  FREE_C_HEAP_ARRAY(char, objectname);
1474  FREE_C_HEAP_ARRAY(char, dirname);
1475
1476  if (sharedmem_fileMapHandle == NULL) {
1477    return NULL;
1478  }
1479
1480  // map the file into the address space
1481  mapAddress = MapViewOfFile(
1482                   sharedmem_fileMapHandle, /* HANDLE = file mapping object */
1483                   FILE_MAP_ALL_ACCESS,     /* DWORD access flags */
1484                   0,                       /* DWORD High word of offset */
1485                   0,                       /* DWORD Low word of offset */
1486                   (DWORD)size);            /* DWORD Number of bytes to map */
1487
1488  if (mapAddress == NULL) {
1489    if (PrintMiscellaneous && Verbose) {
1490      warning("MapViewOfFile failed, lasterror = %d\n", GetLastError());
1491    }
1492    CloseHandle(sharedmem_fileMapHandle);
1493    sharedmem_fileMapHandle = NULL;
1494    return NULL;
1495  }
1496
1497  // clear the shared memory region
1498  (void)memset(mapAddress, '\0', size);
1499
1500  // it does not go through os api, the operation has to record from here
1501  MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress,
1502    size, CURRENT_PC, mtInternal);
1503
1504  return (char*) mapAddress;
1505}
1506
1507// this method deletes the file mapping object.
1508//
1509static void delete_file_mapping(char* addr, size_t size) {
1510
1511  // cleanup the persistent shared memory resources. since DestroyJavaVM does
1512  // not support unloading of the JVM, unmapping of the memory resource is not
1513  // performed. The memory will be reclaimed by the OS upon termination of all
1514  // processes mapping the resource. The file mapping handle and the file
1515  // handle are closed here to expedite the remove of the file by the OS. The
1516  // file is not removed directly because it was created with
1517  // FILE_FLAG_DELETE_ON_CLOSE semantics and any attempt to remove it would
1518  // be unsuccessful.
1519
1520  // close the fileMapHandle. the file mapping will still be retained
1521  // by the OS as long as any other JVM processes has an open file mapping
1522  // handle or a mapped view of the file.
1523  //
1524  if (sharedmem_fileMapHandle != NULL) {
1525    CloseHandle(sharedmem_fileMapHandle);
1526    sharedmem_fileMapHandle = NULL;
1527  }
1528
1529  // close the file handle. This will decrement the reference count on the
1530  // backing store file. When the reference count decrements to 0, the OS
1531  // will delete the file. These semantics apply because the file was
1532  // created with the FILE_FLAG_DELETE_ON_CLOSE flag.
1533  //
1534  if (sharedmem_fileHandle != INVALID_HANDLE_VALUE) {
1535    CloseHandle(sharedmem_fileHandle);
1536    sharedmem_fileHandle = INVALID_HANDLE_VALUE;
1537  }
1538}
1539
1540// this method determines the size of the shared memory file
1541//
1542static size_t sharedmem_filesize(const char* filename, TRAPS) {
1543
1544  struct stat statbuf;
1545
1546  // get the file size
1547  //
1548  // on win95/98/me, _stat returns a file size of 0 bytes, but on
1549  // winnt/2k the appropriate file size is returned. support for
1550  // the sharable aspects of performance counters was abandonded
1551  // on the non-nt win32 platforms due to this and other api
1552  // inconsistencies
1553  //
1554  if (::stat(filename, &statbuf) == OS_ERR) {
1555    if (PrintMiscellaneous && Verbose) {
1556      warning("stat %s failed: %s\n", filename, os::strerror(errno));
1557    }
1558    THROW_MSG_0(vmSymbols::java_io_IOException(),
1559                "Could not determine PerfMemory size");
1560  }
1561
1562  if ((statbuf.st_size == 0) || (statbuf.st_size % os::vm_page_size() != 0)) {
1563    if (PrintMiscellaneous && Verbose) {
1564      warning("unexpected file size: size = " SIZE_FORMAT "\n",
1565              statbuf.st_size);
1566    }
1567    THROW_MSG_0(vmSymbols::java_lang_Exception(),
1568                "Invalid PerfMemory size");
1569  }
1570
1571  return statbuf.st_size;
1572}
1573
1574// this method opens a file mapping object and maps the object
1575// into the address space of the process
1576//
1577static void open_file_mapping(const char* user, int vmid,
1578                              PerfMemory::PerfMemoryMode mode,
1579                              char** addrp, size_t* sizep, TRAPS) {
1580
1581  ResourceMark rm;
1582
1583  void *mapAddress = 0;
1584  size_t size = 0;
1585  HANDLE fmh;
1586  DWORD ofm_access;
1587  DWORD mv_access;
1588  const char* luser = NULL;
1589
1590  if (mode == PerfMemory::PERF_MODE_RO) {
1591    ofm_access = FILE_MAP_READ;
1592    mv_access = FILE_MAP_READ;
1593  }
1594  else if (mode == PerfMemory::PERF_MODE_RW) {
1595#ifdef LATER
1596    ofm_access = FILE_MAP_READ | FILE_MAP_WRITE;
1597    mv_access = FILE_MAP_READ | FILE_MAP_WRITE;
1598#else
1599    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
1600              "Unsupported access mode");
1601#endif
1602  }
1603  else {
1604    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
1605              "Illegal access mode");
1606  }
1607
1608  // if a user name wasn't specified, then find the user name for
1609  // the owner of the target vm.
1610  if (user == NULL || strlen(user) == 0) {
1611    luser = get_user_name(vmid);
1612  }
1613  else {
1614    luser = user;
1615  }
1616
1617  if (luser == NULL) {
1618    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
1619              "Could not map vmid to user name");
1620  }
1621
1622  // get the names for the resources for the target vm
1623  char* dirname = get_user_tmp_dir(luser);
1624
1625  // since we don't follow symbolic links when creating the backing
1626  // store file, we also don't following them when attaching
1627  //
1628  if (!is_directory_secure(dirname)) {
1629    FREE_C_HEAP_ARRAY(char, dirname);
1630    if (luser != user) FREE_C_HEAP_ARRAY(char, luser);
1631    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
1632              "Process not found");
1633  }
1634
1635  char* filename = get_sharedmem_filename(dirname, vmid);
1636  char* objectname = get_sharedmem_objectname(luser, vmid);
1637
1638  // copy heap memory to resource memory. the objectname and
1639  // filename are passed to methods that may throw exceptions.
1640  // using resource arrays for these names prevents the leaks
1641  // that would otherwise occur.
1642  //
1643  char* rfilename = NEW_RESOURCE_ARRAY(char, strlen(filename) + 1);
1644  char* robjectname = NEW_RESOURCE_ARRAY(char, strlen(objectname) + 1);
1645  strcpy(rfilename, filename);
1646  strcpy(robjectname, objectname);
1647
1648  // free the c heap resources that are no longer needed
1649  if (luser != user) FREE_C_HEAP_ARRAY(char, luser);
1650  FREE_C_HEAP_ARRAY(char, dirname);
1651  FREE_C_HEAP_ARRAY(char, filename);
1652  FREE_C_HEAP_ARRAY(char, objectname);
1653
1654  if (*sizep == 0) {
1655    size = sharedmem_filesize(rfilename, CHECK);
1656  } else {
1657    size = *sizep;
1658  }
1659
1660  assert(size > 0, "unexpected size <= 0");
1661
1662  // Open the file mapping object with the given name
1663  fmh = open_sharedmem_object(robjectname, ofm_access, CHECK);
1664
1665  assert(fmh != INVALID_HANDLE_VALUE, "unexpected handle value");
1666
1667  // map the entire file into the address space
1668  mapAddress = MapViewOfFile(
1669                 fmh,             /* HANDLE Handle of file mapping object */
1670                 mv_access,       /* DWORD access flags */
1671                 0,               /* DWORD High word of offset */
1672                 0,               /* DWORD Low word of offset */
1673                 size);           /* DWORD Number of bytes to map */
1674
1675  if (mapAddress == NULL) {
1676    if (PrintMiscellaneous && Verbose) {
1677      warning("MapViewOfFile failed, lasterror = %d\n", GetLastError());
1678    }
1679    CloseHandle(fmh);
1680    THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
1681              "Could not map PerfMemory");
1682  }
1683
1684  // it does not go through os api, the operation has to record from here
1685  MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, size,
1686    CURRENT_PC, mtInternal);
1687
1688
1689  *addrp = (char*)mapAddress;
1690  *sizep = size;
1691
1692  // File mapping object can be closed at this time without
1693  // invalidating the mapped view of the file
1694  CloseHandle(fmh);
1695
1696  if (PerfTraceMemOps) {
1697    tty->print("mapped " SIZE_FORMAT " bytes for vmid %d at "
1698               INTPTR_FORMAT "\n", size, vmid, mapAddress);
1699  }
1700}
1701
1702// this method unmaps the the mapped view of the the
1703// file mapping object.
1704//
1705static void remove_file_mapping(char* addr) {
1706
1707  // the file mapping object was closed in open_file_mapping()
1708  // after the file map view was created. We only need to
1709  // unmap the file view here.
1710  UnmapViewOfFile(addr);
1711}
1712
1713// create the PerfData memory region in shared memory.
1714static char* create_shared_memory(size_t size) {
1715
1716  return mapping_create_shared(size);
1717}
1718
1719// release a named, shared memory region
1720//
1721void delete_shared_memory(char* addr, size_t size) {
1722
1723  delete_file_mapping(addr, size);
1724}
1725
1726
1727
1728
1729// create the PerfData memory region
1730//
1731// This method creates the memory region used to store performance
1732// data for the JVM. The memory may be created in standard or
1733// shared memory.
1734//
1735void PerfMemory::create_memory_region(size_t size) {
1736
1737  if (PerfDisableSharedMem) {
1738    // do not share the memory for the performance data.
1739    PerfDisableSharedMem = true;
1740    _start = create_standard_memory(size);
1741  }
1742  else {
1743    _start = create_shared_memory(size);
1744    if (_start == NULL) {
1745
1746      // creation of the shared memory region failed, attempt
1747      // to create a contiguous, non-shared memory region instead.
1748      //
1749      if (PrintMiscellaneous && Verbose) {
1750        warning("Reverting to non-shared PerfMemory region.\n");
1751      }
1752      PerfDisableSharedMem = true;
1753      _start = create_standard_memory(size);
1754    }
1755  }
1756
1757  if (_start != NULL) _capacity = size;
1758
1759}
1760
1761// delete the PerfData memory region
1762//
1763// This method deletes the memory region used to store performance
1764// data for the JVM. The memory region indicated by the <address, size>
1765// tuple will be inaccessible after a call to this method.
1766//
1767void PerfMemory::delete_memory_region() {
1768
1769  assert((start() != NULL && capacity() > 0), "verify proper state");
1770
1771  // If user specifies PerfDataSaveFile, it will save the performance data
1772  // to the specified file name no matter whether PerfDataSaveToFile is specified
1773  // or not. In other word, -XX:PerfDataSaveFile=.. overrides flag
1774  // -XX:+PerfDataSaveToFile.
1775  if (PerfDataSaveToFile || PerfDataSaveFile != NULL) {
1776    save_memory_to_file(start(), capacity());
1777  }
1778
1779  if (PerfDisableSharedMem) {
1780    delete_standard_memory(start(), capacity());
1781  }
1782  else {
1783    delete_shared_memory(start(), capacity());
1784  }
1785}
1786
1787// attach to the PerfData memory region for another JVM
1788//
1789// This method returns an <address, size> tuple that points to
1790// a memory buffer that is kept reasonably synchronized with
1791// the PerfData memory region for the indicated JVM. This
1792// buffer may be kept in synchronization via shared memory
1793// or some other mechanism that keeps the buffer updated.
1794//
1795// If the JVM chooses not to support the attachability feature,
1796// this method should throw an UnsupportedOperation exception.
1797//
1798// This implementation utilizes named shared memory to map
1799// the indicated process's PerfData memory region into this JVMs
1800// address space.
1801//
1802void PerfMemory::attach(const char* user, int vmid, PerfMemoryMode mode,
1803                        char** addrp, size_t* sizep, TRAPS) {
1804
1805  if (vmid == 0 || vmid == os::current_process_id()) {
1806     *addrp = start();
1807     *sizep = capacity();
1808     return;
1809  }
1810
1811  open_file_mapping(user, vmid, mode, addrp, sizep, CHECK);
1812}
1813
1814// detach from the PerfData memory region of another JVM
1815//
1816// This method detaches the PerfData memory region of another
1817// JVM, specified as an <address, size> tuple of a buffer
1818// in this process's address space. This method may perform
1819// arbitrary actions to accomplish the detachment. The memory
1820// region specified by <address, size> will be inaccessible after
1821// a call to this method.
1822//
1823// If the JVM chooses not to support the attachability feature,
1824// this method should throw an UnsupportedOperation exception.
1825//
1826// This implementation utilizes named shared memory to detach
1827// the indicated process's PerfData memory region from this
1828// process's address space.
1829//
1830void PerfMemory::detach(char* addr, size_t bytes, TRAPS) {
1831
1832  assert(addr != 0, "address sanity check");
1833  assert(bytes > 0, "capacity sanity check");
1834
1835  if (PerfMemory::contains(addr) || PerfMemory::contains(addr + bytes - 1)) {
1836    // prevent accidental detachment of this process's PerfMemory region
1837    return;
1838  }
1839
1840  if (MemTracker::tracking_level() > NMT_minimal) {
1841    // it does not go through os api, the operation has to record from here
1842    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
1843    remove_file_mapping(addr);
1844    tkr.record((address)addr, bytes);
1845  } else {
1846    remove_file_mapping(addr);
1847  }
1848}
1849