Browse Source

fix(items): reject a -Filter of more than 32,767 characters

An independent review found that a very long -Filter pattern (for
example, a run of 120,000 question marks, or 45,000 asterisks) crashes
the whole host process with an uncatchable StackOverflowException: the
matcher recurses roughly once per character of the pattern, and a long
enough pattern exhausts the stack. A pattern this long serves no
purpose that a shorter one could not also serve, and the review
confirmed that patterns of 32,767 characters or fewer, of any shape
(literal, "?" repeated, "*" repeated, "*?" repeated, "*." repeated),
do not come close to exhausting the stack.

Added `[ValidateLength(0, 32767)]` next to the existing
`[ValidateNotNull]` on -Filter, so that a pattern longer than 32,767
characters is rejected at parameter binding, before it ever reaches
the matcher, with the same `ParameterArgumentValidationError` and
`'Filter'` in the message as the existing null rejection; shorter
values, including an empty one, are unaffected.

Tests (Tests\ItemCmdlets.Tests.ps1, "Get-ChildItem2" > "Recursion, type
filters, and depth"): a -Filter of 32,768 characters now gives
ParameterArgumentValidationError, and one of exactly 32,767 characters
("?" repeated, in a folder with one file) returns the right result
without crashing. The crash itself was confirmed in a disposable child
process (not through the shared Pester harness, to avoid taking that
process down too) with the reviewer's probe
(C:\Temp\ntfs-rc9\review-probes-r3\p9-longpattern.ps1 -N 120000 -Kind
qm): the process terminated with a StackOverflowException before this
fix, and after it, the same probe at the exact boundaries (32,767 and
32,768 characters, every pattern kind the probe offers) neither
crashes nor is accepted past the limit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
pull/131/head
Raimund Andree 1 week ago
parent
commit
2deec1761b
  1. 1
      NTFSSecurity/ItemCmdlets/GetChildItem2.cs
  2. 22
      Tests/ItemCmdlets.Tests.ps1

1
NTFSSecurity/ItemCmdlets/GetChildItem2.cs

@ -44,6 +44,7 @@ namespace NTFSSecurity
[Parameter(Position = 2)]
[ValidateNotNull]
[ValidateLength(0, 32767)]
public string Filter
{
get { return filter; }

22
Tests/ItemCmdlets.Tests.ps1

@ -426,6 +426,28 @@ Describe 'Get-ChildItem2' {
Should -Throw -ErrorId 'ParameterArgumentValidationError,NTFSSecurity.GetChildItem2' -ExpectedMessage "*'Filter'*"
}
It 'Should reject a -Filter of more than 32,767 characters' {
$tooLong = '?' * 32768
{ Get-ChildItem2 -Path $tree -Filter $tooLong -ErrorAction Stop } |
Should -Throw -ErrorId 'ParameterArgumentValidationError,NTFSSecurity.GetChildItem2' -ExpectedMessage "*'Filter'*"
}
# A pattern this long is not useful, but the cmdlet must not crash the host: before this test was added, a
# pattern of this length (or a long run of asterisks) recursed deep enough in the matcher to raise an
# uncatchable StackOverflowException and terminate the process.
It 'Should accept a -Filter of exactly 32,767 characters and return the right result' {
$folder = New-TestSandboxItem -Sandbox $sandbox -Name 'FilterMaxLength' -Directory
$file = Join-Path -Path $folder -ChildPath 'a'
Assert-TestSandboxPath -Sandbox $sandbox -Path $file
Set-Content -LiteralPath $file -Value 'a'
$longest = '?' * 32767
$result = @(Get-ChildItem2 -Path $folder -Filter $longest -ErrorAction Stop)
$result | Should -HaveCount 1
$result[0].Name | Should -Be 'a'
}
It 'Should stop a recursive pipeline without recording an enumeration error' {
$result = @(Get-ChildItem2 -Path $tree -Recurse -ErrorVariable childErrors -ErrorAction SilentlyContinue | Select-Object -First 1)

Loading…
Cancel
Save