mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-27 21:48:38 +00:00
fix(macos): harden exec allowlist shell-chain checks
This commit is contained in:
@@ -360,7 +360,9 @@ private enum ExecHostExecutor {
|
||||
let autoAllowSkills: Bool
|
||||
let env: [String: String]?
|
||||
let resolution: ExecCommandResolution?
|
||||
let allowlistMatch: ExecAllowlistEntry?
|
||||
let allowlistResolutions: [ExecCommandResolution]
|
||||
let allowlistMatches: [ExecAllowlistEntry]
|
||||
let allowlistSatisfied: Bool
|
||||
let skillAllow: Bool
|
||||
}
|
||||
|
||||
@@ -393,7 +395,7 @@ private enum ExecHostExecutor {
|
||||
if ExecApprovalHelpers.requiresAsk(
|
||||
ask: context.ask,
|
||||
security: context.security,
|
||||
allowlistMatch: context.allowlistMatch,
|
||||
allowlistMatch: context.allowlistSatisfied ? context.allowlistMatches.first : nil,
|
||||
skillAllow: context.skillAllow),
|
||||
approvalDecision == nil
|
||||
{
|
||||
@@ -425,7 +427,7 @@ private enum ExecHostExecutor {
|
||||
self.persistAllowlistEntry(decision: approvalDecision, context: context)
|
||||
|
||||
if context.security == .allowlist,
|
||||
context.allowlistMatch == nil,
|
||||
!context.allowlistSatisfied,
|
||||
!context.skillAllow,
|
||||
!approvedByAsk
|
||||
{
|
||||
@@ -435,12 +437,21 @@ private enum ExecHostExecutor {
|
||||
reason: "allowlist-miss")
|
||||
}
|
||||
|
||||
if let match = context.allowlistMatch {
|
||||
ExecApprovalsStore.recordAllowlistUse(
|
||||
agentId: context.trimmedAgent,
|
||||
pattern: match.pattern,
|
||||
command: context.displayCommand,
|
||||
resolvedPath: context.resolution?.resolvedPath)
|
||||
if context.allowlistSatisfied {
|
||||
var seenPatterns = Set<String>()
|
||||
for (idx, match) in context.allowlistMatches.enumerated() {
|
||||
if !seenPatterns.insert(match.pattern).inserted {
|
||||
continue
|
||||
}
|
||||
let resolvedPath = idx < context.allowlistResolutions.count
|
||||
? context.allowlistResolutions[idx].resolvedPath
|
||||
: nil
|
||||
ExecApprovalsStore.recordAllowlistUse(
|
||||
agentId: context.trimmedAgent,
|
||||
pattern: match.pattern,
|
||||
command: context.displayCommand,
|
||||
resolvedPath: resolvedPath)
|
||||
}
|
||||
}
|
||||
|
||||
if let errorResponse = await self.ensureScreenRecordingAccess(request.needsScreenRecording) {
|
||||
@@ -465,18 +476,22 @@ private enum ExecHostExecutor {
|
||||
let ask = approvals.agent.ask
|
||||
let autoAllowSkills = approvals.agent.autoAllowSkills
|
||||
let env = self.sanitizedEnv(request.env)
|
||||
let resolution = ExecCommandResolution.resolve(
|
||||
let allowlistResolutions = ExecCommandResolution.resolveForAllowlist(
|
||||
command: command,
|
||||
rawCommand: request.rawCommand,
|
||||
cwd: request.cwd,
|
||||
env: env)
|
||||
let allowlistMatch = security == .allowlist
|
||||
? ExecAllowlistMatcher.match(entries: approvals.allowlist, resolution: resolution)
|
||||
: nil
|
||||
let resolution = allowlistResolutions.first
|
||||
let allowlistMatches = security == .allowlist
|
||||
? ExecAllowlistMatcher.matchAll(entries: approvals.allowlist, resolutions: allowlistResolutions)
|
||||
: []
|
||||
let allowlistSatisfied = security == .allowlist &&
|
||||
!allowlistResolutions.isEmpty &&
|
||||
allowlistMatches.count == allowlistResolutions.count
|
||||
let skillAllow: Bool
|
||||
if autoAllowSkills, let name = resolution?.executableName {
|
||||
if autoAllowSkills, !allowlistResolutions.isEmpty {
|
||||
let bins = await SkillBinsCache.shared.currentBins()
|
||||
skillAllow = bins.contains(name)
|
||||
skillAllow = allowlistResolutions.allSatisfy { bins.contains($0.executableName) }
|
||||
} else {
|
||||
skillAllow = false
|
||||
}
|
||||
@@ -490,7 +505,9 @@ private enum ExecHostExecutor {
|
||||
autoAllowSkills: autoAllowSkills,
|
||||
env: env,
|
||||
resolution: resolution,
|
||||
allowlistMatch: allowlistMatch,
|
||||
allowlistResolutions: allowlistResolutions,
|
||||
allowlistMatches: allowlistMatches,
|
||||
allowlistSatisfied: allowlistSatisfied,
|
||||
skillAllow: skillAllow)
|
||||
}
|
||||
|
||||
@@ -499,13 +516,18 @@ private enum ExecHostExecutor {
|
||||
context: ExecApprovalContext)
|
||||
{
|
||||
guard decision == .allowAlways, context.security == .allowlist else { return }
|
||||
guard let pattern = ExecApprovalHelpers.allowlistPattern(
|
||||
command: context.command,
|
||||
resolution: context.resolution)
|
||||
else {
|
||||
return
|
||||
var seenPatterns = Set<String>()
|
||||
for candidate in context.allowlistResolutions {
|
||||
guard let pattern = ExecApprovalHelpers.allowlistPattern(
|
||||
command: context.command,
|
||||
resolution: candidate)
|
||||
else {
|
||||
continue
|
||||
}
|
||||
if seenPatterns.insert(pattern).inserted {
|
||||
ExecApprovalsStore.addAllowlistEntry(agentId: context.trimmedAgent, pattern: pattern)
|
||||
}
|
||||
}
|
||||
ExecApprovalsStore.addAllowlistEntry(agentId: context.trimmedAgent, pattern: pattern)
|
||||
}
|
||||
|
||||
private static func ensureScreenRecordingAccess(_ needsScreenRecording: Bool?) async -> ExecHostResponse? {
|
||||
|
||||
Reference in New Issue
Block a user