|
1 | 1 | import assert from 'node:assert/strict'; |
| 2 | +import { execFile } from 'node:child_process'; |
2 | 3 | import fs from 'node:fs/promises'; |
3 | 4 | import os from 'node:os'; |
4 | 5 | import path from 'node:path'; |
5 | 6 | import test from 'node:test'; |
| 7 | +import { promisify } from 'node:util'; |
6 | 8 |
|
7 | 9 | import { verifyWindowsSmokeEnvironment, windowsSmokeEnvironment } from './windows-payload.mjs'; |
8 | 10 |
|
@@ -61,6 +63,38 @@ test('Add-Type probe uses constant UTF-16LE encoded source and returns bounded n |
61 | 63 | }); |
62 | 64 | }); |
63 | 65 |
|
| 66 | +test('Windows raw mandatory ACE validator handles labels independently of SDDL formatting', { |
| 67 | + skip: process.platform !== 'win32', timeout: 45_000, |
| 68 | +}, async () => { |
| 69 | + const { tsImport } = await import('tsx/esm/api'); |
| 70 | + const { windowsCodeDomLabelValidationScript } = await tsImport(new URL('../../server/gjc-windows-job.ts', import.meta.url).href, import.meta.url); |
| 71 | + const cases = [ |
| 72 | + { name: 'high', sddl: 'S:(ML;OI;NW;;;HI)', expected: true, count: 1 }, |
| 73 | + { name: 'numeric high SID', sddl: 'S:(ML;OICI;NW;;;S-1-16-12288)', expected: true, count: 1 }, |
| 74 | + { name: 'additional restrictions', sddl: 'S:(ML;OI;NWNR;;;HI)', expected: true, count: 1 }, |
| 75 | + { name: 'medium', sddl: 'S:(ML;OI;NW;;;ME)', expected: false, count: 1 }, |
| 76 | + { name: 'missing no-write-up', sddl: 'S:(ML;OI;NR;;;HI)', expected: false, count: 1 }, |
| 77 | + { name: 'inherit-only', sddl: 'S:(ML;OIIO;NW;;;HI)', expected: false, count: 1 }, |
| 78 | + { name: 'missing SACL', sddl: 'D:(A;;FA;;;BA)', expected: false, count: 0 }, |
| 79 | + { name: 'empty SACL', sddl: 'D:(A;;FA;;;BA)S:AI', expected: false, count: 0 }, |
| 80 | + { name: 'audit ACE is not a label', sddl: 'S:(AU;SA;FA;;;S-1-16-12288)', expected: false, count: 1 }, |
| 81 | + ]; |
| 82 | + const source = `$ErrorActionPreference = 'Stop' |
| 83 | +${windowsCodeDomLabelValidationScript()} |
| 84 | +foreach ($case in ($env:GAJAE_LABEL_FIXTURES | ConvertFrom-Json)) { |
| 85 | + $state = Get-GajaeCompilerLabelState ([Security.AccessControl.RawSecurityDescriptor]::new($case.sddl)) |
| 86 | + [Console]::Out.WriteLine((@{ name = $case.name; valid = $state.hasHighLabel; count = $state.saclCount; aces = $state.aces } | ConvertTo-Json -Compress -Depth 4)) |
| 87 | +}`; |
| 88 | + const systemRoot = process.env.SystemRoot || process.env.WINDIR || 'C:\\Windows'; |
| 89 | + const { stdout } = await promisify(execFile)(path.join(systemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe'), [ |
| 90 | + '-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(source, 'utf16le').toString('base64'), |
| 91 | + ], { env: { ...process.env, GAJAE_LABEL_FIXTURES: JSON.stringify(cases) }, windowsHide: true, shell: false, timeout: 30_000 }); |
| 92 | + const results = stdout.trim().split(/\r?\n/).map(line => JSON.parse(line)); |
| 93 | + assert.deepEqual(results.map(({ name, valid, count }) => ({ name, valid, count })), |
| 94 | + cases.map(({ name, expected, count }) => ({ name, valid: expected, count }))); |
| 95 | + assert.deepEqual(results[0].aces, [{ type: 0x11, size: 20, flags: 1, mask: 1, sid: 'S-1-16-12288' }]); |
| 96 | +}); |
| 97 | + |
64 | 98 | test('real Windows Add-Type works with baseline and isolated Unicode profile, cwd and temp', { |
65 | 99 | skip: process.platform !== 'win32', timeout: 140_000, |
66 | 100 | }, async t => { |
@@ -92,7 +126,10 @@ test('real Windows Add-Type works with baseline and isolated Unicode profile, cw |
92 | 126 | if (result.elevated) { |
93 | 127 | assert.match(result.compilerSddl, /\(D;OI;SD;;;/); |
94 | 128 | assert.match(result.compilerSddl, /\(A;OICI;FA;;;BA\)/); |
95 | | - assert.match(result.compilerSddl, /\(ML;[^;]*;NW;;;HI\)/); |
| 129 | + assert.equal(result.hasHighLabel, true); |
| 130 | + assert.ok(result.compilerSaclCount > 0); |
| 131 | + assert.ok(result.compilerSaclAces.some(ace => ace.type === 0x11 |
| 132 | + && ace.sid === 'S-1-16-12288' && (ace.mask & 1) !== 0 && (ace.flags & 8) === 0)); |
96 | 133 | } |
97 | 134 | await assert.rejects(fs.access(result.compilerTemp), { code: 'ENOENT' }); |
98 | 135 | if (label === 'isolated Unicode') { |
|
0 commit comments