From b34102feac5c5f7301066dfdc7a73d8d64a2c6f2 Mon Sep 17 00:00:00 2001 From: nutbolt9 Date: Sat, 1 Aug 2026 17:28:04 +0100 Subject: [PATCH 1/3] Fall back to unmodified lighthouse config when recompression fails compress() failure was logged but execution continued, assigning the partially written buffer to info.newLighthouseConfig. HidGetFeatureReportHook then served that buffer to driver_lighthouse in place of the device's own config, so a failed recompress produced a corrupt config rather than no change at all. Move the trailer write and assignment into the Z_OK branch and free the buffer on failure, leaving newLighthouseConfig null so the hook passes through to the original config. Co-Authored-By: Claude Opus 5 --- .../src/Driver/HidModifier.cpp | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/CustomHeadsetOpenVR/src/Driver/HidModifier.cpp b/CustomHeadsetOpenVR/src/Driver/HidModifier.cpp index af1542e..0922b96 100644 --- a/CustomHeadsetOpenVR/src/Driver/HidModifier.cpp +++ b/CustomHeadsetOpenVR/src/Driver/HidModifier.cpp @@ -325,16 +325,20 @@ std::string HidModifier::ReadLighthouseConfig(HidDeviceInfo &info){ result = compress(configRecompressed, &recompressedSize, (unsigned char*)newConfigStr.c_str(), newConfigStr.length()); if(result == Z_OK){ DriverLog("Recompressed lighthouse config"); + // not sure why but these are always returned + configRecompressed[recompressedSize] = 0xff; + configRecompressed[recompressedSize + 1] = 0xff; + info.newLighthouseConfig = configRecompressed; + info.newLighthouseConfigLength = recompressedSize; + // info.newLighthouseConfig = configCompressed; + // info.newLighthouseConfigLength = size; }else{ - DriverLog("Failed to recompress lighthouse config"); + // Serving a partially written buffer makes the lighthouse driver parse a corrupt + // config. Leave newLighthouseConfig null so HidGetFeatureReportHook falls through + // to the device's own unmodified config instead. + DriverLog("Failed to recompress lighthouse config, falling back to unmodified config"); + delete[] configRecompressed; } - // not sure why but these are always returned - configRecompressed[recompressedSize] = 0xff; - configRecompressed[recompressedSize + 1] = 0xff; - info.newLighthouseConfig = configRecompressed; - info.newLighthouseConfigLength = recompressedSize; - // info.newLighthouseConfig = configCompressed; - // info.newLighthouseConfigLength = size; } return configStr; From e450067c67825e79a2b974fd10154b9c0dacd28b Mon Sep 17 00:00:00 2001 From: nutbolt9 Date: Sat, 1 Aug 2026 17:29:42 +0100 Subject: [PATCH 2/3] Initialise HidDeviceInfo members AddDevice default-initialises a HidDeviceInfo, leaving device, newLighthouseConfig, newLighthouseConfigLength and newLighthouseConfigOffset indeterminate. ReadLighthouseConfig only assigns newLighthouseConfig on the path where it actually rewrites the config, so every early return (feature report failure, size > 20000, failed decompress) leaves the pointer holding whatever was on the stack. HidGetFeatureReportHook then tests that value against nullptr and, if non-zero, memcpys from it; HidDeviceInfo::Delete() passes it to delete[]. Both are undefined behaviour on any device whose config could not be read. Co-Authored-By: Claude Opus 5 --- CustomHeadsetOpenVR/src/Driver/HidModifier.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CustomHeadsetOpenVR/src/Driver/HidModifier.h b/CustomHeadsetOpenVR/src/Driver/HidModifier.h index 73ca24e..1cc640d 100644 --- a/CustomHeadsetOpenVR/src/Driver/HidModifier.h +++ b/CustomHeadsetOpenVR/src/Driver/HidModifier.h @@ -64,13 +64,18 @@ class HidModifier { // info about device class HidDeviceInfo { public: - hid_device* device; + // These must be initialised here. AddDevice default-initialises a HidDeviceInfo and + // ReadLighthouseConfig only assigns newLighthouseConfig when it modifies the config, + // so every early return (failed feature report, oversized config, failed decompress) + // would otherwise leave an indeterminate pointer that HidGetFeatureReportHook tests + // against nullptr and Delete() passes to delete[]. + hid_device* device = nullptr; std::string lighthouseDeviceName; std::string lighthouseDeviceManufacturer; // std::string lighthouseConfig; - unsigned char* newLighthouseConfig; - int newLighthouseConfigLength; - int newLighthouseConfigOffset; + unsigned char* newLighthouseConfig = nullptr; + int newLighthouseConfigLength = 0; + int newLighthouseConfigOffset = 0; void Delete(){ if(newLighthouseConfig) { delete[] newLighthouseConfig; From 03cb3a1b8214a35cff81ddea13f25c75bbc0328b Mon Sep 17 00:00:00 2001 From: nutbolt9 Date: Sat, 1 Aug 2026 17:30:34 +0100 Subject: [PATCH 3/3] Guard HidGetFeatureReportHook against short buffers The hook read data[0] and wrote data[1..2] without checking length. length is a size_t, so a caller passing 0 or 1 also underflowed the (length - 2) used to size the chunk copy, producing a negative toCopy that memcpy takes as a very large size_t. driver_lighthouse supplies 65 in practice, so this is hardening rather than an observed fault, but the hook runs for every hid_get_feature_report call in that module and the failure mode is heap corruption. Co-Authored-By: Claude Opus 5 --- CustomHeadsetOpenVR/src/Driver/HidModifier.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CustomHeadsetOpenVR/src/Driver/HidModifier.cpp b/CustomHeadsetOpenVR/src/Driver/HidModifier.cpp index 0922b96..635d956 100644 --- a/CustomHeadsetOpenVR/src/Driver/HidModifier.cpp +++ b/CustomHeadsetOpenVR/src/Driver/HidModifier.cpp @@ -371,7 +371,10 @@ int HidModifier::HidGetFeatureReportHook(hid_device* device, unsigned char* data #endif HidDeviceInfo &info = hidModifier.deviceMap[device]; - if(info.newLighthouseConfig != nullptr){ + // Both branches below read data[0] and write data[1], and the 0x10 branch also writes + // data[2]. length is a size_t, so a caller passing less than 2 would also underflow the + // (length - 2) that sizes the chunk copy, yielding a negative toCopy and a huge memcpy. + if(info.newLighthouseConfig != nullptr && length >= 3){ // output the new config if(data[0] == 0x10){ // output new size