Add delegated signal handling support#932
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a boolean AllowDelegatedSignals configuration, exposes it via SNTConfigurator, threads it into Santad and the tamper-resistance client, updates AUTH_SIGNAL handling to validate launchd‑delegated signals (macOS 15.5+ instigator semantics), extends tests, and adds a macOS 15.5 compile guard. ChangesAllowDelegatedSignals + AUTH_SIGNAL validation
Sequence Diagram(s)sequenceDiagram
participant Config as SNTConfigurator
participant Santad as Santad
participant Handler as SNTEndpointSecurityTamperResistance
participant ES as EndpointSecurity
participant LaunchD as launchd
participant Inst as Instigator
Config->>Santad: provide allowDelegatedSignals
Santad->>Handler: init(..., allowDelegatedSignals)
Handler->>Handler: store flag
LaunchD->>ES: delegate signal for target
ES->>Handler: AUTH_SIGNAL (may include instigator v9+)
alt targetPid != getpid()
Handler-->>ES: DENY
else sourcePid != 1
Handler-->>ES: DENY
else macOS 15.5+ and instigator present
Handler->>Handler: check instigator signing-id against allowlist
alt signing-id trusted
Handler-->>ES: ALLOW
else instigator is platform binary and allowDelegatedSignals==YES
Handler-->>ES: ALLOW
else
Handler-->>ES: DENY
end
else older macOS or no instigator
Handler-->>ES: DENY
end
Config->>Santad: KVO notify on change
Santad->>Handler: setAllowDelegatedSignals(BOOL)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Review rate limit: 4/5 reviews remaining, refill in 12 minutes. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Source/santad/EventProviders/SNTEndpointSecurityTamperResistance.mm (1)
288-337:⚠️ Potential issue | 🟠 Major | ⚡ Quick winMake delegated-signal AUTH decisions non-cacheable.
This branch now depends on mutable runtime config (
allowDelegatedSignals) plus per-messageinstigatordata, but successfulAUTH_SIGNALdecisions still inheritcacheable = true. A delegated signal allowed while the flag isYEScan therefore remain effective after the config is tightened back toNO.🛡️ Suggested fix
case ES_EVENT_TYPE_AUTH_SIGNAL: { + // This decision depends on mutable config and per-message instigator + // metadata, so stale ALLOW cache entries can outlive policy changes. + cacheable = false; + if (esMsg->event.signal.sig == 0) { // Signal 0 doesn't actually get sent to the process, it is only used to // check if the process exists. Because of this, we don't need to block it. break; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Source/santad/EventProviders/SNTEndpointSecurityTamperResistance.mm` around lines 288 - 337, The AUTH_SIGNAL branch must mark decisions involving delegated signals as non-cacheable: when handling ES_EVENT_TYPE_AUTH_SIGNAL and esMsg->event.signal.instigator != NULL (and/or when self.allowDelegatedSignals is consulted) ensure the per-decision cacheable flag is set to false so decisions that depended on mutable runtime config (allowDelegatedSignals) or per-message instigator data are not reused; update the logic around the instigator check (the block that computes isAllowlisted / isPermittedPlatformBinary and sets result = ES_AUTH_RESULT_DENY) to also set cacheable = false (or clear any existing cacheable=true) whenever instigator != NULL or when allowDelegatedSignals influenced the outcome.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@Source/santad/EventProviders/SNTEndpointSecurityTamperResistance.mm`:
- Around line 288-337: The AUTH_SIGNAL branch must mark decisions involving
delegated signals as non-cacheable: when handling ES_EVENT_TYPE_AUTH_SIGNAL and
esMsg->event.signal.instigator != NULL (and/or when self.allowDelegatedSignals
is consulted) ensure the per-decision cacheable flag is set to false so
decisions that depended on mutable runtime config (allowDelegatedSignals) or
per-message instigator data are not reused; update the logic around the
instigator check (the block that computes isAllowlisted /
isPermittedPlatformBinary and sets result = ES_AUTH_RESULT_DENY) to also set
cacheable = false (or clear any existing cacheable=true) whenever instigator !=
NULL or when allowDelegatedSignals influenced the outcome.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ae74ae01-401f-4d45-98cc-25cb46b67aea
📒 Files selected for processing (8)
Source/common/Platform.hSource/common/SNTConfigurator.hSource/common/SNTConfigurator.mmSource/common/SNTConfiguratorTest.mmSource/santad/EventProviders/SNTEndpointSecurityTamperResistance.hSource/santad/EventProviders/SNTEndpointSecurityTamperResistance.mmSource/santad/EventProviders/SNTEndpointSecurityTamperResistanceTest.mmSource/santad/Santad.mm
There was a problem hiding this comment.
🧹 Nitpick comments (1)
Source/santad/EventProviders/SNTEndpointSecurityTamperResistanceTest.mm (1)
576-603: ⚡ Quick winAdd
cacheableassertion in the v9 instigator matrix loop.These new cases validate disposition/result, but not cacheability. Since AUTH_SIGNAL is always non-cacheable, this is worth asserting here too.
Suggested patch
@@ XCTAssertSemaTrue(semaMetrics, 5, "Metrics not recorded within expected window"); XCTAssertEqual(gotAuthResult, c.expected, @"%s", c.desc); + XCTAssertFalse(gotCachable, @"%s", c.desc); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Source/santad/EventProviders/SNTEndpointSecurityTamperResistanceTest.mm` around lines 576 - 603, Add an assertion inside the v9 instigator matrix loop (the for (const auto& c : cases) block) to validate cacheability for AUTH_SIGNAL cases: after the handleMessage call and before signaling the semaphore/after XCTAssertEqual(gotAuthResult,...), assert that the event was non-cacheable (e.g., expect cacheable == false) since AUTH_SIGNAL should always be non-cacheable; locate the check around mockTamperClient->handleMessage / recordEventMetrics and add the cacheability assertion referencing the loop variable c (or esMsg.event.signal) and the same c.desc for failure context.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@Source/santad/EventProviders/SNTEndpointSecurityTamperResistanceTest.mm`:
- Around line 576-603: Add an assertion inside the v9 instigator matrix loop
(the for (const auto& c : cases) block) to validate cacheability for AUTH_SIGNAL
cases: after the handleMessage call and before signaling the semaphore/after
XCTAssertEqual(gotAuthResult,...), assert that the event was non-cacheable
(e.g., expect cacheable == false) since AUTH_SIGNAL should always be
non-cacheable; locate the check around mockTamperClient->handleMessage /
recordEventMetrics and add the cacheability assertion referencing the loop
variable c (or esMsg.event.signal) and the same c.desc for failure context.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 36bc34d0-0249-4f5f-b8fb-80cd9d45e954
📒 Files selected for processing (1)
Source/santad/EventProviders/SNTEndpointSecurityTamperResistanceTest.mm
Fixes SNT-404