Skip to content

Commit 10c27f6

Browse files
nglevinluispadron
authored andcommitted
Standing up more secure features bits around the rules.
This doesn't have the arm64e bits set yet, and the test for the entitlements is currently limited to just the keys necessary to ship these features in Xcode 26. Cherry-pick: e5af9f8
1 parent 3d03580 commit 10c27f6

9 files changed

Lines changed: 290 additions & 40 deletions

File tree

apple/internal/BUILD

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ bzl_library(
221221
":apple_product_type",
222222
":bundling_support",
223223
":resource_actions",
224+
":secure_features_support",
224225
"//apple:common",
225226
"//apple/internal/utils:defines",
226227
"@build_bazel_apple_support//lib:apple_support",
@@ -636,6 +637,14 @@ bzl_library(
636637
],
637638
)
638639

640+
bzl_library(
641+
name = "secure_features_support",
642+
srcs = ["secure_features_support.bzl"],
643+
visibility = [
644+
"//apple/internal:__subpackages__",
645+
],
646+
)
647+
639648
bzl_library(
640649
name = "stub_support",
641650
srcs = ["stub_support.bzl"],
@@ -686,6 +695,7 @@ bzl_library(
686695
"//apple:__subpackages__",
687696
],
688697
deps = [
698+
":secure_features_support",
689699
"//apple/build_settings",
690700
"@bazel_skylib//lib:dicts",
691701
"@build_bazel_apple_support//configs:platforms",

apple/internal/entitlements_support.bzl

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ load(
3434
"//apple/internal:resource_actions.bzl",
3535
"resource_actions",
3636
)
37+
load(
38+
"//apple/internal:secure_features_support.bzl",
39+
"secure_features_support",
40+
)
3741
load(
3842
"//apple/internal/utils:defines.bzl",
3943
"defines",
@@ -225,6 +229,8 @@ def _process_entitlements(
225229
actions: The object used to register actions.
226230
apple_mac_toolchain_info: The `struct` of tools from the shared Apple
227231
toolchain.
232+
apple_xplat_toolchain_info: The `struct` of tools from the shared Apple
233+
cross platform toolchain.
228234
bundle_id: The bundle identifier.
229235
entitlements_file: The `File` containing the unprocessed entitlements
230236
(or `None` if none were provided).
@@ -270,11 +276,11 @@ def _process_entitlements(
270276
if secure_features:
271277
if not apple_xplat_toolchain_info.build_settings.enable_wip_features:
272278
fail("secure_features are still a work in progress and not yet supported in the rules.")
273-
274-
# TODO: b/449684779 - Have a mapping to declare which entitlements should be added for the
275-
# given secure_features on Xcode 26.0 and later with validation against supported features.
276-
# Create a new bzl (secure_features_support) to contain this mapping and validation and use
277-
# it here.
279+
secure_features_entitlements = secure_features_support.entitlements_from_secure_features(
280+
secure_features = secure_features,
281+
xcode_version = platform_prerequisites.xcode_version_config.xcode_version(),
282+
)
283+
forced_plists.append(struct(**secure_features_entitlements))
278284

279285
inputs = list(plists)
280286

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# Copyright 2025 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Enhanced security feature support methods."""
16+
17+
visibility([
18+
"//apple/internal/...",
19+
])
20+
21+
# TODO: b/449684779 - Stand up a solution for allowing arm64e as a target arch in a transition when
22+
# building for devices. Simulators don't have adequate support yet (FB20484613), so consider
23+
# fail-ing or warning until that's resolved.
24+
25+
# The name of the secure feature that's required for opting into any set of enhanced security
26+
# features on Xcode 26.0 or later.
27+
#
28+
# TODO: b/449684779 - Use this for a mandatory check for the Xcode 26 opt-in feature, since that
29+
# should always be set if any entitlements are required.
30+
_REQUIRED_XCODE_26_OPT_IN = "apple.xcode_26_minimum_opt_in"
31+
32+
# A map of all of the secure features that requires crosstool support and the entitlements that they
33+
# enable. If a secure feature does not enable any entitlements, it should be mapped to an empty
34+
# object.
35+
_ENTITLEMENTS_FROM_SECURE_FEATURES = {
36+
# A subset of "secure features" will not be mapped to any crosstool features, but they do still
37+
# provide required entitlements for Xcode 26 and later. These are prefixed with "apple." to
38+
# separate them from the crosstool namespace.
39+
"apple.additional_runtime_platform_restrictions": {
40+
"com.apple.security.hardened-process.platform-restrictions": True,
41+
},
42+
"apple.read_only_platform_memory": {
43+
"com.apple.security.hardened-process.dyld-ro": True,
44+
},
45+
"c_bounds_safety": {},
46+
"c_typed_allocator_support": {
47+
"com.apple.security.hardened-process.hardened-heap": True,
48+
},
49+
"cpp_bounds_safe_buffers": {},
50+
"cpp_typed_allocator_support": {
51+
"com.apple.security.hardened-process.hardened-heap": True,
52+
},
53+
"libcxx_hardened_mode": {},
54+
"pointer_authentication": {},
55+
"security_compiler_warnings": {},
56+
"trivial_auto_var_init": {},
57+
"typed_allocator_support": {
58+
"com.apple.security.hardened-process.hardened-heap": True,
59+
},
60+
"warn_unsafe_buffer_usage": {},
61+
_REQUIRED_XCODE_26_OPT_IN: {
62+
"com.apple.security.hardened-process": True,
63+
"com.apple.security.hardened-process.enhanced-security-version": 1,
64+
},
65+
}
66+
67+
# All of the possible values for `--features` reserved for Apple Enhanced Security.
68+
_SUPPORTED_SECURE_FEATURES = set(list(_ENTITLEMENTS_FROM_SECURE_FEATURES.keys()))
69+
70+
_NONE_TYPE = type(None)
71+
72+
def _crosstool_features_from_secure_features(*, features, secure_features):
73+
# If this rule does not allow for enhanced security features to be specified as an attribute,
74+
# which is interpreted as "secure_features" being exactly "None", return the features as-is,
75+
# allowing any secure features that might be in "features" to remain as-is.
76+
if type(secure_features) == _NONE_TYPE:
77+
return features
78+
79+
requested_secure_features = set(secure_features)
80+
81+
# Check that all of the requested secure features are supported.
82+
unsupported_secure_features = requested_secure_features - _SUPPORTED_SECURE_FEATURES
83+
if unsupported_secure_features:
84+
fail("""
85+
Unsupported secure_features requested:
86+
{unsupported_features}
87+
88+
Please remove these from this target's "secure_features" attribute.
89+
90+
The full list of supported secure_features is:
91+
{all_supported_features}
92+
""".format(
93+
unsupported_features = str(list(unsupported_secure_features)),
94+
all_supported_features = str(list(_SUPPORTED_SECURE_FEATURES)),
95+
))
96+
97+
# Start building the set of features to build with, starting from the set of features already
98+
# requested by the user.
99+
requested_features = set(features)
100+
101+
# TODO: b/449684779 - See if we can do anything to account for `-` prefixed features here before
102+
# the entitlements check because those are supposed to be features disabled by the bazel
103+
# invocation. One approach is to consider fail(...)-ing if any `-` prefixed features are
104+
# requested with `secure_features`, because that incoming configuration on the bazel invocation
105+
# would invalidate what is requested from the target definition.
106+
107+
# Remove any secure features from "features" that were not explicitly requested at the top level
108+
# from "secure_features". This is what prevents a command line --features or raw features on the
109+
# rule or package from applying to top level targets that can have "secure_features" specified.
110+
secure_features_not_requested = _SUPPORTED_SECURE_FEATURES - requested_secure_features
111+
requested_features -= secure_features_not_requested
112+
113+
# Amend the list of requested features to include the secure_features within the list of
114+
# features to build with, if they're not already present. Since we deal with sets, this is a
115+
# no-op if they're already present.
116+
requested_features |= requested_secure_features
117+
118+
# If we don't need to make any changes, return the features as-is.
119+
if requested_features == set(features):
120+
return features
121+
122+
# Return the full, sorted list of requested crosstool-relevant features.
123+
return sorted(list(requested_features))
124+
125+
def _entitlements_from_secure_features(*, secure_features, xcode_version):
126+
if not secure_features:
127+
return []
128+
129+
# Check that we're building with Xcode 26.0 or later. If not, return an empty list to signal
130+
# that no entitlements are supported or needed for this build.
131+
if not xcode_version >= apple_common.dotted_version("26.0"):
132+
return []
133+
134+
# TODO: b/449684779 - Check via cc_common.is_enabled(...) for each of the crosstool features to
135+
# see if they're set via the build configuration, assuming that they might be set outside of the
136+
# configuration as seen by the transition. As I understand it, this should be able to determine
137+
# if the features are actually enabled for the build, or if there was an effort made to
138+
# explicitly disable them, which can't be fully determined at transition time.
139+
140+
# Build a set of all of the entitlements that are required by the requested secure features.
141+
required_entitlements = dict()
142+
for feature in secure_features:
143+
required_entitlements |= _ENTITLEMENTS_FROM_SECURE_FEATURES[feature]
144+
145+
# TODO: b/449684779 - Add a mandatory check for the Xcode 26 opt-in feature, since that should
146+
# always be set if any entitlements are required.
147+
148+
return required_entitlements
149+
150+
secure_features_support = struct(
151+
crosstool_features_from_secure_features = _crosstool_features_from_secure_features,
152+
entitlements_from_secure_features = _entitlements_from_secure_features,
153+
)

0 commit comments

Comments
 (0)