Skip to content

fix: parallel pipe reads, WQL validation, tighter regex#381

Merged
laurentiu021 merged 1 commit into
mainfrom
fix/process-deadlock-security
May 15, 2026
Merged

fix: parallel pipe reads, WQL validation, tighter regex#381
laurentiu021 merged 1 commit into
mainfrom
fix/process-deadlock-security

Conversation

@laurentiu021

@laurentiu021 laurentiu021 commented May 15, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes process deadlock and security defense-in-depth findings from the full codebase audit.

Pipe Deadlock Fix (H-04)

  • SpeedTestService — stdout and stderr were read sequentially. If the Ookla CLI writes enough to stderr while stdout is being consumed, the pipe buffer fills and the process deadlocks indefinitely.
  • Fix: Read both pipes in parallel with Task.WhenAll before WaitForExitAsync.

WQL Injection Defense (H-07)

  • DiskHealthService — objectId from prior WMI query was interpolated into a WQL ASSOCIATORS query with only quote/backslash escaping. While the input source is trusted (WMI), defense-in-depth was missing.
  • Fix: Added regex validation that rejects unexpected characters before interpolation.

PowerShell Injection Documentation (H-10)

  • WindowsFeaturesService — the FeatureNamePattern() regex is the sole defense against PowerShell injection. Added SECURITY-CRITICAL comment documenting this constraint so future developers do not relax it.

Package ID Regex Tightening (SVC-50)

  • UninstallerService — PackageIdPattern used \s which allows tabs and newlines. Replaced with literal space to reject control characters in package IDs.

Build

  • 0 errors, 16 warnings (all pre-existing)
  • Tests project: 0 errors

Summary by CodeRabbit

  • Bug Fixes

    • Resolved a potential hang during speed tests on Windows by ensuring process output is handled reliably.
    • Strengthened validation in disk health checks to skip unsafe identifiers and avoid unreliable enrichment.
    • Tightened package ID validation to reduce false positives and improve uninstall operations.
  • Documentation

    • Added a security-critical note clarifying the regex-based protection for feature management commands.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 81c72234-87b2-4b96-a1c3-3d2c9f9fb3cb

📥 Commits

Reviewing files that changed from the base of the PR and between a5f7913d50f54a5ffc3dd66193a0dde142af1423 and f7195d8.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • SysManager/SysManager/Services/DiskHealthService.cs
  • SysManager/SysManager/Services/SpeedTestService.cs
  • SysManager/SysManager/Services/UninstallerService.cs
  • SysManager/SysManager/Services/WindowsFeaturesService.cs
✅ Files skipped from review due to trivial changes (2)
  • SysManager/SysManager/Services/WindowsFeaturesService.cs
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • SysManager/SysManager/Services/DiskHealthService.cs
  • SysManager/SysManager/Services/UninstallerService.cs
  • SysManager/SysManager/Services/SpeedTestService.cs
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build & unit tests
  • GitHub Check: Analyze (csharp)

📝 Walkthrough

Walkthrough

PR 381 implements security and stability hardening across four services: DiskHealthService now validates WMI objectId before WQL interpolation; SpeedTestService switches to parallel stream reading to prevent pipe deadlocks; UninstallerService tightens PackageIdPattern to disallow unintended whitespace; WindowsFeaturesService adds SECURITY-CRITICAL documentation emphasizing FeatureNamePattern as the sole injection defense.

Changes

Security and Stability Hardening v0.48.16

