Skip to content

Commit e0befdc

Browse files
authored
Update Hardened Runtime sub options to work with build settings. (#342)
* Update Hardened Runtime suboptions to work with build settings. * Fixes test, CodeSignTaskConstructionTests.appSandboxEntitlementAndBuildSettingConflictEmitsExpectedDiagnostics
1 parent aaa84a0 commit e0befdc

File tree

6 files changed

+406
-91
lines changed

6 files changed

+406
-91
lines changed

Sources/SWBCore/Settings/BuiltinMacros.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,10 @@ public final class BuiltinMacros {
332332

333333
public static let AD_HOC_CODE_SIGNING_ALLOWED = BuiltinMacros.declareBooleanMacro("AD_HOC_CODE_SIGNING_ALLOWED")
334334
public static let __AD_HOC_CODE_SIGNING_NOT_ALLOWED_SUPPLEMENTAL_MESSAGE = BuiltinMacros.declareStringMacro("__AD_HOC_CODE_SIGNING_NOT_ALLOWED_SUPPLEMENTAL_MESSAGE")
335+
public static let RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES = BuiltinMacros.declareBooleanMacro("RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES")
336+
public static let RUNTIME_EXCEPTION_ALLOW_JIT = BuiltinMacros.declareBooleanMacro("RUNTIME_EXCEPTION_ALLOW_JIT")
337+
public static let RUNTIME_EXCEPTION_ALLOW_UNSIGNED_EXECUTABLE_MEMORY = BuiltinMacros.declareBooleanMacro("RUNTIME_EXCEPTION_ALLOW_UNSIGNED_EXECUTABLE_MEMORY")
338+
public static let AUTOMATION_APPLE_EVENTS = BuiltinMacros.declareBooleanMacro("AUTOMATION_APPLE_EVENTS")
335339
public static let CODE_SIGNING_ALLOWED = BuiltinMacros.declareBooleanMacro("CODE_SIGNING_ALLOWED")
336340
public static let CODE_SIGNING_REQUIRED = BuiltinMacros.declareBooleanMacro("CODE_SIGNING_REQUIRED")
337341
public static let CODE_SIGNING_REQUIRES_TEAM = BuiltinMacros.declareBooleanMacro("CODE_SIGNING_REQUIRES_TEAM")
@@ -345,8 +349,11 @@ public final class BuiltinMacros {
345349
public static let CODE_SIGN_RESTRICT = BuiltinMacros.declareBooleanMacro("CODE_SIGN_RESTRICT")
346350
public static let CODE_SIGN_RESOURCE_RULES_PATH = BuiltinMacros.declareStringMacro("CODE_SIGN_RESOURCE_RULES_PATH")
347351
public static let CODE_SIGN_STYLE = BuiltinMacros.declareStringMacro("CODE_SIGN_STYLE")
352+
public static let RUNTIME_EXCEPTION_DEBUGGING_TOOL = BuiltinMacros.declareBooleanMacro("RUNTIME_EXCEPTION_DEBUGGING_TOOL")
348353
public static let DIAGNOSE_MISSING_TARGET_DEPENDENCIES = BuiltinMacros.declareEnumMacro("DIAGNOSE_MISSING_TARGET_DEPENDENCIES") as EnumMacroDeclaration<BooleanWarningLevel>
354+
public static let RUNTIME_EXCEPTION_DISABLE_EXECUTABLE_PAGE_PROTECTION = BuiltinMacros.declareBooleanMacro("RUNTIME_EXCEPTION_DISABLE_EXECUTABLE_PAGE_PROTECTION")
349355
public static let DISABLE_FREEFORM_CODE_SIGN_OPTION_FLAGS = BuiltinMacros.declareBooleanMacro("DISABLE_FREEFORM_CODE_SIGN_OPTION_FLAGS")
356+
public static let RUNTIME_EXCEPTION_DISABLE_LIBRARY_VALIDATION = BuiltinMacros.declareBooleanMacro("RUNTIME_EXCEPTION_DISABLE_LIBRARY_VALIDATION")
350357
public static let ENABLE_CLOUD_SIGNING = BuiltinMacros.declareBooleanMacro("ENABLE_CLOUD_SIGNING")
351358

352359
public static let ENABLE_GENERIC_TASK_CACHING = BuiltinMacros.declareBooleanMacro("ENABLE_GENERIC_TASK_CACHING")
@@ -2382,6 +2389,13 @@ public final class BuiltinMacros {
23822389

23832390
/// Force initialization of entitlements macros.
23842391
private static let allEntitlementsMacros = [
2392+
RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES,
2393+
RUNTIME_EXCEPTION_ALLOW_JIT,
2394+
RUNTIME_EXCEPTION_ALLOW_UNSIGNED_EXECUTABLE_MEMORY,
2395+
AUTOMATION_APPLE_EVENTS,
2396+
RUNTIME_EXCEPTION_DEBUGGING_TOOL,
2397+
RUNTIME_EXCEPTION_DISABLE_EXECUTABLE_PAGE_PROTECTION,
2398+
RUNTIME_EXCEPTION_DISABLE_LIBRARY_VALIDATION,
23852399
ENABLE_APP_SANDBOX,
23862400
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT,
23872401
ENABLE_RESOURCE_ACCESS_BLUETOOTH,

Sources/SWBCore/SpecImplementations/Tools/ProductPackaging.swift

Lines changed: 84 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,36 @@ public final class ProductPackagingToolSpec : GenericCommandLineToolSpec, SpecId
2121
fatalError("unexpected direct invocation")
2222
}
2323

24+
fileprivate static let sandboxAndHardenedRuntimeBooleanEntitlements = [
25+
BuiltinMacros.RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES: "com.apple.security.cs.allow-dyld-environment-variables",
26+
BuiltinMacros.RUNTIME_EXCEPTION_ALLOW_JIT: "com.apple.security.cs.allow-jit",
27+
BuiltinMacros.RUNTIME_EXCEPTION_ALLOW_UNSIGNED_EXECUTABLE_MEMORY: "com.apple.security.cs.allow-unsigned-executable-memory",
28+
BuiltinMacros.RUNTIME_EXCEPTION_DEBUGGING_TOOL: "com.apple.security.cs.debugger",
29+
BuiltinMacros.RUNTIME_EXCEPTION_DISABLE_EXECUTABLE_PAGE_PROTECTION: "com.apple.security.cs.disable-executable-page-protection",
30+
BuiltinMacros.RUNTIME_EXCEPTION_DISABLE_LIBRARY_VALIDATION: "com.apple.security.cs.disable-library-validation",
31+
BuiltinMacros.ENABLE_APP_SANDBOX: "com.apple.security.app-sandbox",
32+
BuiltinMacros.ENABLE_INCOMING_NETWORK_CONNECTIONS: "com.apple.security.network.server",
33+
BuiltinMacros.ENABLE_OUTGOING_NETWORK_CONNECTIONS: "com.apple.security.network.client",
34+
BuiltinMacros.ENABLE_RESOURCE_ACCESS_AUDIO_INPUT: "com.apple.security.device.audio-input",
35+
BuiltinMacros.ENABLE_RESOURCE_ACCESS_BLUETOOTH: "com.apple.security.device.bluetooth",
36+
BuiltinMacros.ENABLE_RESOURCE_ACCESS_CALENDARS: "com.apple.security.personal-information.calendars",
37+
BuiltinMacros.ENABLE_RESOURCE_ACCESS_CAMERA: "com.apple.security.device.camera",
38+
BuiltinMacros.ENABLE_RESOURCE_ACCESS_CONTACTS: "com.apple.security.personal-information.addressbook",
39+
BuiltinMacros.ENABLE_RESOURCE_ACCESS_LOCATION: "com.apple.security.personal-information.location",
40+
BuiltinMacros.ENABLE_RESOURCE_ACCESS_PHOTO_LIBRARY: "com.apple.security.personal-information.photos-library",
41+
BuiltinMacros.ENABLE_RESOURCE_ACCESS_PRINTING: "com.apple.security.print",
42+
BuiltinMacros.ENABLE_RESOURCE_ACCESS_USB: "com.apple.security.device.usb",
43+
BuiltinMacros.AUTOMATION_APPLE_EVENTS: "com.apple.security.automation.apple-events",
44+
]
45+
46+
fileprivate static let sandboxFileAccessSettingsAndEntitlements: [(EnumMacroDeclaration<FileAccessMode>, String)] = [
47+
(BuiltinMacros.ENABLE_FILE_ACCESS_DOWNLOADS_FOLDER, "com.apple.security.files.downloads"),
48+
(BuiltinMacros.ENABLE_FILE_ACCESS_PICTURE_FOLDER, "com.apple.security.assets.pictures"),
49+
(BuiltinMacros.ENABLE_FILE_ACCESS_MUSIC_FOLDER, "com.apple.security.assets.music"),
50+
(BuiltinMacros.ENABLE_FILE_ACCESS_MOVIES_FOLDER, "com.apple.security.assets.movies"),
51+
(BuiltinMacros.ENABLE_USER_SELECTED_FILES, "com.apple.security.files.user-selected"),
52+
]
53+
2454
/// Construct a task to create the entitlements (`.xcent`) file.
2555
/// - parameter cbc: The command build context. This includes the input file to process (until <rdar://problem/29117572> is fixed), and the output file in the product to which write the contents.
2656
/// - parameter delegate: The task generation delegate.
@@ -88,22 +118,14 @@ public final class ProductPackagingToolSpec : GenericCommandLineToolSpec, SpecId
88118

89119
// rdar://142845111 (Turn on `AppSandboxConflictingValuesEmitsWarning` by default)
90120
if SWBFeatureFlag.enableAppSandboxConflictingValuesEmitsWarning.value {
91-
EntitlementConflictDiagnosticEmitter.checkForConflicts(cbc, delegate, entitlementsDictionary: entitlementsDictionary)
121+
EntitlementConflictDiagnosticEmitter.checkForConflicts(cbc, delegate, entitlementsDictionary: entitlementsDictionary, entitlementsPath: codeSignEntitlementsInput?.absolutePath)
92122
}
93123

94124
if isAppSandboxEnabled || isHardenedRuntimeEnabled {
95125
// Inject entitlements that are settable via build settings.
96126
// This is only supported when App Sandbox or Hardened Runtime is enabled.
97-
let fileAccessSettingsAndEntitlements: [(EnumMacroDeclaration<FileAccessMode>, String)] = [
98-
(BuiltinMacros.ENABLE_FILE_ACCESS_DOWNLOADS_FOLDER, "com.apple.security.files.downloads"),
99-
(BuiltinMacros.ENABLE_FILE_ACCESS_PICTURE_FOLDER, "com.apple.security.assets.pictures"),
100-
(BuiltinMacros.ENABLE_FILE_ACCESS_MUSIC_FOLDER, "com.apple.security.assets.music"),
101-
(BuiltinMacros.ENABLE_FILE_ACCESS_MOVIES_FOLDER, "com.apple.security.assets.movies"),
102-
(BuiltinMacros.ENABLE_USER_SELECTED_FILES, "com.apple.security.files.user-selected"),
103-
]
104-
105-
for (buildSettingSetting, entitlementPrefix) in fileAccessSettingsAndEntitlements {
106-
let fileAccessValue = cbc.scope.evaluate(buildSettingSetting)
127+
for (buildSetting, entitlementPrefix) in Self.sandboxFileAccessSettingsAndEntitlements {
128+
let fileAccessValue = cbc.scope.evaluate(buildSetting)
107129
switch fileAccessValue {
108130
case .readOnly:
109131
entitlementsDictionary["\(entitlementPrefix).read-only"] = .plBool(true)
@@ -114,41 +136,10 @@ public final class ProductPackagingToolSpec : GenericCommandLineToolSpec, SpecId
114136
}
115137
}
116138

117-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_APP_SANDBOX) {
118-
entitlementsDictionary["com.apple.security.app-sandbox"] = .plBool(true)
119-
}
120-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_INCOMING_NETWORK_CONNECTIONS) {
121-
entitlementsDictionary["com.apple.security.network.server"] = .plBool(true)
122-
}
123-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_OUTGOING_NETWORK_CONNECTIONS) {
124-
entitlementsDictionary["com.apple.security.network.client"] = .plBool(true)
125-
}
126-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_RESOURCE_ACCESS_AUDIO_INPUT) {
127-
entitlementsDictionary["com.apple.security.device.audio-input"] = .plBool(true)
128-
}
129-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_RESOURCE_ACCESS_BLUETOOTH) {
130-
entitlementsDictionary["com.apple.security.device.bluetooth"] = .plBool(true)
131-
}
132-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_RESOURCE_ACCESS_CALENDARS) {
133-
entitlementsDictionary["com.apple.security.personal-information.calendars"] = .plBool(true)
134-
}
135-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_RESOURCE_ACCESS_CAMERA) {
136-
entitlementsDictionary["com.apple.security.device.camera"] = .plBool(true)
137-
}
138-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_RESOURCE_ACCESS_CONTACTS) {
139-
entitlementsDictionary["com.apple.security.personal-information.addressbook"] = .plBool(true)
140-
}
141-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_RESOURCE_ACCESS_LOCATION) {
142-
entitlementsDictionary["com.apple.security.personal-information.location"] = .plBool(true)
143-
}
144-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_RESOURCE_ACCESS_PHOTO_LIBRARY) {
145-
entitlementsDictionary["com.apple.security.personal-information.photos-library"] = .plBool(true)
146-
}
147-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_RESOURCE_ACCESS_PRINTING) {
148-
entitlementsDictionary["com.apple.security.print"] = .plBool(true)
149-
}
150-
if cbc.scope.evaluate(BuiltinMacros.ENABLE_RESOURCE_ACCESS_USB) {
151-
entitlementsDictionary["com.apple.security.device.usb"] = .plBool(true)
139+
for (buildSetting, entitlement) in Self.sandboxAndHardenedRuntimeBooleanEntitlements {
140+
if cbc.scope.evaluate(buildSetting) {
141+
entitlementsDictionary[entitlement] = .plBool(true)
142+
}
152143
}
153144
}
154145

