RFC-0118: SWD policy at image assembly | |
---|---|
Status | Accepted |
Areas |
|
Description | Short-term change to apply SWD policy at image assembly time. |
Issues | |
Gerrit change | |
Authors | |
Reviewers | |
Date submitted (year-month-day) | 2021-06-28 |
Date reviewed (year-month-day) | 2021-07-28 |
Summary
This RFC proposes a stopgap to allow for better visibility, understanding, and scalability of Software Delivery (SWD) policy configurations by defining well understood and scoped policies so that any developer can both understand what software can and cannot be run on a device running Fuchsia and be sure that they are not accidentally shipping a less secure configuration.
The current proposal is intended to exist in its current form until sub-assembly based Product Assembly allows for more clearly defined policies for different product use-cases. The intermediary work in this proposal will allow for an easier transition to the system assembly-style configuration, as the work to centralize the application of SWD policy will already have been done.
Motivation
SWD configuration is integral in enforcing verified execution. Currently, SWD configuration is split across several configuration files and packages that interact with each other to determine the actual SWD configuration on the device. This RFC aims to reduce the complexity of understanding the SWD state for a product. Adding strongly understood and deliberate policies also makes adding new products and variants simpler and safer, easing the burden of ensuring that the correct configurations are applied.
Design
Three SWD policies are currently proposed as part of this RFC. They aim to formalize the SWD policy configurations with semantic rather than product-driven naming. These policies are to be applied to product definitions to define SWD state in a more holistic fashion, and product owners will select one of the available policies rather than tune each individual configuration setting.
As need arises, we may add more policies, but this set of policies is expected to remain much smaller than the growth of product and build variants.
Policy Definitions
Base Components Only
All executable code must be directly verified (in base). All configurable SWD restrictions are set to their default secure state: dynamic configuration of repositories is not allowed, and executability restrictions are on, meaning that only base and allowlisted components are resolveable and executable.
Local Dynamic Config
Permits dynamic configuration of repositories and manual resolution of indirectly verified code (universe packages/ephemeral components) if and only if the user has physical access (e.g. a developer).
Unrestricted
There are no limitations or restrictions on the executability or visibility of code. This is the maximally permissive SWD configuration that allows foreign code and dynamic configuration, and also disables executability restrictions.
Table of Policies
POLICY_NAME | enable_dynamic_configuration | persisted_repos_dir | disable_executability_restrictions |
---|---|---|---|
base_components_only | OFF | OFF | OFF |
local_dynamic_config | ON | OFF | OFF |
unrestricted | ON | ON | ON |
Implementation
This RFC proposes that this be implemented at the image assembly level. Since
the SWD configuration requires setting values in both base_packages
and
system_image_deps
, the proposal is to modify the respective group targets
to include a new dependency on a GN group defined based on the
policy_labels
build argument, which is a dictionary that stores a set of
key-value pairs of image assembly-understood key values (in this case swd
)
and their respective policy labels.
This allows us to ensure that there is always exactly one SWD policy configuration defined for a given build.
As an example, given that policies are defined in
//build/security/policies_swd.gni
:
policies_swd = [
{
name = "local_dynamic_config"
base_package_deps = [ /* ... */ ]
system_image_deps = [ /* ... */ ]
bootfs_deps = [ /* ... */ ]
},
{
name = "foo"
// ...
},
]
In a product definition file, a product owner can do:
import("//build/images/policy.gni") # defines policy_labels = {} arg.
policy_labels.swd = "local_dynamic_config"
policy_labels.foo = "bar"
And in the image assembly step:
group("base_packages") {
testonly = base_cache_packages_testonly
visibility = [ ":*" ]
public_deps = [
// ...
]
// Addition for this proposal
deps = []
foreach (policy, policies_swd) {
if (policy.name == policy_labels.swd) {
deps += policy.base_package_deps
}
}
}
Note that this does not completely solve the inheritance of product definitions from ancestor GNI files. It does however simplify the configuration and auditability of SWD policy.
Performance
This change does not affect performance.
Ergonomics
This change improves the ease of understanding and auditing the state of SWD on a device by abstracting away configuration settings such that SWD configuration is controlled by a single build argument.
Backwards Compatibility
This change does not affect backwards compatibility, the changes should be structured in such a way that they can be easily reverted.
Security considerations
This change improves the simplicity, scalability, and readbility of SWD configuration state, which determines which software can be run on a Fuchsia device. This makes it less likely that a developer will ship a product with an insecure configuration, directly improving our security posture. This reduced configuration space also will make it easier for a product-owner to audit.
Privacy considerations
This change does not affect privacy or interact with user data.
Testing
This change will be tested to ensure that builds post this change have the
expected SWD policy configurations. This will be done by manually verifying
the output builds have (or do not have) the expected file (for
disable_executability_restrictions
) and config-data packages (for
enable_dynamic_configuration
and persisted_repos_dir
) before and after the
change.
Documentation
Additional documentation will be added to define the SWD policy configurations.
Drawbacks, alternatives, and unknowns
This change is intended to be a short term solution until platform sub-assemblies exist to allow us to have more fine grained control over the build process. This work is captured in in-progress RFCS for sub-assemblies (fxr/553664) and structured configuration (fxr/549661).
The main caveat of this change is that this abstracts package/dependency inclusion away from the product definitions.
Alternatives that were investigated were:
Not making any changes
We could continue to live in the current environment where each product can modify its own configuration, and each product continues to inherit haphazardly from the union of its ancestors.
But, with the rapidly growing set of Fuchsia products, we made this proposal to proactively make improvements to the SWD configuration mechanism in order to head off possible incidents where the incorrect SWD state was applied to the product, subverting core security assumptions of the Fuchsia platform.
Modifying product definitions
This is similar to how it is done currently, but instead of having the various settings defined haphazardly across the inheritance tree of product definitions, we would define the settings at each level. This was determined to be infeasible as it both put the onus of knowing what each knob did on the developer, and would not scale to the ever growing set of products. This also has the added detriment that any changes to the root/ancestral levels of the tree would necessarily require changes to all child levels to unset or reset the associated components.
Asserting at build verification time
We could offload the problem of determining whether a build was using the correct configuration to build verification, asserting that the correct dependencies were associated with each build. This solves the problem of ensuring that a built image has the correct configuration, but does not solve the audibility/visibility problem, nor does it improve the ergonomics of understanding the SWD stack's behavior in a given configuration.
Modifying/reducing the set of SWD configuration settings
We investigated whether or not it was possible to modify SWD logic in order to reduce the number of settings to change down to a single value. Unfortunately, this was deemed to be infeasible as the SWD stack is implemented in multiple components across multiple packages and the zbi, with configuration spread across all of them.