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