@@ -218,29 +209,32 @@ public final class ProductPackagingToolSpec : GenericCommandLineToolSpec, SpecId
218209

219210
private extension ProductPackagingToolSpec {
220211
enum EntitlementConflictDiagnosticEmitter {
221-
static func checkForConflicts(_ cbc: CommandBuildContext, _ delegate: some TaskGenerationDelegate, entitlementsDictionary: [String: PropertyListItem]) {
222-
223-
let isAppSandboxEnabled = cbc.scope.evaluate(BuiltinMacros.ENABLE_APP_SANDBOX)
224-
225-
switch entitlementsDictionary["com.apple.security.app-sandbox"] {
226-
case let .plBool(value):
227-
if isAppSandboxEnabled != value {
228-
let appSandboxBuildSettingName = BuiltinMacros.ENABLE_APP_SANDBOX.name
212+
private static func validate(entitlement: String, withExpectedValue expectedValue: Bool, entitlementsDictionary: [String: PropertyListItem], entitlementsPath: Path?, buildSettingName: String, buildSettingValue: String, delegate: some TaskGenerationDelegate) {
213+
switch entitlementsDictionary[entitlement] {
214+
case let .plBool(entitlementValue):
215+
if expectedValue != entitlementValue {
229216
let message: String
230217
let childDiagnostics: [Diagnostic]
231218

232-
if isAppSandboxEnabled {
219+
let entitlementsLocation: Diagnostic.Location
220+
if let entitlementsPath {
221+
entitlementsLocation = .path(entitlementsPath)
222+
} else {
223+
entitlementsLocation = .unknown
224+
}
225+
226+
if expectedValue {
233227
// This is when build setting is true and entitlement is false
234-
message = "The \(appSandboxBuildSettingName) build setting is set to YES, but is set to NO in your entitlements file."
228+
message = "The '\(buildSettingName)' build setting is set to '\(buildSettingValue)', but entitlement '\(entitlement)' is set to '\(entitlementValue ? "YES" : "NO")' in your entitlements file."
235229
childDiagnostics = [
236-
.init(behavior: .note, location: .unknown, data: .init("To enable App Sandbox, remove the entitlement from your entitlements file.")),
237-
.init(behavior: .note, location: .unknown, data: .init("To disable App Sandbox, remove the entitlement from your entitlements file, and set the \(appSandboxBuildSettingName) build setting to NO."))
230+
.init(behavior: .note, location: entitlementsLocation, data: .init("To enable '\(buildSettingName)', remove the entitlement from your entitlements file.")),
231+
.init(behavior: .note, location: .buildSettings(names: [buildSettingName]), data: .init("To disable '\(buildSettingName)', remove the entitlement from your entitlements file and disable '\(buildSettingName)' in build settings."))
238232
]
239233
} else {
240-
message = "The \(appSandboxBuildSettingName) build setting is set to NO, but is set to YES in your entitlements file."
234+
message = "The '\(buildSettingName)' build setting is set to '\(buildSettingValue)', but entitlement '\(entitlement)' is set to '\(entitlementValue ? "YES" : "NO")' in your entitlements file."
241235
childDiagnostics = [
242-
.init(behavior: .note, location: .unknown, data: .init("To enable App Sandbox, remove the entitlement from your entitlements file, and set the \(appSandboxBuildSettingName) build setting to YES.")),
243-
.init(behavior: .note, location: .unknown, data: .init("To disable App Sandbox, remove the entitlement from your entitlements file."))
236+
.init(behavior: .note, location: .buildSettings(names: [buildSettingName]), data: .init("To enable '\(buildSettingName)', remove the entitlement from your entitlements file, and enable '\(buildSettingName)' in build settings.")),
237+
.init(behavior: .note, location: entitlementsLocation, data: .init("To disable '\(buildSettingName)', remove the entitlement from your entitlements file."))
244238
]
245239
}
246240

@@ -250,5 +244,34 @@ private extension ProductPackagingToolSpec {
250244
break
251245
}
252246
}
247+
248+
static func checkForConflicts(_ cbc: CommandBuildContext, _ delegate: some TaskGenerationDelegate, entitlementsDictionary: [String: PropertyListItem], entitlementsPath: Path?) {
249+
for (buildSetting, entitlementPrefix) in sandboxFileAccessSettingsAndEntitlements {
250+
let fileAccessValue = cbc.scope.evaluate(buildSetting)
251+
let buildSettingName = buildSetting.name
252+
253+
let readOnlyEntitlement = "\(entitlementPrefix).read-only"
254+
let readWriteEntitlement = "\(entitlementPrefix).read-write"
255+
256+
switch fileAccessValue {
257+
case .readOnly:
258+
validate(entitlement: readOnlyEntitlement, withExpectedValue: true, entitlementsDictionary: entitlementsDictionary, entitlementsPath: entitlementsPath, buildSettingName: buildSettingName, buildSettingValue: "readOnly", delegate: delegate)
259+
260+
case .readWrite:
261+
validate(entitlement: readWriteEntitlement, withExpectedValue: true, entitlementsDictionary: entitlementsDictionary, entitlementsPath: entitlementsPath, buildSettingName: buildSettingName, buildSettingValue: "readWrite", delegate: delegate)
262+
case .none:
263+
validate(entitlement: readOnlyEntitlement, withExpectedValue: false, entitlementsDictionary: entitlementsDictionary, entitlementsPath: entitlementsPath, buildSettingName: buildSettingName, buildSettingValue: "None", delegate: delegate)
264+
validate(entitlement: readWriteEntitlement, withExpectedValue: false, entitlementsDictionary: entitlementsDictionary, entitlementsPath: entitlementsPath, buildSettingName: buildSettingName, buildSettingValue: "None", delegate: delegate)
265+
266+
}
267+
}
268+
269+
for (buildSetting, entitlement) in ProductPackagingToolSpec.sandboxAndHardenedRuntimeBooleanEntitlements {
270+
let buildSettingValue = cbc.scope.evaluate(buildSetting)
271+
let buildSettingName = buildSetting.name
272+
273+
validate(entitlement: entitlement, withExpectedValue: buildSettingValue, entitlementsDictionary: entitlementsDictionary, entitlementsPath: entitlementsPath, buildSettingName: buildSettingName, buildSettingValue: "\(buildSettingValue ? "YES" : "NO")", delegate: delegate)
274+
}
275+
}
253276
}
254277
}

0 commit comments

Comments
 (0)