From 0dfecf815d8bd9465198096063be96c150767869 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Mon, 7 Nov 2016 13:29:09 +0000 Subject: [PATCH] [NTOS:IO][INCLUDES][EVENTLOG]: Fix support for event logging through the "ErrorLogPort" LPC. See the details in CORE-12301 #resolve svn path=/trunk/; revision=73167 --- reactos/base/services/eventlog/CMakeLists.txt | 1 + reactos/base/services/eventlog/eventlog.c | 66 +++--- reactos/base/services/eventlog/eventlog.h | 13 +- reactos/base/services/eventlog/file.c | 53 +++-- reactos/base/services/eventlog/logport.c | 143 +++++++---- reactos/base/services/eventlog/rpc.c | 20 +- reactos/ntoskrnl/include/internal/io.h | 11 +- reactos/ntoskrnl/io/iomgr/error.c | 223 +++++++++++------- .../sdk/include/reactos/subsys/iolog/iolog.h | 31 +++ 9 files changed, 348 insertions(+), 213 deletions(-) create mode 100644 reactos/sdk/include/reactos/subsys/iolog/iolog.h diff --git a/reactos/base/services/eventlog/CMakeLists.txt b/reactos/base/services/eventlog/CMakeLists.txt index b5c4909a782..eafc41561b9 100644 --- a/reactos/base/services/eventlog/CMakeLists.txt +++ b/reactos/base/services/eventlog/CMakeLists.txt @@ -1,6 +1,7 @@ include_directories( ${REACTOS_SOURCE_DIR}/sdk/lib/evtlib + ${REACTOS_SOURCE_DIR}/sdk/include/reactos/subsys ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/reactos/base/services/eventlog/eventlog.c b/reactos/base/services/eventlog/eventlog.c index edb23bbfc2c..4e29c2ed766 100644 --- a/reactos/base/services/eventlog/eventlog.c +++ b/reactos/base/services/eventlog/eventlog.c @@ -548,71 +548,73 @@ VOID PRINT_RECORD(PEVENTLOGRECORD pRec) LARGE_INTEGER SystemTime; TIME_FIELDS Time; - DPRINT("Length = %lu\n", pRec->Length); - DPRINT("Reserved = 0x%x\n", pRec->Reserved); - DPRINT("RecordNumber = %lu\n", pRec->RecordNumber); + DPRINT1("PRINT_RECORD(0x%p)\n", pRec); + + DbgPrint("Length = %lu\n", pRec->Length); + DbgPrint("Reserved = 0x%x\n", pRec->Reserved); + DbgPrint("RecordNumber = %lu\n", pRec->RecordNumber); RtlSecondsSince1970ToTime(pRec->TimeGenerated, &SystemTime); RtlTimeToTimeFields(&SystemTime, &Time); - DPRINT("TimeGenerated = %hu.%hu.%hu %hu:%hu:%hu\n", - Time.Day, Time.Month, Time.Year, - Time.Hour, Time.Minute, Time.Second); + DbgPrint("TimeGenerated = %hu.%hu.%hu %hu:%hu:%hu\n", + Time.Day, Time.Month, Time.Year, + Time.Hour, Time.Minute, Time.Second); RtlSecondsSince1970ToTime(pRec->TimeWritten, &SystemTime); RtlTimeToTimeFields(&SystemTime, &Time); - DPRINT("TimeWritten = %hu.%hu.%hu %hu:%hu:%hu\n", - Time.Day, Time.Month, Time.Year, - Time.Hour, Time.Minute, Time.Second); + DbgPrint("TimeWritten = %hu.%hu.%hu %hu:%hu:%hu\n", + Time.Day, Time.Month, Time.Year, + Time.Hour, Time.Minute, Time.Second); - DPRINT("EventID = %lu\n", pRec->EventID); + DbgPrint("EventID = %lu\n", pRec->EventID); switch (pRec->EventType) { case EVENTLOG_ERROR_TYPE: - DPRINT("EventType = EVENTLOG_ERROR_TYPE\n"); + DbgPrint("EventType = EVENTLOG_ERROR_TYPE\n"); break; case EVENTLOG_WARNING_TYPE: - DPRINT("EventType = EVENTLOG_WARNING_TYPE\n"); + DbgPrint("EventType = EVENTLOG_WARNING_TYPE\n"); break; case EVENTLOG_INFORMATION_TYPE: - DPRINT("EventType = EVENTLOG_INFORMATION_TYPE\n"); + DbgPrint("EventType = EVENTLOG_INFORMATION_TYPE\n"); break; case EVENTLOG_AUDIT_SUCCESS: - DPRINT("EventType = EVENTLOG_AUDIT_SUCCESS\n"); + DbgPrint("EventType = EVENTLOG_AUDIT_SUCCESS\n"); break; case EVENTLOG_AUDIT_FAILURE: - DPRINT("EventType = EVENTLOG_AUDIT_FAILURE\n"); + DbgPrint("EventType = EVENTLOG_AUDIT_FAILURE\n"); break; default: - DPRINT("EventType = %hu\n", pRec->EventType); + DbgPrint("EventType = %hu\n", pRec->EventType); } - DPRINT("NumStrings = %hu\n", pRec->NumStrings); - DPRINT("EventCategory = %hu\n", pRec->EventCategory); - DPRINT("ReservedFlags = 0x%x\n", pRec->ReservedFlags); - DPRINT("ClosingRecordNumber = %lu\n", pRec->ClosingRecordNumber); - DPRINT("StringOffset = %lu\n", pRec->StringOffset); - DPRINT("UserSidLength = %lu\n", pRec->UserSidLength); - DPRINT("UserSidOffset = %lu\n", pRec->UserSidOffset); - DPRINT("DataLength = %lu\n", pRec->DataLength); - DPRINT("DataOffset = %lu\n", pRec->DataOffset); - - DPRINT("SourceName: %S\n", (PWSTR)((ULONG_PTR)pRec + sizeof(EVENTLOGRECORD))); + DbgPrint("NumStrings = %hu\n", pRec->NumStrings); + DbgPrint("EventCategory = %hu\n", pRec->EventCategory); + DbgPrint("ReservedFlags = 0x%x\n", pRec->ReservedFlags); + DbgPrint("ClosingRecordNumber = %lu\n", pRec->ClosingRecordNumber); + DbgPrint("StringOffset = %lu\n", pRec->StringOffset); + DbgPrint("UserSidLength = %lu\n", pRec->UserSidLength); + DbgPrint("UserSidOffset = %lu\n", pRec->UserSidOffset); + DbgPrint("DataLength = %lu\n", pRec->DataLength); + DbgPrint("DataOffset = %lu\n", pRec->DataOffset); - i = (wcslen((PWSTR)((ULONG_PTR)pRec + sizeof(EVENTLOGRECORD))) + 1) * sizeof(WCHAR); + i = sizeof(EVENTLOGRECORD); + DbgPrint("SourceName: %S\n", (PWSTR)((ULONG_PTR)pRec + i)); - DPRINT("ComputerName: %S\n", (PWSTR)((ULONG_PTR)pRec + sizeof(EVENTLOGRECORD) + i)); + i += (wcslen((PWSTR)((ULONG_PTR)pRec + i)) + 1) * sizeof(WCHAR); + DbgPrint("ComputerName: %S\n", (PWSTR)((ULONG_PTR)pRec + i)); if (pRec->StringOffset < pRec->Length && pRec->NumStrings) { - DPRINT("Strings:\n"); + DbgPrint("Strings:\n"); str = (PWSTR)((ULONG_PTR)pRec + pRec->StringOffset); for (i = 0; i < pRec->NumStrings; i++) { - DPRINT("[%u] %S\n", i, str); + DbgPrint("[%u] %S\n", i, str); str += wcslen(str) + 1; } } - DPRINT("Length2 = %lu\n", *(PULONG)((ULONG_PTR)pRec + pRec->Length - 4)); + DbgPrint("Length2 = %lu\n", *(PULONG)((ULONG_PTR)pRec + pRec->Length - 4)); } diff --git a/reactos/base/services/eventlog/eventlog.h b/reactos/base/services/eventlog/eventlog.h index fc64b5b5fe7..b13ef6d3b31 100644 --- a/reactos/base/services/eventlog/eventlog.h +++ b/reactos/base/services/eventlog/eventlog.h @@ -28,15 +28,6 @@ #include #include -// FIXME: For that we may directly include NTOS header?? -typedef struct _IO_ERROR_LPC -{ - PORT_MESSAGE Header; - IO_ERROR_LOG_MESSAGE Message; -} IO_ERROR_LPC, *PIO_ERROR_LPC; - -// C_ASSERT(sizeof(IO_ERROR_LPC) == 0x100); - /* Defined in evtlib.h */ // #define LOGFILE_SIGNATURE 0x654c664c // "LfLe" @@ -140,8 +131,8 @@ LogfAllocAndBuildNewRecord(PSIZE_T pRecSize, USHORT wType, USHORT wCategory, ULONG dwEventId, - PCWSTR SourceName, - PCWSTR ComputerName, + PUNICODE_STRING SourceName, + PUNICODE_STRING ComputerName, ULONG dwSidLength, PSID pUserSid, USHORT wNumStrings, diff --git a/reactos/base/services/eventlog/file.c b/reactos/base/services/eventlog/file.c index 95db1b38efa..0643e299365 100644 --- a/reactos/base/services/eventlog/file.c +++ b/reactos/base/services/eventlog/file.c @@ -898,8 +898,8 @@ LogfAllocAndBuildNewRecord(PSIZE_T pRecSize, USHORT wType, USHORT wCategory, ULONG dwEventId, - PCWSTR SourceName, - PCWSTR ComputerName, + PUNICODE_STRING SourceName, + PUNICODE_STRING ComputerName, ULONG dwSidLength, PSID pUserSid, USHORT wNumStrings, @@ -908,16 +908,17 @@ LogfAllocAndBuildNewRecord(PSIZE_T pRecSize, PVOID pRawData) { SIZE_T RecSize; + SIZE_T SourceNameSize, ComputerNameSize, StringLen; PBYTE Buffer; PEVENTLOGRECORD pRec; PWSTR str; UINT i, pos; - SIZE_T SourceNameLen, ComputerNameLen, StringLen; - SourceNameLen = (SourceName ? wcslen(SourceName) : 0) + 1; - ComputerNameLen = (ComputerName ? wcslen(ComputerName) : 0) + 1; + SourceNameSize = (SourceName && SourceName->Buffer) ? SourceName->Length : 0; + ComputerNameSize = (ComputerName && ComputerName->Buffer) ? ComputerName->Length : 0; - RecSize = sizeof(EVENTLOGRECORD) + (SourceNameLen + ComputerNameLen) * sizeof(WCHAR); + RecSize = sizeof(EVENTLOGRECORD) + /* Add the sizes of the strings, NULL-terminated */ + SourceNameSize + ComputerNameSize + 2*sizeof(UNICODE_NULL); /* Align on DWORD boundary for the SID */ RecSize = ROUND_UP(RecSize, sizeof(ULONG)); @@ -975,12 +976,19 @@ LogfAllocAndBuildNewRecord(PSIZE_T pRecSize, pos = sizeof(EVENTLOGRECORD); - if (SourceName) - StringCchCopyW((PWSTR)(Buffer + pos), SourceNameLen, SourceName); - pos += SourceNameLen * sizeof(WCHAR); - if (ComputerName) - StringCchCopyW((PWSTR)(Buffer + pos), ComputerNameLen, ComputerName); - pos += ComputerNameLen * sizeof(WCHAR); + /* NOTE: Equivalents of RtlStringCbCopyUnicodeString calls */ + if (SourceNameSize) + { + StringCbCopyNW((PWSTR)(Buffer + pos), SourceNameSize + sizeof(UNICODE_NULL), + SourceName->Buffer, SourceNameSize); + } + pos += SourceNameSize + sizeof(UNICODE_NULL); + if (ComputerNameSize) + { + StringCbCopyNW((PWSTR)(Buffer + pos), ComputerNameSize + sizeof(UNICODE_NULL), + ComputerName->Buffer, ComputerNameSize); + } + pos += ComputerNameSize + sizeof(UNICODE_NULL); /* Align on DWORD boundary for the SID */ pos = ROUND_UP(pos, sizeof(ULONG)); @@ -1035,20 +1043,24 @@ LogfReportEvent(USHORT wType, PVOID pRawData) { NTSTATUS Status; - WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1]; - DWORD dwComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1; + UNICODE_STRING SourceName, ComputerName; PEVENTLOGRECORD LogBuffer; LARGE_INTEGER SystemTime; ULONG Time; SIZE_T RecSize; + DWORD dwComputerNameLength; + WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1]; if (!EventLogSource) return; + RtlInitUnicodeString(&SourceName, EventLogSource->szName); + + dwComputerNameLength = ARRAYSIZE(szComputerName); if (!GetComputerNameW(szComputerName, &dwComputerNameLength)) - { szComputerName[0] = L'\0'; - } + + RtlInitUnicodeString(&ComputerName, szComputerName); NtQuerySystemTime(&SystemTime); RtlTimeToSecondsSince1970(&SystemTime, &Time); @@ -1058,14 +1070,19 @@ LogfReportEvent(USHORT wType, wType, wCategory, dwEventId, - EventLogSource->szName, - szComputerName, + &SourceName, + &ComputerName, 0, NULL, wNumStrings, pStrings, dwDataSize, pRawData); + if (LogBuffer == NULL) + { + DPRINT1("LogfAllocAndBuildNewRecord failed!\n"); + return; + } Status = LogfWriteRecord(EventLogSource->LogFile, LogBuffer, RecSize); if (!NT_SUCCESS(Status)) diff --git a/reactos/base/services/eventlog/logport.c b/reactos/base/services/eventlog/logport.c index 0af242a69ac..2294eb7b280 100644 --- a/reactos/base/services/eventlog/logport.c +++ b/reactos/base/services/eventlog/logport.c @@ -11,6 +11,7 @@ #include "eventlog.h" #include +#include #define NDEBUG #include @@ -46,22 +47,20 @@ NTSTATUS WINAPI PortThreadRoutine(PVOID Param) NTSTATUS InitLogPort(VOID) { NTSTATUS Status; - UNICODE_STRING PortName; + UNICODE_STRING PortName = RTL_CONSTANT_STRING(ELF_PORT_NAME); OBJECT_ATTRIBUTES ObjectAttributes; PORT_MESSAGE Request; ConnectPortHandle = NULL; MessagePortHandle = NULL; - RtlInitUnicodeString(&PortName, L"\\ErrorLogPort"); InitializeObjectAttributes(&ObjectAttributes, &PortName, 0, NULL, NULL); Status = NtCreatePort(&ConnectPortHandle, &ObjectAttributes, 0, - 0x100, - 0x2000); - + PORT_MAXIMUM_MESSAGE_LENGTH, // IO_ERROR_LOG_MESSAGE_LENGTH, + 2 * PAGE_SIZE); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreatePort() failed (Status %lx)\n", Status); @@ -76,7 +75,7 @@ NTSTATUS InitLogPort(VOID) } Status = NtAcceptConnectPort(&MessagePortHandle, ConnectPortHandle, - NULL, TRUE, NULL, NULL); + &Request, TRUE, NULL, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("NtAcceptConnectPort() failed (Status %lx)\n", Status); @@ -105,14 +104,17 @@ ByeBye: NTSTATUS ProcessPortMessage(VOID) { NTSTATUS Status; - IO_ERROR_LPC Request; - PIO_ERROR_LOG_MESSAGE Message; - ULONG Time; - PEVENTLOGRECORD pRec; - SIZE_T RecSize; PLOGFILE SystemLog = NULL; + UCHAR Buffer[PORT_MAXIMUM_MESSAGE_LENGTH]; // IO_ERROR_LOG_MESSAGE_LENGTH + PELF_API_MSG Message = (PELF_API_MSG)Buffer; + PIO_ERROR_LOG_MESSAGE ErrorMessage; + PEVENTLOGRECORD LogBuffer; + SIZE_T RecSize; + ULONG Time; + USHORT EventType; + UNICODE_STRING SourceName, ComputerName; + DWORD dwComputerNameLength; WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1]; - DWORD dwComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1; DPRINT("ProcessPortMessage() called\n"); @@ -121,9 +123,9 @@ NTSTATUS ProcessPortMessage(VOID) while (TRUE) { Status = NtReplyWaitReceivePort(MessagePortHandle, - 0, NULL, - &Request.Header); + NULL, + &Message->Header); if (!NT_SUCCESS(Status)) { @@ -133,69 +135,108 @@ NTSTATUS ProcessPortMessage(VOID) DPRINT("Received message\n"); - if (Request.Header.u2.s2.Type == LPC_PORT_CLOSED) + if (Message->Header.u2.s2.Type == LPC_PORT_CLOSED) { DPRINT("Port closed\n"); return STATUS_SUCCESS; } - if (Request.Header.u2.s2.Type == LPC_REQUEST) + if (Message->Header.u2.s2.Type == LPC_REQUEST) { DPRINT("Received request\n"); } - else if (Request.Header.u2.s2.Type == LPC_DATAGRAM) + else if (Message->Header.u2.s2.Type == LPC_DATAGRAM) { - DPRINT("Received datagram\n"); - // Message = (PIO_ERROR_LOG_MESSAGE)&Request.Message; - Message = &Request.Message; + DPRINT("Received datagram (0x%x, 0x%x)\n", + Message->Unknown[0], Message->Unknown[1]); + ErrorMessage = &Message->IoErrorMessage; - if (!GetComputerNameW(szComputerName, &dwComputerNameLength)) + // ASSERT(ErrorMessage->Type == IO_TYPE_ERROR_MESSAGE); + + RtlInitEmptyUnicodeString(&SourceName, NULL, 0); + if (ErrorMessage->DriverNameLength > sizeof(UNICODE_NULL)) // DriverNameLength counts NULL-terminator { - szComputerName[0] = L'\0'; + SourceName.Buffer = (PWSTR)((ULONG_PTR)ErrorMessage + ErrorMessage->DriverNameOffset); + SourceName.MaximumLength = ErrorMessage->DriverNameLength; + SourceName.Length = SourceName.MaximumLength - sizeof(UNICODE_NULL); } - RtlTimeToSecondsSince1970(&Message->TimeStamp, &Time); - - // TODO: Log more information?? - - pRec = LogfAllocAndBuildNewRecord( - &RecSize, - Time, - Message->Type, - Message->EntryData.EventCategory, - Message->EntryData.ErrorCode, - (PWSTR)((ULONG_PTR)Message + Message->DriverNameOffset), // FIXME: Use DriverNameLength too! - szComputerName, - 0, - NULL, - Message->EntryData.NumberOfStrings, - (PWSTR)((ULONG_PTR)Message + Message->EntryData.StringOffset), - Message->EntryData.DumpDataSize, - (PVOID)((ULONG_PTR)Message + FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData))); - - if (pRec == NULL) + dwComputerNameLength = ARRAYSIZE(szComputerName); + if (!GetComputerNameW(szComputerName, &dwComputerNameLength)) + szComputerName[0] = L'\0'; + + RtlInitUnicodeString(&ComputerName, szComputerName); + + RtlTimeToSecondsSince1970(&ErrorMessage->TimeStamp, &Time); + + /* Set the event type based on the error code severity */ + EventType = (USHORT)(ErrorMessage->EntryData.ErrorCode >> 30); + if (EventType == STATUS_SEVERITY_SUCCESS) { - DPRINT("LogfAllocAndBuildNewRecord failed!\n"); - return STATUS_NO_MEMORY; + EventType = EVENTLOG_SUCCESS; + } + else if (EventType == STATUS_SEVERITY_INFORMATIONAL) // NT_INFORMATION + { + EventType = EVENTLOG_INFORMATION_TYPE; + } + else if (EventType == STATUS_SEVERITY_WARNING) // NT_WARNING + { + EventType = EVENTLOG_WARNING_TYPE; + } + else if (EventType == STATUS_SEVERITY_ERROR) // NT_ERROR + { + EventType = EVENTLOG_ERROR_TYPE; + } + else + { + /* Unknown severity, set to error */ + EventType = EVENTLOG_ERROR_TYPE; } - DPRINT("RecSize = %d\n", RecSize); - - DPRINT("\n --- EVENTLOG RECORD ---\n"); - PRINT_RECORD(pRec); - DPRINT("\n"); + /* + * The data being saved consists of the IO_ERROR_LOG_PACKET structure + * header, plus the additional raw data from the driver. + */ + LogBuffer = LogfAllocAndBuildNewRecord( + &RecSize, + Time, + EventType, + ErrorMessage->EntryData.EventCategory, + ErrorMessage->EntryData.ErrorCode, + &SourceName, + &ComputerName, + 0, + NULL, + ErrorMessage->EntryData.NumberOfStrings, + (PWSTR)((ULONG_PTR)ErrorMessage + + ErrorMessage->EntryData.StringOffset), + FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + + ErrorMessage->EntryData.DumpDataSize, + (PVOID)&ErrorMessage->EntryData); + if (LogBuffer == NULL) + { + DPRINT1("LogfAllocAndBuildNewRecord failed!\n"); + // return STATUS_NO_MEMORY; + continue; + } if (!onLiveCD && SystemLog) { - Status = LogfWriteRecord(SystemLog, pRec, RecSize); + Status = LogfWriteRecord(SystemLog, LogBuffer, RecSize); if (!NT_SUCCESS(Status)) { DPRINT1("ERROR writing to event log `%S' (Status 0x%08lx)\n", SystemLog->LogName, Status); } } + else + { + DPRINT1("\n--- EVENTLOG RECORD ---\n"); + PRINT_RECORD(LogBuffer); + DPRINT1("\n"); + } - LogfFreeRecord(pRec); + LogfFreeRecord(LogBuffer); } } diff --git a/reactos/base/services/eventlog/rpc.c b/reactos/base/services/eventlog/rpc.c index 40290fce3e2..01cd920b6b6 100644 --- a/reactos/base/services/eventlog/rpc.c +++ b/reactos/base/services/eventlog/rpc.c @@ -586,6 +586,7 @@ ElfrIntReportEventW( { NTSTATUS Status; PLOGHANDLE pLogHandle; + UNICODE_STRING LocalSourceName, LocalComputerName; PEVENTLOGRECORD LogBuffer; USHORT i; SIZE_T RecSize; @@ -655,21 +656,32 @@ ElfrIntReportEventW( if (UserSID) dwUserSidLength = FIELD_OFFSET(SID, SubAuthority[UserSID->SubAuthorityCount]); + if (SourceName && SourceName->Buffer) + LocalSourceName = *(PUNICODE_STRING)SourceName; + else + RtlInitUnicodeString(&LocalSourceName, pLogHandle->szName); + + LocalComputerName = *(PUNICODE_STRING)ComputerName; + LogBuffer = LogfAllocAndBuildNewRecord(&RecSize, Time, EventType, EventCategory, EventID, - (SourceName && SourceName->Buffer) - ? SourceName->Buffer - : pLogHandle->szName, - ComputerName->Buffer, + &LocalSourceName, + &LocalComputerName, dwUserSidLength, UserSID, NumStrings, lpStrings, DataSize, Data); + if (LogBuffer == NULL) + { + DPRINT1("LogfAllocAndBuildNewRecord failed!\n"); + HeapFree(GetProcessHeap(), 0, lpStrings); + return STATUS_NO_MEMORY; + } Status = LogfWriteRecord(pLogHandle->LogFile, LogBuffer, RecSize); if (!NT_SUCCESS(Status)) diff --git a/reactos/ntoskrnl/include/internal/io.h b/reactos/ntoskrnl/include/internal/io.h index 0b2af9d354f..bd3f5683b93 100644 --- a/reactos/ntoskrnl/include/internal/io.h +++ b/reactos/ntoskrnl/include/internal/io.h @@ -5,6 +5,7 @@ * PURPOSE: Internal header for the I/O Manager * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */ + #include "ntdddisk.h" // @@ -332,16 +333,6 @@ typedef struct _ERROR_LOG_ENTRY LARGE_INTEGER TimeStamp; } ERROR_LOG_ENTRY, *PERROR_LOG_ENTRY; -// -// Event Log LPC Message -// -typedef struct _ELF_API_MSG -{ - PORT_MESSAGE h; - ULONG Unknown[2]; - IO_ERROR_LOG_MESSAGE IoErrorMessage; -} ELF_API_MSG, *PELF_API_MSG; - // // To simplify matters, the kernel is made to support both the checked and free // version of the I/O Remove Lock in the same binary. This structure includes diff --git a/reactos/ntoskrnl/io/iomgr/error.c b/reactos/ntoskrnl/io/iomgr/error.c index f6817dac8cb..e21cb9025d0 100644 --- a/reactos/ntoskrnl/io/iomgr/error.c +++ b/reactos/ntoskrnl/io/iomgr/error.c @@ -6,9 +6,12 @@ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Eric Kohl */ + /* INCLUDES *****************************************************************/ #include +#include + #define NDEBUG #include @@ -22,6 +25,7 @@ typedef struct _IOP_ERROR_LOG_WORKER_DPC /* GLOBALS *******************************************************************/ +#define IOP_MAXIMUM_LOG_SIZE (100 * PAGE_SIZE) LONG IopTotalLogSize; LIST_ENTRY IopErrorLogListHead; KSPIN_LOCK IopLogListLock; @@ -105,16 +109,23 @@ BOOLEAN NTAPI IopConnectLogPort(VOID) { - UNICODE_STRING PortName = RTL_CONSTANT_STRING(L"\\ErrorLogPort"); NTSTATUS Status; + UNICODE_STRING PortName = RTL_CONSTANT_STRING(ELF_PORT_NAME); + SECURITY_QUALITY_OF_SERVICE SecurityQos; /* Make sure we're not already connected */ if (IopLogPortConnected) return TRUE; + /* Setup the QoS structure */ + SecurityQos.Length = sizeof(SecurityQos); + SecurityQos.ImpersonationLevel = SecurityIdentification; + SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + SecurityQos.EffectiveOnly = TRUE; + /* Connect the port */ Status = ZwConnectPort(&IopLogPort, &PortName, - NULL, + &SecurityQos, NULL, NULL, NULL, @@ -136,6 +147,9 @@ VOID NTAPI IopLogWorker(IN PVOID Parameter) { +#define IO_ERROR_OBJECT_NAMES_LENGTH 100 + + NTSTATUS Status; PELF_API_MSG Message; PIO_ERROR_LOG_MESSAGE ErrorMessage; PLIST_ENTRY ListEntry; @@ -144,22 +158,24 @@ IopLogWorker(IN PVOID Parameter) PCHAR StringBuffer; ULONG RemainingLength; PDRIVER_OBJECT DriverObject; - ULONG DriverNameLength = 0, DeviceNameLength; - UNICODE_STRING DriverNameString; - NTSTATUS Status; - UCHAR Buffer[256]; + PWCHAR NameString; + ULONG DriverNameLength, DeviceNameLength; + UCHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + IO_ERROR_OBJECT_NAMES_LENGTH]; POBJECT_NAME_INFORMATION ObjectNameInfo = (POBJECT_NAME_INFORMATION)&Buffer; - POBJECT_NAME_INFORMATION PoolObjectNameInfo = NULL; + POBJECT_NAME_INFORMATION PoolObjectNameInfo; ULONG ReturnedLength, MessageLength; - PWCHAR p; ULONG ExtraStringLength; + PWCHAR p; + PAGED_CODE(); + UNREFERENCED_PARAMETER(Parameter); + /* Connect to the port */ if (!IopConnectLogPort()) return; /* Allocate the message */ - Message = ExAllocatePool(PagedPool, IO_ERROR_LOG_MESSAGE_LENGTH); + Message = ExAllocatePoolWithTag(PagedPool, IO_ERROR_LOG_MESSAGE_LENGTH, TAG_IO); if (!Message) { /* Couldn't allocate, try again */ @@ -167,10 +183,8 @@ IopLogWorker(IN PVOID Parameter) return; } - /* Copy the message */ - RtlZeroMemory(Message, sizeof(ELF_API_MSG)); - - /* Get the actual I/O Structure */ + /* Zero out the message and get the actual I/O structure */ + RtlZeroMemory(Message, sizeof(*Message)); ErrorMessage = &Message->IoErrorMessage; /* Start loop */ @@ -225,21 +239,28 @@ IopLogWorker(IN PVOID Parameter) IO_ERROR_LOG_MESSAGE_LENGTH - (ULONG_PTR)StringBuffer); + NameString = NULL; + DriverNameLength = 0; DeviceNameLength = 0; + PoolObjectNameInfo = NULL; + ObjectNameInfo = (POBJECT_NAME_INFORMATION)&Buffer; + /* Now check if there is a driver object */ DriverObject = LogEntry->DriverObject; if (DriverObject) { - /* Check if the driver has a name */ + /* Check if the driver has a name, and use it if so */ if (DriverObject->DriverName.Buffer) { - /* Use its name */ - DriverNameString.Buffer = DriverObject->DriverName.Buffer; + NameString = DriverObject->DriverName.Buffer; DriverNameLength = DriverObject->DriverName.Length; } else - DriverNameString.Buffer = NULL; + { + NameString = NULL; + DriverNameLength = 0; + } - /* Check if there isn't a valid name*/ + /* Check if there isn't a valid name */ if (!DriverNameLength) { /* Query the name directly */ @@ -247,30 +268,35 @@ IopLogWorker(IN PVOID Parameter) ObjectNameInfo, sizeof(Buffer), &ReturnedLength); - if (!(NT_SUCCESS(Status)) || !(ObjectNameInfo->Name.Length)) + if (!NT_SUCCESS(Status) || (ObjectNameInfo->Name.Length == 0)) { /* We don't have a name */ DriverNameLength = 0; } + else + { + NameString = ObjectNameInfo->Name.Buffer; + DriverNameLength = ObjectNameInfo->Name.Length; + } } } else { /* Use default name */ - DriverNameString.Buffer = L"Application Popup"; - DriverNameLength = (ULONG)wcslen(DriverNameString.Buffer) * sizeof(WCHAR); + NameString = L"Application Popup"; + DriverNameLength = (ULONG)wcslen(NameString) * sizeof(WCHAR); } - /* Check if we have a driver name by here */ + /* Check if we have a driver name */ if (DriverNameLength) { /* Skip to the end of the driver's name */ - p = &DriverNameString.Buffer[DriverNameLength / sizeof(WCHAR)]; + p = &NameString[DriverNameLength / sizeof(WCHAR)]; /* Now we'll walk backwards and assume the minimum size */ DriverNameLength = sizeof(WCHAR); p--; - while ((*p != L'\\') && (p != DriverNameString.Buffer)) + while ((*p != L'\\') && (p != NameString)) { /* No backslash found, keep going */ p--; @@ -285,8 +311,9 @@ IopLogWorker(IN PVOID Parameter) } /* - * Now make sure that the driver name fits in our buffer, minus 3 - * NULL chars, and copy the name in our string buffer + * Now make sure that the driver name fits in the buffer, minus + * 3 NULL chars (driver name, device name, and remaining strings), + * and copy the driver name in the string buffer. */ DriverNameLength = min(DriverNameLength, RemainingLength - 3 * sizeof(UNICODE_NULL)); @@ -294,29 +321,29 @@ IopLogWorker(IN PVOID Parameter) } /* Null-terminate the driver name */ - *((PWSTR)(StringBuffer + DriverNameLength)) = L'\0'; + *((PWSTR)(StringBuffer + DriverNameLength)) = UNICODE_NULL; DriverNameLength += sizeof(WCHAR); /* Go to the next string buffer position */ StringBuffer += DriverNameLength; RemainingLength -= DriverNameLength; - /* Update the string offset and check if we have a device object */ - ErrorMessage->EntryData.StringOffset = (USHORT) - ((ULONG_PTR)StringBuffer - - (ULONG_PTR)ErrorMessage); + /* Update the string offset */ + ErrorMessage->EntryData.StringOffset = + (USHORT)((ULONG_PTR)StringBuffer - (ULONG_PTR)ErrorMessage); + + /* Check if we have a device object */ if (LogEntry->DeviceObject) { /* We do, query its name */ Status = ObQueryNameString(LogEntry->DeviceObject, ObjectNameInfo, - sizeof(Buffer), + sizeof(Buffer) - DriverNameLength, &ReturnedLength); if (!NT_SUCCESS(Status) || (ObjectNameInfo->Name.Length == 0)) { /* Setup an empty name */ - ObjectNameInfo->Name.Length = 0; - ObjectNameInfo->Name.Buffer = L""; + RtlInitEmptyUnicodeString(&ObjectNameInfo->Name, L"", 0); /* Check if we failed because our buffer wasn't large enough */ if (Status == STATUS_INFO_LENGTH_MISMATCH) @@ -337,39 +364,40 @@ IopLogWorker(IN PVOID Parameter) { /* Success, update the information */ ObjectNameInfo->Name.Length = - 100 - (USHORT)DriverNameLength; + IO_ERROR_OBJECT_NAMES_LENGTH - (USHORT)DriverNameLength; } } } } + + NameString = ObjectNameInfo->Name.Buffer; + DeviceNameLength = ObjectNameInfo->Name.Length; } else { /* No device object, setup an empty name */ - ObjectNameInfo->Name.Length = 0; - ObjectNameInfo->Name.Buffer = L""; + NameString = L""; + DeviceNameLength = 0; } /* - * Now make sure that the device name fits in our buffer, minus 2 - * NULL chars, and copy the name in our string buffer + * Now make sure that the device name fits in the buffer, minus + * 2 NULL chars (device name, and remaining strings), and copy + * the device name in the string buffer. */ - DeviceNameLength = min(ObjectNameInfo->Name.Length, + DeviceNameLength = min(DeviceNameLength, RemainingLength - 2 * sizeof(UNICODE_NULL)); - RtlCopyMemory(StringBuffer, - ObjectNameInfo->Name.Buffer, - DeviceNameLength); + RtlCopyMemory(StringBuffer, NameString, DeviceNameLength); /* Null-terminate the device name */ - *((PWSTR)(StringBuffer + DeviceNameLength)) = L'\0'; + *((PWSTR)(StringBuffer + DeviceNameLength)) = UNICODE_NULL; DeviceNameLength += sizeof(WCHAR); /* Free the buffer if we had one */ if (PoolObjectNameInfo) { - ExFreePool(PoolObjectNameInfo); + ExFreePoolWithTag(PoolObjectNameInfo, TAG_IO); PoolObjectNameInfo = NULL; - ObjectNameInfo = (POBJECT_NAME_INFORMATION)&Buffer; } /* Go to the next string buffer position */ @@ -385,6 +413,9 @@ IopLogWorker(IN PVOID Parameter) sizeof(ERROR_LOG_ENTRY) - Packet->StringOffset; + /* Round up the length */ + ExtraStringLength = ROUND_UP(ExtraStringLength, sizeof(WCHAR)); + /* Make sure that the extra strings fit in our buffer */ if (ExtraStringLength > (RemainingLength - sizeof(UNICODE_NULL))) { @@ -399,50 +430,58 @@ IopLogWorker(IN PVOID Parameter) ExtraStringLength); /* Null-terminate them */ - *((PWSTR)(StringBuffer + ExtraStringLength)) = L'\0'; + *((PWSTR)(StringBuffer + ExtraStringLength)) = UNICODE_NULL; } /* Set the driver name length */ ErrorMessage->DriverNameLength = (USHORT)DriverNameLength; - /* Update the message length to include the device and driver names */ - MessageLength += DeviceNameLength + DriverNameLength; + /* Update the message length to include the driver and device names */ + MessageLength += DriverNameLength + DeviceNameLength; ErrorMessage->Size = (USHORT)MessageLength; - /* Now update it again, internally, for the size of the actual LPC */ + /* Now update it again for the size of the actual LPC */ MessageLength += (FIELD_OFFSET(ELF_API_MSG, IoErrorMessage) - FIELD_OFFSET(ELF_API_MSG, Unknown[0])); /* Set the total and data lengths */ - Message->h.u1.s1.TotalLength = (USHORT)(sizeof(PORT_MESSAGE) + - MessageLength); - Message->h.u1.s1.DataLength = (USHORT)(MessageLength); + Message->Header.u1.s1.TotalLength = + (USHORT)(sizeof(PORT_MESSAGE) + MessageLength); + Message->Header.u1.s1.DataLength = (USHORT)MessageLength; /* Send the message */ - Status = NtRequestPort(IopLogPort, (PPORT_MESSAGE)Message); + Status = ZwRequestPort(IopLogPort, &Message->Header); if (!NT_SUCCESS(Status)) { - /* Requeue log message and restart the worker */ - ExInterlockedInsertTailList(&IopErrorLogListHead, + /* + * An error happened while sending the message on the port. + * Close the port, requeue the log message on top of the list + * and restart the worker. + */ + ZwClose(IopLogPort); + IopLogPortConnected = FALSE; + + ExInterlockedInsertHeadList(&IopErrorLogListHead, &LogEntry->ListEntry, &IopLogListLock); - IopLogWorkerRunning = FALSE; + IopRestartLogWorker(); break; } - /* Dereference the device object */ + /* NOTE: The following is basically 'IoFreeErrorLogEntry(Packet)' */ + + /* Dereference both objects */ if (LogEntry->DeviceObject) ObDereferenceObject(LogEntry->DeviceObject); - if (DriverObject) ObDereferenceObject(LogEntry->DriverObject); + if (LogEntry->DriverObject) ObDereferenceObject(LogEntry->DriverObject); - /* Update size */ - InterlockedExchangeAdd(&IopTotalLogSize, - -(LONG)(LogEntry->Size - - sizeof(ERROR_LOG_ENTRY))); + /* Decrease the total allocation size and free the entry */ + InterlockedExchangeAdd(&IopTotalLogSize, -(LONG)LogEntry->Size); + ExFreePoolWithTag(LogEntry, TAG_ERROR_LOG); } /* Free the LPC Message */ - ExFreePool(Message); + ExFreePoolWithTag(Message, TAG_IO); } VOID @@ -495,17 +534,15 @@ IoAllocateErrorLogEntry(IN PVOID IoObject, /* Make sure we have an object */ if (!IoObject) return NULL; - /* Check if we're past our buffer */ - if (IopTotalLogSize > PAGE_SIZE) return NULL; - /* Check if this is a device object or driver object */ - if (((PDEVICE_OBJECT)IoObject)->Type == IO_TYPE_DEVICE) + DeviceObject = (PDEVICE_OBJECT)IoObject; + if (DeviceObject->Type == IO_TYPE_DEVICE) { /* It's a device, get the driver */ - DeviceObject = (PDEVICE_OBJECT)IoObject; + // DeviceObject = (PDEVICE_OBJECT)IoObject; DriverObject = DeviceObject->DriverObject; } - else if (((PDEVICE_OBJECT)IoObject)->Type == IO_TYPE_DRIVER) + else if (DeviceObject->Type == IO_TYPE_DRIVER) { /* It's a driver, so we don't have a device */ DeviceObject = NULL; @@ -517,6 +554,21 @@ IoAllocateErrorLogEntry(IN PVOID IoObject, return NULL; } + /* Check if we're past our buffer */ + // FIXME/TODO: Perform the checks by taking into account EntrySize. + if (IopTotalLogSize > IOP_MAXIMUM_LOG_SIZE) return NULL; + + /* Check whether the size is too small or too large */ + if ((EntrySize < sizeof(IO_ERROR_LOG_PACKET)) || + (EntrySize > ERROR_LOG_MAXIMUM_SIZE)) + { + /* Fail */ + return NULL; + } + + /* Round up the size */ + EntrySize = ROUND_UP(EntrySize, sizeof(PVOID)); + /* Calculate the total size and allocate it */ LogEntrySize = sizeof(ERROR_LOG_ENTRY) + EntrySize; LogEntry = ExAllocatePoolWithTag(NonPagedPool, @@ -529,12 +581,12 @@ IoAllocateErrorLogEntry(IN PVOID IoObject, if (DriverObject) ObReferenceObject(DriverObject); /* Update log size */ - InterlockedExchangeAdd(&IopTotalLogSize, EntrySize); + InterlockedExchangeAdd(&IopTotalLogSize, LogEntrySize); /* Clear the entry and set it up */ - RtlZeroMemory(LogEntry, EntrySize); + RtlZeroMemory(LogEntry, LogEntrySize); LogEntry->Type = IO_TYPE_ERROR_LOG; - LogEntry->Size = EntrySize; + LogEntry->Size = LogEntrySize; LogEntry->DeviceObject = DeviceObject; LogEntry->DriverObject = DriverObject; @@ -551,7 +603,7 @@ IoFreeErrorLogEntry(IN PVOID ElEntry) { PERROR_LOG_ENTRY LogEntry; - /* Make sure there's an entry */ + /* Make sure there is an entry */ if (!ElEntry) return; /* Get the actual header */ @@ -561,10 +613,9 @@ IoFreeErrorLogEntry(IN PVOID ElEntry) if (LogEntry->DeviceObject) ObDereferenceObject(LogEntry->DeviceObject); if (LogEntry->DriverObject) ObDereferenceObject(LogEntry->DriverObject); - /* Decrease total allocation size and free the entry */ - InterlockedExchangeAdd(&IopTotalLogSize, - -(LONG)(LogEntry->Size - sizeof(ERROR_LOG_ENTRY))); - ExFreePool(LogEntry); + /* Decrease the total allocation size and free the entry */ + InterlockedExchangeAdd(&IopTotalLogSize, -(LONG)LogEntry->Size); + ExFreePoolWithTag(LogEntry, TAG_ERROR_LOG); } /* @@ -577,9 +628,11 @@ IoWriteErrorLogEntry(IN PVOID ElEntry) PERROR_LOG_ENTRY LogEntry; KIRQL Irql; - /* Get the main header */ - LogEntry = (PERROR_LOG_ENTRY)((ULONG_PTR)ElEntry - - sizeof(ERROR_LOG_ENTRY)); + /* Make sure there is an entry */ + if (!ElEntry) return; + + /* Get the actual header */ + LogEntry = (PERROR_LOG_ENTRY)((ULONG_PTR)ElEntry - sizeof(ERROR_LOG_ENTRY)); /* Get time stamp */ KeQuerySystemTime(&LogEntry->TimeStamp); @@ -591,14 +644,10 @@ IoWriteErrorLogEntry(IN PVOID ElEntry) /* Check if the worker is running */ if (!IopLogWorkerRunning) { -#if 0 /* It's not, initialize it and queue it */ - ExInitializeWorkItem(&IopErrorLogWorkItem, - IopLogWorker, - &IopErrorLogWorkItem); - ExQueueWorkItem(&IopErrorLogWorkItem, DelayedWorkQueue); IopLogWorkerRunning = TRUE; -#endif + ExInitializeWorkItem(&IopErrorLogWorkItem, IopLogWorker, NULL); + ExQueueWorkItem(&IopErrorLogWorkItem, DelayedWorkQueue); } /* Release the lock and return */ diff --git a/reactos/sdk/include/reactos/subsys/iolog/iolog.h b/reactos/sdk/include/reactos/subsys/iolog/iolog.h new file mode 100644 index 00000000000..abfd9fe5394 --- /dev/null +++ b/reactos/sdk/include/reactos/subsys/iolog/iolog.h @@ -0,0 +1,31 @@ +/* + * PROJECT: ReactOS EventLog Service + * LICENSE: GPL - See COPYING in the top level directory + * FILE: include/reactos/subsys/iolog/iolog.h + * PURPOSE: EventLog LPC API definitions + */ + +#ifndef _IOLOG_H +#define _IOLOG_H + +#pragma once + +// #include // For IO_ERROR_LOG_MESSAGE and associated + +#define ELF_PORT_NAME L"\\ErrorLogPort" + +typedef struct _ELF_API_MSG +{ + PORT_MESSAGE Header; + ULONG Unknown[2]; // FIXME + IO_ERROR_LOG_MESSAGE IoErrorMessage; +} ELF_API_MSG, *PELF_API_MSG; + +/* + * NOTE: The maximum data size sent to the EventLog LPC port + * is equal to: PORT_MAXIMUM_MESSAGE_LENGTH == 0x100 . + */ + +#endif // _IOLOG_H + +/* EOF */ -- 2.17.1