@samitouri / QOSAMI-WSL / commits / 8e1fafb9

Add BUFFER_FIELD macro for safe pretty-printing of flexible array members (#40273)

Message structs with flexible array members (char Buffer[], char Content[]) used FIELD() in PRETTY_PRINT, which streams the member as a C-string until a NUL byte. Add a BUFFER_FIELD macro and PrettyPrintSafeBufferView helper that bounds the read using Header.MessageSize. Also add std::string_view handling to PrettyPrint. Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Ben Hillis committed Apr 22, 2026 at 14:46 UTC 8e1fafb99fb26afd3709a89a0e18af2b0abff245
2 files changed +33 -11
src/shared/inc/lxinitshared.h
+10 -10
@@ -579,7 +579,7 @@ typedef struct _LX_PROCESS_CRASH
579
580 char Buffer[];
581
582 - PRETTY_PRINT(FIELD(Header), FIELD(Timestamp), FIELD(Signal), FIELD(Pid), FIELD(Buffer));
582 + PRETTY_PRINT(FIELD(Header), FIELD(Timestamp), FIELD(Signal), FIELD(Pid), BUFFER_FIELD(Buffer));
583
584 } LX_PROCESS_CRASH, *PLX_PROCESS_CRASH;
585
@@ -701,7 +701,7 @@ typedef struct _LX_INIT_CREATE_LOGIN_SESSION
701 unsigned int Gid;
702 char Buffer[]; // Contains username
703
704 - PRETTY_PRINT(FIELD(Header), FIELD(Uid), FIELD(Gid), FIELD(Buffer));
704 + PRETTY_PRINT(FIELD(Header), FIELD(Uid), FIELD(Gid), BUFFER_FIELD(Buffer));
705 } LX_INIT_CREATE_LOGIN_SESSION, *PLX_INIT_CREATE_LOGIN_SESSION;
706
707 //
@@ -716,7 +716,7 @@ typedef struct _LX_INIT_QUERY_ENVIRONMENT_VARIABLE
716 MESSAGE_HEADER Header;
717 char Buffer[];
718
719 - PRETTY_PRINT(FIELD(Header), FIELD(Buffer));
719 + PRETTY_PRINT(FIELD(Header), BUFFER_FIELD(Buffer));
720 } LX_INIT_QUERY_ENVIRONMENT_VARIABLE, *PLX_INIT_QUERY_ENVIRONMENT_VARIABLE;
721
722 typedef struct _LX_GNS_RESULT
@@ -739,7 +739,7 @@ typedef struct _LX_GNS_INTERFACE_CONFIGURATION
739 MESSAGE_HEADER Header;
740 char Content[];
741
742 - PRETTY_PRINT(FIELD(Header), FIELD(Content));
742 + PRETTY_PRINT(FIELD(Header), BUFFER_FIELD(Content));
743 } LX_GNS_INTERFACE_CONFIGURATION, *PLX_GNS_INTERFACE_CONFIGURATION;
744
745 typedef struct _LX_GNS_NOTIFICATION
@@ -751,7 +751,7 @@ typedef struct _LX_GNS_NOTIFICATION
751 GUID AdapterId;
752 char Content[];
753
754 - PRETTY_PRINT(FIELD(Header), FIELD(AdapterId), FIELD(Content));
754 + PRETTY_PRINT(FIELD(Header), FIELD(AdapterId), BUFFER_FIELD(Content));
755 } LX_GNS_NOTIFICATION, *PLX_GNS_NOTIFICATION;
756
757 typedef struct _LX_GNS_PORT_ALLOCATION_REQUEST
@@ -845,7 +845,7 @@ typedef struct _LX_GNS_JSON_MESSAGE
845 MESSAGE_HEADER Header;
846 char Content[];
847
848 - PRETTY_PRINT(FIELD(Header), FIELD(Content));
848 + PRETTY_PRINT(FIELD(Header), BUFFER_FIELD(Content));
849 } LX_GNS_JSON_MESSAGE, *PLX_GNS_JSON_MESSAGE;
850
851 using PCLX_INIT_NETWORK_INFORMATION = const LX_INIT_NETWORK_INFORMATION*;
@@ -1288,7 +1288,7 @@ typedef struct _LX_MINI_INIT_TELEMETRY_MESSAGE
1288 bool ShowDrvFsNotification;
1289 char Buffer[];
1290
1291 - PRETTY_PRINT(FIELD(Header), FIELD(ShowDrvFsNotification), FIELD(Buffer));
1291 + PRETTY_PRINT(FIELD(Header), FIELD(ShowDrvFsNotification), BUFFER_FIELD(Buffer));
1292
1293 } LX_MINI_INIT_TELEMETRY_MESSAGE, *PLX_MINI_INIT_TELEMETRY_MESSAGE;
1294
@@ -1319,7 +1319,7 @@ typedef struct _LX_MINI_INIT_UNMOUNT_MESSAGE
1319 MESSAGE_HEADER Header;
1320 char Buffer[];
1321
1322 - PRETTY_PRINT(FIELD(Header), FIELD(Buffer));
1322 + PRETTY_PRINT(FIELD(Header), BUFFER_FIELD(Buffer));
1323 } LX_MINI_INIT_UNMOUNT_MESSAGE, *PLX_MINI_INIT_UNMOUNT_MESSAGE;
1324
1325 typedef struct _LX_MINI_INIT_DETACH_MESSAGE
@@ -1368,7 +1368,7 @@ typedef struct _LX_INIT_GUEST_CAPABILITIES
1368 bool SeccompAvailable;
1369 char Buffer[]; // Contains the kernel version string
1370
1371 - PRETTY_PRINT(FIELD(Header), FIELD(SeccompAvailable), FIELD(Buffer));
1371 + PRETTY_PRINT(FIELD(Header), FIELD(SeccompAvailable), BUFFER_FIELD(Buffer));
1372 } LX_INIT_GUEST_CAPABILITIES, *PLX_INIT_GUEST_CAPABILITIES;
1373
1374 typedef struct _LX_MINI_INIT_WAIT_FOR_PMEM_DEVICE_MESSAGE
@@ -1515,7 +1515,7 @@ typedef struct _LX_INIT_QUERY_VM_ID
1515 MESSAGE_HEADER Header;
1516 char Buffer[];
1517
1518 - PRETTY_PRINT(FIELD(Header), FIELD(Buffer));
1518 + PRETTY_PRINT(FIELD(Header), BUFFER_FIELD(Buffer));
1519 } LX_INIT_QUERY_VM_ID, *PLX_INIT_QUERY_VM_ID;
1520
1521 template <>
src/shared/inc/prettyprintshared.h
+23 -1
@@ -17,6 +17,8 @@ Abstract:
17 #pragma once
18
19 #include <sstream>
20 +#include <cstring>
21 +#include <string_view>
22
23 #include "defs.h"
24 #include "stringshared.h"
@@ -31,6 +33,22 @@ Abstract:
33
34 #define STRING_FIELD(Name) #Name, (Name <= 0 ? "<empty>" : ((char*)(this)) + Name)
35
36 +// Safe pretty-print for flexible array members (char Buffer[]). Bounds the read
37 +// using the struct's Header.MessageSize so it never reads past the received data.
38 +#define BUFFER_FIELD(Name) #Name, PrettyPrintSafeBufferView(this, Header.MessageSize, Name)
39 +
40 +inline std::string_view PrettyPrintSafeBufferView(const void* structBase, unsigned int messageSize, const char* buffer)
41 +{
42 + const auto offset = static_cast<size_t>(buffer - reinterpret_cast<const char*>(structBase));
43 + if (offset >= messageSize)
44 + {
45 + return "<out-of-bounds>";
46 + }
47 +
48 + const size_t maxLen = messageSize - offset;
49 + return std::string_view(buffer, strnlen(buffer, maxLen));
50 +}
51 +
52 #define PRETTY_PRINT(...) \
53 void PrettyPrintImpl(std::stringstream& Out) const \
54 { \
@@ -47,7 +65,11 @@ Abstract:
65 template <typename T>
66 inline void PrettyPrint(std::stringstream& Out, const T& Value)
67 {
50 - if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, char[]>)
68 + if constexpr (std::is_same_v<T, std::string_view>)
69 + {
70 + Out << Value;
71 + }
72 + else if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, char[]>)
73 {
74 if (Value == nullptr)
75 {