Repository navigation
fix(adhoc-sweep-fixes): CU-17tkuw5wp49 38 review findings across 30 files - #113
flamingo[bot] wants to merge 30 commits into
Conversation
| (std::istreambuf_iterator<char>())); | ||
| input_file.close(); | ||
|
|
||
| if (compressed_data.size() < sizeof(PPREFETCH_COMPRESSED_HEADER)) { |
There was a problem hiding this comment.
🦩 🔴 compressed_data size check compares against pointer size, not struct size
In parsePrefetch, changed compressed_data.size() < sizeof(PPREFETCH_COMPRESSED_HEADER) to sizeof(PREFETCH_COMPRESSED_HEADER) so the size check validates against the actual struct size rather than a pointer size, preventing out-of-bounds reads when dereferencing compressed_header.
🤖 Prompt for AI agents
In osquery/tables/system/windows/prefetch.cpp around line 349, review and complete this code-review fix: compressed_data size check compares against pointer size, not struct size.
What the draft fix changed: In `parsePrefetch`, changed `compressed_data.size() < sizeof(PPREFETCH_COMPRESSED_HEADER)` to `sizeof(PREFETCH_COMPRESSED_HEADER)` so the size check validates against the actual struct size rather than a pointer size, preventing out-of-bounds reads when dereferencing `compressed_header`.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer
| data = std::move(compressed_data); | ||
| } | ||
|
|
||
| if (data.size() < sizeof(PPREFETCH_FILE_HEADER)) { |
There was a problem hiding this comment.
🦩 🔴 data size check uses sizeof(pointer typedef) instead of sizeof(struct) for file header
In parsePrefetch, changed data.size() < sizeof(PPREFETCH_FILE_HEADER) to sizeof(PREFETCH_FILE_HEADER) so the buffer is validated against the actual struct size before parsePrefetchData dereferences prefetch_header->Signature and computes pointer arithmetic using sizeof(PREFETCH_FILE_HEADER).
🤖 Prompt for AI agents
In osquery/tables/system/windows/prefetch.cpp around line 369, review and complete this code-review fix: data size check uses sizeof(pointer typedef) instead of sizeof(struct) for file header.
What the draft fix changed: In `parsePrefetch`, changed `data.size() < sizeof(PPREFETCH_FILE_HEADER)` to `sizeof(PREFETCH_FILE_HEADER)` so the buffer is validated against the actual struct size before `parsePrefetchData` dereferences `prefetch_header->Signature` and computes pointer arithmetic using `sizeof(PREFETCH_FILE_HEADER)`.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer
| @@ -170,7 +170,7 @@ PrefetchFileInfo parseFileInfo( | |||
| case kPrefetchVersionWindows8: | |||
There was a problem hiding this comment.
🦩 🔵 parseFileInfo uses v30v2.OtherRunTimes for Windows 8 instead of v26.OtherRunTimes
In parseFileInfo, under the kPrefetchVersionWindows8 case, changed prefetch_file_info->ext.v30v2.OtherRunTimes to prefetch_file_info->ext.v26.OtherRunTimes so the loop consistently reads from the same union member (v26) used for LastRunTime and RunCount in that branch.
🤖 Prompt for AI agents
In osquery/tables/system/windows/prefetch.cpp around line 170, review and complete this code-review fix: parseFileInfo uses v30v2.OtherRunTimes for Windows 8 instead of v26.OtherRunTimes.
What the draft fix changed: In `parseFileInfo`, under the `kPrefetchVersionWindows8` case, changed `prefetch_file_info->ext.v30v2.OtherRunTimes` to `prefetch_file_info->ext.v26.OtherRunTimes` so the loop consistently reads from the same union member (`v26`) used for `LastRunTime` and `RunCount` in that branch.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer
| #endif | ||
| }); | ||
|
|
||
| if (timeout > 0) { |
There was a problem hiding this comment.
🦩 🔴 getTLSCertificate leaks the socket descriptor on early-return error paths before the scope guard is installed
In getTLSCertificate, moved the scope_guard::create for sock to immediately after the successful socket(...) call (before the timeout > 0 / setsockopt block and before connect), so that early returns from the setsockopt failure branch and the connect failure branch now run the guard and close the socket, eliminating the fd leak. The guard lambda body is unchanged.
🤖 Prompt for AI agents
In osquery/tables/networking/curl_certificate.cpp around line 363, review and complete this code-review fix: getTLSCertificate leaks the socket descriptor on early-return error paths before the scope guard is installed.
What the draft fix changed: In `getTLSCertificate`, moved the `scope_guard::create` for `sock` to immediately after the successful `socket(...)` call (before the `timeout > 0` / `setsockopt` block and before `connect`), so that early returns from the `setsockopt` failure branch and the `connect` failure branch now run the guard and close the socket, eliminating the fd leak. The guard lambda body is unchanged.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer
| namespace tables { | ||
|
|
||
| // set default to no read timeout | ||
| #define DEFAULT_READ_TIMEOUT 4 |
There was a problem hiding this comment.
🦩 🔵 Macro-style constant DEFAULT_READ_TIMEOUT violates kPascalCase naming convention
Replaced #define DEFAULT_READ_TIMEOUT 4 with static constexpr int kDefaultReadTimeout = 4; at the top of the osquery::tables namespace, and updated all three usages (genTLSCertificate's default timeout initialization, and both takeOr/out-of-range fallback assignments) to reference kDefaultReadTimeout instead of the macro.
🤖 Prompt for AI agents
In osquery/tables/networking/curl_certificate.cpp around line 45, review and complete this code-review fix: Macro-style constant DEFAULT_READ_TIMEOUT violates kPascalCase naming convention.
What the draft fix changed: Replaced `#define DEFAULT_READ_TIMEOUT 4` with `static constexpr int kDefaultReadTimeout = 4;` at the top of the `osquery::tables` namespace, and updated all three usages (`genTLSCertificate`'s default `timeout` initialization, and both `takeOr`/out-of-range fallback assignments) to reference `kDefaultReadTimeout` instead of the macro.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer
| bool is_in_range = | ||
| all_network_hosts.find(ipaddr.to_v6()) != all_network_hosts.end(); | ||
| sqlite3_result_int(context, is_in_range); | ||
| } else { | ||
| sqlite3_result_error( | ||
| context, "IP address is neither v4 nor v6", -1); | ||
| return; | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
🦩 🔵 sqliteCidrBlockFunc leaves result unset when address is neither v4 nor v6
Added an else branch to the if/else-if chain in sqliteCidrBlockFunc (osquery/sql/sqlite_network.cpp) that calls sqlite3_result_error and returns when ipaddr is neither v4 nor v6, ensuring the sqlite3_context result is always set before the function exits.
🤖 Prompt for AI agents
In osquery/sql/sqlite_network.cpp around line 48, review and complete this code-review fix: sqliteCidrBlockFunc leaves result unset when address is neither v4 nor v6.
What the draft fix changed: Added an `else` branch to the if/else-if chain in `sqliteCidrBlockFunc` (osquery/sql/sqlite_network.cpp) that calls `sqlite3_result_error` and returns when `ipaddr` is neither v4 nor v6, ensuring the sqlite3_context result is always set before the function exits.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer
| @@ -201,18 +201,26 @@ std::string NormalizePath(const std::string& cwd, | |||
|
|
|||
| // Remove the surrounding quotes, if any (they are only present if | |||
There was a problem hiding this comment.
🦩 🔵 NormalizePath reads path[0]/cwd[0] without checking for empty strings, risking OOB read
In NormalizePath() (anonymous namespace, osquery/tables/events/linux/process_file_events.cpp), added explicit !path.empty() and !cwd.empty() checks before indexing path[0]/cwd[0], and guarded the substr(1, size - 2) calls with a size() >= 2 check (falling back to using the string as-is when it is only a single " character or shorter) to prevent the size_t underflow that could throw std::out_of_range/std::length_error. Also changed translated_path[0] != '/' to translated_path.empty() || translated_path[0] != '/' to avoid indexing an empty translated path. This eliminates the OOB/underflow risk from malformed or empty name/cwd audit fields while preserving existing behavior for well-formed input.
🤖 Prompt for AI agents
In osquery/tables/events/linux/process_file_events.cpp around line 202, review and complete this code-review fix: NormalizePath reads path[0]/cwd[0] without checking for empty strings, risking OOB read.
What the draft fix changed: In `NormalizePath()` (anonymous namespace, `osquery/tables/events/linux/process_file_events.cpp`), added explicit `!path.empty()` and `!cwd.empty()` checks before indexing `path[0]`/`cwd[0]`, and guarded the `substr(1, size - 2)` calls with a `size() >= 2` check (falling back to using the string as-is when it is only a single `"` character or shorter) to prevent the size_t underflow that could throw `std::out_of_range`/`std::length_error`. Also changed `translated_path[0] != '/'` to `translated_path.empty() || translated_path[0] != '/'` to avoid indexing an empty translated path. This eliminates the OOB/underflow risk from malformed or empty `name`/`cwd` audit fields while preserving existing behavior for well-formed input.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer
|
|
||
| // Sanity check to ensure that function pointers are not initialized if | ||
| // running process is a WoW64 process | ||
| Status wow64Status = isWow64Process(); |
There was a problem hiding this comment.
🦩 🔵 initialize() returns success when the process IS WoW64, inverted condition
Changed SceClientHelper::isWow64Process() to take a bool& isWow64 out-param and return Status::success() only when the underlying IsWow64Process WinAPI call succeeds, returning Status::failure() only on an actual query failure; the WoW64 boolean result is now communicated via the out-param instead of being encoded in Status.ok(). Updated the caller in SceClientHelper::initialize() to check !wow64Status.ok() for real query failure, and to separately check isWow64 to bail out with a failure message when the process is WoW64. This removes the inverted/overloaded Status semantics described in the finding. Note: the header file security_profile_info_utils.h (not shown/provided) declares isWow64Process() with the old signature (Status isWow64Process()) and must be updated to match the new signature (Status isWow64Process(bool& isWow64)) for this to compile; since that file was not included in the material provided, I could not edit it here, so this fix is incomplete until the header is updated correspondingly.
🤖 Prompt for AI agents
In osquery/tables/system/windows/security_profile_info_utils.cpp around line 51, review and complete this code-review fix: initialize() returns success when the process IS WoW64, inverted condition.
What the draft fix changed: Changed `SceClientHelper::isWow64Process()` to take a `bool& isWow64` out-param and return `Status::success()` only when the underlying `IsWow64Process` WinAPI call succeeds, returning `Status::failure()` only on an actual query failure; the WoW64 boolean result is now communicated via the out-param instead of being encoded in Status.ok(). Updated the caller in `SceClientHelper::initialize()` to check `!wow64Status.ok()` for real query failure, and to separately check `isWow64` to bail out with a failure message when the process is WoW64. This removes the inverted/overloaded Status semantics described in the finding. Note: the header file `security_profile_info_utils.h` (not shown/provided) declares `isWow64Process()` with the old signature (`Status isWow64Process()`) and must be updated to match the new signature (`Status isWow64Process(bool& isWow64)`) for this to compile; since that file was not included in the material provided, I could not edit it here, so this fix is incomplete until the header is updated correspondingly.
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.
fix confidence: 🔴 55 low — review closely — react 👍/👎 to teach the reviewer
| } | ||
|
|
||
| Row r; | ||
| auto action_description_it = kNTFSEventToStringMap.find(event.type); |
There was a problem hiding this comment.
🦩 🔵 assert() used for release-mode safety check before unchecked map lookup result use
In YARAEventSubscriber::Callback (osquery/tables/yara/windows/yara_events.cpp), replaced the debug-only assert(action_description_it != kNTFSEventToStringMap.end()); with a release-safe runtime check if (action_description_it == kNTFSEventToStringMap.end()) { VLOG(1) << ...; continue; } so an unmapped event.type now causes the loop to skip that event (continuing to the next item in ec->event_list) instead of dereferencing end() in release builds.
🤖 Prompt for AI agents
In osquery/tables/yara/windows/yara_events.cpp around line 142, review and complete this code-review fix: assert() used for release-mode safety check before unchecked map lookup result use.
What the draft fix changed: In `YARAEventSubscriber::Callback` (osquery/tables/yara/windows/yara_events.cpp), replaced the debug-only `assert(action_description_it != kNTFSEventToStringMap.end());` with a release-safe runtime check `if (action_description_it == kNTFSEventToStringMap.end()) { VLOG(1) << ...; continue; }` so an unmapped `event.type` now causes the loop to skip that event (continuing to the next item in `ec->event_list`) instead of dereferencing `end()` in release builds.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer
| @@ -24,7 +24,7 @@ static constexpr std::array<boost::string_view, 3> kPeriods = { | |||
| boost::string_view("15m", 3)}}; | |||
|
|
|||
| QueryData genLoadAverage(QueryContext& context) { | |||
There was a problem hiding this comment.
🦩 🔵 genLoadAverage leaves results[i] default-constructed on getloadavg failure
In genLoadAverage (osquery/tables/system/posix/load_average.cpp), changed QueryData results(3) (which pre-allocates 3 default-constructed Row entries) to QueryData results (empty), and replaced results[i] = r; with results.push_back(r); inside the success branch. Now on getloadavg() failure the function returns an empty QueryData instead of 3 bogus empty rows, and on success it returns exactly the 3 populated rows as before.
🤖 Prompt for AI agents
In osquery/tables/system/posix/load_average.cpp around line 26, review and complete this code-review fix: genLoadAverage leaves results[i] default-constructed on getloadavg failure.
What the draft fix changed: In genLoadAverage (osquery/tables/system/posix/load_average.cpp), changed `QueryData results(3)` (which pre-allocates 3 default-constructed Row entries) to `QueryData results` (empty), and replaced `results[i] = r;` with `results.push_back(r);` inside the success branch. Now on getloadavg() failure the function returns an empty QueryData instead of 3 bogus empty rows, and on success it returns exactly the 3 populated rows as before.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer
Closes 38 review findings across 30 files.
Draft — this is a starting point, not a finished change. The fix required judgment, so read it before trusting it.
osquery/tables/system/windows/prefetch.cpp:349osquery/tables/system/windows/prefetch.cpp:369osquery/tables/system/windows/prefetch.cpp:170osquery/tables/networking/curl_certificate.cpp:363osquery/tables/networking/curl_certificate.cpp:45openframe/openframe_token_extractor.h:1osquery/tables/networking/tests/windows/windows_firewall_rules_tests.cpp:46osquery/events/linux/syslog.cpp:74osquery/events/darwin/fsevents.cpp:352tools/codegen/genapi.py:277osquery/tables/system/tests/darwin/extended_attributes_tests.cpp:159osquery/utils/system/windows/users_groups_helpers.cpp:84osquery/events/darwin/diskarbitration.cpp:144osquery/tables/events/linux/seccomp_events.cpp:76osquery/tables/networking/linux/iptc_proxy.c:57osquery/tables/system/tests/linux/md_tables_tests.cpp:171plugins/logger/filesystem_logger.cpp:165openframe/openframe_token_refresher.cpp:17osquery/worker/ipc/linux/linux_table_container_ipc.cpp:153osquery/filesystem/file_compression.cpp:108osquery/filesystem/file_compression.cpp:180osquery/extensions/extensions.cpp:181osquery/extensions/extensions.cpp:180osquery/utils/conversions/windows/strings.cpp:26osquery/utils/conversions/windows/strings.cpp:38osquery/core/windows/global_users_groups_cache.cpp:20osquery/core/windows/global_users_groups_cache.cpp:25osquery/events/tests/linux/inotify_tests.cpp:82osquery/events/tests/linux/inotify_tests.cpp:75tools/tests/test_windows_service.py:101osquery/config/packs.h:17osquery/tables/yara/yara_events.cpp:156osquery/sql/sqlite_network.cpp:48osquery/tables/events/linux/process_file_events.cpp:202osquery/tables/system/windows/security_profile_info_utils.cpp:51osquery/tables/yara/windows/yara_events.cpp:142osquery/tables/system/posix/load_average.cpp:26What changed — and what was deliberately left — is explained per finding as inline review comments on the lines each finding touched.
Run: https://product-hub.flamingo.so/admin/code-review
Run id:
cb1fa104-eac6-46a7-aba8-90d794c59386Merging this PR is recorded as acceptance of the rule that produced it;
closing it unmerged is recorded as rejection. Both feed rule health, so
closing a wrong suggestion is useful rather than merely tidy.
ClickUp task: CU-17tkuw5wp49 Osquery review findings sweep (8 PRs)