blob: b7fff687d66a3e718391de9da53997b3f5a76fed [file] [log] [blame]
Cole Faust3552eb62024-11-06 18:07:26 -08001// Copyright (C) 2024 The Android Open Source Project
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
15package fsgen
16
17import (
18 "android/soong/android"
19 "android/soong/filesystem"
20 "slices"
21 "strconv"
22
23 "github.com/google/blueprint/proptools"
24)
25
26type vbmetaModuleInfo struct {
27 // The name of the generated vbmeta module
28 moduleName string
29 // The name of the module that avb understands. This is the name passed to --chain_partition,
30 // and also the basename of the output file. (the output file is called partitionName + ".img")
31 partitionName string
32}
33
34// Creates the vbmeta partition and the chained vbmeta partitions. Returns the list of module names
35// that the function created. May return nil if the product isn't using avb.
36//
37// AVB is Android Verified Boot: https://source.android.com/docs/security/features/verifiedboot
38// It works by signing all the partitions, but then also including an extra metadata paritition
39// called vbmeta that depends on all the other signed partitions. This creates a requirement
40// that you update all those partitions and the vbmeta partition together, so in order to relax
41// that requirement products can set up "chained" vbmeta partitions, where a chained partition
42// like vbmeta_system might contain the avb metadata for just a few products. In cuttlefish
43// vbmeta_system contains metadata about product, system, and system_ext. Using chained partitions,
44// that group of partitions can be updated independently from the other signed partitions.
45func createVbmetaPartitions(ctx android.LoadHookContext, generatedPartitionTypes []string) []vbmetaModuleInfo {
46 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
47 // Some products seem to have BuildingVbmetaImage as true even when BoardAvbEnable is false
48 if !partitionVars.BuildingVbmetaImage || !partitionVars.BoardAvbEnable {
49 return nil
50 }
51
52 var result []vbmetaModuleInfo
53
Cole Faustb3d6e752024-11-08 12:44:33 -080054 var chainedPartitions []string
Cole Faust3552eb62024-11-06 18:07:26 -080055 var partitionTypesHandledByChainedPartitions []string
Cole Faust481a7252024-11-13 11:46:22 -080056 for _, chainedName := range android.SortedKeys(partitionVars.ChainedVbmetaPartitions) {
57 props := partitionVars.ChainedVbmetaPartitions[chainedName]
Cole Faust3552eb62024-11-06 18:07:26 -080058 chainedName = "vbmeta_" + chainedName
59 if len(props.Partitions) == 0 {
60 continue
61 }
62 if len(props.Key) == 0 {
63 ctx.ModuleErrorf("No key found for chained avb partition %q", chainedName)
64 continue
65 }
66 if len(props.Algorithm) == 0 {
67 ctx.ModuleErrorf("No algorithm found for chained avb partition %q", chainedName)
68 continue
69 }
70 if len(props.RollbackIndex) == 0 {
71 ctx.ModuleErrorf("No rollback index found for chained avb partition %q", chainedName)
72 continue
73 }
74 ril, err := strconv.ParseInt(props.RollbackIndexLocation, 10, 32)
75 if err != nil {
76 ctx.ModuleErrorf("Rollback index location must be an int, got %q", props.RollbackIndexLocation)
77 continue
78 }
79 // The default is to use the PlatformSecurityPatch, and a lot of product config files
80 // just set it to the platform security patch, so detect that and don't set the property
81 // in soong.
82 var rollbackIndex *int64
83 if props.RollbackIndex != ctx.Config().PlatformSecurityPatch() {
84 i, err := strconv.ParseInt(props.RollbackIndex, 10, 32)
85 if err != nil {
86 ctx.ModuleErrorf("Rollback index must be an int, got %q", props.RollbackIndex)
87 continue
88 }
89 rollbackIndex = &i
90 }
91
92 var partitionModules []string
93 for _, partition := range props.Partitions {
94 partitionTypesHandledByChainedPartitions = append(partitionTypesHandledByChainedPartitions, partition)
95 if !slices.Contains(generatedPartitionTypes, partition) {
96 // The partition is probably unsupported.
97 continue
98 }
99 partitionModules = append(partitionModules, generatedModuleNameForPartition(ctx.Config(), partition))
100 }
101
102 name := generatedModuleName(ctx.Config(), chainedName)
103 ctx.CreateModuleInDirectory(
104 filesystem.VbmetaFactory,
105 ".", // Create in the root directory for now so its easy to get the key
106 &filesystem.VbmetaProperties{
107 Partition_name: proptools.StringPtr(chainedName),
108 Stem: proptools.StringPtr(chainedName + ".img"),
109 Private_key: proptools.StringPtr(props.Key),
110 Algorithm: &props.Algorithm,
111 Rollback_index: rollbackIndex,
112 Rollback_index_location: &ril,
113 Partitions: proptools.NewSimpleConfigurable(partitionModules),
114 }, &struct {
115 Name *string
116 }{
117 Name: &name,
118 },
119 ).HideFromMake()
120
Cole Faustb3d6e752024-11-08 12:44:33 -0800121 chainedPartitions = append(chainedPartitions, name)
Cole Faust3552eb62024-11-06 18:07:26 -0800122
123 result = append(result, vbmetaModuleInfo{
124 moduleName: name,
125 partitionName: chainedName,
126 })
127 }
128
129 vbmetaModuleName := generatedModuleName(ctx.Config(), "vbmeta")
130
131 var algorithm *string
132 var ri *int64
133 var key *string
134 if len(partitionVars.BoardAvbKeyPath) == 0 {
135 // Match make's defaults: https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4568;drc=5b55f926830963c02ab1d2d91e46442f04ba3af0
136 key = proptools.StringPtr("external/avb/test/data/testkey_rsa4096.pem")
137 algorithm = proptools.StringPtr("SHA256_RSA4096")
138 } else {
139 key = proptools.StringPtr(partitionVars.BoardAvbKeyPath)
140 algorithm = proptools.StringPtr(partitionVars.BoardAvbAlgorithm)
141 }
142 if len(partitionVars.BoardAvbRollbackIndex) > 0 {
143 parsedRi, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 32)
144 if err != nil {
145 ctx.ModuleErrorf("Rollback index location must be an int, got %q", partitionVars.BoardAvbRollbackIndex)
146 }
147 ri = &parsedRi
148 }
149
150 var partitionModules []string
151 for _, partitionType := range generatedPartitionTypes {
152 if slices.Contains(partitionTypesHandledByChainedPartitions, partitionType) {
153 // Already handled by a chained vbmeta partition
154 continue
155 }
Cole Faust76a6e952024-11-07 16:56:45 -0800156 if partitionType == "ramdisk" {
157 // ramdisk is never signed with avb information
158 continue
159 }
Cole Faust3552eb62024-11-06 18:07:26 -0800160 partitionModules = append(partitionModules, generatedModuleNameForPartition(ctx.Config(), partitionType))
161 }
162
163 ctx.CreateModuleInDirectory(
164 filesystem.VbmetaFactory,
165 ".", // Create in the root directory for now so its easy to get the key
166 &filesystem.VbmetaProperties{
167 Stem: proptools.StringPtr("vbmeta.img"),
168 Algorithm: algorithm,
169 Private_key: key,
170 Rollback_index: ri,
171 Chained_partitions: chainedPartitions,
172 Partitions: proptools.NewSimpleConfigurable(partitionModules),
173 }, &struct {
174 Name *string
175 }{
176 Name: &vbmetaModuleName,
177 },
178 ).HideFromMake()
179
180 result = append(result, vbmetaModuleInfo{
181 moduleName: vbmetaModuleName,
182 partitionName: "vbmeta",
183 })
184 return result
185}