Layer / File(s) Summary
Disk Health WMI objectId Validation
SysManager/SysManager/Services/DiskHealthService.cs
Added Serilog import and a regex-based validation guard for WMI objectId before constructing the reliability-counter WQL query; logs a warning and skips enrichment on mismatch.
SpeedTest Process I/O Stability
SysManager/SysManager/Services/SpeedTestService.cs
RunOoklaAsync now reads StandardOutput and StandardError concurrently via ReadToEndAsync and Task.WhenAll instead of sequential reads, preventing Windows pipe deadlocks.
UninstallerService PackageIdPattern Tightening
SysManager/SysManager/Services/UninstallerService.cs
PackageIdPattern() regex updated to allow only literal space characters instead of \s, preserving length constraints while disallowing unintended whitespace.
WindowsFeaturesService Injection Defense Documentation
SysManager/SysManager/Services/WindowsFeaturesService.cs
SECURITY-CRITICAL comment added above FeatureNamePattern() documenting that the regex is the sole PowerShell injection mitigation for feature name interpolation.
Release Notes (0.48.16)
CHANGELOG.md
Version 0.48.16 entries documenting all four hardening fixes and the security documentation addition.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 A rabbit hopped in, tidy and spry,
validating names and draining pipes dry,
patterns tightened, logs set to warn,
changelog penned on a bright release morn,
safe and secure — hop on, deploy! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes all three main fixes: parallel pipe reads (SpeedTestService), WQL validation (DiskHealthService), and tighter regex (UninstallerService).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/process-deadlock-security

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@SysManager/SysManager/Services/SpeedTestService.cs`:
- Around line 209-220: Wrap the parallel stream reads (the
StandardOutput.ReadToEndAsync calls assigned to stdoutTask and stderrTask) and
the await proc.WaitForExitAsync(linked) inside a single try/catch/finally so
that any OperationCanceledException or other failure during Task.WhenAll will
run your cleanup; on catch (or finally if preferred) call
proc.Kill(entireProcessTree: true) (targeting the speedtest.exe child) and then
await proc.WaitForExitAsync() to ensure the process is reaped, and only after
successful cleanup read stdoutTask.Result and stderrTask.Result or handle their
cancellation/exception states accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0ed746d3-a921-4089-98d8-3ed7d37a1826

📥 Commits

Reviewing files that changed from the base of the PR and between d6bf10b and a5f7913d50f54a5ffc3dd66193a0dde142af1423.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • SysManager/SysManager/Services/DiskHealthService.cs
  • SysManager/SysManager/Services/SpeedTestService.cs
  • SysManager/SysManager/Services/UninstallerService.cs
  • SysManager/SysManager/Services/WindowsFeaturesService.cs
📜 Review details
🔇 Additional comments (4)
CHANGELOG.md (1)

9-23: LGTM!

SysManager/SysManager/Services/DiskHealthService.cs (1)

6-6: LGTM!

Also applies to: 72-79

SysManager/SysManager/Services/UninstallerService.cs (1)

68-68: LGTM!

SysManager/SysManager/Services/WindowsFeaturesService.cs (1)

158-160: LGTM!

Comment on lines +209 to 220
// Read stdout and stderr in parallel to prevent pipe buffer deadlock.
// If one pipe fills while the other is being read sequentially, the
// child process blocks indefinitely (classic Windows pipe deadlock).
var stdoutTask = proc.StandardOutput.ReadToEndAsync(linked);
var stderrTask = proc.StandardError.ReadToEndAsync(linked);
await Task.WhenAll(stdoutTask, stderrTask).ConfigureAwait(false);
var stdout = stdoutTask.Result;
var stderr = stderrTask.Result;

try
{
await proc.WaitForExitAsync(linked);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether Task.WhenAll cancellation is covered by the same cleanup catch that kills the process tree.
# Expected: Task.WhenAll + WaitForExitAsync both appear within one try/catch(OperationCanceledException) path.
rg -n -C5 'Task\.WhenAll\(stdoutTask,\s*stderrTask\)|WaitForExitAsync\(linked\)|OperationCanceledException|Kill\(entireProcessTree:\s*true\)' --type cs

Repository: laurentiu021/SystemManager

Length of output: 50382


Move parallel pipe reads into the cancellation cleanup path to prevent orphaned processes.

If linked is canceled during Task.WhenAll at line 214, the exception is thrown before reaching the try/catch block at line 218, so the process cleanup never executes and speedtest.exe may remain running. Wrap the stream reads and exit wait in a single try/catch to ensure proc.Kill(entireProcessTree: true) always runs on cancellation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/Services/SpeedTestService.cs` around lines 209 - 220,
Wrap the parallel stream reads (the StandardOutput.ReadToEndAsync calls assigned
to stdoutTask and stderrTask) and the await proc.WaitForExitAsync(linked) inside
a single try/catch/finally so that any OperationCanceledException or other
failure during Task.WhenAll will run your cleanup; on catch (or finally if
preferred) call proc.Kill(entireProcessTree: true) (targeting the speedtest.exe
child) and then await proc.WaitForExitAsync() to ensure the process is reaped,
and only after successful cleanup read stdoutTask.Result and stderrTask.Result
or handle their cancellation/exception states accordingly.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 25.00000% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
SysManager/SysManager/Services/SpeedTestService.cs 0.00% 5 Missing ⚠️
...ysManager/SysManager/Services/DiskHealthService.cs 66.66% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

- SpeedTestService: read stdout/stderr in parallel with Task.WhenAll
  to prevent pipe buffer deadlock on Ookla CLI
- DiskHealthService: validate objectId with regex before WQL interpolation
  (defense-in-depth against injection)
- WindowsFeaturesService: add SECURITY-CRITICAL comment on FeatureNamePattern
- UninstallerService: replace \s with literal space in PackageIdPattern
  (reject tabs/newlines in package IDs)
- Add audit JSON files to .gitignore
@laurentiu021
laurentiu021 force-pushed the fix/process-deadlock-security branch from a5f7913 to f7195d8 Compare May 15, 2026 08:59
@laurentiu021
laurentiu021 merged commit c19660c into main May 15, 2026
5 checks passed
@laurentiu021
laurentiu021 deleted the fix/process-deadlock-security branch May 15, 2026 09:07
laurentiu021 added a commit that referenced this pull request May 22, 2026
…afety indicators (#476)

## Summary

Adds a built-in JSON database of 107 common Windows processes and
popular applications with plain-language descriptions, categories, and
safety indicators to the Process Manager tab.

## Changes

- **New**: \ProcessDescriptions.json\ — embedded resource with entries
for system processes, browsers, dev tools, communication apps, media
players, games, graphics drivers, productivity apps, creative tools,
cloud services, utilities, network tools, and security software
- **New**: \ProcessDescriptionService\ — singleton with fast
case-insensitive lookup, .exe stripping, category and safety queries
- **Extended**: \ProcessEntry\ model with \PlainDescription\,
\Category\, \SafetyLevel\ fields
- **Enhanced**: Process Manager filter now searches description and
category
- **Tests**: 10 unit tests for ProcessDescriptionService

## Categories

System, Security, Browser, Development, Communication, Media, Gaming,
Graphics, Productivity, Creative, Cloud, Utility, Network

## Safety Levels

- **System** — known Windows component (safe, do not kill)
- **Trusted** — well-known third-party application
- **Unknown** — not in database

Closes #381

Co-authored-by: laurentiu021 <laurentiu021@users.noreply.github.com>
laurentiu021 added a commit that referenced this pull request May 22, 2026
- SpeedTestService: read stdout/stderr in parallel with Task.WhenAll
  to prevent pipe buffer deadlock on Ookla CLI
- DiskHealthService: validate objectId with regex before WQL interpolation
  (defense-in-depth against injection)
- WindowsFeaturesService: add SECURITY-CRITICAL comment on FeatureNamePattern
- UninstallerService: replace \s with literal space in PackageIdPattern
  (reject tabs/newlines in package IDs)
- Add audit JSON files to .gitignore

Co-authored-by: laurentiu021 <laurentiu021@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants