fix(launcher): harden Campaign LA11 gate evidence

This commit is contained in:
Erik 2026-08-15 01:08:41 +02:00
parent 134edabed2
commit accd01a008
16 changed files with 1820 additions and 210 deletions

View file

@ -0,0 +1,93 @@
Set-StrictMode -Version Latest
function Get-CampaignLaSessionProcessCorrelations {
[CmdletBinding()]
param()
$matches = [Collections.Generic.List[object]]::new()
if ($IsWindows) {
$pattern = '(?i)(?:^|\s)(?:--config|--session-config)\s+(?:"([^"]+)"|(\S+))'
foreach ($candidate in @(Get-CimInstance Win32_Process -ErrorAction Stop)) {
$commandLine = [string]$candidate.CommandLine
if ([string]::IsNullOrWhiteSpace($commandLine)) { continue }
foreach ($match in [Text.RegularExpressions.Regex]::Matches(
$commandLine,
$pattern)) {
$value = if ($match.Groups[1].Success) {
$match.Groups[1].Value
} else { $match.Groups[2].Value }
if ([IO.Path]::IsPathFullyQualified($value)) {
$matches.Add([pscustomobject]@{
ProcessId = [int]$candidate.ProcessId
SessionConfigPath = [IO.Path]::GetFullPath($value)
})
}
}
}
}
elseif ($IsLinux) {
foreach ($directory in [IO.Directory]::EnumerateDirectories('/proc')) {
$leaf = [IO.Path]::GetFileName($directory)
$processId = 0
if (-not [int]::TryParse(
$leaf,
[Globalization.NumberStyles]::None,
[Globalization.CultureInfo]::InvariantCulture,
[ref]$processId)) {
continue
}
try {
$bytes = [IO.File]::ReadAllBytes((Join-Path $directory 'cmdline'))
if ($bytes.Length -eq 0) { continue }
$arguments = @([Text.Encoding]::UTF8.GetString($bytes).Split(
[char]0,
[StringSplitOptions]::RemoveEmptyEntries))
for ($index = 0; $index + 1 -lt $arguments.Count; $index++) {
if ($arguments[$index] -cin @('--config', '--session-config') -and
[IO.Path]::IsPathFullyQualified($arguments[$index + 1])) {
$matches.Add([pscustomobject]@{
ProcessId = $processId
SessionConfigPath = [IO.Path]::GetFullPath(
$arguments[$index + 1])
})
}
}
}
catch [IO.IOException] {
# A process may exit between /proc enumeration and cmdline read.
}
catch [UnauthorizedAccessException] {
# Other-user processes cannot be the owner-readable gate child.
}
}
}
else {
throw 'Campaign LA process correlation supports Windows and Linux only.'
}
return @($matches)
}
function Get-CampaignLaCorrelatedProcessIds {
[CmdletBinding()]
param([Parameter(Mandatory = $true)][string]$SessionConfigPath)
if (-not [IO.Path]::IsPathFullyQualified($SessionConfigPath)) {
throw 'Session-config correlation requires an absolute path.'
}
$SessionConfigPath = [IO.Path]::GetFullPath($SessionConfigPath)
$comparison = if ($IsWindows) {
[StringComparison]::OrdinalIgnoreCase
} else { [StringComparison]::Ordinal }
$matches = [Collections.Generic.HashSet[int]]::new()
foreach ($candidate in @(Get-CampaignLaSessionProcessCorrelations)) {
if ([string]::Equals(
$candidate.SessionConfigPath,
$SessionConfigPath,
$comparison)) {
$null = $matches.Add([int]$candidate.ProcessId)
}
}
return @($matches | Sort-Object)
}