Skip to content

Commit 1ceda13

Browse files
senamakelmedullabot
andcommitted
test(audit): diagnose namespace rename failures
Co-authored-by: Medulla <medulla@tinyhumans.ai>
1 parent c8408c4 commit 1ceda13

1 file changed

Lines changed: 36 additions & 26 deletions

File tree

‎crates/tinysecurity-audit/src/sink_windows_negative_tests.rs‎

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -336,31 +336,9 @@ try {
336336
if ([Convert]::ToBase64String($control) -cne 'dGlueXNlY3VyaXR5LXJlYWQtY29udHJvbC12MQ==') { exit 85 }
337337
} catch { exit 85 }
338338
Write-Output 'audit-account-stage=91 exact-control-read=1'
339-
$auditFileOrdinal = 0
340-
$auditOperation = 0
341-
$auditCallsite = 0
342-
try {
343-
foreach ($name in @('audit', 'audit.1', 'audit.2', 'audit.3', 'audit.lock', 'audit.journal')) {
344-
$auditFileOrdinal++
345-
$auditOperation = 1
346-
$auditCallsite = 1
347-
try { [void][IO.File]::ReadAllBytes((Join-Path $env:TINYSECURITY_TEST_DIRECTORY $name)); exit 83 }
348-
catch [UnauthorizedAccessException] { }
349-
$auditOperation = 2
350-
$auditCallsite = 2
351-
try { [IO.File]::WriteAllBytes((Join-Path $env:TINYSECURITY_TEST_DIRECTORY $name), [byte[]]@(0)); exit 87 }
352-
catch [UnauthorizedAccessException] { }
353-
$auditOperation = 3
354-
$auditCallsite = 3
355-
# Framework File.Move checks InternalExists first, masking denied metadata
356-
# as FileNotFound. FileInfo.MoveTo reaches native MoveFile without that check.
357-
try { [IO.FileInfo]::new((Join-Path $env:TINYSECURITY_TEST_DIRECTORY $name)).MoveTo((Join-Path $env:TINYSECURITY_TEST_DIRECTORY ($name + '.outsider'))); exit 88 }
358-
catch [UnauthorizedAccessException] { }
359-
}
360-
} catch {
339+
function Write-AuditFailureMetadata($failure, $auditFileOrdinal, $auditOperation, $auditCallsite) {
361340
# Unexpected errors still fail. Emit only fixed file/operation ordinals and
362341
# numeric exception metadata; never stringify paths, records or messages.
363-
$failure = $_
364342
[Console]::WriteLine(('audit-account-stage=99 file={0} operation={1} callsite={2} line={3} offset={4} category={5}' -f $auditFileOrdinal,$auditOperation,$auditCallsite,$failure.InvocationInfo.ScriptLineNumber,$failure.InvocationInfo.OffsetInLine,[int]$failure.CategoryInfo.Category))
365343
$exception = $failure.Exception
366344
for ($depth = 0; ($null -ne $exception) -and ($depth -lt 8); $depth++) {
@@ -382,11 +360,43 @@ try {
382360
[Console]::WriteLine(('audit-account-stage=99 depth={0} kind={1} hresult={2} lowword={3} native={4}' -f $depth,$kind,$exception.HResult,($exception.HResult -band 65535),$native))
383361
$exception = $exception.InnerException
384362
}
363+
}
364+
$auditFileOrdinal = 0
365+
$auditOperation = 0
366+
$auditCallsite = 0
367+
try {
368+
foreach ($name in @('audit', 'audit.1', 'audit.2', 'audit.3', 'audit.lock', 'audit.journal')) {
369+
$auditFileOrdinal++
370+
$auditOperation = 1
371+
$auditCallsite = 1
372+
try { [void][IO.File]::ReadAllBytes((Join-Path $env:TINYSECURITY_TEST_DIRECTORY $name)); exit 83 }
373+
catch [UnauthorizedAccessException] { }
374+
$auditOperation = 2
375+
$auditCallsite = 2
376+
try { [IO.File]::WriteAllBytes((Join-Path $env:TINYSECURITY_TEST_DIRECTORY $name), [byte[]]@(0)); exit 87 }
377+
catch [UnauthorizedAccessException] { }
378+
$auditOperation = 3
379+
$auditCallsite = 3
380+
# Framework File.Move checks InternalExists first, masking denied metadata
381+
# as FileNotFound. FileInfo.MoveTo reaches native MoveFile without that check.
382+
try { [IO.FileInfo]::new((Join-Path $env:TINYSECURITY_TEST_DIRECTORY $name)).MoveTo((Join-Path $env:TINYSECURITY_TEST_DIRECTORY ($name + '.outsider'))); exit 88 }
383+
catch [UnauthorizedAccessException] { }
384+
}
385+
} catch {
386+
Write-AuditFailureMetadata $_ $auditFileOrdinal $auditOperation $auditCallsite
385387
throw
386388
}
387389
Write-Output 'audit-account-stage=92 private-file-denials=6'
388-
try { [IO.Directory]::Move($env:TINYSECURITY_TEST_DIRECTORY, ($env:TINYSECURITY_TEST_DIRECTORY + '.outsider')); exit 84 }
389-
catch [UnauthorizedAccessException] { }
390+
$auditFileOrdinal = 7
391+
$auditOperation = 3
392+
$auditCallsite = 4
393+
try {
394+
try { [IO.Directory]::Move($env:TINYSECURITY_TEST_DIRECTORY, ($env:TINYSECURITY_TEST_DIRECTORY + '.outsider')); exit 84 }
395+
catch [UnauthorizedAccessException] { }
396+
} catch {
397+
Write-AuditFailureMetadata $_ $auditFileOrdinal $auditOperation $auditCallsite
398+
throw
399+
}
390400
Write-Output 'audit-account-stage=93 namespace-denial=1'
391401
exit 0
392402
'@
@@ -437,7 +447,7 @@ exit 0
437447
$requiredPhases = @('audit-account-stage=90 foreign-identity=1 nonadmin=1', 'audit-account-stage=91 exact-control-read=1', 'audit-account-stage=92 private-file-denials=6', 'audit-account-stage=93 namespace-denial=1')
438448
$allLines = @($stdout.Result.Split([char]10) | ForEach-Object { $_.TrimEnd([char]13) } | Where-Object { $_.Length -gt 0 })
439449
$lines = @($allLines | Where-Object { $requiredPhases -ccontains $_ })
440-
$diagnostics = @($allLines | Where-Object { $_ -cmatch '^audit-account-stage=94 parsed=1 source-first=[0-9]+ ordinal-prefix=[01] ordinal-first=[01]$|^audit-account-stage=95 preference-extra=[0-2] codepoint=[0-9]+ length=[0-9]+ category=[0-9]+ hresult=-?[0-9]+$|^audit-account-stage=96 (child-entry|identity-read)=1$|^audit-account-stage=98 child-foreign-present=[01] child-foreign-nonempty=[01] child-owner-present=[01] child-owner-nonempty=[01] child-directory-present=[01] child-directory-nonempty=[01] identity-foreign-match=[01] identity-owner-match=[01]$|^audit-account-stage=99 file=[0-6] operation=[0-3] callsite=[0-3] line=[0-9]+ offset=[0-9]+ category=[0-9]+$|^audit-account-stage=99 depth=[0-7] kind=(10|[0-9]) hresult=-?[0-9]+ lowword=[0-9]+ native=-?[0-9]+$' })
450+
$diagnostics = @($allLines | Where-Object { $_ -cmatch '^audit-account-stage=94 parsed=1 source-first=[0-9]+ ordinal-prefix=[01] ordinal-first=[01]$|^audit-account-stage=95 preference-extra=[0-2] codepoint=[0-9]+ length=[0-9]+ category=[0-9]+ hresult=-?[0-9]+$|^audit-account-stage=96 (child-entry|identity-read)=1$|^audit-account-stage=98 child-foreign-present=[01] child-foreign-nonempty=[01] child-owner-present=[01] child-owner-nonempty=[01] child-directory-present=[01] child-directory-nonempty=[01] identity-foreign-match=[01] identity-owner-match=[01]$|^audit-account-stage=99 file=[0-7] operation=[0-3] callsite=[0-4] line=[0-9]+ offset=[0-9]+ category=[0-9]+$|^audit-account-stage=99 depth=[0-7] kind=(10|[0-9]) hresult=-?[0-9]+ lowword=[0-9]+ native=-?[0-9]+$' })
441451
foreach ($line in $allLines) {
442452
if (($requiredPhases -ccontains $line) -or ($diagnostics -ccontains $line)) { Write-Output $line }
443453
}

0 commit comments

Comments
 (0)