Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/native/sun/tools/attach/WindowsVirtualMachine.c
32288 views
1
/*
2
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
#include <windows.h>
26
#include <Sddl.h>
27
#include <string.h>
28
29
#include "jni.h"
30
#include "jni_util.h"
31
32
#include "sun_tools_attach_WindowsVirtualMachine.h"
33
34
35
/* kernel32 */
36
typedef HINSTANCE (WINAPI* GetModuleHandleFunc) (LPCTSTR);
37
typedef FARPROC (WINAPI* GetProcAddressFunc)(HMODULE, LPCSTR);
38
39
/* only on Windows 64-bit or 32-bit application running under WOW64 */
40
typedef BOOL (WINAPI *IsWow64ProcessFunc) (HANDLE, PBOOL);
41
42
static GetModuleHandleFunc _GetModuleHandle;
43
static GetProcAddressFunc _GetProcAddress;
44
static IsWow64ProcessFunc _IsWow64Process;
45
46
/* psapi */
47
typedef BOOL (WINAPI *EnumProcessModulesFunc) (HANDLE, HMODULE *, DWORD, LPDWORD );
48
typedef DWORD (WINAPI *GetModuleFileNameExFunc) ( HANDLE, HMODULE, LPTSTR, DWORD );
49
50
/* exported function in target VM */
51
typedef jint (WINAPI* EnqueueOperationFunc)
52
(const char* cmd, const char* arg1, const char* arg2, const char* arg3, const char* pipename);
53
54
/* OpenProcess with SE_DEBUG_NAME privilege */
55
static HANDLE
56
doPrivilegedOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
57
58
/* convert jstring to C string */
59
static void jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, int len);
60
61
62
/*
63
* Data copied to target process
64
*/
65
66
#define MAX_LIBNAME_LENGTH 16
67
#define MAX_FUNC_LENGTH 32
68
#define MAX_CMD_LENGTH 16
69
#define MAX_ARG_LENGTH 1024
70
#define MAX_ARGS 3
71
#define MAX_PIPE_NAME_LENGTH 256
72
73
typedef struct {
74
GetModuleHandleFunc _GetModuleHandle;
75
GetProcAddressFunc _GetProcAddress;
76
char jvmLib[MAX_LIBNAME_LENGTH]; /* "jvm.dll" */
77
char func1[MAX_FUNC_LENGTH];
78
char func2[MAX_FUNC_LENGTH];
79
char cmd[MAX_CMD_LENGTH]; /* "load", "dump", ... */
80
char arg[MAX_ARGS][MAX_ARG_LENGTH]; /* arguments to command */
81
char pipename[MAX_PIPE_NAME_LENGTH];
82
} DataBlock;
83
84
/*
85
* Return codes from enqueue function executed in target VM
86
*/
87
#define ERR_OPEN_JVM_FAIL 200
88
#define ERR_GET_ENQUEUE_FUNC_FAIL 201
89
90
91
/*
92
* Code copied to target process
93
*/
94
#pragma check_stack (off)
95
DWORD WINAPI jvm_attach_thread_func(DataBlock *pData)
96
{
97
HINSTANCE h;
98
EnqueueOperationFunc addr;
99
100
h = pData->_GetModuleHandle(pData->jvmLib);
101
if (h == NULL) {
102
return ERR_OPEN_JVM_FAIL;
103
}
104
105
addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func1));
106
if (addr == NULL) {
107
addr = (EnqueueOperationFunc)(pData->_GetProcAddress(h, pData->func2));
108
}
109
if (addr == NULL) {
110
return ERR_GET_ENQUEUE_FUNC_FAIL;
111
}
112
113
/* "null" command - does nothing in the target VM */
114
if (pData->cmd[0] == '\0') {
115
return 0;
116
} else {
117
return (*addr)(pData->cmd, pData->arg[0], pData->arg[1], pData->arg[2], pData->pipename);
118
}
119
}
120
121
/* This function marks the end of jvm_attach_thread_func. */
122
void jvm_attach_thread_func_end (void) {
123
}
124
#pragma check_stack
125
126
127
/*
128
* Class: sun_tools_attach_WindowsVirtualMachine
129
* Method: init
130
* Signature: ()V
131
*/
132
JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_init
133
(JNIEnv *env, jclass cls)
134
{
135
// All following APIs exist on Windows XP with SP2/Windows Server 2008
136
_GetModuleHandle = (GetModuleHandleFunc)GetModuleHandle;
137
_GetProcAddress = (GetProcAddressFunc)GetProcAddress;
138
_IsWow64Process = (IsWow64ProcessFunc)IsWow64Process;
139
}
140
141
142
/*
143
* Class: sun_tools_attach_WindowsVirtualMachine
144
* Method: generateStub
145
* Signature: ()[B
146
*/
147
JNIEXPORT jbyteArray JNICALL Java_sun_tools_attach_WindowsVirtualMachine_generateStub
148
(JNIEnv *env, jclass cls)
149
{
150
/*
151
* We should replace this with a real stub generator at some point
152
*/
153
DWORD len;
154
jbyteArray array;
155
156
len = (DWORD)((LPBYTE) jvm_attach_thread_func_end - (LPBYTE) jvm_attach_thread_func);
157
array= (*env)->NewByteArray(env, (jsize)len);
158
if (array != NULL) {
159
(*env)->SetByteArrayRegion(env, array, 0, (jint)len, (jbyte*)&jvm_attach_thread_func);
160
}
161
return array;
162
}
163
164
/*
165
* Class: sun_tools_attach_WindowsVirtualMachine
166
* Method: openProcess
167
* Signature: (I)J
168
*/
169
JNIEXPORT jlong JNICALL Java_sun_tools_attach_WindowsVirtualMachine_openProcess
170
(JNIEnv *env, jclass cls, jint pid)
171
{
172
HANDLE hProcess = NULL;
173
174
if (pid == (jint) GetCurrentProcessId()) {
175
/* process is attaching to itself; get a pseudo handle instead */
176
hProcess = GetCurrentProcess();
177
/* duplicate the pseudo handle so it can be used in more contexts */
178
if (DuplicateHandle(hProcess, hProcess, hProcess, &hProcess,
179
PROCESS_ALL_ACCESS, FALSE, 0) == 0) {
180
/*
181
* Could not duplicate the handle which isn't a good sign,
182
* but we'll try again with OpenProcess() below.
183
*/
184
hProcess = NULL;
185
}
186
}
187
188
if (hProcess == NULL) {
189
/*
190
* Attempt to open process. If it fails then we try to enable the
191
* SE_DEBUG_NAME privilege and retry.
192
*/
193
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
194
if (hProcess == NULL && GetLastError() == ERROR_ACCESS_DENIED) {
195
hProcess = doPrivilegedOpenProcess(PROCESS_ALL_ACCESS, FALSE,
196
(DWORD)pid);
197
}
198
199
if (hProcess == NULL) {
200
if (GetLastError() == ERROR_INVALID_PARAMETER) {
201
JNU_ThrowIOException(env, "no such process");
202
} else {
203
char err_mesg[255];
204
/* include the last error in the default detail message */
205
sprintf(err_mesg, "OpenProcess(pid=%d) failed; LastError=0x%x",
206
(int)pid, (int)GetLastError());
207
JNU_ThrowIOExceptionWithLastError(env, err_mesg);
208
}
209
return (jlong)0;
210
}
211
}
212
213
/*
214
* On Windows 64-bit we need to handle 32-bit tools trying to attach to 64-bit
215
* processes (and visa versa). X-architecture attaching is currently not supported
216
* by this implementation.
217
*/
218
if (_IsWow64Process != NULL) {
219
BOOL isCurrent32bit, isTarget32bit;
220
(*_IsWow64Process)(GetCurrentProcess(), &isCurrent32bit);
221
(*_IsWow64Process)(hProcess, &isTarget32bit);
222
223
if (isCurrent32bit != isTarget32bit) {
224
CloseHandle(hProcess);
225
#ifdef _WIN64
226
JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException",
227
"Unable to attach to 32-bit process running under WOW64");
228
#else
229
JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException",
230
"Unable to attach to 64-bit process");
231
#endif
232
}
233
}
234
235
return (jlong)hProcess;
236
}
237
238
239
/*
240
* Class: sun_tools_attach_WindowsVirtualMachine
241
* Method: closeProcess
242
* Signature: (J)V
243
*/
244
JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_closeProcess
245
(JNIEnv *env, jclass cls, jlong hProcess)
246
{
247
CloseHandle((HANDLE)hProcess);
248
}
249
250
251
/*
252
* Class: sun_tools_attach_WindowsVirtualMachine
253
* Method: createPipe
254
* Signature: (Ljava/lang/String;)J
255
*/
256
JNIEXPORT jlong JNICALL Java_sun_tools_attach_WindowsVirtualMachine_createPipe
257
(JNIEnv *env, jclass cls, jstring pipename)
258
{
259
HANDLE hPipe;
260
char name[MAX_PIPE_NAME_LENGTH];
261
262
SECURITY_ATTRIBUTES sa;
263
LPSECURITY_ATTRIBUTES lpSA = NULL;
264
// Custom Security Descriptor is required here to "get" Medium Integrity Level.
265
// In order to allow Medium Integrity Level clients to open
266
// and use a NamedPipe created by an High Integrity Level process.
267
TCHAR *szSD = TEXT("D:") // Discretionary ACL
268
TEXT("(A;OICI;GRGW;;;WD)") // Allow read/write to Everybody
269
TEXT("(A;OICI;GA;;;SY)") // Allow full control to System
270
TEXT("(A;OICI;GA;;;BA)"); // Allow full control to Administrators
271
272
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
273
sa.bInheritHandle = FALSE;
274
sa.lpSecurityDescriptor = NULL;
275
276
if (ConvertStringSecurityDescriptorToSecurityDescriptor
277
(szSD, SDDL_REVISION_1, &(sa.lpSecurityDescriptor), NULL)) {
278
lpSA = &sa;
279
}
280
281
jstring_to_cstring(env, pipename, name, MAX_PIPE_NAME_LENGTH);
282
283
hPipe = CreateNamedPipe(
284
name, // pipe name
285
PIPE_ACCESS_INBOUND, // read access
286
PIPE_TYPE_BYTE | // byte mode
287
PIPE_READMODE_BYTE |
288
PIPE_WAIT, // blocking mode
289
1, // max. instances
290
128, // output buffer size
291
8192, // input buffer size
292
NMPWAIT_USE_DEFAULT_WAIT, // client time-out
293
lpSA); // security attributes
294
295
LocalFree(sa.lpSecurityDescriptor);
296
297
if (hPipe == INVALID_HANDLE_VALUE) {
298
JNU_ThrowIOExceptionWithLastError(env, "CreateNamedPipe failed");
299
}
300
return (jlong)hPipe;
301
}
302
303
/*
304
* Class: sun_tools_attach_WindowsVirtualMachine
305
* Method: closePipe
306
* Signature: (J)V
307
*/
308
JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_closePipe
309
(JNIEnv *env, jclass cls, jlong hPipe)
310
{
311
CloseHandle( (HANDLE)hPipe );
312
}
313
314
/*
315
* Class: sun_tools_attach_WindowsVirtualMachine
316
* Method: connectPipe
317
* Signature: (J)V
318
*/
319
JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_connectPipe
320
(JNIEnv *env, jclass cls, jlong hPipe)
321
{
322
BOOL fConnected;
323
324
fConnected = ConnectNamedPipe((HANDLE)hPipe, NULL) ?
325
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
326
if (!fConnected) {
327
JNU_ThrowIOExceptionWithLastError(env, "ConnectNamedPipe failed");
328
}
329
}
330
331
/*
332
* Class: sun_tools_attach_WindowsVirtualMachine
333
* Method: readPipe
334
* Signature: (J[BII)I
335
*/
336
JNIEXPORT jint JNICALL Java_sun_tools_attach_WindowsVirtualMachine_readPipe
337
(JNIEnv *env, jclass cls, jlong hPipe, jbyteArray ba, jint off, jint baLen)
338
{
339
unsigned char buf[128];
340
DWORD len, nread, remaining;
341
BOOL fSuccess;
342
343
len = sizeof(buf);
344
remaining = (DWORD)(baLen - off);
345
if (len > remaining) {
346
len = remaining;
347
}
348
349
fSuccess = ReadFile(
350
(HANDLE)hPipe, // handle to pipe
351
buf, // buffer to receive data
352
len, // size of buffer
353
&nread, // number of bytes read
354
NULL); // not overlapped I/O
355
356
if (!fSuccess) {
357
if (GetLastError() == ERROR_BROKEN_PIPE) {
358
return (jint)-1;
359
} else {
360
JNU_ThrowIOExceptionWithLastError(env, "ReadFile");
361
}
362
} else {
363
if (nread == 0) {
364
return (jint)-1; // EOF
365
} else {
366
(*env)->SetByteArrayRegion(env, ba, off, (jint)nread, (jbyte *)(buf));
367
}
368
}
369
370
return (jint)nread;
371
}
372
373
374
/*
375
* Class: sun_tools_attach_WindowsVirtualMachine
376
* Method: enqueue
377
* Signature: (JZLjava/lang/String;[Ljava/lang/Object;)V
378
*/
379
JNIEXPORT void JNICALL Java_sun_tools_attach_WindowsVirtualMachine_enqueue
380
(JNIEnv *env, jclass cls, jlong handle, jbyteArray stub, jstring cmd,
381
jstring pipename, jobjectArray args)
382
{
383
DataBlock data;
384
DataBlock* pData;
385
DWORD* pCode;
386
DWORD stubLen;
387
HANDLE hProcess, hThread;
388
jint argsLen, i;
389
jbyte* stubCode;
390
jboolean isCopy;
391
392
/*
393
* Setup data to copy to target process
394
*/
395
data._GetModuleHandle = _GetModuleHandle;
396
data._GetProcAddress = _GetProcAddress;
397
398
strcpy(data.jvmLib, "jvm");
399
strcpy(data.func1, "JVM_EnqueueOperation");
400
strcpy(data.func2, "_JVM_EnqueueOperation@20");
401
402
/*
403
* Command and arguments
404
*/
405
jstring_to_cstring(env, cmd, data.cmd, MAX_CMD_LENGTH);
406
argsLen = (*env)->GetArrayLength(env, args);
407
408
if (argsLen > 0) {
409
if (argsLen > MAX_ARGS) {
410
JNU_ThrowInternalError(env, "Too many arguments");
411
return;
412
}
413
for (i=0; i<argsLen; i++) {
414
jobject obj = (*env)->GetObjectArrayElement(env, args, i);
415
if (obj == NULL) {
416
data.arg[i][0] = '\0';
417
} else {
418
jstring_to_cstring(env, obj, data.arg[i], MAX_ARG_LENGTH);
419
}
420
if ((*env)->ExceptionOccurred(env)) return;
421
}
422
}
423
for (i=argsLen; i<MAX_ARGS; i++) {
424
data.arg[i][0] = '\0';
425
}
426
427
/* pipe name */
428
jstring_to_cstring(env, pipename, data.pipename, MAX_PIPE_NAME_LENGTH);
429
430
/*
431
* Allocate memory in target process for data and code stub
432
* (assumed aligned and matches architecture of target process)
433
*/
434
hProcess = (HANDLE)handle;
435
436
pData = (DataBlock*) VirtualAllocEx( hProcess, 0, sizeof(DataBlock), MEM_COMMIT, PAGE_READWRITE );
437
if (pData == NULL) {
438
JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed");
439
return;
440
}
441
WriteProcessMemory( hProcess, (LPVOID)pData, (LPCVOID)&data, (SIZE_T)sizeof(DataBlock), NULL );
442
443
444
stubLen = (DWORD)(*env)->GetArrayLength(env, stub);
445
stubCode = (*env)->GetByteArrayElements(env, stub, &isCopy);
446
447
if ((*env)->ExceptionOccurred(env)) return;
448
449
pCode = (PDWORD) VirtualAllocEx( hProcess, 0, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
450
if (pCode == NULL) {
451
JNU_ThrowIOExceptionWithLastError(env, "VirtualAllocEx failed");
452
VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE);
453
return;
454
}
455
WriteProcessMemory( hProcess, (LPVOID)pCode, (LPCVOID)stubCode, (SIZE_T)stubLen, NULL );
456
if (isCopy) {
457
(*env)->ReleaseByteArrayElements(env, stub, stubCode, JNI_ABORT);
458
}
459
460
/*
461
* Create thread in target process to execute code
462
*/
463
hThread = CreateRemoteThread( hProcess,
464
NULL,
465
0,
466
(LPTHREAD_START_ROUTINE) pCode,
467
pData,
468
0,
469
NULL );
470
if (hThread != NULL) {
471
if (WaitForSingleObject(hThread, INFINITE) != WAIT_OBJECT_0) {
472
JNU_ThrowIOExceptionWithLastError(env, "WaitForSingleObject failed");
473
} else {
474
DWORD exitCode;
475
GetExitCodeThread(hThread, &exitCode);
476
if (exitCode) {
477
switch (exitCode) {
478
case ERR_OPEN_JVM_FAIL :
479
JNU_ThrowIOException(env,
480
"jvm.dll not loaded by target process");
481
break;
482
case ERR_GET_ENQUEUE_FUNC_FAIL :
483
JNU_ThrowIOException(env,
484
"Unable to enqueue operation: the target VM does not support attach mechanism");
485
break;
486
default :
487
JNU_ThrowInternalError(env,
488
"Remote thread failed for unknown reason");
489
}
490
}
491
}
492
CloseHandle(hThread);
493
} else {
494
if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
495
//
496
// This error will occur when attaching to a process belonging to
497
// another terminal session. See "Remarks":
498
// http://msdn.microsoft.com/en-us/library/ms682437%28VS.85%29.aspx
499
//
500
JNU_ThrowIOException(env,
501
"Insufficient memory or insufficient privileges to attach");
502
} else {
503
JNU_ThrowIOExceptionWithLastError(env, "CreateRemoteThread failed");
504
}
505
}
506
507
VirtualFreeEx(hProcess, pCode, 0, MEM_RELEASE);
508
VirtualFreeEx(hProcess, pData, 0, MEM_RELEASE);
509
}
510
511
/*
512
* Attempts to enable the SE_DEBUG_NAME privilege and open the given process.
513
*/
514
static HANDLE
515
doPrivilegedOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) {
516
HANDLE hToken;
517
HANDLE hProcess = NULL;
518
LUID luid;
519
TOKEN_PRIVILEGES tp, tpPrevious;
520
DWORD retLength, error;
521
522
/*
523
* Get the access token
524
*/
525
if (!OpenThreadToken(GetCurrentThread(),
526
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
527
FALSE,
528
&hToken)) {
529
if (GetLastError() != ERROR_NO_TOKEN) {
530
return (HANDLE)NULL;
531
}
532
533
/*
534
* No access token for the thread so impersonate the security context
535
* of the process.
536
*/
537
if (!ImpersonateSelf(SecurityImpersonation)) {
538
return (HANDLE)NULL;
539
}
540
if (!OpenThreadToken(GetCurrentThread(),
541
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
542
FALSE,
543
&hToken)) {
544
return (HANDLE)NULL;
545
}
546
}
547
548
/*
549
* Get LUID for the privilege
550
*/
551
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
552
error = GetLastError();
553
CloseHandle(hToken);
554
SetLastError(error);
555
return (HANDLE)NULL;
556
}
557
558
/*
559
* Enable the privilege
560
*/
561
ZeroMemory(&tp, sizeof(tp));
562
tp.PrivilegeCount = 1;
563
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
564
tp.Privileges[0].Luid = luid;
565
566
error = 0;
567
if (AdjustTokenPrivileges(hToken,
568
FALSE,
569
&tp,
570
sizeof(TOKEN_PRIVILEGES),
571
&tpPrevious,
572
&retLength)) {
573
/*
574
* If we enabled the privilege then attempt to open the
575
* process.
576
*/
577
if (GetLastError() == ERROR_SUCCESS) {
578
hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
579
if (hProcess == NULL) {
580
error = GetLastError();
581
}
582
} else {
583
error = ERROR_ACCESS_DENIED;
584
}
585
586
/*
587
* Revert to the previous privileges
588
*/
589
AdjustTokenPrivileges(hToken,
590
FALSE,
591
&tpPrevious,
592
retLength,
593
NULL,
594
NULL);
595
} else {
596
error = GetLastError();
597
}
598
599
600
/*
601
* Close token and restore error
602
*/
603
CloseHandle(hToken);
604
SetLastError(error);
605
606
return hProcess;
607
}
608
609
/* convert jstring to C string */
610
static void jstring_to_cstring(JNIEnv* env, jstring jstr, char* cstr, int len) {
611
jboolean isCopy;
612
const char* str;
613
614
if (jstr == NULL) {
615
cstr[0] = '\0';
616
} else {
617
str = JNU_GetStringPlatformChars(env, jstr, &isCopy);
618
if ((*env)->ExceptionOccurred(env)) return;
619
620
strncpy(cstr, str, len);
621
cstr[len-1] = '\0';
622
if (isCopy) {
623
JNU_ReleaseStringPlatformChars(env, jstr, str);
624
}
625
}
626
}
627
628