/* * Class: sun_tools_attach_VirtualMachineImpl * Method: checkPermissions * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions (JNIEnv *env, jclass cls, jstring path) { jboolean isCopy; const char* p = GetStringPlatformChars(env, path, &isCopy); if (p != NULL) { struct stat64 sb; uid_t uid, gid; int res; /* * Check that the path is owned by the effective uid/gid of this * process. Also check that group/other access is not allowed. */ uid = geteuid(); gid = getegid(); res = stat64(p, &sb); if (res != 0) { /* save errno */ res = errno; } if (res == 0) { char msg[100]; jboolean isError = JNI_FALSE; if (sb.st_uid != uid) { jio_snprintf(msg, sizeof(msg)-1, "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid); isError = JNI_TRUE; } else if (sb.st_gid != gid) { jio_snprintf(msg, sizeof(msg)-1, "file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid); isError = JNI_TRUE; } else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) { jio_snprintf(msg, sizeof(msg)-1, "file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777); isError = JNI_TRUE; } if (isError) { char buf[256]; jio_snprintf(buf, sizeof(buf)-1, "well-known file %s is not secure: %s", p, msg); JNU_ThrowIOException(env, buf); } } else { char* msg = strdup(strerror(res)); JNU_ThrowIOException(env, msg); if (msg != NULL) { free(msg); } } if (isCopy) { JNU_ReleaseStringPlatformChars(env, path, p); } } }
JNIEXPORT jint JNICALL Java_java_util_zip_ZipFile_read(JNIEnv *env, jclass cls, jlong zfile, jlong zentry, jint pos, jbyteArray bytes, jint off, jint len) { #define BUFSIZE 8192 jzfile *zip = jlong_to_ptr(zfile); jbyte buf[BUFSIZE]; char *msg; if (len > BUFSIZE) { len = BUFSIZE; } ZIP_Lock(zip); len = ZIP_Read(zip, jlong_to_ptr(zentry), pos, buf, len); msg = zip->msg; ZIP_Unlock(zip); if (len == -1) { if (msg != 0) { ThrowZipException(env, msg); } else { JNU_ThrowIOException(env, strerror(errno)); } } else { (*env)->SetByteArrayRegion(env, bytes, off, len, buf); } return len; }
/* * Class: sun_tools_attach_BSDVirtualMachine * Method: createAttachFile * Signature: (Ljava.lang.String;)V */ JNIEXPORT void JNICALL Java_sun_tools_attach_BsdVirtualMachine_createAttachFile(JNIEnv *env, jclass cls, jstring path) { const char* _path; jboolean isCopy; int fd, rc; _path = GetStringPlatformChars(env, path, &isCopy); if (_path == NULL) { JNU_ThrowIOException(env, "Must specify a path"); return; } RESTARTABLE(open(_path, O_CREAT | O_EXCL, S_IWUSR | S_IRUSR), fd); if (fd == -1) { /* release p here before we throw an I/O exception */ if (isCopy) { JNU_ReleaseStringPlatformChars(env, path, _path); } JNU_ThrowIOExceptionWithLastError(env, "open"); return; } RESTARTABLE(chown(_path, geteuid(), getegid()), rc); RESTARTABLE(close(fd), rc); /* release p here */ if (isCopy) { JNU_ReleaseStringPlatformChars(env, path, _path); } }
static void win32Error(JNIEnv *env, const WCHAR *functionName) { WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100]; WCHAR utf16_javaMessage[MESSAGE_LENGTH]; /*Good suggestion about 2-bytes-per-symbol in localized error reports*/ char utf8_javaMessage[MESSAGE_LENGTH*2]; const int errnum = (int)GetLastError(); int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg)); n = (n > 0) ? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg) : swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum); if (n > 0) /*terminate '\0' is not a part of conversion procedure*/ n = WideCharToMultiByte( CP_UTF8, 0, utf16_javaMessage, n, /*by creation n <= MESSAGE_LENGTH*/ utf8_javaMessage, MESSAGE_LENGTH*2, NULL, NULL); /*no way to die*/ { const char *errorMessage = "Secondary error while OS message extraction"; if (n > 0) { utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0'; errorMessage = utf8_javaMessage; } JNU_ThrowIOException(env, errorMessage); } }
/* * Class: sun_awt_shell_Win32ShellFolder2 * Method: parseDisplayName0 * Signature: (JLjava/lang/String;)J */ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_parseDisplayName0 (JNIEnv* env, jclass cls, jlong jpIShellFolder, jstring jname) { // Get desktop IShellFolder interface IShellFolder* pIShellFolder = (IShellFolder*)jpIShellFolder; if (pIShellFolder == NULL) { JNU_ThrowInternalError(env, "Desktop shell folder missing"); return 0; } // Get relative PIDL for name LPITEMIDLIST pIDL; int nLength = env->GetStringLength(jname); const jchar* strPath = env->GetStringChars(jname, NULL); JNU_CHECK_EXCEPTION_RETURN(env, 0); jchar* wszPath = new jchar[nLength + 1]; wcsncpy(reinterpret_cast<LPWSTR>(wszPath), reinterpret_cast<LPCWSTR>(strPath), nLength); wszPath[nLength] = 0; HRESULT res = pIShellFolder->ParseDisplayName(NULL, NULL, reinterpret_cast<LPWSTR>(wszPath), NULL, &pIDL, NULL); if (res != S_OK) { JNU_ThrowIOException(env, "Could not parse name"); pIDL = 0; } delete[] wszPath; env->ReleaseStringChars(jname, strPath); return (jlong)pIDL; }
/* * Class: sun_awt_shell_Win32ShellFolder2 * Method: initSpecial * Signature: (JI)V */ JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_initSpecial (JNIEnv* env, jobject folder, jlong desktopIShellFolder, jint folderType) { // Get desktop IShellFolder interface IShellFolder* pDesktop = (IShellFolder*)desktopIShellFolder; if (pDesktop == NULL) { JNU_ThrowInternalError(env, "Desktop shell folder missing"); return; } // Get special folder relative PIDL LPITEMIDLIST relPIDL; HRESULT res = fn_SHGetSpecialFolderLocation(NULL, folderType, &relPIDL); if (res != S_OK) { JNU_ThrowIOException(env, "Could not get shell folder ID list"); return; } // Set field ID for relative PIDL env->CallVoidMethod(folder, MID_relativePIDL, (jlong)relPIDL); // Get special folder IShellFolder interface IShellFolder* pFolder; res = pDesktop->BindToObject(relPIDL, NULL, IID_IShellFolder, (void**)&pFolder); if (res != S_OK) { JNU_ThrowInternalError(env, "Could not bind shell folder to interface"); return; } // Set field ID for pIShellFolder env->CallVoidMethod(folder, MID_pIShellFolder, (jlong)pFolder); }
/* * Class: sun_tools_attach_VirtualMachineImpl * Method: open * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_open (JNIEnv *env, jclass cls, jstring path) { jboolean isCopy; const char* p = GetStringPlatformChars(env, path, &isCopy); if (p == NULL) { return 0; } else { int fd; int err = 0; fd = open(p, O_RDWR); if (fd == -1) { err = errno; } if (isCopy) { JNU_ReleaseStringPlatformChars(env, path, p); } if (fd == -1) { if (err == ENOENT) { JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL); } else { char* msg = strdup(strerror(err)); JNU_ThrowIOException(env, msg); if (msg != NULL) { free(msg); } } } return fd; } }
JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_Secmod_nssLoadLibrary (JNIEnv *env, jclass thisClass, jstring jName) { HINSTANCE hModule; LPVOID lpMsgBuf; const char *libName = (*env)->GetStringUTFChars(env, jName, NULL); dprintf1("-lib %s\n", libName); hModule = LoadLibrary(libName); (*env)->ReleaseStringUTFChars(env, jName, libName); if (hModule == NULL) { FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, /* Default language */ (LPTSTR) &lpMsgBuf, 0, NULL ); dprintf1("-error: %s\n", lpMsgBuf); JNU_ThrowIOException(env, (char*)lpMsgBuf); LocalFree(lpMsgBuf); return 0; } dprintf2("-handle: %d (0X%X)\n", hModule, hModule); return (jlong)hModule; }
/** * Creates a SDP socket. */ static int create(JNIEnv* env) { int s; #if defined(__solaris__) #ifdef AF_INET6 int domain = ipv6_available() ? AF_INET6 : AF_INET; #else int domain = AF_INET; #endif s = socket(domain, SOCK_STREAM, PROTO_SDP); #elif defined(__linux__) /** * IPv6 not supported by SDP on Linux */ if (ipv6_available()) { JNU_ThrowIOException(env, "IPv6 not supported"); return -1; } s = socket(AF_INET_SDP, SOCK_STREAM, 0); #else /* not supported on other platforms at this time */ s = -1; errno = EPROTONOSUPPORT; #endif if (s < 0) JNU_ThrowIOExceptionWithLastError(env, "socket"); return s; }
static char *fullPath(JNIEnv *env, char *part, char *full) { char **tmp; struct stat b; int ret; /* * If the filename we want to exec has any slashes in it then * we shouldn't do a path search, as in /foo ./foo or foo/bar. */ if ((strchr(part, '/') == NULL) && PATH) { for (tmp = PATH; *tmp; tmp++) { strcpy(full, *tmp); /* * empty path elements are like '.' so we don't want to append * a slash to them. Otherwise foo becomes /foo. */ if (full[0] != '\0') { strcat(full, "/"); } strcat(full, part); ret = statExecutable(full, &b); if (ret == -1) { /* doesn't exist */ continue; } else if (ret == -2) { /* can't execute */ continue; /* bug 4199993 - got to keep searching. */ } else { return full; } } } else if (!(ret = statExecutable(part, &b))) { /* always copy value to be returned so `part' may always be freed * after call (if needed) */ strcpy(full, part); return full; } else if (ret == -2) { /* cannot execute */ jio_snprintf(full, MAXPATHLEN, "%s: cannot execute", part); JNU_ThrowIOException(env, full); return 0; } /* not found if we got here */ jio_snprintf(full, MAXPATHLEN, "%s: not found", part); JNU_ThrowIOException(env, full); return 0; }
/* * Class: sun_tools_attach_LinuxVirtualMachine * Method: checkPermissions * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_sun_tools_attach_LinuxVirtualMachine_checkPermissions (JNIEnv *env, jclass cls, jstring path) { jboolean isCopy; const char* p = GetStringPlatformChars(env, path, &isCopy); if (p != NULL) { struct stat64 sb; uid_t uid, gid; int res; /* * Check that the path is owned by the effective uid/gid of this * process. Also check that group/other access is not allowed. */ uid = geteuid(); gid = getegid(); res = stat64(p, &sb); if (res != 0) { /* save errno */ res = errno; } /* release p here before we throw an I/O exception */ if (isCopy) { JNU_ReleaseStringPlatformChars(env, path, p); } if (res == 0) { if ( (sb.st_uid != uid) || (sb.st_gid != gid) || ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) ) { JNU_ThrowIOException(env, "well-known file is not secure"); } } else { char* msg = strdup(strerror(res)); JNU_ThrowIOException(env, msg); if (msg != NULL) { free(msg); } } } }
/* * Class: sun_awt_shell_Win32ShellFolder * Method: initFile * Signature: (JLjava/lang/String;Z)J */ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder_initFile (JNIEnv* env, jobject folder, jlong desktopIShellFolder, jstring absolutePath, jboolean initAttributes) { // Get desktop IShellFolder interface IShellFolder* pDesktop = (IShellFolder*)desktopIShellFolder; if (pDesktop == NULL) { JNU_ThrowInternalError(env, "Desktop shell folder missing"); return 0; } // Get PIDL for file from desktop LPITEMIDLIST pIDL; int nLength = env->GetStringLength(absolutePath); jchar* wszPath = new jchar[nLength + 1]; const jchar* strPath = env->GetStringChars(absolutePath, NULL); wcsncpy(wszPath, strPath, nLength); wszPath[nLength] = 0; HRESULT res = pDesktop->ParseDisplayName(NULL, NULL, const_cast<jchar*>(wszPath), NULL, &pIDL, NULL); if (res != S_OK) { JNU_ThrowIOException(env, "Could not parse file path"); delete[] wszPath; env->ReleaseStringChars(absolutePath, strPath); return 0; } delete[] wszPath; env->ReleaseStringChars(absolutePath, strPath); // Get display name, folder type, and possibly attributes SHFILEINFO fileInfo; UINT flags; if (initAttributes) { flags = SHGFI_ATTRIBUTES | SHGFI_DISPLAYNAME | SHGFI_TYPENAME | SHGFI_PIDL; } else { flags = SHGFI_DISPLAYNAME | SHGFI_TYPENAME | SHGFI_PIDL; } if (fn_SHGetFileInfo((char *)pIDL, 0L, &fileInfo, sizeof(fileInfo), flags) != 0) { if (initAttributes) { env->SetLongField(folder, FID_attributes, (jlong)fileInfo.dwAttributes); } env->SetObjectField(folder, FID_displayName, JNU_NewStringPlatform(env, fileInfo.szDisplayName)); env->SetObjectField(folder, FID_folderType, JNU_NewStringPlatform(env, fileInfo.szTypeName)); } return (jlong)pIDL; }
static void win32Error(JNIEnv *env, const char *functionName) { static const char * const format = "%s error=%d, %s"; static const char * const fallbackFormat = "%s failed, error=%d"; char buf[256]; char errmsg[sizeof(buf) + 100]; const int errnum = GetLastError(); const int n = JVM_GetLastErrorString(buf, sizeof(buf)); if (n > 0) sprintf(errmsg, format, functionName, errnum, buf); else sprintf(errmsg, fallbackFormat, functionName, errnum); JNU_ThrowIOException(env, errmsg); }
/* * Class: sun_awt_shell_Win32ShellFolder2 * Method: getFileSystemPath0 * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileSystemPath0 (JNIEnv* env, jclass cls, jint csidl) { LPITEMIDLIST relPIDL; TCHAR szBuf[MAX_PATH]; HRESULT res = fn_SHGetSpecialFolderLocation(NULL, csidl, &relPIDL); if (res != S_OK) { JNU_ThrowIOException(env, "Could not get shell folder ID list"); return NULL; } if (fn_SHGetPathFromIDList(relPIDL, szBuf)) { return JNU_NewStringPlatform(env, szBuf); } else { return NULL; } }
/* * Class: sun_tools_attach_WindowsVirtualMachine * Method: openProcess * Signature: (I)J */ JNIEXPORT jlong JNICALL Java_sun_tools_attach_WindowsVirtualMachine_openProcess (JNIEnv *env, jclass cls, jint pid) { HANDLE hProcess; /* * Attempt to open process. If it fails then we try to enable the * SE_DEBUG_NAME privilege and retry. */ hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid); if (hProcess == NULL && GetLastError() == ERROR_ACCESS_DENIED) { hProcess = doPrivilegedOpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid); } if (hProcess == NULL) { if (GetLastError() == ERROR_INVALID_PARAMETER) { JNU_ThrowIOException(env, "no such process"); } else { JNU_ThrowIOExceptionWithLastError(env, "OpenProcess failed"); } return (jlong)0; } /* * On Windows 64-bit we need to handle 32-bit tools trying to attach to 64-bit * processes (and visa versa). X-architecture attaching is currently not supported * by this implementation. */ if (_IsWow64Process != NULL) { BOOL isCurrent32bit, isTarget32bit; (*_IsWow64Process)(GetCurrentProcess(), &isCurrent32bit); (*_IsWow64Process)(hProcess, &isTarget32bit); if (isCurrent32bit != isTarget32bit) { CloseHandle(hProcess); #ifdef _WIN64 JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException", "Unable to attach to 32-bit process running under WOW64"); #else JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException", "Unable to attach to 64-bit process"); #endif } } return (jlong)hProcess; }
JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_Secmod_nssLoadLibrary (JNIEnv *env, jclass thisClass, jstring jLibName) { void *hModule; const char *libName = (*env)->GetStringUTFChars(env, jLibName, NULL); dprintf1("-lib %s\n", libName); hModule = dlopen(libName, RTLD_LAZY); (*env)->ReleaseStringUTFChars(env, jLibName, libName); dprintf2("-handle: %u (0X%X)\n", hModule, hModule); if (hModule == NULL) { JNU_ThrowIOException(env, dlerror()); return 0; } return (jlong)hModule; }
JNIEXPORT void JNICALL Java_sun_security_smartcardio_PlatformPCSC_initialize (JNIEnv *env, jclass thisClass, jstring jLibName) { const char *libName = (*env)->GetStringUTFChars(env, jLibName, NULL); hModule = dlopen(libName, RTLD_LAZY); (*env)->ReleaseStringUTFChars(env, jLibName, libName); if (hModule == NULL) { JNU_ThrowIOException(env, dlerror()); return; } scardEstablishContext = (FPTR_SCardEstablishContext)findFunction(env, hModule, "SCardEstablishContext"); scardConnect = (FPTR_SCardConnect) findFunction(env, hModule, "SCardConnect"); scardDisconnect = (FPTR_SCardDisconnect) findFunction(env, hModule, "SCardDisconnect"); scardStatus = (FPTR_SCardStatus) findFunction(env, hModule, "SCardStatus"); scardGetStatusChange = (FPTR_SCardGetStatusChange) findFunction(env, hModule, "SCardGetStatusChange"); scardTransmit = (FPTR_SCardTransmit) findFunction(env, hModule, "SCardTransmit"); scardListReaders = (FPTR_SCardListReaders) findFunction(env, hModule, "SCardListReaders"); scardBeginTransaction = (FPTR_SCardBeginTransaction)findFunction(env, hModule, "SCardBeginTransaction"); scardEndTransaction = (FPTR_SCardEndTransaction) findFunction(env, hModule, "SCardEndTransaction"); scardControl = (FPTR_SCardControl) findFunction(env, hModule, "SCardControl"); }
/* * Class: sun_tools_attach_VirtualMachineImpl * Method: connect * Signature: (ILjava/lang/String;)I */ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connect (JNIEnv *env, jclass cls, jint fd, jstring path) { jboolean isCopy; const char* p = GetStringPlatformChars(env, path, &isCopy); if (p != NULL) { struct sockaddr_un addr; int err = 0; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; /* strncpy is safe because addr.sun_path was zero-initialized before. */ strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1); if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { err = errno; } if (isCopy) { JNU_ReleaseStringPlatformChars(env, path, p); } /* * If the connect failed then we throw the appropriate exception * here (can't throw it before releasing the string as can't call * JNI with pending exception) */ if (err != 0) { if (err == ENOENT) { JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL); } else { char* msg = strdup(strerror(err)); JNU_ThrowIOException(env, msg); if (msg != NULL) { free(msg); } } } } }
/* * Class: sun_tools_attach_LinuxVirtualMachine * Method: getLinuxThreadsManager * Signature: (I)I */ JNIEXPORT jint JNICALL Java_sun_tools_attach_LinuxVirtualMachine_getLinuxThreadsManager (JNIEnv *env, jclass cls, jint pid) { ChildCountContext context; /* * Iterate over all processes to find how many children 'pid' has */ context.ppid = pid; context.count = 0; context.mpid = (pid_t)0; forEachProcess(ChildCountCallback, (void*)&context); /* * If there's no children then this is likely the pid of the primordial * created by the launcher - in that case the LinuxThreads manager is the * parent of this process. */ if (context.count == 0) { pid_t parent = getParent(pid); if ((int)parent > 0) { return (jint)parent; } } /* * There's one child so this is likely the embedded VM case where the * the primordial thread == LinuxThreads initial thread. The LinuxThreads * manager in that case is the child. */ if (context.count == 1) { return (jint)context.mpid; } /* * If we get here it's most likely we were given the wrong pid */ JNU_ThrowIOException(env, "Unable to get pid of LinuxThreads manager thread"); return -1; }
/* * Returns JNI_TRUE if the specified file is on a file system that supports * persistent ACLs (On NTFS file systems returns true, on FAT32 file systems * returns false). */ static jboolean isSecuritySupported(JNIEnv* env, const char* path) { char* root; char* p; BOOL res; DWORD dwMaxComponentLength; DWORD dwFlags; char fsName[128]; DWORD fsNameLength; /* * Get root directory. Assume that files are absolute paths. For UNCs * the slash after the share name is required. */ root = strdup(path); if (*root == '\\') { /* * \\server\share\file ==> \\server\share\ */ int slashskip = 3; p = root; while ((*p == '\\') && (slashskip > 0)) { char* p2; p++; p2 = strchr(p, '\\'); if ((p2 == NULL) || (*p2 != '\\')) { free(root); JNU_ThrowIOException(env, "Malformed UNC"); return JNI_FALSE; } p = p2; slashskip--; } if (slashskip != 0) { free(root); JNU_ThrowIOException(env, "Malformed UNC"); return JNI_FALSE; } p++; *p = '\0'; } else { p = strchr(root, '\\'); if (p == NULL) { free(root); JNU_ThrowIOException(env, "Absolute filename not specified"); return JNI_FALSE; } p++; *p = '\0'; } /* * Get the volume information - this gives us the file system file and * also tells us if the file system supports persistent ACLs. */ fsNameLength = sizeof(fsName)-1; res = GetVolumeInformation(root, NULL, // address of name of the volume, can be NULL 0, // length of volume name NULL, // address of volume serial number, can be NULL &dwMaxComponentLength, &dwFlags, fsName, fsNameLength); if (res == 0) { free(root); JNU_ThrowIOExceptionWithLastError(env, "GetVolumeInformation failed"); return JNI_FALSE; } free(root); return (dwFlags & FS_PERSISTENT_ACLS) ? JNI_TRUE : JNI_FALSE; }
/* * Class: sun_tools_attach_VirtualMachineImpl * Method: openProcess * Signature: (I)J */ JNIEXPORT jlong JNICALL Java_sun_tools_attach_VirtualMachineImpl_openProcess (JNIEnv *env, jclass cls, jint pid) { HANDLE hProcess = NULL; if (pid == (jint) GetCurrentProcessId()) { /* process is attaching to itself; get a pseudo handle instead */ hProcess = GetCurrentProcess(); /* duplicate the pseudo handle so it can be used in more contexts */ if (DuplicateHandle(hProcess, hProcess, hProcess, &hProcess, PROCESS_ALL_ACCESS, FALSE, 0) == 0) { /* * Could not duplicate the handle which isn't a good sign, * but we'll try again with OpenProcess() below. */ hProcess = NULL; } } if (hProcess == NULL) { /* * Attempt to open process. If it fails then we try to enable the * SE_DEBUG_NAME privilege and retry. */ hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid); if (hProcess == NULL && GetLastError() == ERROR_ACCESS_DENIED) { hProcess = doPrivilegedOpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid); } if (hProcess == NULL) { if (GetLastError() == ERROR_INVALID_PARAMETER) { JNU_ThrowIOException(env, "no such process"); } else { char err_mesg[255]; /* include the last error in the default detail message */ sprintf(err_mesg, "OpenProcess(pid=%d) failed; LastError=0x%x", (int)pid, (int)GetLastError()); JNU_ThrowIOExceptionWithLastError(env, err_mesg); } return (jlong)0; } } /* * On Windows 64-bit we need to handle 32-bit tools trying to attach to 64-bit * processes (and visa versa). X-architecture attaching is currently not supported * by this implementation. */ if (_IsWow64Process != NULL) { BOOL isCurrent32bit, isTarget32bit; (*_IsWow64Process)(GetCurrentProcess(), &isCurrent32bit); (*_IsWow64Process)(hProcess, &isTarget32bit); if (isCurrent32bit != isTarget32bit) { CloseHandle(hProcess); #ifdef _WIN64 JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException", "Unable to attach to 32-bit process running under WOW64"); #else JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException", "Unable to attach to 64-bit process"); #endif } } return (jlong)hProcess; }
/* * Class: sun_tools_attach_VirtualMachineImpl * Method: enqueue * Signature: (JILjava/lang/String;[Ljava/lang/Object;)V */ JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue (JNIEnv *env, jclass cls, jint fd, jstring cmd, jobjectArray args) { jint arg_count, i; size_t size; jboolean isCopy; door_arg_t door_args; char res_buffer[128]; jint result = -1; int rc; const char* cstr; char* buf; /* * First we get the command string and create the start of the * argument string to send to the target VM: * <ver>\0<cmd>\0 */ cstr = JNU_GetStringPlatformChars(env, cmd, &isCopy); if (cstr == NULL) { return -1; /* pending exception */ } size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2; buf = (char*)malloc(size); if (buf != NULL) { char* pos = buf; strcpy(buf, PROTOCOL_VERSION); pos += strlen(PROTOCOL_VERSION)+1; strcpy(pos, cstr); } if (isCopy) { JNU_ReleaseStringPlatformChars(env, cmd, cstr); } if (buf == NULL) { JNU_ThrowOutOfMemoryError(env, "malloc failed"); return -1; } /* * Next we iterate over the arguments and extend the buffer * to include them. */ arg_count = (*env)->GetArrayLength(env, args); for (i=0; i<arg_count; i++) { jobject obj = (*env)->GetObjectArrayElement(env, args, i); if (obj != NULL) { cstr = JNU_GetStringPlatformChars(env, obj, &isCopy); if (cstr != NULL) { size_t len = strlen(cstr); char* newbuf = (char*)realloc(buf, size+len+1); if (newbuf != NULL) { buf = newbuf; strcpy(buf+size, cstr); size += len+1; } if (isCopy) { JNU_ReleaseStringPlatformChars(env, obj, cstr); } if (newbuf == NULL) { free(buf); JNU_ThrowOutOfMemoryError(env, "realloc failed"); return -1; } } } if ((*env)->ExceptionOccurred(env)) { free(buf); return -1; } } /* * The arguments to the door function are in 'buf' so we now * do the door call */ door_args.data_ptr = buf; door_args.data_size = size; door_args.desc_ptr = NULL; door_args.desc_num = 0; door_args.rbuf = (char*)&res_buffer; door_args.rsize = sizeof(res_buffer); RESTARTABLE(door_call(fd, &door_args), rc); /* * door_call failed */ if (rc == -1) { JNU_ThrowIOExceptionWithLastError(env, "door_call"); } else { /* * door_call succeeded but the call didn't return the expected jint. */ if (door_args.data_size < sizeof(jint)) { JNU_ThrowIOException(env, "Enqueue error - reason unknown as result is truncated!"); } else { jint* res = (jint*)(door_args.data_ptr); if (*res != JNI_OK) { const char* msg = translate_error(*res); char buf[255]; if (msg == NULL) { sprintf(buf, "Unable to enqueue command to target VM: %d", *res); } else { sprintf(buf, "Unable to enqueue command to target VM: %s", msg); } JNU_ThrowIOException(env, buf); } else { /* * The door call should return a file descriptor to one end of * a socket pair */ if ((door_args.desc_ptr != NULL) && (door_args.desc_num == 1) && (door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) { result = door_args.desc_ptr->d_data.d_desc.d_descriptor; } else { JNU_ThrowIOException(env, "Reply from enqueue missing descriptor!"); } } } } free(buf); return result; }
/* * Class: sun_awt_windows_WDataTransferer * Method: platformImageBytesToImageData * Signature: ([BI)[I */ JNIEXPORT jintArray JNICALL Java_sun_awt_windows_WDataTransferer_platformImageBytesToImageData( JNIEnv *env, jobject self, jbyteArray bytes, jlong format) { TRY; HDC hdc = NULL; LOGPALETTE* pLogPalette = NULL; WORD uPaletteEntries = 0; SIZE_T uOffset = 0; HPALETTE hPalette = NULL; HPALETTE hOldPalette = NULL; BITMAPINFO* pSrcBmi = NULL; BITMAPINFOHEADER* pSrcBmih = NULL; LPVOID pSrcBits = NULL; BITMAPINFO* pDstBmi = NULL; BITMAPINFOHEADER* pDstBmih = NULL; LPVOID pDstBits = NULL; LPBYTE lpEnhMetaFileBits = NULL; HENHMETAFILE hEnhMetaFile = NULL; HBITMAP hDibSection = NULL; HBITMAP hOldBitmap = NULL; jintArray buffer = NULL; LONG width = 0; LONG height = 0; int numPixels = 0; if (JNU_IsNull(env, bytes)) { return NULL; } jsize size = env->GetArrayLength(bytes); if (size == 0) { return NULL; } jbyte* bBytes = (jbyte*)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, size, sizeof(jbyte)); try { env->GetByteArrayRegion(bytes, 0, size, bBytes); pLogPalette = (LOGPALETTE*)bBytes; uPaletteEntries = pLogPalette->palNumEntries; uOffset = sizeof(LOGPALETTE) + uPaletteEntries * sizeof(PALETTEENTRY); DASSERT(uOffset < (SIZE_T)size); if (uPaletteEntries == 0) { pLogPalette = NULL; } hdc = ::CreateCompatibleDC(NULL); if (hdc == NULL) { free(bBytes); return NULL; } switch (format) { case CF_DIB: pSrcBmi = (BITMAPINFO*)((LPSTR)bBytes + uOffset); pSrcBmih = &pSrcBmi->bmiHeader; width = pSrcBmih->biWidth; height = abs(pSrcBmih->biHeight); { DWORD nColorEntries = 0; switch (pSrcBmih->biBitCount) { case 0: nColorEntries = 0; break; case 1: nColorEntries = 2; break; case 4: case 8: nColorEntries = (pSrcBmih->biClrUsed != 0) ? pSrcBmih->biClrUsed : (1 << pSrcBmih->biBitCount); break; case 16: case 24: case 32: nColorEntries = pSrcBmih->biClrUsed; // If biBitCount is 16 or 32 and biCompression is // BI_BITFIELDS the color table will be prefixed with // three DWORD color masks. if (pSrcBmih->biCompression == BI_BITFIELDS && (pSrcBmih->biBitCount == 16 || pSrcBmih->biBitCount == 32)) { nColorEntries += 3; } break; default: // The header is probably corrupted. // Fail immediatelly to avoid memory access violation. free(bBytes); ::DeleteDC(hdc); return NULL; } pSrcBits = (LPSTR)pSrcBmi + pSrcBmih->biSize + nColorEntries * sizeof(RGBQUAD); } break; case CF_ENHMETAFILE: case CF_METAFILEPICT: lpEnhMetaFileBits = (BYTE*)bBytes + uOffset; // Warning C4244. size is jsize, uOffset is SIZE_T. // We assert that size > uOffset, so it is safe to cast to jsize. hEnhMetaFile = ::SetEnhMetaFileBits(size - (jsize)uOffset, lpEnhMetaFileBits); DASSERT(hEnhMetaFile != NULL); { UINT uHeaderSize = ::GetEnhMetaFileHeader(hEnhMetaFile, 0, NULL); DASSERT(uHeaderSize != 0); ENHMETAHEADER* lpemh = (ENHMETAHEADER*)safe_Malloc(uHeaderSize); VERIFY(::GetEnhMetaFileHeader(hEnhMetaFile, uHeaderSize, lpemh) == uHeaderSize); LPRECTL lpFrame = &lpemh->rclFrame; POINT p = { abs(lpFrame->right - lpFrame->left), abs(lpFrame->bottom - lpFrame->top) }; VERIFY(::SaveDC(hdc)); VERIFY(::SetMapMode(hdc, MM_HIMETRIC)); VERIFY(::LPtoDP(hdc, &p, 1)); VERIFY(::RestoreDC(hdc, -1)); width = p.x; height = -p.y; free(lpemh); } break; default: DASSERT(FALSE); // Other formats are not supported yet. free(bBytes); ::DeleteDC(hdc); return NULL; } // JNI doesn't allow to store more than INT_MAX in a single array. // We report conversion failure in this case. if (width * height > INT_MAX) { free(bBytes); ::DeleteDC(hdc); return NULL; } numPixels = width * height; if (pLogPalette != NULL) { hPalette = ::CreatePalette(pLogPalette); if (hPalette == NULL) { free(bBytes); ::DeleteDC(hdc); return NULL; } hOldPalette = ::SelectPalette(hdc, hPalette, FALSE); ::RealizePalette(hdc); } // allocate memory for BITMAPINFO pDstBmi = (BITMAPINFO *)safe_Calloc(1, sizeof(BITMAPINFO)); pDstBmih = &pDstBmi->bmiHeader; static const int BITS_PER_PIXEL = 32; // prepare BITMAPINFO for a 32-bit RGB bitmap pDstBmih->biSize = sizeof(BITMAPINFOHEADER); pDstBmih->biWidth = width; pDstBmih->biHeight = -height; // negative height means a top-down DIB pDstBmih->biPlanes = 1; pDstBmih->biBitCount = BITS_PER_PIXEL; pDstBmih->biCompression = BI_RGB; // NOTE: MSDN says that biSizeImage may be set to 0 for BI_RGB bitmaps, // but this causes CreateDIBSection to allocate zero-size memory block // for DIB data. It works okay when biSizeImage is explicitly specified. pDstBmih->biSizeImage = width * height * (BITS_PER_PIXEL >> 3); hDibSection = ::CreateDIBSection(hdc, (BITMAPINFO*)pDstBmi, DIB_RGB_COLORS, &pDstBits, NULL, 0); if (hDibSection == NULL) { free(pDstBmi); pDstBmi = NULL; if (hPalette != NULL) { VERIFY(::SelectPalette(hdc, hOldPalette, FALSE) != NULL); hOldPalette = NULL; VERIFY(::DeleteObject(hPalette)); hPalette = NULL; } VERIFY(::DeleteDC(hdc)); hdc = NULL; free(bBytes); bBytes = NULL; JNU_ThrowIOException(env, "failed to get drop data"); return NULL; } hOldBitmap = (HBITMAP)::SelectObject(hdc, hDibSection); DASSERT(hOldBitmap != NULL); switch (format) { case CF_DIB: VERIFY(::StretchDIBits(hdc, 0, 0, width, height, 0, 0, width, height, pSrcBits, pSrcBmi, DIB_RGB_COLORS, SRCCOPY) != GDI_ERROR); break; case CF_ENHMETAFILE: case CF_METAFILEPICT: { RECT rect = { 0, 0, width, height }; VERIFY(::PlayEnhMetaFile(hdc, hEnhMetaFile, &rect)); VERIFY(::DeleteEnhMetaFile(hEnhMetaFile)); hEnhMetaFile = NULL; break; } default: // Other formats are not supported yet. DASSERT(FALSE); break; } // convert Win32 pixel format (BGRX) to Java format (ARGB) DASSERT(sizeof(jint) == sizeof(RGBQUAD)); RGBQUAD* prgbq = (RGBQUAD*)pDstBits; for(int nPixel = 0; nPixel < numPixels; nPixel++, prgbq++) { jint jpixel = WIN_TO_JAVA_PIXEL(prgbq->rgbRed, prgbq->rgbGreen, prgbq->rgbBlue); // stuff the 32-bit pixel back into the 32-bit RGBQUAD *prgbq = *((RGBQUAD*)(&jpixel)); } buffer = env->NewIntArray(numPixels + 2); if (buffer == NULL) { throw std::bad_alloc(); } // copy pixels into Java array env->SetIntArrayRegion(buffer, 0, numPixels, (jint*)pDstBits); // copy dimensions into Java array env->SetIntArrayRegion(buffer, numPixels, 1, (jint*)&width); env->SetIntArrayRegion(buffer, numPixels + 1, 1, (jint*)&height); VERIFY(::SelectObject(hdc, hOldBitmap) != NULL); hOldBitmap = NULL; VERIFY(::DeleteObject(hDibSection)); hDibSection = NULL; free(pDstBmi); pDstBmi = NULL; if (hPalette != NULL) { VERIFY(::SelectPalette(hdc, hOldPalette, FALSE) != NULL); hOldPalette = NULL; VERIFY(::DeleteObject(hPalette)); hPalette = NULL; } VERIFY(::DeleteDC(hdc)); hdc = NULL; free(bBytes); bBytes = NULL; } catch (...) { if (hdc != NULL && hOldBitmap != NULL) { VERIFY(::SelectObject(hdc, hOldBitmap) != NULL); hOldBitmap = NULL; } if (hDibSection != NULL) { VERIFY(::DeleteObject(hDibSection)); hDibSection = NULL; } if (pDstBmi != NULL) { free(pDstBmi); pDstBmi = NULL; } if (hPalette != NULL) { if (hdc != NULL) { VERIFY(::SelectPalette(hdc, hOldPalette, FALSE) != NULL); hOldPalette = NULL; } VERIFY(::DeleteObject(hPalette)); hPalette = NULL; } if (hdc != NULL) { VERIFY(::DeleteDC(hdc)); hdc = NULL; } if (hEnhMetaFile != NULL) { VERIFY(::DeleteEnhMetaFile(hEnhMetaFile)); hEnhMetaFile = NULL; } if (bBytes != NULL) { free(bBytes); bBytes = NULL; } throw; } return buffer; CATCH_BAD_ALLOC_RET(NULL); }
/* * Class: sun_awt_windows_WClipboard * Method: getClipboardData * Signature: (J)[B */ JNIEXPORT jbyteArray JNICALL Java_sun_awt_windows_WClipboard_getClipboardData (JNIEnv *env, jobject self, jlong format) { TRY; DASSERT(::GetOpenClipboardWindow() == AwtToolkit::GetInstance().GetHWnd()); HANDLE handle = ::GetClipboardData((UINT)format); if (handle == NULL) { JNU_ThrowIOException(env, "system clipboard data unavailable"); return NULL; } jbyteArray bytes = NULL; jbyteArray paletteData = NULL; switch (format) { case CF_ENHMETAFILE: case CF_METAFILEPICT: { HENHMETAFILE hemf = NULL; if (format == CF_METAFILEPICT) { HMETAFILEPICT hMetaFilePict = (HMETAFILEPICT)handle; LPMETAFILEPICT lpMetaFilePict = (LPMETAFILEPICT)::GlobalLock(hMetaFilePict); UINT uSize = ::GetMetaFileBitsEx(lpMetaFilePict->hMF, 0, NULL); DASSERT(uSize != 0); try { LPBYTE lpMfBits = (LPBYTE)safe_Malloc(uSize); VERIFY(::GetMetaFileBitsEx(lpMetaFilePict->hMF, uSize, lpMfBits) == uSize); hemf = ::SetWinMetaFileBits(uSize, lpMfBits, NULL, lpMetaFilePict); free(lpMfBits); if (hemf == NULL) { ::GlobalUnlock(hMetaFilePict); JNU_ThrowIOException(env, "failed to get system clipboard data"); return NULL; } } catch (...) { ::GlobalUnlock(hMetaFilePict); throw; } ::GlobalUnlock(hMetaFilePict); } else { hemf = (HENHMETAFILE)handle; } UINT uEmfSize = ::GetEnhMetaFileBits(hemf, 0, NULL); if (uEmfSize == 0) { JNU_ThrowIOException(env, "cannot retrieve metafile bits"); return NULL; } bytes = env->NewByteArray(uEmfSize); if (bytes == NULL) { throw std::bad_alloc(); } LPBYTE lpbEmfBuffer = (LPBYTE)env->GetPrimitiveArrayCritical(bytes, NULL); if (lpbEmfBuffer == NULL) { env->DeleteLocalRef(bytes); throw std::bad_alloc(); } VERIFY(::GetEnhMetaFileBits(hemf, uEmfSize, lpbEmfBuffer) == uEmfSize); env->ReleasePrimitiveArrayCritical(bytes, lpbEmfBuffer, 0); paletteData = AwtDataTransferer::GetPaletteBytes(hemf, OBJ_ENHMETAFILE, FALSE); break; } case CF_LOCALE: { LCID *lcid = (LCID *)::GlobalLock(handle); if (lcid == NULL) { JNU_ThrowIOException(env, "invalid LCID"); return NULL; } try { bytes = AwtDataTransferer::LCIDToTextEncoding(env, *lcid); } catch (...) { ::GlobalUnlock(handle); throw; } ::GlobalUnlock(handle); break; } default: { ::SetLastError(0); // clear error // Warning C4244. // Cast SIZE_T (__int64 on 64-bit/unsigned int on 32-bit) // to jsize (long). SIZE_T globalSize = ::GlobalSize(handle); jsize size = (globalSize <= INT_MAX) ? (jsize)globalSize : INT_MAX; if (::GetLastError() != 0) { JNU_ThrowIOException(env, "invalid global memory block handle"); return NULL; } bytes = env->NewByteArray(size); if (bytes == NULL) { throw std::bad_alloc(); } if (size != 0) { LPVOID data = ::GlobalLock(handle); env->SetByteArrayRegion(bytes, 0, size, (jbyte *)data); ::GlobalUnlock(handle); } break; } } switch (format) { case CF_ENHMETAFILE: case CF_METAFILEPICT: case CF_DIB: { if (JNU_IsNull(env, paletteData)) { HPALETTE hPalette = (HPALETTE)::GetClipboardData(CF_PALETTE); paletteData = AwtDataTransferer::GetPaletteBytes(hPalette, OBJ_PAL, TRUE); } DASSERT(!JNU_IsNull(env, paletteData) && !JNU_IsNull(env, bytes)); jbyteArray concat = (jbyteArray)AwtDataTransferer::ConcatData(env, paletteData, bytes); if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) { env->ExceptionDescribe(); env->ExceptionClear(); env->DeleteLocalRef(bytes); env->DeleteLocalRef(paletteData); return NULL; } env->DeleteLocalRef(bytes); env->DeleteLocalRef(paletteData); bytes = concat; break; } } return bytes; CATCH_BAD_ALLOC_RET(NULL); }
/* * Class: sun_tools_attach_WindowsVirtualMachine * Method: enqueue * Signature: (JZLjava/lang/String;[Ljava/lang/Object;)V */ JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_enqueue (JNIEnv *env, jclass cls, jlong handle, jbyteArray stub, jstring cmd, jstring pipename, jobjectArray args) { DataBlock data; DataBlock* pData; DWORD* pCode; DWORD numBytes; DWORD stubLen; HANDLE hProcess, hThread; jint argsLen, i; jbyte* stubCode; jboolean isCopy; /* * Setup data to copy to target process */ data._LoadLibrary = _LoadLibrary; data._GetProcAddress = _GetProcAddress; strcpy(data.jvmLib, "jvm"); strcpy(data.func1, "JVM_EnqueueOperation"); strcpy(data.func2, "_JVM_EnqueueOperation@20"); /* * Command and arguments */ jstring_to_cstring(env, cmd, data.cmd, MAX_CMD_LENGTH); argsLen = (*env)->GetArrayLength(env, args); if (argsLen > 0) { if (argsLen > MAX_ARGS) { JNU_ThrowInternalError(env, "Too many arguments"); } for (i=0; i<argsLen; i++) { jobject obj = (*env)->GetObjectArrayElement(env, args, i); if (obj == NULL) { data.arg[i][0] = '\0'; } else { jstring_to_cstring(env, obj, data.arg[i], MAX_ARG_LENGTH); } if ((*env)->ExceptionOccurred(env)) return; } } for (i=argsLen; i<MAX_ARGS; i++) { data.arg[i][0] = '\0'; } /* pipe name */ jstring_to_cstring(env, pipename, data.pipename, MAX_PIPE_NAME_LENGTH); /* * Allocate memory in target process for data and code stub * (assumed aligned and matches architecture of target process) */ hProcess = (HANDLE)handle; pData = (DataBlock*) VirtualAllocEx( hProcess, 0, sizeof(DataBlock), MEM_COMMIT, PAGE_READWRITE ); if (pData == NULL) { JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed"); return; } WriteProcessMemory( hProcess, (LPVOID)pData, (LPVOID)&data, (DWORD)sizeof(DataBlock), &numBytes ); stubLen = (DWORD)(*env)->GetArrayLength(env, stub); stubCode = (*env)->GetByteArrayElements(env, stub, &isCopy); pCode = (PDWORD) VirtualAllocEx( hProcess, 0, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if (pCode == NULL) { JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed"); VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE); return; } WriteProcessMemory( hProcess, (LPVOID)pCode, (LPVOID)stubCode, (DWORD)stubLen, &numBytes ); if (isCopy) { (*env)->ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT); } /* * Create thread in target process to execute code */ hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) pCode, pData, 0, NULL ); if (hThread != NULL) { if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0) { JNU_ThrowIOExceptionWithLastError(env, "WaitForSingleObject failed"); } else { DWORD exitCode; GetExitCodeThread(hThread, &exitCode); if (exitCode) { switch (exitCode) { case ERR_OPEN_JVM_FAIL : JNU_ThrowIOException(env, "jvm.dll not loaded by target process"); break; case ERR_GET_ENQUEUE_FUNC_FAIL : JNU_ThrowIOException(env, "Unable to enqueue operation: the target VM does not support attach mechanism"); break; default : JNU_ThrowInternalError(env, "Remote thread failed for unknown reason"); } } } CloseHandle(hThread); } else { JNU_ThrowIOExceptionWithLastError(env, "CreateRemoteThread failed"); } VirtualFreeEx(hProcess, pCode, 0, MEM_RELEASE); VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE); }