Skip to content

Commit 86b4e36

Browse files
committed
DotNetTools: Fix unaligned ETW crash #2369
1 parent 7fc2abc commit 86b4e36

File tree

3 files changed

+163
-63
lines changed

3 files changed

+163
-63
lines changed

plugins/DotNetTools/asmpage.c

Lines changed: 146 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,11 +1085,10 @@ static ULONG StartDotNetTrace(
10851085
bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + DotNetLoggerName.Length + sizeof(UNICODE_NULL);
10861086
properties = PhAllocateZero(bufferSize);
10871087
properties->Wnode.BufferSize = bufferSize;
1088-
properties->Wnode.ClientContext = 1;
1088+
properties->Wnode.ClientContext = EVENT_TRACE_CLOCK_RAW;
10891089
properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
10901090
properties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY;
10911091
properties->EnableFlags = EVENT_TRACE_FLAG_NO_SYSCONFIG;
1092-
properties->LogFileNameOffset = 0;
10931092
properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
10941093

10951094
result = StartTrace(&sessionHandle, DotNetLoggerName.Buffer, properties);
@@ -1133,8 +1132,38 @@ static ULONG NTAPI DotNetBufferCallback(
11331132
return TRUE;
11341133
}
11351134

1136-
static VOID NTAPI DotNetEventCallback(
1137-
_In_ PEVENT_RECORD EventRecord
1135+
PPH_STRING DnCreateStringSafe(
1136+
_In_ UNALIGNED PWSTR UnalignedString
1137+
)
1138+
{
1139+
if (IS_ALIGNED(UnalignedString, MAX_NATURAL_ALIGNMENT))
1140+
{
1141+
// Address is aligned, access directly
1142+
1143+
return PhCreateString(UnalignedString);
1144+
}
1145+
else // if (((ULONG_PTR)UnalignedString % sizeof(PWSTR)) != 0)
1146+
{
1147+
SIZE_T alignedLength = 0;
1148+
WCHAR alignedBuffer[0x400];
1149+
1150+
// Address is not aligned, use memcpy to access the string.
1151+
1152+
while (UnalignedString[alignedLength] != UNICODE_NULL && alignedLength < RTL_NUMBER_OF(alignedBuffer) - sizeof(UNICODE_NULL))
1153+
{
1154+
alignedLength++;
1155+
}
1156+
1157+
memcpy(alignedBuffer, UnalignedString, alignedLength * sizeof(WCHAR));
1158+
alignedBuffer[alignedLength] = UNICODE_NULL;
1159+
1160+
return PhCreateString(alignedBuffer);
1161+
}
1162+
}
1163+
1164+
static VOID DotNetUserDataCallback(
1165+
_In_ PEVENT_RECORD EventRecord,
1166+
_In_ PVOID UserData
11381167
)
11391168
{
11401169
PASMPAGE_QUERY_CONTEXT context = EventRecord->UserContext;
@@ -1149,7 +1178,7 @@ static VOID NTAPI DotNetEventCallback(
11491178
{
11501179
case RuntimeInformationDCStart:
11511180
{
1152-
PRuntimeInformationRundown data = EventRecord->UserData;
1181+
PRuntimeInformationRundown data = UserData;
11531182
PDNA_NODE node;
11541183
PPH_STRING startupFlagsString;
11551184
PPH_STRING startupModeString;
@@ -1186,24 +1215,28 @@ static VOID NTAPI DotNetEventCallback(
11861215
PhDereferenceObject(startupFlagsString);
11871216
}
11881217

1189-
if (data->CommandLine[0])
1190-
node->PathText = PhCreateString(data->CommandLine);
1191-
1218+
node->PathText = DnCreateStringSafe(PTR_ADD_OFFSET(UserData, RTL_SIZEOF_THROUGH_FIELD(RuntimeInformationRundown, StartupMode)));
11921219
node->RootNode = TRUE;
11931220
node->Node.Expanded = TRUE;
11941221
PhAddItemList(context->NodeRootList, node);
11951222
}
11961223
break;
11971224
case AppDomainDCStart_V1:
11981225
{
1199-
PAppDomainLoadUnloadRundown_V1 data = EventRecord->UserData;
1200-
SIZE_T appDomainNameLength;
1226+
static CONST PH_STRINGREF appDomainString = PH_STRINGREF_INIT(L"AppDomain: ");
1227+
PAppDomainLoadUnloadRundown_V1 data = UserData;
1228+
UNALIGNED PVOID offset;
1229+
PPH_STRING appDomainNameString;
1230+
PPH_STRING displayNameString;
12011231
USHORT clrInstanceID;
12021232
PDNA_NODE parentNode;
12031233
PDNA_NODE node;
12041234

1205-
appDomainNameLength = PhCountStringZ(data->AppDomainName) * sizeof(WCHAR);
1206-
clrInstanceID = *(PUSHORT)PTR_ADD_OFFSET(data, FIELD_OFFSET(AppDomainLoadUnloadRundown_V1, AppDomainName) + appDomainNameLength + sizeof(UNICODE_NULL) + sizeof(ULONG));
1235+
offset = PTR_ADD_OFFSET(UserData, RTL_SIZEOF_THROUGH_FIELD(AppDomainLoadUnloadRundown_V1, AppDomainFlags));
1236+
appDomainNameString = DnCreateStringSafe(offset);
1237+
displayNameString = PhConcatStringRef2(&appDomainString, &appDomainNameString->sr);
1238+
offset = PTR_ADD_OFFSET(offset, appDomainNameString->Length + sizeof(UNICODE_NULL) + sizeof(ULONG));
1239+
clrInstanceID = *(UNALIGNED PUSHORT)offset;
12071240

12081241
// Find the CLR node to add the AppDomain node to.
12091242
parentNode = FindClrNode(context, clrInstanceID);
@@ -1212,94 +1245,124 @@ static VOID NTAPI DotNetEventCallback(
12121245
{
12131246
// Check for duplicates.
12141247
if (FindAppDomainNode(parentNode, data->AppDomainID))
1248+
{
1249+
PhDereferenceObject(displayNameString);
1250+
PhDereferenceObject(appDomainNameString);
12151251
break;
1252+
}
12161253

12171254
node = AddNode(context);
12181255
node->Type = DNA_TYPE_APPDOMAIN;
12191256
node->u.AppDomain.AppDomainID = data->AppDomainID;
12201257
node->u.AppDomain.AppDomainFlags = data->AppDomainFlags;
1221-
node->u.AppDomain.DisplayName = PhConcatStrings2(L"AppDomain: ", data->AppDomainName);
1258+
node->u.AppDomain.DisplayName = displayNameString;
12221259
node->StructureText = node->u.AppDomain.DisplayName->sr;
12231260
node->IdText = FormatToHexString(data->AppDomainID);
12241261
node->FlagsText = FlagsToString(data->AppDomainFlags, AppDomainFlagsMap, sizeof(AppDomainFlagsMap));
12251262

12261263
node->RootNode = TRUE; // HACK
12271264
node->Node.Expanded = TRUE;
12281265
PhAddItemList(parentNode->Children, node);
1266+
1267+
PhDereferenceObject(appDomainNameString);
1268+
}
1269+
else
1270+
{
1271+
PhDereferenceObject(displayNameString);
1272+
PhDereferenceObject(appDomainNameString);
12291273
}
12301274
}
12311275
break;
12321276
case AssemblyDCStart_V1:
12331277
{
1234-
PAssemblyLoadUnloadRundown_V1 data = EventRecord->UserData;
1235-
SIZE_T fullyQualifiedAssemblyNameLength;
1278+
PAssemblyLoadUnloadRundown_V1 data = UserData;
1279+
UNALIGNED PVOID offset;
1280+
PPH_STRING assemblyNameString;
12361281
USHORT clrInstanceID;
12371282
PDNA_NODE parentNode;
12381283
PDNA_NODE node;
12391284
PH_STRINGREF remainingPart;
12401285

1241-
fullyQualifiedAssemblyNameLength = PhCountStringZ(data->FullyQualifiedAssemblyName) * sizeof(WCHAR);
1242-
clrInstanceID = *(PUSHORT)PTR_ADD_OFFSET(data, FIELD_OFFSET(AssemblyLoadUnloadRundown_V1, FullyQualifiedAssemblyName) + fullyQualifiedAssemblyNameLength + sizeof(UNICODE_NULL));
1286+
offset = PTR_ADD_OFFSET(UserData, RTL_SIZEOF_THROUGH_FIELD(AssemblyLoadUnloadRundown_V1, AssemblyFlags));
1287+
assemblyNameString = DnCreateStringSafe(offset);
1288+
offset = PTR_ADD_OFFSET(offset, assemblyNameString->Length + sizeof(UNICODE_NULL));
1289+
clrInstanceID = *(UNALIGNED PUSHORT)offset;
12431290

12441291
// Find the AppDomain node to add the Assembly node to.
12451292

12461293
parentNode = FindClrNode(context, clrInstanceID);
12471294

12481295
if (parentNode)
1296+
{
12491297
parentNode = FindAppDomainNode(parentNode, data->AppDomainID);
1298+
}
12501299

12511300
if (parentNode)
12521301
{
12531302
// Check for duplicates.
12541303
if (FindAssemblyNode(parentNode, data->AssemblyID))
1304+
{
1305+
PhDereferenceObject(assemblyNameString);
12551306
break;
1307+
}
12561308

12571309
node = AddNode(context);
12581310
node->Type = DNA_TYPE_ASSEMBLY;
12591311
node->u.Assembly.AssemblyID = data->AssemblyID;
12601312
node->u.Assembly.AssemblyFlags = data->AssemblyFlags;
1261-
node->u.Assembly.FullyQualifiedAssemblyName = PhCreateStringEx(data->FullyQualifiedAssemblyName, fullyQualifiedAssemblyNameLength);
1313+
node->u.Assembly.FullyQualifiedAssemblyName = assemblyNameString;
12621314

12631315
// Display only the assembly name, not the whole fully qualified name.
12641316
if (!PhSplitStringRefAtChar(&node->u.Assembly.FullyQualifiedAssemblyName->sr, L',', &node->StructureText, &remainingPart))
1317+
{
12651318
node->StructureText = node->u.Assembly.FullyQualifiedAssemblyName->sr;
1319+
}
12661320

12671321
node->IdText = FormatToHexString(data->AssemblyID);
12681322
node->FlagsText = FlagsToString(data->AssemblyFlags, AssemblyFlagsMap, sizeof(AssemblyFlagsMap));
12691323

12701324
PhAddItemList(parentNode->Children, node);
12711325
}
1326+
else
1327+
{
1328+
PhDereferenceObject(assemblyNameString);
1329+
}
12721330
}
12731331
break;
12741332
case ModuleDCStart_V1:
12751333
{
1276-
PModuleLoadUnloadRundown_V1 data = EventRecord->UserData;
1277-
PCWSTR moduleILPath;
1278-
SIZE_T moduleILPathLength;
1279-
PCWSTR moduleNativePath;
1280-
SIZE_T moduleNativePathLength;
1334+
PModuleLoadUnloadRundown_V1 data = UserData;
1335+
UNALIGNED PVOID offset;
1336+
PPH_STRING moduleILPathString;
1337+
PPH_STRING moduleNativeString;
12811338
USHORT clrInstanceID;
12821339
PDNA_NODE node;
12831340

1284-
moduleILPath = data->ModuleILPath;
1285-
moduleILPathLength = PhCountStringZ(moduleILPath) * sizeof(WCHAR);
1286-
moduleNativePath = PTR_ADD_OFFSET(moduleILPath, moduleILPathLength + sizeof(UNICODE_NULL));
1287-
moduleNativePathLength = PhCountStringZ(moduleNativePath) * sizeof(WCHAR);
1288-
clrInstanceID = *(PUSHORT)PTR_ADD_OFFSET(moduleNativePath, moduleNativePathLength + sizeof(UNICODE_NULL));
1341+
offset = PTR_ADD_OFFSET(UserData, RTL_SIZEOF_THROUGH_FIELD(ModuleLoadUnloadRundown_V1, Reserved1));
1342+
moduleILPathString = DnCreateStringSafe(offset);
1343+
offset = PTR_ADD_OFFSET(offset, moduleILPathString->Length + sizeof(UNICODE_NULL));
1344+
moduleNativeString = DnCreateStringSafe(offset);
1345+
offset = PTR_ADD_OFFSET(offset, moduleNativeString->Length + sizeof(UNICODE_NULL));
1346+
clrInstanceID = *(UNALIGNED PUSHORT)offset;
12891347

12901348
// Find the Assembly node to set the path on.
12911349

12921350
node = FindClrNode(context, clrInstanceID);
12931351

12941352
if (node)
1353+
{
12951354
node = FindAssemblyNode2(node, data->AssemblyID);
1355+
}
12961356

12971357
if (node)
12981358
{
1299-
PhMoveReference(&node->PathText, PhCreateStringEx(moduleILPath, moduleILPathLength));
1300-
1301-
if (moduleNativePathLength != 0)
1302-
PhMoveReference(&node->NativePathText, PhCreateStringEx(moduleNativePath, moduleNativePathLength));
1359+
PhMoveReference(&node->PathText, moduleILPathString);
1360+
PhMoveReference(&node->NativePathText, moduleNativeString);
1361+
}
1362+
else
1363+
{
1364+
PhDereferenceObject(moduleNativeString);
1365+
PhDereferenceObject(moduleILPathString);
13031366
}
13041367
}
13051368
break;
@@ -1321,29 +1384,26 @@ static VOID NTAPI DotNetEventCallback(
13211384
{
13221385
case CLR_MODULEDCSTART_OPCODE:
13231386
{
1324-
PModuleLoadUnloadRundown_V1 data = EventRecord->UserData;
1325-
PWSTR moduleILPath;
1326-
SIZE_T moduleILPathLength;
1327-
PWSTR moduleNativePath;
1328-
SIZE_T moduleNativePathLength;
1387+
PModuleLoadUnloadRundown_V1 data = UserData;
1388+
UNALIGNED PVOID offset;
1389+
PPH_STRING moduleILPathString;
1390+
PPH_STRING moduleNativeString;
13291391
PDNA_NODE node;
13301392
ULONG_PTR indexOfBackslash;
13311393
ULONG_PTR indexOfLastDot;
13321394

1333-
moduleILPath = data->ModuleILPath;
1334-
moduleILPathLength = PhCountStringZ(moduleILPath) * sizeof(WCHAR);
1335-
moduleNativePath = PTR_ADD_OFFSET(moduleILPath, moduleILPathLength + sizeof(UNICODE_NULL));
1336-
moduleNativePathLength = PhCountStringZ(moduleNativePath) * sizeof(WCHAR);
1395+
offset = PTR_ADD_OFFSET(UserData, RTL_SIZEOF_THROUGH_FIELD(ModuleLoadUnloadRundown_V1, Reserved1));
1396+
moduleILPathString = DnCreateStringSafe(offset);
1397+
offset = PTR_ADD_OFFSET(offset, moduleILPathString->Length + sizeof(UNICODE_NULL));
1398+
moduleNativeString = DnCreateStringSafe(offset);
13371399

1338-
if (context->ClrV2Node && (moduleILPathLength != 0 || moduleNativePathLength != 0))
1400+
if (context->ClrV2Node && (moduleILPathString->Length != 0 || moduleNativeString->Length != 0))
13391401
{
13401402
node = AddNode(context);
13411403
node->Type = DNA_TYPE_ASSEMBLY;
13421404
node->FlagsText = FlagsToString(data->ModuleFlags, ModuleFlagsMap, sizeof(ModuleFlagsMap));
1343-
node->PathText = PhCreateStringEx(moduleILPath, moduleILPathLength);
1344-
1345-
if (moduleNativePathLength != 0)
1346-
node->NativePathText = PhCreateStringEx(moduleNativePath, moduleNativePathLength);
1405+
node->PathText = moduleILPathString;
1406+
node->NativePathText = moduleNativeString;
13471407

13481408
// Use the name between the last backslash and the last dot for the structure column text.
13491409
// (E.g. C:\...\AcmeSoft.BigLib.dll -> AcmeSoft.BigLib)
@@ -1371,6 +1431,11 @@ static VOID NTAPI DotNetEventCallback(
13711431

13721432
PhAddItemList(context->ClrV2Node->Children, node);
13731433
}
1434+
else
1435+
{
1436+
PhDereferenceObject(moduleNativeString);
1437+
PhDereferenceObject(moduleILPathString);
1438+
}
13741439
}
13751440
break;
13761441
case CLR_METHODDC_DCSTARTCOMPLETE_OPCODE:
@@ -1386,6 +1451,41 @@ static VOID NTAPI DotNetEventCallback(
13861451
}
13871452
}
13881453

1454+
static VOID NTAPI DotNetEventCallback(
1455+
_In_ PEVENT_RECORD EventRecord
1456+
)
1457+
{
1458+
if (EventRecord->UserDataLength)
1459+
{
1460+
// Note: ETW does not force an alignment between event data values.
1461+
1462+
if (EventRecord->UserDataLength != ROUND_TO_SIZE(EventRecord->UserDataLength, MEMORY_ALLOCATION_ALIGNMENT))
1463+
{
1464+
PVOID alignedUserData;
1465+
1466+
alignedUserData = _aligned_malloc(EventRecord->UserDataLength, MEMORY_ALLOCATION_ALIGNMENT);
1467+
1468+
if (alignedUserData)
1469+
{
1470+
RtlSecureZeroMemory(alignedUserData, EventRecord->UserDataLength);
1471+
RtlCopyMemory(alignedUserData, EventRecord->UserData, EventRecord->UserDataLength);
1472+
1473+
DotNetUserDataCallback(EventRecord, alignedUserData);
1474+
1475+
_aligned_free(alignedUserData);
1476+
}
1477+
}
1478+
else
1479+
{
1480+
DotNetUserDataCallback(EventRecord, EventRecord->UserData);
1481+
}
1482+
}
1483+
else
1484+
{
1485+
DotNetUserDataCallback(EventRecord, EventRecord->UserData);
1486+
}
1487+
}
1488+
13891489
static ULONG ProcessDotNetTrace(
13901490
_In_ PASMPAGE_QUERY_CONTEXT Context
13911491
)

plugins/DotNetTools/clr/dbgappdomain.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
typedef struct _AppDomainInfo
2727
{
2828
ULONG Id; // unique identifier
29-
INT NameLengthInBytes;
29+
LONG NameLengthInBytes;
3030
PWSTR AppDomainName;
3131
PVOID AppDomains;
3232
} AppDomainInfo;
@@ -38,7 +38,7 @@ typedef struct _AppDomainInfo
3838
typedef struct _AppDomainInfo_Wow64
3939
{
4040
ULONG Id; // unique identifier
41-
INT NameLengthInBytes;
41+
LONG NameLengthInBytes;
4242
ULONG AppDomainName;
4343
ULONG AppDomains;
4444
} AppDomainInfo_Wow64;
@@ -54,12 +54,12 @@ typedef struct _AppDomainEnumerationIPCBlock
5454
{
5555
HANDLE Mutex; // lock for serialization while manipulating AppDomain list.
5656

57-
INT TotalSlots; // Number of slots in AppDomainListElement array
58-
INT NumOfUsedSlots;
59-
INT LastFreedSlot;
60-
INT SizeInBytes; // Size of AppDomainInfo in bytes
57+
LONG TotalSlots; // Number of slots in AppDomainListElement array
58+
LONG NumOfUsedSlots;
59+
LONG LastFreedSlot;
60+
LONG SizeInBytes; // Size of AppDomainInfo in bytes
6161

62-
INT ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name.
62+
LONG ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name.
6363
PVOID ProcessName; // This provides an alternative.
6464

6565
PVOID ListOfAppDomains;
@@ -74,12 +74,12 @@ typedef struct _AppDomainEnumerationIPCBlock_Wow64
7474
{
7575
ULONG Mutex; // lock for serialization while manipulating AppDomain list.
7676

77-
INT TotalSlots; // Number of slots in AppDomainListElement array
78-
INT NumOfUsedSlots;
79-
INT LastFreedSlot;
80-
INT SizeInBytes; // Size of AppDomainInfo in bytes
77+
LONG TotalSlots; // Number of slots in AppDomainListElement array
78+
LONG NumOfUsedSlots;
79+
LONG LastFreedSlot;
80+
LONG SizeInBytes; // Size of AppDomainInfo in bytes
8181

82-
INT ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name.
82+
LONG ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name.
8383
ULONG ProcessName; // This provides an alternative.
8484

8585
ULONG ListOfAppDomains;

0 commit comments

Comments
 (0)