blob: 6a3fc1f188b4ef118bef686f08ccc48b3f6de484 [file] [log] [blame]
Jiyong Park972e06c2021-03-15 23:32:49 +09001// Copyright (C) 2021 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 filesystem
16
17import (
18 "fmt"
19 "strconv"
20
21 "github.com/google/blueprint"
22 "github.com/google/blueprint/proptools"
23
24 "android/soong/android"
25)
26
27func init() {
Cole Faust3552eb62024-11-06 18:07:26 -080028 android.RegisterModuleType("vbmeta", VbmetaFactory)
Jiyong Park972e06c2021-03-15 23:32:49 +090029}
30
31type vbmeta struct {
32 android.ModuleBase
33
Cole Faust3552eb62024-11-06 18:07:26 -080034 properties VbmetaProperties
Jiyong Park972e06c2021-03-15 23:32:49 +090035
36 output android.OutputPath
37 installDir android.InstallPath
38}
39
Cole Faust3552eb62024-11-06 18:07:26 -080040type VbmetaProperties struct {
Jiyong Park972e06c2021-03-15 23:32:49 +090041 // Name of the partition stored in vbmeta desc. Defaults to the name of this module.
42 Partition_name *string
43
44 // Set the name of the output. Defaults to <module_name>.img.
45 Stem *string
46
47 // Path to the private key that avbtool will use to sign this vbmeta image.
48 Private_key *string `android:"path"`
49
50 // Algorithm that avbtool will use to sign this vbmeta image. Default is SHA256_RSA4096.
51 Algorithm *string
52
Cole Faust3552eb62024-11-06 18:07:26 -080053 // The rollback index. If unspecified, the rollback index is from PLATFORM_SECURITY_PATCH
54 Rollback_index *int64
Jiyong Park972e06c2021-03-15 23:32:49 +090055
56 // Rollback index location of this vbmeta image. Must be 0, 1, 2, etc. Default is 0.
57 Rollback_index_location *int64
58
59 // List of filesystem modules that this vbmeta has descriptors for. The filesystem modules
60 // have to be signed (use_avb: true).
Inseob Kim4daca6b2024-07-26 11:17:52 +090061 Partitions proptools.Configurable[[]string]
Jiyong Park972e06c2021-03-15 23:32:49 +090062
63 // List of chained partitions that this vbmeta deletages the verification.
Cole Faust3552eb62024-11-06 18:07:26 -080064 Chained_partitions []ChainedPartitionProperties
Seungjae Yoo9f263712023-11-16 17:22:57 +090065
66 // List of key-value pair of avb properties
67 Avb_properties []avbProperty
68}
69
70type avbProperty struct {
71 // Key of given avb property
72 Key *string
73
74 // Value of given avb property
75 Value *string
Jiyong Park972e06c2021-03-15 23:32:49 +090076}
77
Cole Faust3552eb62024-11-06 18:07:26 -080078type ChainedPartitionProperties struct {
Jiyong Park972e06c2021-03-15 23:32:49 +090079 // Name of the chained partition
80 Name *string
81
82 // Rollback index location of the chained partition. Must be 0, 1, 2, etc. Default is the
83 // index of this partition in the list + 1.
84 Rollback_index_location *int64
85
86 // Path to the public key that the chained partition is signed with. If this is specified,
87 // private_key is ignored.
88 Public_key *string `android:"path"`
89
90 // Path to the private key that the chained partition is signed with. If this is specified,
91 // and public_key is not specified, a public key is extracted from this private key and
92 // the extracted public key is embedded in the vbmeta image.
93 Private_key *string `android:"path"`
94}
95
96// vbmeta is the partition image that has the verification information for other partitions.
Cole Faust3552eb62024-11-06 18:07:26 -080097func VbmetaFactory() android.Module {
Jiyong Park972e06c2021-03-15 23:32:49 +090098 module := &vbmeta{}
99 module.AddProperties(&module.properties)
Cole Faust65cb40a2024-10-21 15:41:42 -0700100 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
Jiyong Park972e06c2021-03-15 23:32:49 +0900101 return module
102}
103
104type vbmetaDep struct {
105 blueprint.BaseDependencyTag
106 kind string
107}
108
109var vbmetaPartitionDep = vbmetaDep{kind: "partition"}
110
111func (v *vbmeta) DepsMutator(ctx android.BottomUpMutatorContext) {
Cole Faustbf1d92a2024-07-29 12:24:25 -0700112 ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions.GetOrDefault(ctx, nil)...)
Jiyong Park972e06c2021-03-15 23:32:49 +0900113}
114
115func (v *vbmeta) installFileName() string {
116 return proptools.StringDefault(v.properties.Stem, v.BaseModuleName()+".img")
117}
118
119func (v *vbmeta) partitionName() string {
120 return proptools.StringDefault(v.properties.Partition_name, v.BaseModuleName())
121}
122
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900123// See external/avb/libavb/avb_slot_verify.c#VBMETA_MAX_SIZE
124const vbmetaMaxSize = 64 * 1024
125
Jiyong Park972e06c2021-03-15 23:32:49 +0900126func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) {
127 extractedPublicKeys := v.extractPublicKeys(ctx)
128
129 v.output = android.PathForModuleOut(ctx, v.installFileName()).OutputPath
130
131 builder := android.NewRuleBuilder(pctx, ctx)
132 cmd := builder.Command().BuiltTool("avbtool").Text("make_vbmeta_image")
133
134 key := android.PathForModuleSrc(ctx, proptools.String(v.properties.Private_key))
135 cmd.FlagWithInput("--key ", key)
136
137 algorithm := proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096")
138 cmd.FlagWithArg("--algorithm ", algorithm)
139
140 cmd.FlagWithArg("--rollback_index ", v.rollbackIndexCommand(ctx))
141 ril := proptools.IntDefault(v.properties.Rollback_index_location, 0)
142 if ril < 0 {
143 ctx.PropertyErrorf("rollback_index_location", "must be 0, 1, 2, ...")
144 return
145 }
146 cmd.FlagWithArg("--rollback_index_location ", strconv.Itoa(ril))
147
Seungjae Yoo9f263712023-11-16 17:22:57 +0900148 for _, avb_prop := range v.properties.Avb_properties {
149 key := proptools.String(avb_prop.Key)
150 if key == "" {
151 ctx.PropertyErrorf("avb_properties", "key must be specified")
152 continue
153 }
154 value := proptools.String(avb_prop.Value)
155 if value == "" {
156 ctx.PropertyErrorf("avb_properties", "value must be specified")
157 continue
158 }
159 cmd.FlagWithArg("--prop ", key+":"+value)
160 }
161
Jiyong Park972e06c2021-03-15 23:32:49 +0900162 for _, p := range ctx.GetDirectDepsWithTag(vbmetaPartitionDep) {
163 f, ok := p.(Filesystem)
164 if !ok {
165 ctx.PropertyErrorf("partitions", "%q(type: %s) is not supported",
166 p.Name(), ctx.OtherModuleType(p))
167 continue
168 }
169 signedImage := f.SignedOutputPath()
170 if signedImage == nil {
171 ctx.PropertyErrorf("partitions", "%q(type: %s) is not signed. Use `use_avb: true`",
172 p.Name(), ctx.OtherModuleType(p))
173 continue
174 }
175 cmd.FlagWithInput("--include_descriptors_from_image ", signedImage)
176 }
177
178 for i, cp := range v.properties.Chained_partitions {
179 name := proptools.String(cp.Name)
180 if name == "" {
181 ctx.PropertyErrorf("chained_partitions", "name must be specified")
182 continue
183 }
184
185 ril := proptools.IntDefault(cp.Rollback_index_location, i+1)
186 if ril < 0 {
187 ctx.PropertyErrorf("chained_partitions", "must be 0, 1, 2, ...")
188 continue
189 }
190
191 var publicKey android.Path
192 if cp.Public_key != nil {
193 publicKey = android.PathForModuleSrc(ctx, proptools.String(cp.Public_key))
194 } else {
195 publicKey = extractedPublicKeys[name]
196 }
197 cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", name, ril, publicKey.String()))
198 cmd.Implicit(publicKey)
199 }
200
201 cmd.FlagWithOutput("--output ", v.output)
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900202
203 // libavb expects to be able to read the maximum vbmeta size, so we must provide a partition
204 // which matches this or the read will fail.
205 builder.Command().Text("truncate").
206 FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)).
207 Output(v.output)
208
Jiyong Park972e06c2021-03-15 23:32:49 +0900209 builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
210
211 v.installDir = android.PathForModuleInstall(ctx, "etc")
212 ctx.InstallFile(v.installDir, v.installFileName(), v.output)
mrziwang555d1332024-06-07 11:15:33 -0700213
214 ctx.SetOutputFiles([]android.Path{v.output}, "")
Jiyong Park972e06c2021-03-15 23:32:49 +0900215}
216
217// Returns the embedded shell command that prints the rollback index
218func (v *vbmeta) rollbackIndexCommand(ctx android.ModuleContext) string {
Cole Faust3552eb62024-11-06 18:07:26 -0800219 if v.properties.Rollback_index != nil {
220 return fmt.Sprintf("%d", *v.properties.Rollback_index)
Jiyong Park972e06c2021-03-15 23:32:49 +0900221 } else {
Cole Faust3552eb62024-11-06 18:07:26 -0800222 // Take the first line and remove the newline char
223 return "$(date -d 'TZ=\"GMT\" " + ctx.Config().PlatformSecurityPatch() + "' +%s | head -1 | tr -d '\n'" + ")"
Jiyong Park972e06c2021-03-15 23:32:49 +0900224 }
Jiyong Park972e06c2021-03-15 23:32:49 +0900225}
226
227// Extract public keys from chained_partitions.private_key. The keys are indexed with the partition
228// name.
229func (v *vbmeta) extractPublicKeys(ctx android.ModuleContext) map[string]android.OutputPath {
230 result := make(map[string]android.OutputPath)
231
232 builder := android.NewRuleBuilder(pctx, ctx)
233 for _, cp := range v.properties.Chained_partitions {
234 if cp.Private_key == nil {
235 continue
236 }
237
238 name := proptools.String(cp.Name)
239 if name == "" {
240 ctx.PropertyErrorf("chained_partitions", "name must be specified")
241 continue
242 }
243
244 if _, ok := result[name]; ok {
245 ctx.PropertyErrorf("chained_partitions", "name %q is duplicated", name)
246 continue
247 }
248
249 privateKeyFile := android.PathForModuleSrc(ctx, proptools.String(cp.Private_key))
250 publicKeyFile := android.PathForModuleOut(ctx, name+".avbpubkey").OutputPath
251
252 builder.Command().
253 BuiltTool("avbtool").
254 Text("extract_public_key").
255 FlagWithInput("--key ", privateKeyFile).
256 FlagWithOutput("--output ", publicKeyFile)
257
258 result[name] = publicKeyFile
259 }
260 builder.Build("vbmeta_extract_public_key", fmt.Sprintf("Extract public keys for %s", ctx.ModuleName()))
261 return result
262}
263
Yu Liue70976d2024-10-15 20:45:35 +0000264var _ android.AndroidMkProviderInfoProducer = (*vbmeta)(nil)
265
266func (v *vbmeta) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
mrziwang18420972024-09-03 15:12:51 -0700267 providerData := android.AndroidMkProviderInfo{
268 PrimaryInfo: android.AndroidMkInfo{
269 Class: "ETC",
270 OutputFile: android.OptionalPathForPath(v.output),
271 EntryMap: make(map[string][]string),
Jiyong Park972e06c2021-03-15 23:32:49 +0900272 },
mrziwang18420972024-09-03 15:12:51 -0700273 }
274 providerData.PrimaryInfo.SetString("LOCAL_MODULE_PATH", v.installDir.String())
275 providerData.PrimaryInfo.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
276 return &providerData
Jiyong Park972e06c2021-03-15 23:32:49 +0900277}
278
279var _ Filesystem = (*vbmeta)(nil)
280
281func (v *vbmeta) OutputPath() android.Path {
282 return v.output
283}
284
285func (v *vbmeta) SignedOutputPath() android.Path {
286 return v.OutputPath() // vbmeta is always signed
287}