[PATCH 0/1] MR10611: LPC: Implement proper LPC system
Until now, LPC was just a stub, any application that relied on LPC for communication would fail. This change implements parts of LPC, to allow for IPC between programs. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30069 - fully fixed, sqlservr is able to run as expected Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59494 - partially fixed, starmoney doesn't flat out crash anymore, but it doesn't start fully, possibly because it uses the ALPC system which was introduced in Windows Vista, the version Starmoney 10 was advertised for -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10611
From: Rose Hellsing <rose@pinkro.se> Until now, LPC was just a stub, any application that relied on LPC for communication would fail. This change implements parts of LPC, to allow for IPC between programs. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30069 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59494 --- dlls/ntdll/ntdll.spec | 6 +- dlls/ntdll/ntsyscalls.h | 492 +++++++-------- dlls/ntdll/signal_arm64ec.c | 2 + dlls/ntdll/tests/port.c | 32 +- dlls/ntdll/unix/sync.c | 428 ++++++++++++- dlls/wow64/sync.c | 32 + include/wine/server_protocol.h | 177 +++++- include/winternl.h | 1 + server/Makefile.in | 1 + server/lpc_port.c | 1044 ++++++++++++++++++++++++++++++++ server/object.h | 4 + server/protocol.def | 90 +++ server/request_handlers.h | 72 +++ server/request_trace.h | 141 +++++ server/thread.c | 4 + server/thread.h | 1 + 16 files changed, 2238 insertions(+), 289 deletions(-) create mode 100644 server/lpc_port.c diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index f396c334e2d..7ec32bf83cc 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -206,7 +206,7 @@ @ stdcall -syscall NtCreateToken(ptr long ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) @ stdcall -syscall NtCreateTransaction(ptr long ptr ptr long long long long ptr ptr) @ stdcall -syscall NtCreateUserProcess(ptr ptr long long ptr ptr long long ptr ptr ptr) -# @ stub NtCreateWaitablePort +@ stdcall -syscall NtCreateWaitablePort(ptr ptr long long long) @ stdcall -arch=i386 NtCurrentTeb() @ stdcall -syscall NtDebugActiveProcess(long long) @ stdcall -syscall NtDebugContinue(long ptr long) @@ -370,7 +370,7 @@ @ stdcall -syscall=0x000b NtReplyWaitReceivePort(ptr ptr ptr ptr) @ stdcall -syscall=0x002b NtReplyWaitReceivePortEx(long ptr ptr ptr ptr) # @ stub NtReplyWaitReplyPort -# @ stub NtRequestPort +@ stdcall -syscall NtRequestPort(ptr ptr) @ stdcall -syscall=0x0022 NtRequestWaitReplyPort(ptr ptr ptr) @ stdcall -syscall NtResetEvent(long ptr) @ stdcall -syscall NtResetWriteWatch(long ptr long) @@ -1280,7 +1280,7 @@ @ stdcall -private ZwCreateToken(ptr long ptr long ptr ptr ptr ptr ptr ptr ptr ptr ptr) NtCreateToken @ stdcall -private ZwCreateTransaction(ptr long ptr ptr long long long long ptr ptr) NtCreateTransaction @ stdcall -private ZwCreateUserProcess(ptr ptr long long ptr ptr long long ptr ptr ptr) NtCreateUserProcess -# @ stub ZwCreateWaitablePort +@ stdcall -private ZwCreateWaitablePort(ptr ptr long long long) NtCreateWaitablePort @ stdcall -private ZwDebugActiveProcess(long long) NtDebugActiveProcess @ stdcall -private ZwDebugContinue(long ptr long) NtDebugContinue @ stdcall -private ZwDelayExecution(long ptr) NtDelayExecution diff --git a/dlls/ntdll/ntsyscalls.h b/dlls/ntdll/ntsyscalls.h index ba7cc060c66..2c8c307e5c7 100644 --- a/dlls/ntdll/ntsyscalls.h +++ b/dlls/ntdll/ntsyscalls.h @@ -139,132 +139,134 @@ SYSCALL_ENTRY( 0x0087, NtCreateToken, 52 ) \ SYSCALL_ENTRY( 0x0088, NtCreateTransaction, 40 ) \ SYSCALL_ENTRY( 0x0089, NtCreateUserProcess, 44 ) \ - SYSCALL_ENTRY( 0x008a, NtDebugActiveProcess, 8 ) \ - SYSCALL_ENTRY( 0x008b, NtDebugContinue, 12 ) \ - SYSCALL_ENTRY( 0x008c, NtDeleteAtom, 4 ) \ - SYSCALL_ENTRY( 0x008d, NtDeleteFile, 4 ) \ - SYSCALL_ENTRY( 0x008e, NtDeleteKey, 4 ) \ - SYSCALL_ENTRY( 0x008f, NtDeleteValueKey, 8 ) \ - SYSCALL_ENTRY( 0x0090, NtDisplayString, 4 ) \ - SYSCALL_ENTRY( 0x0091, NtFilterToken, 24 ) \ - SYSCALL_ENTRY( 0x0092, NtFlushBuffersFileEx, 20 ) \ - SYSCALL_ENTRY( 0x0093, NtFlushInstructionCache, 12 ) \ - SYSCALL_ENTRY( 0x0094, NtFlushKey, 4 ) \ - SYSCALL_ENTRY( 0x0095, NtFlushProcessWriteBuffers, 0 ) \ - SYSCALL_ENTRY( 0x0096, NtFlushVirtualMemory, 16 ) \ - SYSCALL_ENTRY( 0x0097, NtGetContextThread, 8 ) \ - SYSCALL_ENTRY( 0x0098, NtGetCurrentProcessorNumber, 0 ) \ - SYSCALL_ENTRY( 0x0099, NtGetNextProcess, 20 ) \ - SYSCALL_ENTRY( 0x009a, NtGetNextThread, 24 ) \ - SYSCALL_ENTRY( 0x009b, NtGetNlsSectionPtr, 20 ) \ - SYSCALL_ENTRY( 0x009c, NtGetWriteWatch, 28 ) \ - SYSCALL_ENTRY( 0x009d, NtImpersonateAnonymousToken, 4 ) \ - SYSCALL_ENTRY( 0x009e, NtInitializeNlsFiles, 12 ) \ - SYSCALL_ENTRY( 0x009f, NtInitiatePowerAction, 16 ) \ - SYSCALL_ENTRY( 0x00a0, NtListenPort, 8 ) \ - SYSCALL_ENTRY( 0x00a1, NtLoadDriver, 4 ) \ - SYSCALL_ENTRY( 0x00a2, NtLoadKey, 8 ) \ - SYSCALL_ENTRY( 0x00a3, NtLoadKey2, 12 ) \ - SYSCALL_ENTRY( 0x00a4, NtLoadKeyEx, 32 ) \ - SYSCALL_ENTRY( 0x00a5, NtLockFile, 40 ) \ + SYSCALL_ENTRY( 0x008a, NtCreateWaitablePort, 20 ) \ + SYSCALL_ENTRY( 0x008b, NtDebugActiveProcess, 8 ) \ + SYSCALL_ENTRY( 0x008c, NtDebugContinue, 12 ) \ + SYSCALL_ENTRY( 0x008d, NtDeleteAtom, 4 ) \ + SYSCALL_ENTRY( 0x008e, NtDeleteFile, 4 ) \ + SYSCALL_ENTRY( 0x008f, NtDeleteKey, 4 ) \ + SYSCALL_ENTRY( 0x0090, NtDeleteValueKey, 8 ) \ + SYSCALL_ENTRY( 0x0091, NtDisplayString, 4 ) \ + SYSCALL_ENTRY( 0x0092, NtFilterToken, 24 ) \ + SYSCALL_ENTRY( 0x0093, NtFlushBuffersFileEx, 20 ) \ + SYSCALL_ENTRY( 0x0094, NtFlushInstructionCache, 12 ) \ + SYSCALL_ENTRY( 0x0095, NtFlushKey, 4 ) \ + SYSCALL_ENTRY( 0x0096, NtFlushProcessWriteBuffers, 0 ) \ + SYSCALL_ENTRY( 0x0097, NtFlushVirtualMemory, 16 ) \ + SYSCALL_ENTRY( 0x0098, NtGetContextThread, 8 ) \ + SYSCALL_ENTRY( 0x0099, NtGetCurrentProcessorNumber, 0 ) \ + SYSCALL_ENTRY( 0x009a, NtGetNextProcess, 20 ) \ + SYSCALL_ENTRY( 0x009b, NtGetNextThread, 24 ) \ + SYSCALL_ENTRY( 0x009c, NtGetNlsSectionPtr, 20 ) \ + SYSCALL_ENTRY( 0x009d, NtGetWriteWatch, 28 ) \ + SYSCALL_ENTRY( 0x009e, NtImpersonateAnonymousToken, 4 ) \ + SYSCALL_ENTRY( 0x009f, NtInitializeNlsFiles, 12 ) \ + SYSCALL_ENTRY( 0x00a0, NtInitiatePowerAction, 16 ) \ + SYSCALL_ENTRY( 0x00a1, NtListenPort, 8 ) \ + SYSCALL_ENTRY( 0x00a2, NtLoadDriver, 4 ) \ + SYSCALL_ENTRY( 0x00a3, NtLoadKey, 8 ) \ + SYSCALL_ENTRY( 0x00a4, NtLoadKey2, 12 ) \ + SYSCALL_ENTRY( 0x00a5, NtLoadKeyEx, 32 ) \ SYSCALL_ENTRY( 0x00a6, NtCreateDebugObject, 16 ) \ - SYSCALL_ENTRY( 0x00a7, NtLockVirtualMemory, 16 ) \ - SYSCALL_ENTRY( 0x00a8, NtMakePermanentObject, 4 ) \ - SYSCALL_ENTRY( 0x00a9, NtMakeTemporaryObject, 4 ) \ - SYSCALL_ENTRY( 0x00aa, NtMapViewOfSectionEx, 36 ) \ - SYSCALL_ENTRY( 0x00ab, NtNotifyChangeDirectoryFile, 36 ) \ - SYSCALL_ENTRY( 0x00ac, NtNotifyChangeKey, 40 ) \ - SYSCALL_ENTRY( 0x00ad, NtNotifyChangeMultipleKeys, 48 ) \ - SYSCALL_ENTRY( 0x00ae, NtOpenIoCompletion, 12 ) \ - SYSCALL_ENTRY( 0x00af, NtOpenJobObject, 12 ) \ - SYSCALL_ENTRY( 0x00b0, NtOpenKeyEx, 16 ) \ - SYSCALL_ENTRY( 0x00b1, NtOpenKeyTransacted, 16 ) \ - SYSCALL_ENTRY( 0x00b2, NtOpenKeyTransactedEx, 20 ) \ - SYSCALL_ENTRY( 0x00b3, NtOpenKeyedEvent, 12 ) \ - SYSCALL_ENTRY( 0x00b4, NtOpenMutant, 12 ) \ - SYSCALL_ENTRY( 0x00b5, NtOpenProcessToken, 12 ) \ - SYSCALL_ENTRY( 0x00b6, NtOpenSemaphore, 12 ) \ - SYSCALL_ENTRY( 0x00b7, NtOpenSymbolicLinkObject, 12 ) \ - SYSCALL_ENTRY( 0x00b8, NtOpenThread, 16 ) \ - SYSCALL_ENTRY( 0x00b9, NtOpenTimer, 12 ) \ - SYSCALL_ENTRY( 0x00ba, NtPrivilegeCheck, 12 ) \ - SYSCALL_ENTRY( 0x00bb, NtPulseEvent, 8 ) \ - SYSCALL_ENTRY( 0x00bc, NtQueryDirectoryObject, 28 ) \ - SYSCALL_ENTRY( 0x00bd, NtQueryEaFile, 36 ) \ - SYSCALL_ENTRY( 0x00be, NtQueryFullAttributesFile, 8 ) \ - SYSCALL_ENTRY( 0x00bf, NtQueryInformationAtom, 20 ) \ - SYSCALL_ENTRY( 0x00c0, NtQueryInformationJobObject, 20 ) \ - SYSCALL_ENTRY( 0x00c1, NtQueryInstallUILanguage, 4 ) \ - SYSCALL_ENTRY( 0x00c2, NtQueryIoCompletion, 20 ) \ - SYSCALL_ENTRY( 0x00c3, NtQueryLicenseValue, 20 ) \ - SYSCALL_ENTRY( 0x00c4, NtQueryMultipleValueKey, 24 ) \ - SYSCALL_ENTRY( 0x00c5, NtQueryMutant, 20 ) \ - SYSCALL_ENTRY( 0x00c6, NtQuerySecurityObject, 20 ) \ - SYSCALL_ENTRY( 0x00c7, NtQuerySemaphore, 20 ) \ - SYSCALL_ENTRY( 0x00c8, NtQuerySymbolicLinkObject, 12 ) \ - SYSCALL_ENTRY( 0x00c9, NtQuerySystemEnvironmentValue, 16 ) \ - SYSCALL_ENTRY( 0x00ca, NtQuerySystemEnvironmentValueEx, 20 ) \ - SYSCALL_ENTRY( 0x00cb, NtQuerySystemInformationEx, 24 ) \ - SYSCALL_ENTRY( 0x00cc, NtQueryTimerResolution, 12 ) \ - SYSCALL_ENTRY( 0x00cd, NtQueueApcThreadEx, 24 ) \ - SYSCALL_ENTRY( 0x00ce, NtQueueApcThreadEx2, 28 ) \ - SYSCALL_ENTRY( 0x00cf, NtRaiseException, 12 ) \ - SYSCALL_ENTRY( 0x00d0, NtRaiseHardError, 24 ) \ - SYSCALL_ENTRY( 0x00d1, NtRegisterThreadTerminatePort, 4 ) \ - SYSCALL_ENTRY( 0x00d2, NtReleaseKeyedEvent, 16 ) \ - SYSCALL_ENTRY( 0x00d3, NtRemoveIoCompletionEx, 24 ) \ - SYSCALL_ENTRY( 0x00d4, NtRemoveProcessDebug, 8 ) \ - SYSCALL_ENTRY( 0x00d5, NtRenameKey, 8 ) \ - SYSCALL_ENTRY( 0x00d6, NtReplaceKey, 12 ) \ - SYSCALL_ENTRY( 0x00d7, NtResetEvent, 8 ) \ - SYSCALL_ENTRY( 0x00d8, NtResetWriteWatch, 12 ) \ - SYSCALL_ENTRY( 0x00d9, NtRestoreKey, 12 ) \ - SYSCALL_ENTRY( 0x00da, NtResumeProcess, 4 ) \ - SYSCALL_ENTRY( 0x00db, NtRollbackTransaction, 8 ) \ - SYSCALL_ENTRY( 0x00dc, NtSaveKey, 8 ) \ - SYSCALL_ENTRY( 0x00dd, NtSecureConnectPort, 36 ) \ - SYSCALL_ENTRY( 0x00de, NtSetContextThread, 8 ) \ - SYSCALL_ENTRY( 0x00df, NtSetDebugFilterState, 12 ) \ - SYSCALL_ENTRY( 0x00e0, NtSetDefaultLocale, 8 ) \ - SYSCALL_ENTRY( 0x00e1, NtSetDefaultUILanguage, 4 ) \ - SYSCALL_ENTRY( 0x00e2, NtSetEaFile, 16 ) \ - SYSCALL_ENTRY( 0x00e3, NtSetInformationDebugObject, 20 ) \ - SYSCALL_ENTRY( 0x00e4, NtSetInformationJobObject, 16 ) \ - SYSCALL_ENTRY( 0x00e5, NtSetInformationKey, 16 ) \ - SYSCALL_ENTRY( 0x00e6, NtSetInformationToken, 16 ) \ - SYSCALL_ENTRY( 0x00e7, NtSetInformationVirtualMemory, 24 ) \ - SYSCALL_ENTRY( 0x00e8, NtSetIntervalProfile, 8 ) \ - SYSCALL_ENTRY( 0x00e9, NtSetIoCompletion, 20 ) \ - SYSCALL_ENTRY( 0x00ea, NtSetIoCompletionEx, 24 ) \ - SYSCALL_ENTRY( 0x00eb, NtSetLdtEntries, 24 ) \ - SYSCALL_ENTRY( 0x00ec, NtSetSecurityObject, 12 ) \ - SYSCALL_ENTRY( 0x00ed, NtSetSystemInformation, 12 ) \ - SYSCALL_ENTRY( 0x00ee, NtSetSystemTime, 8 ) \ - SYSCALL_ENTRY( 0x00ef, NtSetThreadExecutionState, 8 ) \ - SYSCALL_ENTRY( 0x00f0, NtSetTimerResolution, 12 ) \ - SYSCALL_ENTRY( 0x00f1, NtSetVolumeInformationFile, 20 ) \ - SYSCALL_ENTRY( 0x00f2, NtShutdownSystem, 4 ) \ - SYSCALL_ENTRY( 0x00f3, NtSignalAndWaitForSingleObject, 16 ) \ - SYSCALL_ENTRY( 0x00f4, NtSuspendProcess, 4 ) \ - SYSCALL_ENTRY( 0x00f5, NtSuspendThread, 8 ) \ - SYSCALL_ENTRY( 0x00f6, NtSystemDebugControl, 24 ) \ - SYSCALL_ENTRY( 0x00f7, NtTerminateJobObject, 8 ) \ - SYSCALL_ENTRY( 0x00f8, NtTestAlert, 0 ) \ - SYSCALL_ENTRY( 0x00f9, NtTraceControl, 24 ) \ - SYSCALL_ENTRY( 0x00fa, NtUnloadDriver, 4 ) \ - SYSCALL_ENTRY( 0x00fb, NtUnloadKey, 4 ) \ - SYSCALL_ENTRY( 0x00fc, NtUnlockFile, 20 ) \ - SYSCALL_ENTRY( 0x00fd, NtUnlockVirtualMemory, 16 ) \ - SYSCALL_ENTRY( 0x00fe, NtUnmapViewOfSectionEx, 12 ) \ - SYSCALL_ENTRY( 0x00ff, NtWaitForAlertByThreadId, 8 ) \ - SYSCALL_ENTRY( 0x0100, NtWaitForDebugEvent, 16 ) \ - SYSCALL_ENTRY( 0x0101, NtWaitForKeyedEvent, 16 ) \ - SYSCALL_ENTRY( 0x0102, NtWow64AllocateVirtualMemory64, 28 ) \ - SYSCALL_ENTRY( 0x0103, NtWow64GetNativeSystemInformation, 16 ) \ - SYSCALL_ENTRY( 0x0104, NtWow64IsProcessorFeaturePresent, 4 ) \ - SYSCALL_ENTRY( 0x0105, NtWow64QueryInformationProcess64, 20 ) \ - SYSCALL_ENTRY( 0x0106, NtWow64ReadVirtualMemory64, 28 ) \ - SYSCALL_ENTRY( 0x0107, NtWow64WriteVirtualMemory64, 28 ) + SYSCALL_ENTRY( 0x00a7, NtLockFile, 40 ) \ + SYSCALL_ENTRY( 0x00a8, NtLockVirtualMemory, 16 ) \ + SYSCALL_ENTRY( 0x00a9, NtMakePermanentObject, 4 ) \ + SYSCALL_ENTRY( 0x00aa, NtMakeTemporaryObject, 4 ) \ + SYSCALL_ENTRY( 0x00ab, NtMapViewOfSectionEx, 36 ) \ + SYSCALL_ENTRY( 0x00ac, NtNotifyChangeDirectoryFile, 36 ) \ + SYSCALL_ENTRY( 0x00ad, NtNotifyChangeKey, 40 ) \ + SYSCALL_ENTRY( 0x00ae, NtNotifyChangeMultipleKeys, 48 ) \ + SYSCALL_ENTRY( 0x00af, NtOpenIoCompletion, 12 ) \ + SYSCALL_ENTRY( 0x00b0, NtOpenJobObject, 12 ) \ + SYSCALL_ENTRY( 0x00b1, NtOpenKeyEx, 16 ) \ + SYSCALL_ENTRY( 0x00b2, NtOpenKeyTransacted, 16 ) \ + SYSCALL_ENTRY( 0x00b3, NtOpenKeyTransactedEx, 20 ) \ + SYSCALL_ENTRY( 0x00b4, NtOpenKeyedEvent, 12 ) \ + SYSCALL_ENTRY( 0x00b5, NtOpenMutant, 12 ) \ + SYSCALL_ENTRY( 0x00b6, NtOpenProcessToken, 12 ) \ + SYSCALL_ENTRY( 0x00b7, NtOpenSemaphore, 12 ) \ + SYSCALL_ENTRY( 0x00b8, NtOpenSymbolicLinkObject, 12 ) \ + SYSCALL_ENTRY( 0x00b9, NtOpenThread, 16 ) \ + SYSCALL_ENTRY( 0x00ba, NtOpenTimer, 12 ) \ + SYSCALL_ENTRY( 0x00bb, NtPrivilegeCheck, 12 ) \ + SYSCALL_ENTRY( 0x00bc, NtPulseEvent, 8 ) \ + SYSCALL_ENTRY( 0x00bd, NtQueryDirectoryObject, 28 ) \ + SYSCALL_ENTRY( 0x00be, NtQueryEaFile, 36 ) \ + SYSCALL_ENTRY( 0x00bf, NtQueryFullAttributesFile, 8 ) \ + SYSCALL_ENTRY( 0x00c0, NtQueryInformationAtom, 20 ) \ + SYSCALL_ENTRY( 0x00c1, NtQueryInformationJobObject, 20 ) \ + SYSCALL_ENTRY( 0x00c2, NtQueryInstallUILanguage, 4 ) \ + SYSCALL_ENTRY( 0x00c3, NtQueryIoCompletion, 20 ) \ + SYSCALL_ENTRY( 0x00c4, NtQueryLicenseValue, 20 ) \ + SYSCALL_ENTRY( 0x00c5, NtQueryMultipleValueKey, 24 ) \ + SYSCALL_ENTRY( 0x00c6, NtQueryMutant, 20 ) \ + SYSCALL_ENTRY( 0x00c7, NtQuerySecurityObject, 20 ) \ + SYSCALL_ENTRY( 0x00c8, NtQuerySemaphore, 20 ) \ + SYSCALL_ENTRY( 0x00c9, NtQuerySymbolicLinkObject, 12 ) \ + SYSCALL_ENTRY( 0x00ca, NtQuerySystemEnvironmentValue, 16 ) \ + SYSCALL_ENTRY( 0x00cb, NtQuerySystemEnvironmentValueEx, 20 ) \ + SYSCALL_ENTRY( 0x00cc, NtQuerySystemInformationEx, 24 ) \ + SYSCALL_ENTRY( 0x00cd, NtQueryTimerResolution, 12 ) \ + SYSCALL_ENTRY( 0x00ce, NtQueueApcThreadEx, 24 ) \ + SYSCALL_ENTRY( 0x00cf, NtQueueApcThreadEx2, 28 ) \ + SYSCALL_ENTRY( 0x00d0, NtRaiseException, 12 ) \ + SYSCALL_ENTRY( 0x00d1, NtRaiseHardError, 24 ) \ + SYSCALL_ENTRY( 0x00d2, NtRegisterThreadTerminatePort, 4 ) \ + SYSCALL_ENTRY( 0x00d3, NtReleaseKeyedEvent, 16 ) \ + SYSCALL_ENTRY( 0x00d4, NtRemoveIoCompletionEx, 24 ) \ + SYSCALL_ENTRY( 0x00d5, NtRemoveProcessDebug, 8 ) \ + SYSCALL_ENTRY( 0x00d6, NtRenameKey, 8 ) \ + SYSCALL_ENTRY( 0x00d7, NtReplaceKey, 12 ) \ + SYSCALL_ENTRY( 0x00d8, NtRequestPort, 8 ) \ + SYSCALL_ENTRY( 0x00d9, NtResetEvent, 8 ) \ + SYSCALL_ENTRY( 0x00da, NtResetWriteWatch, 12 ) \ + SYSCALL_ENTRY( 0x00db, NtRestoreKey, 12 ) \ + SYSCALL_ENTRY( 0x00dc, NtResumeProcess, 4 ) \ + SYSCALL_ENTRY( 0x00dd, NtRollbackTransaction, 8 ) \ + SYSCALL_ENTRY( 0x00de, NtSaveKey, 8 ) \ + SYSCALL_ENTRY( 0x00df, NtSecureConnectPort, 36 ) \ + SYSCALL_ENTRY( 0x00e0, NtSetContextThread, 8 ) \ + SYSCALL_ENTRY( 0x00e1, NtSetDebugFilterState, 12 ) \ + SYSCALL_ENTRY( 0x00e2, NtSetDefaultLocale, 8 ) \ + SYSCALL_ENTRY( 0x00e3, NtSetDefaultUILanguage, 4 ) \ + SYSCALL_ENTRY( 0x00e4, NtSetEaFile, 16 ) \ + SYSCALL_ENTRY( 0x00e5, NtSetInformationDebugObject, 20 ) \ + SYSCALL_ENTRY( 0x00e6, NtSetInformationJobObject, 16 ) \ + SYSCALL_ENTRY( 0x00e7, NtSetInformationKey, 16 ) \ + SYSCALL_ENTRY( 0x00e8, NtSetInformationToken, 16 ) \ + SYSCALL_ENTRY( 0x00e9, NtSetInformationVirtualMemory, 24 ) \ + SYSCALL_ENTRY( 0x00ea, NtSetIntervalProfile, 8 ) \ + SYSCALL_ENTRY( 0x00eb, NtSetIoCompletion, 20 ) \ + SYSCALL_ENTRY( 0x00ec, NtSetIoCompletionEx, 24 ) \ + SYSCALL_ENTRY( 0x00ed, NtSetLdtEntries, 24 ) \ + SYSCALL_ENTRY( 0x00ee, NtSetSecurityObject, 12 ) \ + SYSCALL_ENTRY( 0x00ef, NtSetSystemInformation, 12 ) \ + SYSCALL_ENTRY( 0x00f0, NtSetSystemTime, 8 ) \ + SYSCALL_ENTRY( 0x00f1, NtSetThreadExecutionState, 8 ) \ + SYSCALL_ENTRY( 0x00f2, NtSetTimerResolution, 12 ) \ + SYSCALL_ENTRY( 0x00f3, NtSetVolumeInformationFile, 20 ) \ + SYSCALL_ENTRY( 0x00f4, NtShutdownSystem, 4 ) \ + SYSCALL_ENTRY( 0x00f5, NtSignalAndWaitForSingleObject, 16 ) \ + SYSCALL_ENTRY( 0x00f6, NtSuspendProcess, 4 ) \ + SYSCALL_ENTRY( 0x00f7, NtSuspendThread, 8 ) \ + SYSCALL_ENTRY( 0x00f8, NtSystemDebugControl, 24 ) \ + SYSCALL_ENTRY( 0x00f9, NtTerminateJobObject, 8 ) \ + SYSCALL_ENTRY( 0x00fa, NtTestAlert, 0 ) \ + SYSCALL_ENTRY( 0x00fb, NtTraceControl, 24 ) \ + SYSCALL_ENTRY( 0x00fc, NtUnloadDriver, 4 ) \ + SYSCALL_ENTRY( 0x00fd, NtUnloadKey, 4 ) \ + SYSCALL_ENTRY( 0x00fe, NtUnlockFile, 20 ) \ + SYSCALL_ENTRY( 0x00ff, NtUnlockVirtualMemory, 16 ) \ + SYSCALL_ENTRY( 0x0100, NtUnmapViewOfSectionEx, 12 ) \ + SYSCALL_ENTRY( 0x0101, NtWaitForAlertByThreadId, 8 ) \ + SYSCALL_ENTRY( 0x0102, NtWaitForDebugEvent, 16 ) \ + SYSCALL_ENTRY( 0x0103, NtWaitForKeyedEvent, 16 ) \ + SYSCALL_ENTRY( 0x0104, NtWow64AllocateVirtualMemory64, 28 ) \ + SYSCALL_ENTRY( 0x0105, NtWow64GetNativeSystemInformation, 16 ) \ + SYSCALL_ENTRY( 0x0106, NtWow64IsProcessorFeaturePresent, 4 ) \ + SYSCALL_ENTRY( 0x0107, NtWow64QueryInformationProcess64, 20 ) \ + SYSCALL_ENTRY( 0x0108, NtWow64ReadVirtualMemory64, 28 ) \ + SYSCALL_ENTRY( 0x0109, NtWow64WriteVirtualMemory64, 28 ) #ifdef _WIN64 #define ALL_SYSCALLS \ SYSCALL_ENTRY( 0x0000, NtAccessCheck, 64 ) \ @@ -405,126 +407,128 @@ SYSCALL_ENTRY( 0x0087, NtCreateToken, 104 ) \ SYSCALL_ENTRY( 0x0088, NtCreateTransaction, 80 ) \ SYSCALL_ENTRY( 0x0089, NtCreateUserProcess, 88 ) \ - SYSCALL_ENTRY( 0x008a, NtDebugActiveProcess, 16 ) \ - SYSCALL_ENTRY( 0x008b, NtDebugContinue, 24 ) \ - SYSCALL_ENTRY( 0x008c, NtDeleteAtom, 8 ) \ - SYSCALL_ENTRY( 0x008d, NtDeleteFile, 8 ) \ - SYSCALL_ENTRY( 0x008e, NtDeleteKey, 8 ) \ - SYSCALL_ENTRY( 0x008f, NtDeleteValueKey, 16 ) \ - SYSCALL_ENTRY( 0x0090, NtDisplayString, 8 ) \ - SYSCALL_ENTRY( 0x0091, NtFilterToken, 48 ) \ - SYSCALL_ENTRY( 0x0092, NtFlushBuffersFileEx, 40 ) \ - SYSCALL_ENTRY( 0x0093, NtFlushInstructionCache, 24 ) \ - SYSCALL_ENTRY( 0x0094, NtFlushKey, 8 ) \ - SYSCALL_ENTRY( 0x0095, NtFlushProcessWriteBuffers, 0 ) \ - SYSCALL_ENTRY( 0x0096, NtFlushVirtualMemory, 32 ) \ - SYSCALL_ENTRY( 0x0097, NtGetContextThread, 16 ) \ - SYSCALL_ENTRY( 0x0098, NtGetCurrentProcessorNumber, 0 ) \ - SYSCALL_ENTRY( 0x0099, NtGetNextProcess, 40 ) \ - SYSCALL_ENTRY( 0x009a, NtGetNextThread, 48 ) \ - SYSCALL_ENTRY( 0x009b, NtGetNlsSectionPtr, 40 ) \ - SYSCALL_ENTRY( 0x009c, NtGetWriteWatch, 56 ) \ - SYSCALL_ENTRY( 0x009d, NtImpersonateAnonymousToken, 8 ) \ - SYSCALL_ENTRY( 0x009e, NtInitializeNlsFiles, 24 ) \ - SYSCALL_ENTRY( 0x009f, NtInitiatePowerAction, 32 ) \ - SYSCALL_ENTRY( 0x00a0, NtListenPort, 16 ) \ - SYSCALL_ENTRY( 0x00a1, NtLoadDriver, 8 ) \ - SYSCALL_ENTRY( 0x00a2, NtLoadKey, 16 ) \ - SYSCALL_ENTRY( 0x00a3, NtLoadKey2, 24 ) \ - SYSCALL_ENTRY( 0x00a4, NtLoadKeyEx, 64 ) \ - SYSCALL_ENTRY( 0x00a5, NtLockFile, 80 ) \ + SYSCALL_ENTRY( 0x008a, NtCreateWaitablePort, 40 ) \ + SYSCALL_ENTRY( 0x008b, NtDebugActiveProcess, 16 ) \ + SYSCALL_ENTRY( 0x008c, NtDebugContinue, 24 ) \ + SYSCALL_ENTRY( 0x008d, NtDeleteAtom, 8 ) \ + SYSCALL_ENTRY( 0x008e, NtDeleteFile, 8 ) \ + SYSCALL_ENTRY( 0x008f, NtDeleteKey, 8 ) \ + SYSCALL_ENTRY( 0x0090, NtDeleteValueKey, 16 ) \ + SYSCALL_ENTRY( 0x0091, NtDisplayString, 8 ) \ + SYSCALL_ENTRY( 0x0092, NtFilterToken, 48 ) \ + SYSCALL_ENTRY( 0x0093, NtFlushBuffersFileEx, 40 ) \ + SYSCALL_ENTRY( 0x0094, NtFlushInstructionCache, 24 ) \ + SYSCALL_ENTRY( 0x0095, NtFlushKey, 8 ) \ + SYSCALL_ENTRY( 0x0096, NtFlushProcessWriteBuffers, 0 ) \ + SYSCALL_ENTRY( 0x0097, NtFlushVirtualMemory, 32 ) \ + SYSCALL_ENTRY( 0x0098, NtGetContextThread, 16 ) \ + SYSCALL_ENTRY( 0x0099, NtGetCurrentProcessorNumber, 0 ) \ + SYSCALL_ENTRY( 0x009a, NtGetNextProcess, 40 ) \ + SYSCALL_ENTRY( 0x009b, NtGetNextThread, 48 ) \ + SYSCALL_ENTRY( 0x009c, NtGetNlsSectionPtr, 40 ) \ + SYSCALL_ENTRY( 0x009d, NtGetWriteWatch, 56 ) \ + SYSCALL_ENTRY( 0x009e, NtImpersonateAnonymousToken, 8 ) \ + SYSCALL_ENTRY( 0x009f, NtInitializeNlsFiles, 24 ) \ + SYSCALL_ENTRY( 0x00a0, NtInitiatePowerAction, 32 ) \ + SYSCALL_ENTRY( 0x00a1, NtListenPort, 16 ) \ + SYSCALL_ENTRY( 0x00a2, NtLoadDriver, 8 ) \ + SYSCALL_ENTRY( 0x00a3, NtLoadKey, 16 ) \ + SYSCALL_ENTRY( 0x00a4, NtLoadKey2, 24 ) \ + SYSCALL_ENTRY( 0x00a5, NtLoadKeyEx, 64 ) \ SYSCALL_ENTRY( 0x00a6, NtCreateDebugObject, 32 ) \ - SYSCALL_ENTRY( 0x00a7, NtLockVirtualMemory, 32 ) \ - SYSCALL_ENTRY( 0x00a8, NtMakePermanentObject, 8 ) \ - SYSCALL_ENTRY( 0x00a9, NtMakeTemporaryObject, 8 ) \ - SYSCALL_ENTRY( 0x00aa, NtMapViewOfSectionEx, 72 ) \ - SYSCALL_ENTRY( 0x00ab, NtNotifyChangeDirectoryFile, 72 ) \ - SYSCALL_ENTRY( 0x00ac, NtNotifyChangeKey, 80 ) \ - SYSCALL_ENTRY( 0x00ad, NtNotifyChangeMultipleKeys, 96 ) \ - SYSCALL_ENTRY( 0x00ae, NtOpenIoCompletion, 24 ) \ - SYSCALL_ENTRY( 0x00af, NtOpenJobObject, 24 ) \ - SYSCALL_ENTRY( 0x00b0, NtOpenKeyEx, 32 ) \ - SYSCALL_ENTRY( 0x00b1, NtOpenKeyTransacted, 32 ) \ - SYSCALL_ENTRY( 0x00b2, NtOpenKeyTransactedEx, 40 ) \ - SYSCALL_ENTRY( 0x00b3, NtOpenKeyedEvent, 24 ) \ - SYSCALL_ENTRY( 0x00b4, NtOpenMutant, 24 ) \ - SYSCALL_ENTRY( 0x00b5, NtOpenProcessToken, 24 ) \ - SYSCALL_ENTRY( 0x00b6, NtOpenSemaphore, 24 ) \ - SYSCALL_ENTRY( 0x00b7, NtOpenSymbolicLinkObject, 24 ) \ - SYSCALL_ENTRY( 0x00b8, NtOpenThread, 32 ) \ - SYSCALL_ENTRY( 0x00b9, NtOpenTimer, 24 ) \ - SYSCALL_ENTRY( 0x00ba, NtPrivilegeCheck, 24 ) \ - SYSCALL_ENTRY( 0x00bb, NtPulseEvent, 16 ) \ - SYSCALL_ENTRY( 0x00bc, NtQueryDirectoryObject, 56 ) \ - SYSCALL_ENTRY( 0x00bd, NtQueryEaFile, 72 ) \ - SYSCALL_ENTRY( 0x00be, NtQueryFullAttributesFile, 16 ) \ - SYSCALL_ENTRY( 0x00bf, NtQueryInformationAtom, 40 ) \ - SYSCALL_ENTRY( 0x00c0, NtQueryInformationJobObject, 40 ) \ - SYSCALL_ENTRY( 0x00c1, NtQueryInstallUILanguage, 8 ) \ - SYSCALL_ENTRY( 0x00c2, NtQueryIoCompletion, 40 ) \ - SYSCALL_ENTRY( 0x00c3, NtQueryLicenseValue, 40 ) \ - SYSCALL_ENTRY( 0x00c4, NtQueryMultipleValueKey, 48 ) \ - SYSCALL_ENTRY( 0x00c5, NtQueryMutant, 40 ) \ - SYSCALL_ENTRY( 0x00c6, NtQuerySecurityObject, 40 ) \ - SYSCALL_ENTRY( 0x00c7, NtQuerySemaphore, 40 ) \ - SYSCALL_ENTRY( 0x00c8, NtQuerySymbolicLinkObject, 24 ) \ - SYSCALL_ENTRY( 0x00c9, NtQuerySystemEnvironmentValue, 32 ) \ - SYSCALL_ENTRY( 0x00ca, NtQuerySystemEnvironmentValueEx, 40 ) \ - SYSCALL_ENTRY( 0x00cb, NtQuerySystemInformationEx, 48 ) \ - SYSCALL_ENTRY( 0x00cc, NtQueryTimerResolution, 24 ) \ - SYSCALL_ENTRY( 0x00cd, NtQueueApcThreadEx, 48 ) \ - SYSCALL_ENTRY( 0x00ce, NtQueueApcThreadEx2, 56 ) \ - SYSCALL_ENTRY( 0x00cf, NtRaiseException, 24 ) \ - SYSCALL_ENTRY( 0x00d0, NtRaiseHardError, 48 ) \ - SYSCALL_ENTRY( 0x00d1, NtRegisterThreadTerminatePort, 8 ) \ - SYSCALL_ENTRY( 0x00d2, NtReleaseKeyedEvent, 32 ) \ - SYSCALL_ENTRY( 0x00d3, NtRemoveIoCompletionEx, 48 ) \ - SYSCALL_ENTRY( 0x00d4, NtRemoveProcessDebug, 16 ) \ - SYSCALL_ENTRY( 0x00d5, NtRenameKey, 16 ) \ - SYSCALL_ENTRY( 0x00d6, NtReplaceKey, 24 ) \ - SYSCALL_ENTRY( 0x00d7, NtResetEvent, 16 ) \ - SYSCALL_ENTRY( 0x00d8, NtResetWriteWatch, 24 ) \ - SYSCALL_ENTRY( 0x00d9, NtRestoreKey, 24 ) \ - SYSCALL_ENTRY( 0x00da, NtResumeProcess, 8 ) \ - SYSCALL_ENTRY( 0x00db, NtRollbackTransaction, 16 ) \ - SYSCALL_ENTRY( 0x00dc, NtSaveKey, 16 ) \ - SYSCALL_ENTRY( 0x00dd, NtSecureConnectPort, 72 ) \ - SYSCALL_ENTRY( 0x00de, NtSetContextThread, 16 ) \ - SYSCALL_ENTRY( 0x00df, NtSetDebugFilterState, 24 ) \ - SYSCALL_ENTRY( 0x00e0, NtSetDefaultLocale, 16 ) \ - SYSCALL_ENTRY( 0x00e1, NtSetDefaultUILanguage, 8 ) \ - SYSCALL_ENTRY( 0x00e2, NtSetEaFile, 32 ) \ - SYSCALL_ENTRY( 0x00e3, NtSetInformationDebugObject, 40 ) \ - SYSCALL_ENTRY( 0x00e4, NtSetInformationJobObject, 32 ) \ - SYSCALL_ENTRY( 0x00e5, NtSetInformationKey, 32 ) \ - SYSCALL_ENTRY( 0x00e6, NtSetInformationToken, 32 ) \ - SYSCALL_ENTRY( 0x00e7, NtSetInformationVirtualMemory, 48 ) \ - SYSCALL_ENTRY( 0x00e8, NtSetIntervalProfile, 16 ) \ - SYSCALL_ENTRY( 0x00e9, NtSetIoCompletion, 40 ) \ - SYSCALL_ENTRY( 0x00ea, NtSetIoCompletionEx, 48 ) \ - SYSCALL_ENTRY( 0x00eb, NtSetLdtEntries, 48 ) \ - SYSCALL_ENTRY( 0x00ec, NtSetSecurityObject, 24 ) \ - SYSCALL_ENTRY( 0x00ed, NtSetSystemInformation, 24 ) \ - SYSCALL_ENTRY( 0x00ee, NtSetSystemTime, 16 ) \ - SYSCALL_ENTRY( 0x00ef, NtSetThreadExecutionState, 16 ) \ - SYSCALL_ENTRY( 0x00f0, NtSetTimerResolution, 24 ) \ - SYSCALL_ENTRY( 0x00f1, NtSetVolumeInformationFile, 40 ) \ - SYSCALL_ENTRY( 0x00f2, NtShutdownSystem, 8 ) \ - SYSCALL_ENTRY( 0x00f3, NtSignalAndWaitForSingleObject, 32 ) \ - SYSCALL_ENTRY( 0x00f4, NtSuspendProcess, 8 ) \ - SYSCALL_ENTRY( 0x00f5, NtSuspendThread, 16 ) \ - SYSCALL_ENTRY( 0x00f6, NtSystemDebugControl, 48 ) \ - SYSCALL_ENTRY( 0x00f7, NtTerminateJobObject, 16 ) \ - SYSCALL_ENTRY( 0x00f8, NtTestAlert, 0 ) \ - SYSCALL_ENTRY( 0x00f9, NtTraceControl, 48 ) \ - SYSCALL_ENTRY( 0x00fa, NtUnloadDriver, 8 ) \ - SYSCALL_ENTRY( 0x00fb, NtUnloadKey, 8 ) \ - SYSCALL_ENTRY( 0x00fc, NtUnlockFile, 40 ) \ - SYSCALL_ENTRY( 0x00fd, NtUnlockVirtualMemory, 32 ) \ - SYSCALL_ENTRY( 0x00fe, NtUnmapViewOfSectionEx, 24 ) \ - SYSCALL_ENTRY( 0x00ff, NtWaitForAlertByThreadId, 16 ) \ - SYSCALL_ENTRY( 0x0100, NtWaitForDebugEvent, 32 ) \ - SYSCALL_ENTRY( 0x0101, NtWaitForKeyedEvent, 32 ) + SYSCALL_ENTRY( 0x00a7, NtLockFile, 80 ) \ + SYSCALL_ENTRY( 0x00a8, NtLockVirtualMemory, 32 ) \ + SYSCALL_ENTRY( 0x00a9, NtMakePermanentObject, 8 ) \ + SYSCALL_ENTRY( 0x00aa, NtMakeTemporaryObject, 8 ) \ + SYSCALL_ENTRY( 0x00ab, NtMapViewOfSectionEx, 72 ) \ + SYSCALL_ENTRY( 0x00ac, NtNotifyChangeDirectoryFile, 72 ) \ + SYSCALL_ENTRY( 0x00ad, NtNotifyChangeKey, 80 ) \ + SYSCALL_ENTRY( 0x00ae, NtNotifyChangeMultipleKeys, 96 ) \ + SYSCALL_ENTRY( 0x00af, NtOpenIoCompletion, 24 ) \ + SYSCALL_ENTRY( 0x00b0, NtOpenJobObject, 24 ) \ + SYSCALL_ENTRY( 0x00b1, NtOpenKeyEx, 32 ) \ + SYSCALL_ENTRY( 0x00b2, NtOpenKeyTransacted, 32 ) \ + SYSCALL_ENTRY( 0x00b3, NtOpenKeyTransactedEx, 40 ) \ + SYSCALL_ENTRY( 0x00b4, NtOpenKeyedEvent, 24 ) \ + SYSCALL_ENTRY( 0x00b5, NtOpenMutant, 24 ) \ + SYSCALL_ENTRY( 0x00b6, NtOpenProcessToken, 24 ) \ + SYSCALL_ENTRY( 0x00b7, NtOpenSemaphore, 24 ) \ + SYSCALL_ENTRY( 0x00b8, NtOpenSymbolicLinkObject, 24 ) \ + SYSCALL_ENTRY( 0x00b9, NtOpenThread, 32 ) \ + SYSCALL_ENTRY( 0x00ba, NtOpenTimer, 24 ) \ + SYSCALL_ENTRY( 0x00bb, NtPrivilegeCheck, 24 ) \ + SYSCALL_ENTRY( 0x00bc, NtPulseEvent, 16 ) \ + SYSCALL_ENTRY( 0x00bd, NtQueryDirectoryObject, 56 ) \ + SYSCALL_ENTRY( 0x00be, NtQueryEaFile, 72 ) \ + SYSCALL_ENTRY( 0x00bf, NtQueryFullAttributesFile, 16 ) \ + SYSCALL_ENTRY( 0x00c0, NtQueryInformationAtom, 40 ) \ + SYSCALL_ENTRY( 0x00c1, NtQueryInformationJobObject, 40 ) \ + SYSCALL_ENTRY( 0x00c2, NtQueryInstallUILanguage, 8 ) \ + SYSCALL_ENTRY( 0x00c3, NtQueryIoCompletion, 40 ) \ + SYSCALL_ENTRY( 0x00c4, NtQueryLicenseValue, 40 ) \ + SYSCALL_ENTRY( 0x00c5, NtQueryMultipleValueKey, 48 ) \ + SYSCALL_ENTRY( 0x00c6, NtQueryMutant, 40 ) \ + SYSCALL_ENTRY( 0x00c7, NtQuerySecurityObject, 40 ) \ + SYSCALL_ENTRY( 0x00c8, NtQuerySemaphore, 40 ) \ + SYSCALL_ENTRY( 0x00c9, NtQuerySymbolicLinkObject, 24 ) \ + SYSCALL_ENTRY( 0x00ca, NtQuerySystemEnvironmentValue, 32 ) \ + SYSCALL_ENTRY( 0x00cb, NtQuerySystemEnvironmentValueEx, 40 ) \ + SYSCALL_ENTRY( 0x00cc, NtQuerySystemInformationEx, 48 ) \ + SYSCALL_ENTRY( 0x00cd, NtQueryTimerResolution, 24 ) \ + SYSCALL_ENTRY( 0x00ce, NtQueueApcThreadEx, 48 ) \ + SYSCALL_ENTRY( 0x00cf, NtQueueApcThreadEx2, 56 ) \ + SYSCALL_ENTRY( 0x00d0, NtRaiseException, 24 ) \ + SYSCALL_ENTRY( 0x00d1, NtRaiseHardError, 48 ) \ + SYSCALL_ENTRY( 0x00d2, NtRegisterThreadTerminatePort, 8 ) \ + SYSCALL_ENTRY( 0x00d3, NtReleaseKeyedEvent, 32 ) \ + SYSCALL_ENTRY( 0x00d4, NtRemoveIoCompletionEx, 48 ) \ + SYSCALL_ENTRY( 0x00d5, NtRemoveProcessDebug, 16 ) \ + SYSCALL_ENTRY( 0x00d6, NtRenameKey, 16 ) \ + SYSCALL_ENTRY( 0x00d7, NtReplaceKey, 24 ) \ + SYSCALL_ENTRY( 0x00d8, NtRequestPort, 16 ) \ + SYSCALL_ENTRY( 0x00d9, NtResetEvent, 16 ) \ + SYSCALL_ENTRY( 0x00da, NtResetWriteWatch, 24 ) \ + SYSCALL_ENTRY( 0x00db, NtRestoreKey, 24 ) \ + SYSCALL_ENTRY( 0x00dc, NtResumeProcess, 8 ) \ + SYSCALL_ENTRY( 0x00dd, NtRollbackTransaction, 16 ) \ + SYSCALL_ENTRY( 0x00de, NtSaveKey, 16 ) \ + SYSCALL_ENTRY( 0x00df, NtSecureConnectPort, 72 ) \ + SYSCALL_ENTRY( 0x00e0, NtSetContextThread, 16 ) \ + SYSCALL_ENTRY( 0x00e1, NtSetDebugFilterState, 24 ) \ + SYSCALL_ENTRY( 0x00e2, NtSetDefaultLocale, 16 ) \ + SYSCALL_ENTRY( 0x00e3, NtSetDefaultUILanguage, 8 ) \ + SYSCALL_ENTRY( 0x00e4, NtSetEaFile, 32 ) \ + SYSCALL_ENTRY( 0x00e5, NtSetInformationDebugObject, 40 ) \ + SYSCALL_ENTRY( 0x00e6, NtSetInformationJobObject, 32 ) \ + SYSCALL_ENTRY( 0x00e7, NtSetInformationKey, 32 ) \ + SYSCALL_ENTRY( 0x00e8, NtSetInformationToken, 32 ) \ + SYSCALL_ENTRY( 0x00e9, NtSetInformationVirtualMemory, 48 ) \ + SYSCALL_ENTRY( 0x00ea, NtSetIntervalProfile, 16 ) \ + SYSCALL_ENTRY( 0x00eb, NtSetIoCompletion, 40 ) \ + SYSCALL_ENTRY( 0x00ec, NtSetIoCompletionEx, 48 ) \ + SYSCALL_ENTRY( 0x00ed, NtSetLdtEntries, 48 ) \ + SYSCALL_ENTRY( 0x00ee, NtSetSecurityObject, 24 ) \ + SYSCALL_ENTRY( 0x00ef, NtSetSystemInformation, 24 ) \ + SYSCALL_ENTRY( 0x00f0, NtSetSystemTime, 16 ) \ + SYSCALL_ENTRY( 0x00f1, NtSetThreadExecutionState, 16 ) \ + SYSCALL_ENTRY( 0x00f2, NtSetTimerResolution, 24 ) \ + SYSCALL_ENTRY( 0x00f3, NtSetVolumeInformationFile, 40 ) \ + SYSCALL_ENTRY( 0x00f4, NtShutdownSystem, 8 ) \ + SYSCALL_ENTRY( 0x00f5, NtSignalAndWaitForSingleObject, 32 ) \ + SYSCALL_ENTRY( 0x00f6, NtSuspendProcess, 8 ) \ + SYSCALL_ENTRY( 0x00f7, NtSuspendThread, 16 ) \ + SYSCALL_ENTRY( 0x00f8, NtSystemDebugControl, 48 ) \ + SYSCALL_ENTRY( 0x00f9, NtTerminateJobObject, 16 ) \ + SYSCALL_ENTRY( 0x00fa, NtTestAlert, 0 ) \ + SYSCALL_ENTRY( 0x00fb, NtTraceControl, 48 ) \ + SYSCALL_ENTRY( 0x00fc, NtUnloadDriver, 8 ) \ + SYSCALL_ENTRY( 0x00fd, NtUnloadKey, 8 ) \ + SYSCALL_ENTRY( 0x00fe, NtUnlockFile, 40 ) \ + SYSCALL_ENTRY( 0x00ff, NtUnlockVirtualMemory, 32 ) \ + SYSCALL_ENTRY( 0x0100, NtUnmapViewOfSectionEx, 24 ) \ + SYSCALL_ENTRY( 0x0101, NtWaitForAlertByThreadId, 16 ) \ + SYSCALL_ENTRY( 0x0102, NtWaitForDebugEvent, 32 ) \ + SYSCALL_ENTRY( 0x0103, NtWaitForKeyedEvent, 32 ) #else #define ALL_SYSCALLS ALL_SYSCALLS32 #endif diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index 954ace7824e..dd139721966 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -400,6 +400,7 @@ DEFINE_SYSCALL(NtCreateTimer, (HANDLE *handle, ACCESS_MASK access, const OBJECT_ DEFINE_SYSCALL(NtCreateToken, (HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr, TOKEN_TYPE type, LUID *token_id, LARGE_INTEGER *expire, TOKEN_USER *user, TOKEN_GROUPS *groups, TOKEN_PRIVILEGES *privs, TOKEN_OWNER *owner, TOKEN_PRIMARY_GROUP *group, TOKEN_DEFAULT_DACL *dacl, TOKEN_SOURCE *source)) DEFINE_SYSCALL(NtCreateTransaction, (HANDLE *handle, ACCESS_MASK mask, OBJECT_ATTRIBUTES *obj_attr, GUID *guid, HANDLE tm, ULONG options, ULONG isol_level, ULONG isol_flags, PLARGE_INTEGER timeout, UNICODE_STRING *description)) DEFINE_SYSCALL(NtCreateUserProcess, (HANDLE *process_handle_ptr, HANDLE *thread_handle_ptr, ACCESS_MASK process_access, ACCESS_MASK thread_access, OBJECT_ATTRIBUTES *process_attr, OBJECT_ATTRIBUTES *thread_attr, ULONG process_flags, ULONG thread_flags, RTL_USER_PROCESS_PARAMETERS *params, PS_CREATE_INFO *info, PS_ATTRIBUTE_LIST *ps_attr)) +DEFINE_SYSCALL(NtCreateWaitablePort, (HANDLE *handle, OBJECT_ATTRIBUTES *attr, ULONG info_len, ULONG data_len, ULONG reserved)) DEFINE_SYSCALL(NtDebugActiveProcess, (HANDLE process, HANDLE debug)) DEFINE_SYSCALL(NtDebugContinue, (HANDLE handle, CLIENT_ID *client, NTSTATUS status)) DEFINE_SYSCALL(NtDelayExecution, (BOOLEAN alertable, const LARGE_INTEGER *timeout)) @@ -531,6 +532,7 @@ DEFINE_SYSCALL(NtReplaceKey, (OBJECT_ATTRIBUTES *attr, HANDLE key, OBJECT_ATTRIB DEFINE_SYSCALL(NtReplyPort, (HANDLE handle, LPC_MESSAGE *reply)) DEFINE_SYSCALL(NtReplyWaitReceivePort, (HANDLE handle, ULONG *id, LPC_MESSAGE *reply, LPC_MESSAGE *msg)) DEFINE_SYSCALL(NtReplyWaitReceivePortEx, (HANDLE handle, ULONG *id, LPC_MESSAGE *reply, LPC_MESSAGE *msg, LARGE_INTEGER *timeout)) +DEFINE_SYSCALL(NtRequestPort, (HANDLE handle, LPC_MESSAGE *msg)) DEFINE_SYSCALL(NtRequestWaitReplyPort, (HANDLE handle, LPC_MESSAGE *msg_in, LPC_MESSAGE *msg_out)) DEFINE_SYSCALL(NtResetEvent, (HANDLE handle, LONG *prev_state)) DEFINE_SYSCALL(NtResetWriteWatch, (HANDLE process, PVOID base, SIZE_T size)) diff --git a/dlls/ntdll/tests/port.c b/dlls/ntdll/tests/port.c index 80c60d09683..2d907c7ba0b 100644 --- a/dlls/ntdll/tests/port.c +++ b/dlls/ntdll/tests/port.c @@ -102,6 +102,7 @@ union lpc_message #define LPC_CONNECTION_REQUEST 10 static const WCHAR PORTNAME[] = {'\\','M','y','P','o','r','t',0}; +static const WCHAR WAITABLEPORTNAME[] = {'\\','M','y','W','P','o','r','t',0}; #define REQUEST1 "Request1" #define REQUEST2 "Request2" @@ -120,6 +121,7 @@ static NTSTATUS (WINAPI *pNtReplyPort)(HANDLE,PLPC_MESSAGE); static NTSTATUS (WINAPI *pNtReplyWaitReceivePort)(PHANDLE,PULONG,PLPC_MESSAGE, PLPC_MESSAGE); static NTSTATUS (WINAPI *pNtCreatePort)(PHANDLE,POBJECT_ATTRIBUTES,ULONG,ULONG,ULONG); +static NTSTATUS (WINAPI *pNtCreateWaitablePort)(PHANDLE,POBJECT_ATTRIBUTES,ULONG,ULONG,ULONG); static NTSTATUS (WINAPI *pNtRequestWaitReplyPort)(HANDLE,PLPC_MESSAGE,PLPC_MESSAGE); static NTSTATUS (WINAPI *pNtRequestPort)(HANDLE,PLPC_MESSAGE); static NTSTATUS (WINAPI *pNtRegisterThreadTerminatePort)(HANDLE); @@ -144,6 +146,7 @@ static BOOL init_function_ptrs(void) pNtReplyPort = (void *)GetProcAddress(hntdll, "NtReplyPort"); pNtReplyWaitReceivePort = (void *)GetProcAddress(hntdll, "NtReplyWaitReceivePort"); pNtCreatePort = (void *)GetProcAddress(hntdll, "NtCreatePort"); + pNtCreateWaitablePort = (void *)GetProcAddress(hntdll, "NtCreateWaitablePort"); pNtRequestWaitReplyPort = (void *)GetProcAddress(hntdll, "NtRequestWaitReplyPort"); pNtRequestPort = (void *)GetProcAddress(hntdll, "NtRequestPort"); pNtRegisterThreadTerminatePort = (void *)GetProcAddress(hntdll, "NtRegisterThreadTerminatePort"); @@ -151,7 +154,8 @@ static BOOL init_function_ptrs(void) pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); if (!pNtCompleteConnectPort || !pNtAcceptConnectPort || - !pNtReplyWaitReceivePort || !pNtCreatePort || !pNtRequestWaitReplyPort || + !pNtReplyWaitReceivePort || !pNtCreatePort || + !pNtCreateWaitablePort || !pNtRequestWaitReplyPort || !pNtRequestPort || !pNtRegisterThreadTerminatePort || !pNtConnectPort || !pRtlInitUnicodeString) { @@ -239,7 +243,7 @@ static DWORD WINAPI test_ports_client(LPVOID arg) sqos.EffectiveOnly = TRUE; status = pNtConnectPort(&PortHandle, &port, &sqos, 0, 0, &len, NULL, NULL); - todo_wine ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status); + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %lx\n", status); if (status != STATUS_SUCCESS) return 1; status = pNtRegisterThreadTerminatePort(PortHandle); @@ -322,10 +326,7 @@ static void test_ports_server( HANDLE PortHandle ) while (TRUE) { status = pNtReplyWaitReceivePort(PortHandle, NULL, NULL, &LpcMessage->msg); - todo_wine - { - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld(%lx)\n", status, status); - } + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld(%lx)\n", status, status); /* STATUS_INVALID_HANDLE: win2k without admin rights will perform an * endless loop here */ @@ -386,6 +387,25 @@ START_TEST(port) if (status == STATUS_ACCESS_DENIED) skip("Not enough rights\n"); else ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld\n", status); + if (status == STATUS_SUCCESS) + { + DWORD id; + HANDLE thread = CreateThread(NULL, 0, test_ports_client, NULL, 0, &id); + ok(thread != NULL, "Expected non-NULL thread handle!\n"); + + test_ports_server( port_handle ); + ok( WaitForSingleObject( thread, 10000 ) == 0, "thread didn't exit\n" ); + CloseHandle(thread); + } + + pRtlInitUnicodeString(&port, WAITABLEPORTNAME); + + obj.ObjectName = &port; + + status = pNtCreateWaitablePort(&port_handle, &obj, 100, 100, 0); + if (status == STATUS_ACCESS_DENIED) skip("Not enough rights\n"); + else ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08lx\n", status); + if (status == STATUS_SUCCESS) { DWORD id; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index bc9bbf2c30d..5ceaeec5ed2 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -74,6 +74,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(sync); +/* LPC port access rights */ +#define PORT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x0001) + HANDLE keyed_event = 0; int inproc_device_fd = -1; @@ -3068,10 +3071,61 @@ NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ NTSTATUS WINAPI NtCreatePort( HANDLE *handle, OBJECT_ATTRIBUTES *attr, ULONG info_len, ULONG data_len, ULONG *reserved ) { - FIXME( "(%p,%p,%u,%u,%p),stub!\n", handle, attr, info_len, data_len, reserved ); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + data_size_t len; + struct object_attributes *objattr; + + TRACE( "(%p,%p,%u,%u,%p)\n", handle, attr, info_len, data_len, reserved ); + + *handle = 0; + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) + return ret; + + SERVER_START_REQ( create_lpc_port ) + { + req->access = PORT_ALL_ACCESS; + req->flags = 0; + req->max_msg_len = data_len; + req->max_connect_info = info_len; + wine_server_add_data( req, objattr, len ); + if (!(ret = wine_server_call( req ))) + *handle = wine_server_ptr_handle( reply->handle ); + } + SERVER_END_REQ; + free( objattr ); + return ret; } +/*********************************************************************** + * NtCreateWaitablePort (NTDLL.@) + */ +NTSTATUS WINAPI NtCreateWaitablePort( HANDLE *handle, OBJECT_ATTRIBUTES *attr, ULONG info_len, + ULONG data_len, ULONG reserved ) +{ + unsigned int ret; + data_size_t len; + struct object_attributes *objattr; + + TRACE( "(%p,%p,%u,%u,%u)\n", handle, attr, info_len, data_len, reserved ); + + *handle = 0; + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) + return ret; + + SERVER_START_REQ( create_lpc_port ) + { + req->access = PORT_ALL_ACCESS; + req->flags = 0x0001; /* PORT_FLAG_WAITABLE */ + req->max_msg_len = data_len; + req->max_connect_info = info_len; + wine_server_add_data( req, objattr, len ); + if (!(ret = wine_server_call( req ))) + *handle = wine_server_ptr_handle( reply->handle ); + } + SERVER_END_REQ; + free( objattr ); + return ret; +} /*********************************************************************** * NtConnectPort (NTDLL.@) @@ -3080,10 +3134,94 @@ NTSTATUS WINAPI NtConnectPort( HANDLE *handle, UNICODE_STRING *name, SECURITY_QU LPC_SECTION_WRITE *write, LPC_SECTION_READ *read, ULONG *max_len, void *info, ULONG *info_len ) { - FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p),stub!\n", handle, debugstr_us(name), qos, - write, read, max_len, info, info_len ); - if (info && info_len) TRACE("msg = %s\n", debugstr_an( info, *info_len )); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + data_size_t len; + struct object_attributes *objattr; + OBJECT_ATTRIBUTES attr; + ULONG in_len = (info && info_len) ? *info_len : 0; + HANDLE port_handle; + + TRACE( "(%p,%s,%p,%p,%p,%p,%p,%p)\n", handle, debugstr_us(name), qos, write, read, max_len, info, info_len ); + + if (write) + FIXME( "LPC_SECTION_WRITE not supported\n" ); + if (read) + FIXME( "LPC_SECTION_READ not supported\n" ); + + *handle = 0; + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = name; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = qos; + + if ((ret = alloc_object_attributes( &attr, &objattr, &len ))) + return ret; + + SERVER_START_REQ( connect_lpc_port ) + { + req->access = PORT_ALL_ACCESS; + req->info_size = in_len; + wine_server_add_data( req, objattr, len ); + if (in_len) wine_server_add_data( req, info, in_len ); + if (!(ret = wine_server_call( req ))) + { + port_handle = wine_server_ptr_handle( reply->handle ); + if (info_len) + *info_len = reply->info_size; + } + } + SERVER_END_REQ; + free( objattr ); + + if (ret) return ret; + + /* Wait for the connection to be accepted/rejected by the server. + * The server will signal the port's connect_event when NtCompleteConnectPort + * is called (or immediately for rejected connections). */ + for (;;) + { + unsigned int connect_status; + + /* Check current connection status */ + SERVER_START_REQ( get_lpc_connect_status ) + { + req->handle = wine_server_obj_handle( port_handle ); + ret = wine_server_call( req ); + connect_status = reply->status; + } + SERVER_END_REQ; + + if (ret) + { + NtClose( port_handle ); + return ret; + } + + if (connect_status != STATUS_PENDING) + { + /* Connection complete */ + if (connect_status == STATUS_SUCCESS) + { + *handle = port_handle; + return STATUS_SUCCESS; + } + else + { + NtClose( port_handle ); + return connect_status; + } + } + + /* Still pending */ + ret = NtWaitForSingleObject( port_handle, FALSE, NULL ); + if (ret) + { + NtClose( port_handle ); + return ret; + } + } } @@ -3094,9 +3232,11 @@ NTSTATUS WINAPI NtSecureConnectPort( HANDLE *handle, UNICODE_STRING *name, SECUR LPC_SECTION_WRITE *write, PSID sid, LPC_SECTION_READ *read, ULONG *max_len, void *info, ULONG *info_len ) { - FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p,%p),stub!\n", handle, debugstr_us(name), qos, - write, sid, read, max_len, info, info_len ); - return STATUS_NOT_IMPLEMENTED; + TRACE( "(%p,%s,%p,%p,%p,%p,%p,%p,%p)\n", handle, debugstr_us(name), qos, write, sid, read, max_len, info, info_len ); + + if (sid) + FIXME( "SID verification not implemented\n" ); + return NtConnectPort( handle, name, qos, write, read, max_len, info, info_len ); } @@ -3105,8 +3245,40 @@ NTSTATUS WINAPI NtSecureConnectPort( HANDLE *handle, UNICODE_STRING *name, SECUR */ NTSTATUS WINAPI NtListenPort( HANDLE handle, LPC_MESSAGE *msg ) { - FIXME("(%p,%p),stub!\n", handle, msg ); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + + TRACE( "(%p,%p)\n", handle, msg ); + + for (;;) + { + SERVER_START_REQ( listen_lpc_port ) + { + req->handle = wine_server_obj_handle( handle ); + /* Use a reasonable max size for LPC message data. + * sizeof(msg->Data) is just 1 due to ANYSIZE_ARRAY. */ + wine_server_set_reply( req, msg ? msg->Data : NULL, msg ? 0x1000 : 0 ); + ret = wine_server_call( req ); + if (!ret && msg) + { + msg->DataSize = reply->msg_size; + msg->MessageSize = sizeof(*msg) + reply->msg_size; + msg->MessageType = 10; /* LPC_CONNECTION_REQUEST */ + msg->VirtualRangesOffset = 0; + msg->ClientId.UniqueProcess = ULongToHandle( reply->client_pid ); + msg->ClientId.UniqueThread = ULongToHandle( reply->client_tid ); + msg->MessageId = reply->msg_id; + msg->SectionSize = 0; + } + } + SERVER_END_REQ; + + if (ret != STATUS_PENDING) break; + + /* Wait for a connection request */ + ret = NtWaitForSingleObject( handle, FALSE, NULL ); + if (ret) break; + } + return ret; } @@ -3116,8 +3288,30 @@ NTSTATUS WINAPI NtListenPort( HANDLE handle, LPC_MESSAGE *msg ) NTSTATUS WINAPI NtAcceptConnectPort( HANDLE *handle, ULONG id, LPC_MESSAGE *msg, BOOLEAN accept, LPC_SECTION_WRITE *write, LPC_SECTION_READ *read ) { - FIXME("(%p,%u,%p,%d,%p,%p),stub!\n", handle, id, msg, accept, write, read ); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + + TRACE( "(%p,%u,%p,%d,%p,%p)\n", handle, id, msg, accept, write, read ); + + if (write) + FIXME( "LPC_SECTION_WRITE not supported\n" ); + if (read) + FIXME( "LPC_SECTION_READ not supported\n" ); + + *handle = 0; + + SERVER_START_REQ( accept_lpc_connect ) + { + /* Note: handle is not used, the server finds the pending connection + * by message ID from a global list. */ + req->handle = 0; + req->accept = accept; + req->msg_id = msg ? msg->MessageId : 0; + req->context = id; + if (!(ret = wine_server_call( req )) && accept) + *handle = wine_server_ptr_handle( reply->handle ); + } + SERVER_END_REQ; + return ret; } @@ -3126,8 +3320,17 @@ NTSTATUS WINAPI NtAcceptConnectPort( HANDLE *handle, ULONG id, LPC_MESSAGE *msg, */ NTSTATUS WINAPI NtCompleteConnectPort( HANDLE handle ) { - FIXME( "(%p),stub!\n", handle ); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + + TRACE( "(%p)\n", handle ); + + SERVER_START_REQ( complete_lpc_connect ) + { + req->handle = wine_server_obj_handle( handle ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + return ret; } @@ -3157,8 +3360,46 @@ NTSTATUS WINAPI NtReadRequestData( HANDLE handle, LPC_MESSAGE *request, ULONG id */ NTSTATUS WINAPI NtRegisterThreadTerminatePort( HANDLE handle ) { - FIXME( "(%p),stub!\n", handle ); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + + TRACE( "(%p)\n", handle ); + + SERVER_START_REQ( register_lpc_terminate_port ) + { + req->handle = wine_server_obj_handle( handle ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + + return ret; +} + + +/*********************************************************************** + * NtRequestPort (NTDLL.@) + */ +NTSTATUS WINAPI NtRequestPort( HANDLE handle, LPC_MESSAGE *msg ) +{ + unsigned int ret; + USHORT data_size; + + TRACE( "(%p,%p)\n", handle, msg ); + + if (!msg) + return STATUS_INVALID_PARAMETER; + + data_size = msg->DataSize; + + SERVER_START_REQ( request_lpc_reply ) + { + req->handle = wine_server_obj_handle( handle ); + req->data_size = data_size; + req->msg_type = 3; /* datagram */ + wine_server_add_data( req, msg->Data, data_size ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + return ret; } @@ -3167,44 +3408,165 @@ NTSTATUS WINAPI NtRegisterThreadTerminatePort( HANDLE handle ) */ NTSTATUS WINAPI NtRequestWaitReplyPort( HANDLE handle, LPC_MESSAGE *msg_in, LPC_MESSAGE *msg_out ) { - FIXME( "(%p,%p,%p),stub!\n", handle, msg_in, msg_out ); - if (msg_in) - TRACE("datasize %u msgsize %u type %u ranges %u client %p/%p msgid %lu size %lu data %s\n", - msg_in->DataSize, msg_in->MessageSize, msg_in->MessageType, msg_in->VirtualRangesOffset, - msg_in->ClientId.UniqueProcess, msg_in->ClientId.UniqueThread, msg_in->MessageId, - msg_in->SectionSize, debugstr_an( (const char *)msg_in->Data, msg_in->DataSize )); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + USHORT data_size; + + TRACE( "(%p,%p,%p)\n", handle, msg_in, msg_out ); + + if (!msg_in || !msg_out) return STATUS_INVALID_PARAMETER; + + data_size = msg_in->DataSize; + + /* Send the request message */ + SERVER_START_REQ( request_lpc_reply ) + { + req->handle = wine_server_obj_handle( handle ); + req->data_size = data_size; + req->msg_type = 1; /* request */ + wine_server_add_data( req, msg_in->Data, data_size ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + + if (ret) return ret; + + /* Wait for and receive the reply */ + for (;;) + { + SERVER_START_REQ( reply_wait_receive_lpc ) + { + req->handle = wine_server_obj_handle( handle ); + req->reply_msg_id = 0; + req->reply_size = 0; + req->timeout = TIMEOUT_INFINITE; + /* Use a reasonable max size for LPC message data. + * sizeof(msg_out->Data) is just 1 due to ANYSIZE_ARRAY. */ + wine_server_set_reply( req, msg_out->Data, 0x1000 ); + ret = wine_server_call( req ); + if (!ret) + { + msg_out->DataSize = reply->data_size; + msg_out->MessageSize = sizeof(*msg_out) + reply->data_size; + msg_out->MessageType = reply->msg_type; + msg_out->VirtualRangesOffset = 0; + msg_out->ClientId.UniqueProcess = ULongToHandle( reply->client_pid ); + msg_out->ClientId.UniqueThread = ULongToHandle( reply->client_tid ); + msg_out->MessageId = reply->msg_id; + msg_out->SectionSize = 0; + } + } + SERVER_END_REQ; + + if (ret != STATUS_PENDING) break; + + /* Wait on port for message availability */ + ret = NtWaitForSingleObject( handle, FALSE, NULL ); + if (ret) break; + } + return ret; } /*********************************************************************** * NtReplyPort (NTDLL.@) */ -NTSTATUS WINAPI NtReplyPort( HANDLE handle, LPC_MESSAGE *reply ) +NTSTATUS WINAPI NtReplyPort( HANDLE handle, LPC_MESSAGE *reply_msg ) { - FIXME("(%p,%p),stub!\n", handle, reply ); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + + TRACE( "(%p,%p)\n", handle, reply_msg ); + + if (!reply_msg) + return STATUS_INVALID_PARAMETER; + + SERVER_START_REQ( reply_wait_receive_lpc ) + { + req->handle = wine_server_obj_handle( handle ); + req->reply_msg_id = reply_msg->MessageId; + req->reply_size = reply_msg->DataSize; + req->timeout = 0; /* Don't wait for a new message */ + wine_server_add_data( req, reply_msg->Data, reply_msg->DataSize ); + ret = wine_server_call( req ); + /* STATUS_PENDING just means no new message, which is fine for NtReplyPort */ + if (ret == STATUS_PENDING) + ret = STATUS_SUCCESS; + } + SERVER_END_REQ; + return ret; } /*********************************************************************** * NtReplyWaitReceivePort (NTDLL.@) */ -NTSTATUS WINAPI NtReplyWaitReceivePort( HANDLE handle, ULONG *id, LPC_MESSAGE *reply, LPC_MESSAGE *msg ) +NTSTATUS WINAPI NtReplyWaitReceivePort( HANDLE handle, ULONG *id, LPC_MESSAGE *reply_msg, LPC_MESSAGE *msg ) { - FIXME("(%p,%p,%p,%p),stub!\n", handle, id, reply, msg ); - return STATUS_NOT_IMPLEMENTED; + return NtReplyWaitReceivePortEx( handle, id, reply_msg, msg, NULL ); } /*********************************************************************** * NtReplyWaitReceivePortEx (NTDLL.@) */ -NTSTATUS WINAPI NtReplyWaitReceivePortEx( HANDLE handle, ULONG *id, LPC_MESSAGE *reply, LPC_MESSAGE *msg, +NTSTATUS WINAPI NtReplyWaitReceivePortEx( HANDLE handle, ULONG *id, LPC_MESSAGE *reply_msg, LPC_MESSAGE *msg, LARGE_INTEGER *timeout ) { - FIXME("(%p,%p,%p,%p,%p),stub!\n", handle, id, reply, msg, timeout ); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; + unsigned int reply_msg_id = 0; + USHORT reply_size = 0; + + TRACE( "(%p,%p,%p,%p,%p)\n", handle, id, reply_msg, msg, timeout ); + + if (reply_msg) + { + reply_msg_id = reply_msg->MessageId; + reply_size = reply_msg->DataSize; + } + + for (;;) + { + SERVER_START_REQ( reply_wait_receive_lpc ) + { + req->handle = wine_server_obj_handle( handle ); + req->reply_msg_id = reply_msg_id; + req->reply_size = reply_size; + req->timeout = abs_timeout; + if (reply_msg && reply_size) + wine_server_add_data( req, reply_msg->Data, reply_size ); + if (msg) + { + /* Use a reasonable max size for LPC message data. + * sizeof(msg->Data) is just 1 due to ANYSIZE_ARRAY. */ + wine_server_set_reply( req, msg->Data, 0x1000 ); + } + ret = wine_server_call( req ); + if (!ret && msg) + { + msg->DataSize = reply->data_size; + msg->MessageSize = sizeof(*msg) + reply->data_size; + msg->MessageType = reply->msg_type; + msg->VirtualRangesOffset = 0; + msg->ClientId.UniqueProcess = ULongToHandle( reply->client_pid ); + msg->ClientId.UniqueThread = ULongToHandle( reply->client_tid ); + msg->MessageId = reply->msg_id; + msg->SectionSize = 0; + if (id) *id = (ULONG)(ULONG_PTR)reply->context; + } + } + SERVER_END_REQ; + + /* After first iteration, don't send reply again */ + reply_msg_id = 0; + reply_size = 0; + + if (ret != STATUS_PENDING) break; + + /* Wait on port for message availability */ + ret = NtWaitForSingleObject( handle, FALSE, timeout ); + if (ret) break; + } + return ret; } diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c index d5b52a5c815..fd982d0aa3c 100644 --- a/dlls/wow64/sync.c +++ b/dlls/wow64/sync.c @@ -378,6 +378,26 @@ NTSTATUS WINAPI wow64_NtCreatePort( UINT *args ) return status; } +/********************************************************************** + * wow64_NtCreateWaitablePort + */ +NTSTATUS WINAPI wow64_NtCreateWaitablePort( UINT *args ) +{ + ULONG *handle_ptr = get_ptr( &args ); + OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args ); + ULONG info_len = get_ulong( &args ); + ULONG data_len = get_ulong( &args ); + ULONG reserved = get_ulong( &args ); + + struct object_attr64 attr; + HANDLE handle = 0; + NTSTATUS status; + + *handle_ptr = 0; + status = NtCreateWaitablePort( &handle, objattr_32to64( &attr, attr32 ), info_len, data_len, reserved ); + put_handle( handle_ptr, handle ); + return status; +} /********************************************************************** * wow64_NtCreateSection @@ -1332,6 +1352,18 @@ NTSTATUS WINAPI wow64_NtReplyWaitReceivePortEx( UINT *args ) } +/********************************************************************** + * wow64_NtRequestPort + */ +NTSTATUS WINAPI wow64_NtRequestPort( UINT *args ) +{ + HANDLE handle = get_handle( &args ); + LPC_MESSAGE *msg = get_ptr( &args ); + + return NtRequestPort( handle, msg ); +} + + /********************************************************************** * wow64_NtRequestWaitReplyPort */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 85f636dd995..0b996367f97 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -6162,6 +6162,150 @@ struct d3dkmt_mutex_release_reply }; +struct create_lpc_port_request +{ + struct request_header __header; + unsigned int access; + unsigned int flags; + unsigned int max_msg_len; + unsigned int max_connect_info; + /* VARARG(objattr,object_attributes); */ + char __pad_28[4]; +}; +struct create_lpc_port_reply +{ + struct reply_header __header; + obj_handle_t handle; + char __pad_12[4]; +}; + + +struct connect_lpc_port_request +{ + struct request_header __header; + unsigned int access; + data_size_t info_size; + /* VARARG(objattr,object_attributes); */ + /* VARARG(info,bytes); */ + char __pad_20[4]; +}; +struct connect_lpc_port_reply +{ + struct reply_header __header; + obj_handle_t handle; + data_size_t info_size; + /* VARARG(info,bytes); */ +}; + + +struct listen_lpc_port_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct listen_lpc_port_reply +{ + struct reply_header __header; + client_ptr_t message; + data_size_t msg_size; + process_id_t client_pid; + thread_id_t client_tid; + unsigned int msg_id; + /* VARARG(info,bytes); */ +}; + + +struct accept_lpc_connect_request +{ + struct request_header __header; + obj_handle_t handle; + int accept; + unsigned int msg_id; + client_ptr_t context; + /* VARARG(info,bytes); */ +}; +struct accept_lpc_connect_reply +{ + struct reply_header __header; + obj_handle_t handle; + char __pad_12[4]; +}; + + +struct complete_lpc_connect_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct complete_lpc_connect_reply +{ + struct reply_header __header; +}; + + +struct get_lpc_connect_status_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_lpc_connect_status_reply +{ + struct reply_header __header; + unsigned int status; + char __pad_12[4]; +}; + + +struct request_lpc_reply_request +{ + struct request_header __header; + obj_handle_t handle; + data_size_t data_size; + unsigned int msg_type; + /* VARARG(data,bytes); */ +}; +struct request_lpc_reply_reply +{ + struct reply_header __header; + unsigned int msg_id; + char __pad_12[4]; +}; + + +struct reply_wait_receive_lpc_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int reply_msg_id; + data_size_t reply_size; + timeout_t timeout; + /* VARARG(reply,bytes); */ +}; +struct reply_wait_receive_lpc_reply +{ + struct reply_header __header; + unsigned int msg_id; + unsigned int msg_type; + process_id_t client_pid; + thread_id_t client_tid; + client_ptr_t context; + data_size_t data_size; + /* VARARG(data,bytes); */ + char __pad_36[4]; +}; + + +struct register_lpc_terminate_port_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct register_lpc_terminate_port_reply +{ + struct reply_header __header; +}; + + enum request { REQ_new_process, @@ -6470,6 +6614,15 @@ enum request REQ_d3dkmt_object_open_name, REQ_d3dkmt_mutex_acquire, REQ_d3dkmt_mutex_release, + REQ_create_lpc_port, + REQ_connect_lpc_port, + REQ_listen_lpc_port, + REQ_accept_lpc_connect, + REQ_complete_lpc_connect, + REQ_get_lpc_connect_status, + REQ_request_lpc_reply, + REQ_reply_wait_receive_lpc, + REQ_register_lpc_terminate_port, REQ_NB_REQUESTS }; @@ -6783,6 +6936,15 @@ union generic_request struct d3dkmt_object_open_name_request d3dkmt_object_open_name_request; struct d3dkmt_mutex_acquire_request d3dkmt_mutex_acquire_request; struct d3dkmt_mutex_release_request d3dkmt_mutex_release_request; + struct create_lpc_port_request create_lpc_port_request; + struct connect_lpc_port_request connect_lpc_port_request; + struct listen_lpc_port_request listen_lpc_port_request; + struct accept_lpc_connect_request accept_lpc_connect_request; + struct complete_lpc_connect_request complete_lpc_connect_request; + struct get_lpc_connect_status_request get_lpc_connect_status_request; + struct request_lpc_reply_request request_lpc_reply_request; + struct reply_wait_receive_lpc_request reply_wait_receive_lpc_request; + struct register_lpc_terminate_port_request register_lpc_terminate_port_request; }; union generic_reply { @@ -7094,8 +7256,17 @@ union generic_reply struct d3dkmt_object_open_name_reply d3dkmt_object_open_name_reply; struct d3dkmt_mutex_acquire_reply d3dkmt_mutex_acquire_reply; struct d3dkmt_mutex_release_reply d3dkmt_mutex_release_reply; -}; - -#define SERVER_PROTOCOL_VERSION 931 + struct create_lpc_port_reply create_lpc_port_reply; + struct connect_lpc_port_reply connect_lpc_port_reply; + struct listen_lpc_port_reply listen_lpc_port_reply; + struct accept_lpc_connect_reply accept_lpc_connect_reply; + struct complete_lpc_connect_reply complete_lpc_connect_reply; + struct get_lpc_connect_status_reply get_lpc_connect_status_reply; + struct request_lpc_reply_reply request_lpc_reply_reply; + struct reply_wait_receive_lpc_reply reply_wait_receive_lpc_reply; + struct register_lpc_terminate_port_reply register_lpc_terminate_port_reply; +}; + +#define SERVER_PROTOCOL_VERSION 936 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/include/winternl.h b/include/winternl.h index a20aca55a0e..3abf69f06b7 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4784,6 +4784,7 @@ NTSYSAPI NTSTATUS WINAPI NtCreateTimer(HANDLE*, ACCESS_MASK, const OBJECT_ATTRI NTSYSAPI NTSTATUS WINAPI NtCreateToken(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,TOKEN_TYPE,PLUID,PLARGE_INTEGER,PTOKEN_USER,PTOKEN_GROUPS,PTOKEN_PRIVILEGES,PTOKEN_OWNER,PTOKEN_PRIMARY_GROUP,PTOKEN_DEFAULT_DACL,PTOKEN_SOURCE); NTSYSAPI NTSTATUS WINAPI NtCreateTransaction(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,LPGUID,HANDLE,ULONG,ULONG,ULONG,PLARGE_INTEGER,PUNICODE_STRING); NTSYSAPI NTSTATUS WINAPI NtCreateUserProcess(HANDLE*,HANDLE*,ACCESS_MASK,ACCESS_MASK,OBJECT_ATTRIBUTES*,OBJECT_ATTRIBUTES*,ULONG,ULONG,RTL_USER_PROCESS_PARAMETERS*,PS_CREATE_INFO*,PS_ATTRIBUTE_LIST*); +NTSYSAPI NTSTATUS WINAPI NtCreateWaitablePort(PHANDLE,POBJECT_ATTRIBUTES,ULONG,ULONG,ULONG); NTSYSAPI NTSTATUS WINAPI NtDebugActiveProcess(HANDLE,HANDLE); NTSYSAPI NTSTATUS WINAPI NtDebugContinue(HANDLE,CLIENT_ID*,NTSTATUS); NTSYSAPI NTSTATUS WINAPI NtDelayExecution(BOOLEAN,const LARGE_INTEGER*); diff --git a/server/Makefile.in b/server/Makefile.in index 84a6bd74d9d..b6dc080896c 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -18,6 +18,7 @@ SOURCES = \ handle.c \ hook.c \ inproc_sync.c \ + lpc_port.c \ mach.c \ mailslot.c \ main.c \ diff --git a/server/lpc_port.c b/server/lpc_port.c new file mode 100644 index 00000000000..2f1d4cc83ff --- /dev/null +++ b/server/lpc_port.c @@ -0,0 +1,1044 @@ +/* + * Server-side LPC port management + * + * Copyright 2026 Wine project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" + +#include "handle.h" +#include "thread.h" +#include "process.h" +#include "request.h" +#include "security.h" +#include "object.h" + +/* PORT_ALL_ACCESS, combining standard rights with port-specific rights */ +#define PORT_CONNECT 0x0001 +#define PORT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | PORT_CONNECT) + +/* Port types */ +#define PORT_TYPE_SERVER 0x01 /* Named port that server listens on */ +#define PORT_TYPE_CLIENT 0x02 /* Client's end of connection */ +#define PORT_TYPE_CHANNEL 0x03 /* Server's per-client communication channel */ +#define PORT_TYPE_UNNAMED 0x04 /* Unnamed port */ + +/* Port flags */ +#define PORT_FLAG_WAITABLE 0x0001 + +/* LPC message types */ +#define LPC_REQUEST 1 +#define LPC_REPLY 2 +#define LPC_DATAGRAM 3 +#define LPC_LOST_REPLY 4 +#define LPC_PORT_CLOSED 5 +#define LPC_CLIENT_DIED 6 +#define LPC_EXCEPTION 7 +#define LPC_DEBUG_EVENT 8 +#define LPC_ERROR_EVENT 9 +#define LPC_CONNECTION_REQUEST 10 + +/* Maximum message size */ +#define MAX_LPC_MESSAGE_SIZE 0x40000 +#define MAX_LPC_DATA_SIZE 0x100000 + +/* Global counter for generating unique message IDs across all ports */ +static unsigned int global_msg_id_counter = 0; + +/* Global list of pending connection requests, allows NtAcceptConnectPort to find + * connections by message ID without needing a server port handle */ +static struct list global_pending_connects = LIST_INIT(global_pending_connects); + +/* Global list of pending requests awaiting replies, tracks which client is + * waiting for a reply to which message ID */ +static struct list global_pending_requests = LIST_INIT(global_pending_requests); + +/* Pending request entry, tracks who sent a request and is waiting for reply */ +struct pending_request +{ + struct list entry; /* entry in global_pending_requests */ + unsigned int msg_id; /* message ID waiting for reply */ + struct lpc_port *client_port; /* client port to deliver reply to */ +}; + +/* Entry in thread's list of registered terminate ports */ +struct lpc_terminate_port_entry +{ + struct list entry; /* entry in thread's lpc_terminate_ports list */ + struct lpc_port *port; /* port to notify on thread termination */ +}; + +static const WCHAR lpc_port_name[] = {'L','P','C',' ','P','o','r','t'}; + +struct type_descr lpc_port_type = +{ + { lpc_port_name, sizeof(lpc_port_name) }, /* name */ + PORT_ALL_ACCESS, /* valid_access */ + { /* mapping */ + STANDARD_RIGHTS_READ | PORT_CONNECT, + STANDARD_RIGHTS_WRITE, + STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, + PORT_ALL_ACCESS + }, +}; + +/* Internal message structure, holds queued messages */ +struct lpc_message +{ + struct list entry; /* queue entry (port's pending_connects list) */ + struct list global_entry; /* entry in global_pending_connects */ + struct lpc_port *sender_port; /* port that sent this message */ + struct lpc_port *server_port; /* server port (for connection requests) */ + struct thread *sender_thread; /* thread that sent this message */ + unsigned int msg_id; /* unique message ID */ + unsigned int msg_type; /* LPC_REQUEST, LPC_REPLY, etc. */ + process_id_t client_pid; /* sender's process ID */ + thread_id_t client_tid; /* sender's thread ID */ + client_ptr_t port_context; /* port context for this message */ + data_size_t data_size; /* size of message data */ + char data[1]; /* variable-length message data */ +}; + +/* Thread waiting for a reply */ +struct lpc_reply_wait +{ + struct list entry; /* list entry in reply_waiters */ + struct thread *thread; /* thread waiting for reply */ + unsigned int msg_id; /* message ID we're waiting for */ + struct object *event; /* sync object to signal when reply arrives */ + struct lpc_message *reply; /* reply message (set when received) */ +}; + +/* LPC port object */ +struct lpc_port +{ + struct object obj; /* object header */ + unsigned int port_type; /* PORT_TYPE_* */ + unsigned int flags; /* PORT_FLAG_* */ + + /* Port relationships */ + struct lpc_port *connection_port; /* reference to connection port */ + struct lpc_port *connected_port; /* paired port: client <-> communication */ + + /* Message queue */ + struct list msg_queue; /* list of pending lpc_message */ + struct object *queue_event; /* event signaled when message arrives */ + + /* Connection tracking */ + struct list pending_connects;/* list of pending connection lpc_message */ + struct list reply_waiters; /* list of lpc_reply_wait entries */ + + /* Limits */ + unsigned int max_msg_len; /* maximum message length */ + unsigned int max_connect_info;/* maximum connection info length */ + + /* Waitable port support */ + struct object *wait_event; /* event for WaitForSingleObject (waitable ports) */ + + /* Security/context */ + struct process *server_process; /* server process (for connection ports) */ + client_ptr_t port_context; /* user-defined port context */ + + /* For communication ports: track the client thread during accept */ + struct thread *client_thread; /* client thread (for NtCompleteConnectPort) */ + + /* Message ID counter */ + unsigned int next_msg_id; + + /* Connection status */ + struct object *connect_event; /* event signaled when connection completes */ + unsigned int connect_status; /* STATUS_SUCCESS or error code from accept */ +}; + +static void lpc_port_dump( struct object *obj, int verbose ); +static struct object *lpc_port_get_sync( struct object *obj ); +static void lpc_port_destroy( struct object *obj ); + +static const struct object_ops lpc_port_ops = +{ + sizeof(struct lpc_port), /* size */ + &lpc_port_type, /* type */ + lpc_port_dump, /* dump */ + NULL, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + lpc_port_get_sync, /* get_sync */ + default_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + default_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + directory_link_name, /* link_name */ + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + lpc_port_destroy /* destroy */ +}; + +/* Allocate a new message with the given data size */ +static struct lpc_message *alloc_lpc_message( data_size_t data_size ) +{ + struct lpc_message *msg; + data_size_t alloc_size; + + if (data_size > MAX_LPC_DATA_SIZE) + { + set_error( STATUS_INVALID_PARAMETER ); + return NULL; + } + + /* Allocate at least enough for the full struct (including 1-byte data array) */ + alloc_size = max( sizeof(struct lpc_message), offsetof(struct lpc_message, data) + data_size ); + msg = mem_alloc( alloc_size ); + if (msg) + { + memset( msg, 0, alloc_size ); + list_init( &msg->global_entry ); + msg->data_size = data_size; + } + return msg; +} + +/* Free a message */ +static void free_lpc_message( struct lpc_message *msg ) +{ + if (msg) + { + /* Remove from global list if present */ + if (!list_empty( &msg->global_entry )) + list_remove( &msg->global_entry ); + if (msg->sender_port) release_object( msg->sender_port ); + if (msg->server_port) release_object( msg->server_port ); + if (msg->sender_thread) release_object( msg->sender_thread ); + free( msg ); + } +} + +/* Get the next globally unique message ID */ +static unsigned int get_next_msg_id( void ) +{ + return ++global_msg_id_counter; +} + +/* Signal the port's queue event to wake waiting threads */ +static void signal_port_queue( struct lpc_port *port ) +{ + if (port->queue_event) + signal_sync( port->queue_event ); + if (port->wait_event) + signal_sync( port->wait_event ); +} + +/* Reset the port's queue event after receiving a message */ +static void reset_port_queue( struct lpc_port *port ) +{ + if (list_empty( &port->msg_queue ) && list_empty( &port->pending_connects )) + { + if (port->queue_event) + reset_sync( port->queue_event ); + if (port->wait_event) + reset_sync( port->wait_event ); + } +} + +static struct lpc_port *create_lpc_port( struct object *root, const struct unicode_str *name, + unsigned int attr, unsigned int flags, + unsigned int max_msg_len, unsigned int max_connect_info, + const struct security_descriptor *sd ) +{ + struct lpc_port *port; + + if (max_msg_len > MAX_LPC_MESSAGE_SIZE) + max_msg_len = MAX_LPC_MESSAGE_SIZE; + if (max_connect_info > MAX_LPC_MESSAGE_SIZE) + max_connect_info = MAX_LPC_MESSAGE_SIZE; + + if ((port = create_named_object( root, &lpc_port_ops, name, attr, sd ))) + { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) + { + /* Initialize new port */ + port->flags = flags; + port->connection_port = NULL; + port->connected_port = NULL; + list_init( &port->msg_queue ); + port->queue_event = NULL; + list_init( &port->pending_connects ); + list_init( &port->reply_waiters ); + port->max_msg_len = max_msg_len ? max_msg_len : MAX_LPC_MESSAGE_SIZE; + port->max_connect_info = max_connect_info ? max_connect_info : 256; + port->wait_event = NULL; + port->server_process = NULL; + port->port_context = 0; + port->client_thread = NULL; + port->next_msg_id = 0; + port->connect_event = NULL; + port->connect_status = STATUS_PENDING; + + /* Determine port type based on whether it has a name */ + if (name->len) + { + port->port_type = PORT_TYPE_SERVER; + port->connection_port = (struct lpc_port *)grab_object( port ); + port->server_process = (struct process *)grab_object( current->process ); + } + else + { + port->port_type = PORT_TYPE_UNNAMED; + port->connected_port = (struct lpc_port *)grab_object( port ); + } + + /* Create queue event for message notification */ + port->queue_event = create_internal_sync( 0, 0 ); + if (!port->queue_event) + { + release_object( port ); + return NULL; + } + + /* Create wait event for waitable ports */ + if (flags & PORT_FLAG_WAITABLE) + { + port->wait_event = create_internal_sync( 1, 0 ); + if (!port->wait_event) + { + release_object( port ); + return NULL; + } + } + } + } + return port; +} + +/* Create a client or communication port (internal, no name) */ +static struct lpc_port *create_port_internal( unsigned int port_type, struct lpc_port *connection_port ) +{ + struct lpc_port *port; + + port = alloc_object( &lpc_port_ops ); + if (!port) return NULL; + + port->port_type = port_type; + port->flags = 0; + port->connection_port = (struct lpc_port *)grab_object( connection_port ); + port->connected_port = NULL; + list_init( &port->msg_queue ); + port->queue_event = create_internal_sync( 0, 0 ); + list_init( &port->pending_connects ); + list_init( &port->reply_waiters ); + port->max_msg_len = connection_port->max_msg_len; + port->max_connect_info = connection_port->max_connect_info; + port->wait_event = NULL; + port->server_process = NULL; + port->port_context = 0; + port->client_thread = NULL; + port->next_msg_id = 0; + port->connect_event = NULL; + port->connect_status = STATUS_PENDING; + + /* For client ports, create a connect event for NtConnectPort to wait on. + * Use create_server_internal_sync (not create_internal_sync) so this works + * even when inproc sync is available, inproc sync objects can't be waited + * on via server-side wait queues. */ + if (port_type == PORT_TYPE_CLIENT) + { + port->connect_event = (struct object *)create_server_internal_sync( 1, 0 ); /* manual reset, not signaled */ + if (!port->connect_event) + { + release_object( port ); + return NULL; + } + } + + if (!port->queue_event) + { + release_object( port ); + return NULL; + } + + return port; +} + +/* Find a pending connection message by message ID (global) */ +static struct lpc_message *find_pending_connect_global( unsigned int msg_id ) +{ + struct lpc_message *msg; + + LIST_FOR_EACH_ENTRY( msg, &global_pending_connects, struct lpc_message, global_entry ) + { + if (msg->msg_id == msg_id) + return msg; + } + return NULL; +} + +/* Track a pending request awaiting reply */ +static void track_pending_request( unsigned int msg_id, struct lpc_port *client_port ) +{ + struct pending_request *pr = mem_alloc( sizeof(*pr) ); + if (pr) + { + pr->msg_id = msg_id; + pr->client_port = (struct lpc_port *)grab_object( client_port ); + list_add_tail( &global_pending_requests, &pr->entry ); + } +} + +/* Find and remove a pending request by message ID */ +static struct lpc_port *find_pending_request_client( unsigned int msg_id ) +{ + struct pending_request *pr; + + LIST_FOR_EACH_ENTRY( pr, &global_pending_requests, struct pending_request, entry ) + { + if (pr->msg_id == msg_id) + { + struct lpc_port *client = pr->client_port; + list_remove( &pr->entry ); + /* Don't release client_port, caller takes ownership */ + free( pr ); + return client; + } + } + return NULL; +} + +static void lpc_port_dump( struct object *obj, int verbose ) +{ + struct lpc_port *port = (struct lpc_port *)obj; + static const char *type_names[] = { "???", "SERVER", "CLIENT", "CHANNEL", "UNNAMED" }; + const char *type_name = port->port_type < 5 ? type_names[port->port_type] : "???"; + + assert( obj->ops == &lpc_port_ops ); + fprintf( stderr, "LPC Port type=%s flags=%04x max_msg=%u max_connect=%u\n", + type_name, port->flags, port->max_msg_len, port->max_connect_info ); +} + +static struct object *lpc_port_get_sync( struct object *obj ) +{ + struct lpc_port *port = (struct lpc_port *)obj; + assert( obj->ops == &lpc_port_ops ); + + /* For client ports with a connect_event, always return it. The event + * will be signaled when the connection completes (either success or refused). + * This allows NtConnectPort to wait on the port handle until complete. */ + if (port->port_type == PORT_TYPE_CLIENT && port->connect_event) + return grab_object( port->connect_event ); + + /* For waitable ports, return the wait event */ + if (port->wait_event) + return grab_object( port->wait_event ); + + /* For non-waitable ports, return the queue event (allows internal waiting) */ + if (port->queue_event) + return grab_object( port->queue_event ); + + return grab_object( obj ); +} + +static void lpc_port_destroy( struct object *obj ) +{ + struct lpc_port *port = (struct lpc_port *)obj; + struct lpc_message *msg, *next_msg; + struct lpc_reply_wait *wait, *next_wait; + + assert( obj->ops == &lpc_port_ops ); + + /* Free all queued messages */ + LIST_FOR_EACH_ENTRY_SAFE( msg, next_msg, &port->msg_queue, struct lpc_message, entry ) + { + list_remove( &msg->entry ); + free_lpc_message( msg ); + } + + /* Free all pending connection messages */ + LIST_FOR_EACH_ENTRY_SAFE( msg, next_msg, &port->pending_connects, struct lpc_message, entry ) + { + list_remove( &msg->entry ); + free_lpc_message( msg ); + } + + /* Wake and clean up any reply waiters */ + LIST_FOR_EACH_ENTRY_SAFE( wait, next_wait, &port->reply_waiters, struct lpc_reply_wait, entry ) + { + list_remove( &wait->entry ); + if (wait->event) + { + signal_sync( wait->event ); + release_object( wait->event ); + } + if (wait->thread) release_object( wait->thread ); + if (wait->reply) free_lpc_message( wait->reply ); + free( wait ); + } + + /* Release references */ + if (port->queue_event) release_object( port->queue_event ); + if (port->wait_event) release_object( port->wait_event ); + if (port->connect_event) release_object( port->connect_event ); + if (port->connection_port && port->connection_port != port) + release_object( port->connection_port ); + if (port->connected_port && port->connected_port != port) + release_object( port->connected_port ); + if (port->server_process) release_object( port->server_process ); + if (port->client_thread) release_object( port->client_thread ); +} + +/* Create an LPC port */ +DECL_HANDLER(create_lpc_port) +{ + struct lpc_port *port; + struct unicode_str name; + struct object *root; + const struct security_descriptor *sd; + const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); + + if (!objattr) return; + + if ((port = create_lpc_port( root, &name, objattr->attributes, req->flags, + req->max_msg_len, req->max_connect_info, sd ))) + { + if (get_error() == STATUS_OBJECT_NAME_EXISTS) + reply->handle = alloc_handle( current->process, port, req->access, objattr->attributes ); + else + reply->handle = alloc_handle_no_access_check( current->process, port, + req->access, objattr->attributes ); + release_object( port ); + } + + if (root) release_object( root ); +} + +/* Connect to an LPC port */ +DECL_HANDLER(connect_lpc_port) +{ + struct lpc_port *connection_port; + struct lpc_port *client_port; + struct lpc_message *msg; + struct unicode_str name; + struct object *root; + const struct security_descriptor *sd; + const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); + data_size_t info_size = get_req_data_size(); + + if (!objattr) return; + + /* Look up the connection port by name */ + connection_port = (struct lpc_port *)open_named_object( root, &lpc_port_ops, &name, objattr->attributes ); + if (root) release_object( root ); + + if (!connection_port) + { + set_error( STATUS_OBJECT_NAME_NOT_FOUND ); + return; + } + + if (connection_port->port_type != PORT_TYPE_SERVER) + { + release_object( connection_port ); + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + return; + } + + /* Create the client port */ + client_port = create_port_internal( PORT_TYPE_CLIENT, connection_port ); + if (!client_port) + { + release_object( connection_port ); + return; + } + + /* Create connection request message */ + msg = alloc_lpc_message( info_size ); + if (!msg) + { + release_object( client_port ); + release_object( connection_port ); + return; + } + + msg->sender_port = (struct lpc_port *)grab_object( client_port ); + msg->server_port = (struct lpc_port *)grab_object( connection_port ); + msg->sender_thread = (struct thread *)grab_object( current ); + msg->msg_id = get_next_msg_id(); + msg->msg_type = LPC_CONNECTION_REQUEST; + msg->client_pid = current->process->id; + msg->client_tid = current->id; + if (info_size) + memcpy( msg->data, get_req_data(), info_size ); + + /* Queue the connection request on the connection port and global list */ + list_add_tail( &connection_port->pending_connects, &msg->entry ); + list_add_tail( &global_pending_connects, &msg->global_entry ); + signal_port_queue( connection_port ); + + /* Return the client port handle, actual connection completes later */ + reply->handle = alloc_handle_no_access_check( current->process, client_port, + req->access, objattr->attributes ); + reply->info_size = 0; + + release_object( client_port ); + release_object( connection_port ); +} + +/* Listen for connection requests on a port */ +DECL_HANDLER(listen_lpc_port) +{ + struct lpc_port *port; + struct lpc_message *msg; + + port = (struct lpc_port *)get_handle_obj( current->process, req->handle, + PORT_CONNECT, &lpc_port_ops ); + if (!port) return; + + if (port->port_type != PORT_TYPE_SERVER) + { + set_error( STATUS_INVALID_PORT_HANDLE ); + release_object( port ); + return; + } + + /* Check for pending connection requests */ + if (list_empty( &port->pending_connects )) + { + /* No pending connections, caller should wait on the port */ + set_error( STATUS_PENDING ); + release_object( port ); + return; + } + + /* Get the first pending connection */ + msg = LIST_ENTRY( list_head( &port->pending_connects ), struct lpc_message, entry ); + + reply->message = 0; /* Currently unused */ + reply->msg_size = msg->data_size; + reply->client_pid = msg->client_pid; + reply->client_tid = msg->client_tid; + reply->msg_id = msg->msg_id; + + /* Return connection info */ + if (msg->data_size) + set_reply_data( msg->data, min( msg->data_size, get_reply_max_size() ) ); + + reset_port_queue( port ); + release_object( port ); +} + +/* Accept or reject a connection */ +DECL_HANDLER(accept_lpc_connect) +{ + struct lpc_port *connection_port; + struct lpc_port *comm_port = NULL; + struct lpc_port *client_port; + struct lpc_message *msg; + + /* Find the pending connection by message ID from global list. */ + msg = find_pending_connect_global( req->msg_id ); + if (!msg) + { + set_error( STATUS_INVALID_CID ); + return; + } + + /* Get the server port from the message */ + connection_port = msg->server_port; + if (!connection_port || connection_port->port_type != PORT_TYPE_SERVER) + { + set_error( STATUS_INVALID_PORT_HANDLE ); + return; + } + + client_port = msg->sender_port; + + /* Note: The message was already removed from the port's pending_connects list + * by reply_wait_receive_lpc. The global_entry is removed by free_lpc_message. */ + + if (req->accept) + { + /* Create server communication port */ + comm_port = create_port_internal( PORT_TYPE_CHANNEL, connection_port ); + if (!comm_port) + { + free_lpc_message( msg ); + return; + } + + /* Link client and communication ports */ + comm_port->connected_port = (struct lpc_port *)grab_object( client_port ); + client_port->connected_port = (struct lpc_port *)grab_object( comm_port ); + + /* Mark client connection as successful (will be completed by NtCompleteConnectPort) */ + client_port->connect_status = STATUS_SUCCESS; + + /* Set port context */ + comm_port->port_context = req->context; + + /* Save client thread for NtCompleteConnectPort */ + if (msg->sender_thread) + comm_port->client_thread = (struct thread *)grab_object( msg->sender_thread ); + + reply->handle = alloc_handle_no_access_check( current->process, comm_port, + PORT_ALL_ACCESS, 0 ); + release_object( comm_port ); + } + else + { + /* Connection refused. Set status and signal client immediately */ + client_port->connect_status = STATUS_PORT_CONNECTION_REFUSED; + if (client_port->connect_event) + signal_sync( client_port->connect_event ); + reply->handle = 0; + } + + free_lpc_message( msg ); +} + +/* Complete the connection (wake the client) */ +DECL_HANDLER(complete_lpc_connect) +{ + struct lpc_port *port; + struct lpc_port *client_port; + + port = (struct lpc_port *)get_handle_obj( current->process, req->handle, + PORT_CONNECT, &lpc_port_ops ); + if (!port) return; + + if (port->port_type != PORT_TYPE_CHANNEL) + { + set_error( STATUS_INVALID_PORT_HANDLE ); + release_object( port ); + return; + } + + /* Signal the client port's connect_event to wake up the waiting NtConnectPort call */ + client_port = port->connected_port; + if (client_port && client_port->connect_event) + signal_sync( client_port->connect_event ); + + /* Release client thread reference */ + if (port->client_thread) + { + release_object( port->client_thread ); + port->client_thread = NULL; + } + + release_object( port ); +} + +/* Get connection status for client port */ +DECL_HANDLER(get_lpc_connect_status) +{ + struct lpc_port *port; + + port = (struct lpc_port *)get_handle_obj( current->process, req->handle, + PORT_CONNECT, &lpc_port_ops ); + if (!port) return; + + if (port->port_type != PORT_TYPE_CLIENT) + { + set_error( STATUS_INVALID_PORT_HANDLE ); + release_object( port ); + return; + } + + reply->status = port->connect_status; + release_object( port ); +} + +/* Send a request and wait for reply */ +DECL_HANDLER(request_lpc_reply) +{ + struct lpc_port *port; + struct lpc_port *target_port; + struct lpc_message *msg; + data_size_t data_size = get_req_data_size(); + + port = (struct lpc_port *)get_handle_obj( current->process, req->handle, + PORT_CONNECT, &lpc_port_ops ); + if (!port) return; + + /* Determine target port based on port type */ + if (port->port_type == PORT_TYPE_CLIENT) + { + /* Client sends to server. Messages go to the server's connection port + * so they can be received via NtReplyWaitReceivePort on the server port. */ + if (!port->connected_port || !port->connected_port->connection_port) + { + set_error( STATUS_PORT_DISCONNECTED ); + release_object( port ); + return; + } + /* Target is the connection (server) port */ + target_port = port->connected_port->connection_port; + } + else if (port->port_type == PORT_TYPE_CHANNEL) + { + /* Server sends to client via connected client port */ + if (!port->connected_port) + { + set_error( STATUS_PORT_DISCONNECTED ); + release_object( port ); + return; + } + target_port = port->connected_port; + } + else + { + set_error( STATUS_INVALID_PORT_HANDLE ); + release_object( port ); + return; + } + + msg = alloc_lpc_message( data_size ); + if (!msg) + { + release_object( port ); + return; + } + + msg->sender_port = (struct lpc_port *)grab_object( port ); + msg->sender_thread = (struct thread *)grab_object( current ); + msg->msg_id = get_next_msg_id(); + msg->msg_type = req->msg_type ? req->msg_type : LPC_REQUEST; + msg->client_pid = current->process->id; + msg->client_tid = current->id; + msg->port_context = port->port_context; + if (data_size) + memcpy( msg->data, get_req_data(), data_size ); + + /* For LPC_REQUEST messages, track that client is waiting for a reply */ + if (msg->msg_type == LPC_REQUEST && port->port_type == PORT_TYPE_CLIENT) + track_pending_request( msg->msg_id, port ); + + /* Queue message to target */ + list_add_tail( &target_port->msg_queue, &msg->entry ); + signal_port_queue( target_port ); + + reply->msg_id = msg->msg_id; + + release_object( port ); +} + +/* Reply to a message and wait for next one */ +DECL_HANDLER(reply_wait_receive_lpc) +{ + struct lpc_port *port; + struct lpc_port *receive_port; + struct lpc_message *msg; + data_size_t reply_size = get_req_data_size(); + + port = (struct lpc_port *)get_handle_obj( current->process, req->handle, + PORT_CONNECT, &lpc_port_ops ); + if (!port) return; + + /* Handle reply to previous message */ + if (req->reply_msg_id) + { + struct lpc_port *client_port; + struct lpc_message *reply_msg; + + /* Find the client that's waiting for this reply */ + client_port = find_pending_request_client( req->reply_msg_id ); + if (client_port) + { + /* Create and queue reply message to client */ + reply_msg = alloc_lpc_message( reply_size ); + if (reply_msg) + { + reply_msg->msg_type = LPC_REPLY; + reply_msg->msg_id = req->reply_msg_id; + reply_msg->client_pid = current->process->id; + reply_msg->client_tid = current->id; + reply_msg->data_size = reply_size; + if (reply_size) + memcpy( reply_msg->data, get_req_data(), reply_size ); + + list_add_tail( &client_port->msg_queue, &reply_msg->entry ); + signal_port_queue( client_port ); + } + release_object( client_port ); + } + } + + /* Determine which port to receive from */ + if (port->port_type == PORT_TYPE_CHANNEL || port->port_type == PORT_TYPE_CLIENT) + receive_port = port; + else if (port->port_type == PORT_TYPE_SERVER) + receive_port = port; + else + { + set_error( STATUS_INVALID_PORT_HANDLE ); + release_object( port ); + return; + } + + /* Check for pending messages */ + if (list_empty( &receive_port->msg_queue )) + { + /* Also check pending connects for connection ports */ + if (port->port_type == PORT_TYPE_SERVER && !list_empty( &port->pending_connects )) + { + msg = LIST_ENTRY( list_head( &port->pending_connects ), struct lpc_message, entry ); + + /* Remove from port's pending list so it won't be returned again. + * Keep it in the global list so NtAcceptConnectPort can find it by message ID. */ + list_remove( &msg->entry ); + + /* Return message info */ + reply->msg_id = msg->msg_id; + reply->msg_type = msg->msg_type; + reply->client_pid = msg->client_pid; + reply->client_tid = msg->client_tid; + reply->context = msg->port_context; + reply->data_size = msg->data_size; + + if (msg->data_size) + set_reply_data( msg->data, min( msg->data_size, get_reply_max_size() ) ); + + reset_port_queue( receive_port ); + release_object( port ); + return; + } + else + { + /* No messages. Caller should wait */ + set_error( STATUS_PENDING ); + release_object( port ); + return; + } + } + else + { + /* Get first message from queue */ + msg = LIST_ENTRY( list_head( &receive_port->msg_queue ), struct lpc_message, entry ); + list_remove( &msg->entry ); + } + + /* Return message info */ + reply->msg_id = msg->msg_id; + reply->msg_type = msg->msg_type; + reply->client_pid = msg->client_pid; + reply->client_tid = msg->client_tid; + reply->context = msg->port_context; + reply->data_size = msg->data_size; + + if (msg->data_size) + set_reply_data( msg->data, min( msg->data_size, get_reply_max_size() ) ); + + free_lpc_message( msg ); + reset_port_queue( receive_port ); + release_object( port ); +} + +/* Register a port to receive LPC_CLIENT_DIED when thread terminates */ +DECL_HANDLER(register_lpc_terminate_port) +{ + struct lpc_port *port; + struct lpc_terminate_port_entry *entry; + + port = (struct lpc_port *)get_handle_obj( current->process, req->handle, + 0, &lpc_port_ops ); + if (!port) return; + + /* Only client ports should be registered for termination */ + if (port->port_type != PORT_TYPE_CLIENT) + { + set_error( STATUS_INVALID_PORT_HANDLE ); + release_object( port ); + return; + } + + /* Check if already registered */ + LIST_FOR_EACH_ENTRY( entry, ¤t->lpc_terminate_ports, struct lpc_terminate_port_entry, entry ) + { + if (entry->port == port) + { + release_object( port ); + return; + } + } + + /* Add to thread's terminate port list */ + entry = mem_alloc( sizeof(*entry) ); + if (entry) + { + entry->port = port; + list_add_tail( ¤t->lpc_terminate_ports, &entry->entry ); + } + else + { + release_object( port ); + } +} + +/* Send LPC_CLIENT_DIED messages to all registered ports for a thread. + * Called from cleanup_thread in thread.c */ +void lpc_send_client_died( struct thread *thread ) +{ + struct lpc_terminate_port_entry *entry, *next; + + LIST_FOR_EACH_ENTRY_SAFE( entry, next, &thread->lpc_terminate_ports, + struct lpc_terminate_port_entry, entry ) + { + struct lpc_port *client_port = entry->port; + + /* Send LPC_CLIENT_DIED to the server port via the communication channel */ + if (client_port && client_port->connected_port) + { + struct lpc_port *comm_port = client_port->connected_port; + struct lpc_port *server_port = comm_port->connection_port; + + if (server_port && server_port->port_type == PORT_TYPE_SERVER) + { + struct lpc_message *died_msg = alloc_lpc_message( 0 ); + if (died_msg) + { + died_msg->msg_id = get_next_msg_id(); + died_msg->msg_type = LPC_CLIENT_DIED; + died_msg->client_pid = thread->process->id; + died_msg->client_tid = thread->id; + died_msg->port_context = comm_port->port_context; + + /* Queue on server port */ + list_add_tail( &server_port->msg_queue, &died_msg->entry ); + signal_port_queue( server_port ); + } + } + } + + /* Clean up the entry */ + list_remove( &entry->entry ); + release_object( client_port ); + free( entry ); + } +} diff --git a/server/object.h b/server/object.h index 4d96740de03..b0f0784d2e4 100644 --- a/server/object.h +++ b/server/object.h @@ -242,6 +242,10 @@ extern void reset_event( struct event *event ); extern void abandon_mutexes( struct thread *thread ); extern void abandon_d3dkmt_mutexes( struct thread *thread ); +/* LPC port functions */ + +extern void lpc_send_client_died( struct thread *thread ); + /* in-process synchronization functions */ struct inproc_sync; diff --git a/server/protocol.def b/server/protocol.def index 5bca381fd91..3b91cf4e5bb 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -4274,3 +4274,93 @@ enum inproc_sync_type data_size_t runtime_size; /* size of client runtime data */ VARARG(runtime,bytes); /* client runtime data */ @END + +/* Create an LPC port */ +@REQ(create_lpc_port) + unsigned int access; + unsigned int flags; + unsigned int max_msg_len; + unsigned int max_connect_info; + VARARG(objattr,object_attributes); +@REPLY + obj_handle_t handle; +@END + +/* Connect to an LPC port */ +@REQ(connect_lpc_port) + unsigned int access; + data_size_t info_size; + VARARG(objattr,object_attributes); + VARARG(info,bytes); +@REPLY + obj_handle_t handle; + data_size_t info_size; + VARARG(info,bytes); +@END + +/* Listen fo connection requests */ +@REQ(listen_lpc_port) + obj_handle_t handle; +@REPLY + client_ptr_t message; + data_size_t msg_size; + process_id_t client_pid; + thread_id_t client_tid; + unsigned int msg_id; + VARARG(info,bytes); +@END + +/* Accept or reject a connection */ +@REQ(accept_lpc_connect) + obj_handle_t handle; + int accept; + unsigned int msg_id; + client_ptr_t context; + VARARG(info,bytes); +@REPLY + obj_handle_t handle; +@END + +/* Complete connection */ +@REQ(complete_lpc_connect) + obj_handle_t handle; +@END + +/* Get connection status for client port */ +@REQ(get_lpc_connect_status) + obj_handle_t handle; +@REPLY + unsigned int status; +@END + +/* Send request and wait for reply */ +@REQ(request_lpc_reply) + obj_handle_t handle; + data_size_t data_size; + unsigned int msg_type; + VARARG(data,bytes); +@REPLY + unsigned int msg_id; +@END + +/* Wait for message and reply to previous */ +@REQ(reply_wait_receive_lpc) + obj_handle_t handle; + unsigned int reply_msg_id; + data_size_t reply_size; + timeout_t timeout; + VARARG(reply,bytes); +@REPLY + unsigned int msg_id; + unsigned int msg_type; + process_id_t client_pid; + thread_id_t client_tid; + client_ptr_t context; + data_size_t data_size; + VARARG(data,bytes); +@END + +/* Register a port to receive LPC_CLIENT_DIED when thread terminates */ +@REQ(register_lpc_terminate_port) + obj_handle_t handle; +@END diff --git a/server/request_handlers.h b/server/request_handlers.h index 3c518795340..b337d210aaa 100644 --- a/server/request_handlers.h +++ b/server/request_handlers.h @@ -313,6 +313,15 @@ DECL_HANDLER(d3dkmt_share_objects); DECL_HANDLER(d3dkmt_object_open_name); DECL_HANDLER(d3dkmt_mutex_acquire); DECL_HANDLER(d3dkmt_mutex_release); +DECL_HANDLER(create_lpc_port); +DECL_HANDLER(connect_lpc_port); +DECL_HANDLER(listen_lpc_port); +DECL_HANDLER(accept_lpc_connect); +DECL_HANDLER(complete_lpc_connect); +DECL_HANDLER(get_lpc_connect_status); +DECL_HANDLER(request_lpc_reply); +DECL_HANDLER(reply_wait_receive_lpc); +DECL_HANDLER(register_lpc_terminate_port); typedef void (*req_handler)( const void *req, void *reply ); static const req_handler req_handlers[REQ_NB_REQUESTS] = @@ -623,6 +632,15 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_d3dkmt_object_open_name, (req_handler)req_d3dkmt_mutex_acquire, (req_handler)req_d3dkmt_mutex_release, + (req_handler)req_create_lpc_port, + (req_handler)req_connect_lpc_port, + (req_handler)req_listen_lpc_port, + (req_handler)req_accept_lpc_connect, + (req_handler)req_complete_lpc_connect, + (req_handler)req_get_lpc_connect_status, + (req_handler)req_request_lpc_reply, + (req_handler)req_reply_wait_receive_lpc, + (req_handler)req_register_lpc_terminate_port, }; C_ASSERT( sizeof(abstime_t) == 8 ); @@ -2375,3 +2393,57 @@ C_ASSERT( offsetof(struct d3dkmt_mutex_release_request, key_value) == 20 ); C_ASSERT( offsetof(struct d3dkmt_mutex_release_request, fence_value) == 24 ); C_ASSERT( offsetof(struct d3dkmt_mutex_release_request, runtime_size) == 32 ); C_ASSERT( sizeof(struct d3dkmt_mutex_release_request) == 40 ); +C_ASSERT( offsetof(struct create_lpc_port_request, access) == 12 ); +C_ASSERT( offsetof(struct create_lpc_port_request, flags) == 16 ); +C_ASSERT( offsetof(struct create_lpc_port_request, max_msg_len) == 20 ); +C_ASSERT( offsetof(struct create_lpc_port_request, max_connect_info) == 24 ); +C_ASSERT( sizeof(struct create_lpc_port_request) == 32 ); +C_ASSERT( offsetof(struct create_lpc_port_reply, handle) == 8 ); +C_ASSERT( sizeof(struct create_lpc_port_reply) == 16 ); +C_ASSERT( offsetof(struct connect_lpc_port_request, access) == 12 ); +C_ASSERT( offsetof(struct connect_lpc_port_request, info_size) == 16 ); +C_ASSERT( sizeof(struct connect_lpc_port_request) == 24 ); +C_ASSERT( offsetof(struct connect_lpc_port_reply, handle) == 8 ); +C_ASSERT( offsetof(struct connect_lpc_port_reply, info_size) == 12 ); +C_ASSERT( sizeof(struct connect_lpc_port_reply) == 16 ); +C_ASSERT( offsetof(struct listen_lpc_port_request, handle) == 12 ); +C_ASSERT( sizeof(struct listen_lpc_port_request) == 16 ); +C_ASSERT( offsetof(struct listen_lpc_port_reply, message) == 8 ); +C_ASSERT( offsetof(struct listen_lpc_port_reply, msg_size) == 16 ); +C_ASSERT( offsetof(struct listen_lpc_port_reply, client_pid) == 20 ); +C_ASSERT( offsetof(struct listen_lpc_port_reply, client_tid) == 24 ); +C_ASSERT( offsetof(struct listen_lpc_port_reply, msg_id) == 28 ); +C_ASSERT( sizeof(struct listen_lpc_port_reply) == 32 ); +C_ASSERT( offsetof(struct accept_lpc_connect_request, handle) == 12 ); +C_ASSERT( offsetof(struct accept_lpc_connect_request, accept) == 16 ); +C_ASSERT( offsetof(struct accept_lpc_connect_request, msg_id) == 20 ); +C_ASSERT( offsetof(struct accept_lpc_connect_request, context) == 24 ); +C_ASSERT( sizeof(struct accept_lpc_connect_request) == 32 ); +C_ASSERT( offsetof(struct accept_lpc_connect_reply, handle) == 8 ); +C_ASSERT( sizeof(struct accept_lpc_connect_reply) == 16 ); +C_ASSERT( offsetof(struct complete_lpc_connect_request, handle) == 12 ); +C_ASSERT( sizeof(struct complete_lpc_connect_request) == 16 ); +C_ASSERT( offsetof(struct get_lpc_connect_status_request, handle) == 12 ); +C_ASSERT( sizeof(struct get_lpc_connect_status_request) == 16 ); +C_ASSERT( offsetof(struct get_lpc_connect_status_reply, status) == 8 ); +C_ASSERT( sizeof(struct get_lpc_connect_status_reply) == 16 ); +C_ASSERT( offsetof(struct request_lpc_reply_request, handle) == 12 ); +C_ASSERT( offsetof(struct request_lpc_reply_request, data_size) == 16 ); +C_ASSERT( offsetof(struct request_lpc_reply_request, msg_type) == 20 ); +C_ASSERT( sizeof(struct request_lpc_reply_request) == 24 ); +C_ASSERT( offsetof(struct request_lpc_reply_reply, msg_id) == 8 ); +C_ASSERT( sizeof(struct request_lpc_reply_reply) == 16 ); +C_ASSERT( offsetof(struct reply_wait_receive_lpc_request, handle) == 12 ); +C_ASSERT( offsetof(struct reply_wait_receive_lpc_request, reply_msg_id) == 16 ); +C_ASSERT( offsetof(struct reply_wait_receive_lpc_request, reply_size) == 20 ); +C_ASSERT( offsetof(struct reply_wait_receive_lpc_request, timeout) == 24 ); +C_ASSERT( sizeof(struct reply_wait_receive_lpc_request) == 32 ); +C_ASSERT( offsetof(struct reply_wait_receive_lpc_reply, msg_id) == 8 ); +C_ASSERT( offsetof(struct reply_wait_receive_lpc_reply, msg_type) == 12 ); +C_ASSERT( offsetof(struct reply_wait_receive_lpc_reply, client_pid) == 16 ); +C_ASSERT( offsetof(struct reply_wait_receive_lpc_reply, client_tid) == 20 ); +C_ASSERT( offsetof(struct reply_wait_receive_lpc_reply, context) == 24 ); +C_ASSERT( offsetof(struct reply_wait_receive_lpc_reply, data_size) == 32 ); +C_ASSERT( sizeof(struct reply_wait_receive_lpc_reply) == 40 ); +C_ASSERT( offsetof(struct register_lpc_terminate_port_request, handle) == 12 ); +C_ASSERT( sizeof(struct register_lpc_terminate_port_request) == 16 ); diff --git a/server/request_trace.h b/server/request_trace.h index d31263cbfb4..80f7b467796 100644 --- a/server/request_trace.h +++ b/server/request_trace.h @@ -3512,6 +3512,117 @@ static void dump_d3dkmt_mutex_release_request( const struct d3dkmt_mutex_release dump_varargs_bytes( ", runtime=", cur_size ); } +static void dump_create_lpc_port_request( const struct create_lpc_port_request *req ) +{ + fprintf( stderr, " access=%08x", req->access ); + fprintf( stderr, ", flags=%08x", req->flags ); + fprintf( stderr, ", max_msg_len=%08x", req->max_msg_len ); + fprintf( stderr, ", max_connect_info=%08x", req->max_connect_info ); + dump_varargs_object_attributes( ", objattr=", cur_size ); +} + +static void dump_create_lpc_port_reply( const struct create_lpc_port_reply *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_connect_lpc_port_request( const struct connect_lpc_port_request *req ) +{ + fprintf( stderr, " access=%08x", req->access ); + fprintf( stderr, ", info_size=%u", req->info_size ); + dump_varargs_object_attributes( ", objattr=", cur_size ); + dump_varargs_bytes( ", info=", cur_size ); +} + +static void dump_connect_lpc_port_reply( const struct connect_lpc_port_reply *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", info_size=%u", req->info_size ); + dump_varargs_bytes( ", info=", cur_size ); +} + +static void dump_listen_lpc_port_request( const struct listen_lpc_port_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_listen_lpc_port_reply( const struct listen_lpc_port_reply *req ) +{ + dump_uint64( " message=", &req->message ); + fprintf( stderr, ", msg_size=%u", req->msg_size ); + fprintf( stderr, ", client_pid=%04x", req->client_pid ); + fprintf( stderr, ", client_tid=%04x", req->client_tid ); + fprintf( stderr, ", msg_id=%08x", req->msg_id ); + dump_varargs_bytes( ", info=", cur_size ); +} + +static void dump_accept_lpc_connect_request( const struct accept_lpc_connect_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", accept=%d", req->accept ); + fprintf( stderr, ", msg_id=%08x", req->msg_id ); + dump_uint64( ", context=", &req->context ); + dump_varargs_bytes( ", info=", cur_size ); +} + +static void dump_accept_lpc_connect_reply( const struct accept_lpc_connect_reply *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_complete_lpc_connect_request( const struct complete_lpc_connect_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_get_lpc_connect_status_request( const struct get_lpc_connect_status_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_get_lpc_connect_status_reply( const struct get_lpc_connect_status_reply *req ) +{ + fprintf( stderr, " status=%08x", req->status ); +} + +static void dump_request_lpc_reply_request( const struct request_lpc_reply_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", data_size=%u", req->data_size ); + fprintf( stderr, ", msg_type=%08x", req->msg_type ); + dump_varargs_bytes( ", data=", cur_size ); +} + +static void dump_request_lpc_reply_reply( const struct request_lpc_reply_reply *req ) +{ + fprintf( stderr, " msg_id=%08x", req->msg_id ); +} + +static void dump_reply_wait_receive_lpc_request( const struct reply_wait_receive_lpc_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", reply_msg_id=%08x", req->reply_msg_id ); + fprintf( stderr, ", reply_size=%u", req->reply_size ); + dump_timeout( ", timeout=", &req->timeout ); + dump_varargs_bytes( ", reply=", cur_size ); +} + +static void dump_reply_wait_receive_lpc_reply( const struct reply_wait_receive_lpc_reply *req ) +{ + fprintf( stderr, " msg_id=%08x", req->msg_id ); + fprintf( stderr, ", msg_type=%08x", req->msg_type ); + fprintf( stderr, ", client_pid=%04x", req->client_pid ); + fprintf( stderr, ", client_tid=%04x", req->client_tid ); + dump_uint64( ", context=", &req->context ); + fprintf( stderr, ", data_size=%u", req->data_size ); + dump_varargs_bytes( ", data=", cur_size ); +} + +static void dump_register_lpc_terminate_port_request( const struct register_lpc_terminate_port_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + typedef void (*dump_func)( const void *req ); static const dump_func req_dumpers[REQ_NB_REQUESTS] = @@ -3822,6 +3933,15 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = (dump_func)dump_d3dkmt_object_open_name_request, (dump_func)dump_d3dkmt_mutex_acquire_request, (dump_func)dump_d3dkmt_mutex_release_request, + (dump_func)dump_create_lpc_port_request, + (dump_func)dump_connect_lpc_port_request, + (dump_func)dump_listen_lpc_port_request, + (dump_func)dump_accept_lpc_connect_request, + (dump_func)dump_complete_lpc_connect_request, + (dump_func)dump_get_lpc_connect_status_request, + (dump_func)dump_request_lpc_reply_request, + (dump_func)dump_reply_wait_receive_lpc_request, + (dump_func)dump_register_lpc_terminate_port_request, }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = @@ -4132,6 +4252,15 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = (dump_func)dump_d3dkmt_object_open_name_reply, (dump_func)dump_d3dkmt_mutex_acquire_reply, NULL, + (dump_func)dump_create_lpc_port_reply, + (dump_func)dump_connect_lpc_port_reply, + (dump_func)dump_listen_lpc_port_reply, + (dump_func)dump_accept_lpc_connect_reply, + NULL, + (dump_func)dump_get_lpc_connect_status_reply, + (dump_func)dump_request_lpc_reply_reply, + (dump_func)dump_reply_wait_receive_lpc_reply, + NULL, }; static const char * const req_names[REQ_NB_REQUESTS] = @@ -4442,6 +4571,15 @@ static const char * const req_names[REQ_NB_REQUESTS] = "d3dkmt_object_open_name", "d3dkmt_mutex_acquire", "d3dkmt_mutex_release", + "create_lpc_port", + "connect_lpc_port", + "listen_lpc_port", + "accept_lpc_connect", + "complete_lpc_connect", + "get_lpc_connect_status", + "request_lpc_reply", + "reply_wait_receive_lpc", + "register_lpc_terminate_port", }; static const struct @@ -4519,6 +4657,7 @@ static const struct { "INVALID_PARAMETER", STATUS_INVALID_PARAMETER }, { "INVALID_PARAMETER_2", STATUS_INVALID_PARAMETER_2 }, { "INVALID_PIPE_STATE", STATUS_INVALID_PIPE_STATE }, + { "INVALID_PORT_HANDLE", STATUS_INVALID_PORT_HANDLE }, { "INVALID_READ_MODE", STATUS_INVALID_READ_MODE }, { "INVALID_SECURITY_DESCR", STATUS_INVALID_SECURITY_DESCR }, { "INVALID_USER_BUFFER", STATUS_INVALID_USER_BUFFER }, @@ -4568,6 +4707,8 @@ static const struct { "PIPE_EMPTY", STATUS_PIPE_EMPTY }, { "PIPE_LISTENING", STATUS_PIPE_LISTENING }, { "PIPE_NOT_AVAILABLE", STATUS_PIPE_NOT_AVAILABLE }, + { "PORT_CONNECTION_REFUSED", STATUS_PORT_CONNECTION_REFUSED }, + { "PORT_DISCONNECTED", STATUS_PORT_DISCONNECTED }, { "PORT_NOT_SET", STATUS_PORT_NOT_SET }, { "PREDEFINED_HANDLE", STATUS_PREDEFINED_HANDLE }, { "PRIVILEGE_NOT_HELD", STATUS_PRIVILEGE_NOT_HELD }, diff --git a/server/thread.c b/server/thread.c index 7207f918400..ebff38815dc 100644 --- a/server/thread.c +++ b/server/thread.c @@ -437,6 +437,7 @@ static inline void init_thread_structure( struct thread *thread ) list_init( &thread->system_apc ); list_init( &thread->user_apc ); list_init( &thread->kernel_object ); + list_init( &thread->lpc_terminate_ports ); for (i = 0; i < MAX_INFLIGHT_FDS; i++) thread->inflight[i].server = thread->inflight[i].client = -1; @@ -609,6 +610,9 @@ static void cleanup_thread( struct thread *thread ) { int i; + /* Send LPC_CLIENT_DIED to registered terminate ports */ + lpc_send_client_died( thread ); + cleanup_thread_completion( thread ); if (thread->context) { diff --git a/server/thread.h b/server/thread.h index 77ea355483d..2d0337410c9 100644 --- a/server/thread.h +++ b/server/thread.h @@ -99,6 +99,7 @@ struct thread data_size_t desc_len; /* thread description length in bytes */ WCHAR *desc; /* thread description string */ struct completion_wait *completion_wait; /* completion port wait object the thread is associated with */ + struct list lpc_terminate_ports; /* list of ports to notify on thread termination */ }; extern struct thread *current; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10611
Please split this MR into smaller patches, for example, implement one function per commit. And avoid including generated files, for example, `ntsyscalls.h` and `server_protocol.h`. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10611#note_135679
participants (3)
-
Rose Hellsing -
Rose Hellsing (@axtlos) -
Zhiyi Zhang (@zhiyi)