blob: d59a2aec51d84ec89fe6502bfe4eea920ee4476b [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"
Spandan Das2e1338e2025-03-19 23:57:36 +000019 "sort"
Jiyong Park972e06c2021-03-15 23:32:49 +090020 "strconv"
Spandan Das2e1338e2025-03-19 23:57:36 +000021 "strings"
22 "time"
Jiyong Park972e06c2021-03-15 23:32:49 +090023
24 "github.com/google/blueprint"
25 "github.com/google/blueprint/proptools"
26
27 "android/soong/android"
28)
29
30func init() {
Cole Faust3552eb62024-11-06 18:07:26 -080031 android.RegisterModuleType("vbmeta", VbmetaFactory)
Cole Faustb3d6e752024-11-08 12:44:33 -080032 pctx.HostBinToolVariable("avbtool", "avbtool")
Jiyong Park972e06c2021-03-15 23:32:49 +090033}
34
Cole Faustb3d6e752024-11-08 12:44:33 -080035var (
36 extractPublicKeyRule = pctx.AndroidStaticRule("avb_extract_public_key",
37 blueprint.RuleParams{
38 Command: `${avbtool} extract_public_key --key $in --output $out`,
39 CommandDeps: []string{
40 "${avbtool}",
41 },
42 })
43)
44
Jiyong Park972e06c2021-03-15 23:32:49 +090045type vbmeta struct {
46 android.ModuleBase
47
Cole Faust3552eb62024-11-06 18:07:26 -080048 properties VbmetaProperties
Jiyong Park972e06c2021-03-15 23:32:49 +090049
Cole Faust4e9f5922024-11-13 16:09:23 -080050 output android.Path
Jiyong Park972e06c2021-03-15 23:32:49 +090051 installDir android.InstallPath
52}
53
Cole Faust3552eb62024-11-06 18:07:26 -080054type VbmetaProperties struct {
Jiyong Park972e06c2021-03-15 23:32:49 +090055 // Name of the partition stored in vbmeta desc. Defaults to the name of this module.
56 Partition_name *string
57
58 // Set the name of the output. Defaults to <module_name>.img.
59 Stem *string
60
61 // Path to the private key that avbtool will use to sign this vbmeta image.
62 Private_key *string `android:"path"`
63
64 // Algorithm that avbtool will use to sign this vbmeta image. Default is SHA256_RSA4096.
65 Algorithm *string
66
Cole Faust3552eb62024-11-06 18:07:26 -080067 // The rollback index. If unspecified, the rollback index is from PLATFORM_SECURITY_PATCH
68 Rollback_index *int64
Jiyong Park972e06c2021-03-15 23:32:49 +090069
70 // Rollback index location of this vbmeta image. Must be 0, 1, 2, etc. Default is 0.
71 Rollback_index_location *int64
72
73 // List of filesystem modules that this vbmeta has descriptors for. The filesystem modules
74 // have to be signed (use_avb: true).
Inseob Kim4daca6b2024-07-26 11:17:52 +090075 Partitions proptools.Configurable[[]string]
Jiyong Park972e06c2021-03-15 23:32:49 +090076
Cole Faustb3d6e752024-11-08 12:44:33 -080077 // Metadata about the chained partitions that this vbmeta delegates the verification.
78 // This is an alternative to chained_partitions, using chained_partitions instead is simpler
79 // in most cases. However, this property allows building this vbmeta partition without
80 // its chained partitions existing in this build.
81 Chained_partition_metadata []ChainedPartitionProperties
82
83 // List of chained partitions that this vbmeta delegates the verification. They are the
84 // names of other vbmeta modules.
85 Chained_partitions []string
Seungjae Yoo9f263712023-11-16 17:22:57 +090086
87 // List of key-value pair of avb properties
88 Avb_properties []avbProperty
89}
90
91type avbProperty struct {
92 // Key of given avb property
93 Key *string
94
95 // Value of given avb property
96 Value *string
Jiyong Park972e06c2021-03-15 23:32:49 +090097}
98
Cole Faust3552eb62024-11-06 18:07:26 -080099type ChainedPartitionProperties struct {
Jiyong Park972e06c2021-03-15 23:32:49 +0900100 // Name of the chained partition
101 Name *string
102
Luca Stefani9235f4c2025-02-08 12:09:34 +0100103 // Rollback index location of the chained partition. Must be 1, 2, 3, etc. Default is the
Jiyong Park972e06c2021-03-15 23:32:49 +0900104 // index of this partition in the list + 1.
105 Rollback_index_location *int64
106
107 // Path to the public key that the chained partition is signed with. If this is specified,
108 // private_key is ignored.
109 Public_key *string `android:"path"`
110
111 // Path to the private key that the chained partition is signed with. If this is specified,
112 // and public_key is not specified, a public key is extracted from this private key and
113 // the extracted public key is embedded in the vbmeta image.
114 Private_key *string `android:"path"`
115}
116
Cole Faustb3d6e752024-11-08 12:44:33 -0800117type vbmetaPartitionInfo struct {
118 // Name of the partition
119 Name string
120
121 // Rollback index location, non-negative int
122 RollbackIndexLocation int
123
124 // The path to the public key of the private key used to sign this partition. Derived from
125 // the private key.
126 PublicKey android.Path
Spandan Dasf7098442025-01-10 22:35:53 +0000127
128 // The output of the vbmeta module
129 Output android.Path
Spandan Das2e1338e2025-03-19 23:57:36 +0000130
131 // Information about the vbmeta partition that will be added to misc_info.txt
132 // created by android_device
133 PropFileForMiscInfo android.Path
Cole Faustb3d6e752024-11-08 12:44:33 -0800134}
135
136var vbmetaPartitionProvider = blueprint.NewProvider[vbmetaPartitionInfo]()
137
Jiyong Park972e06c2021-03-15 23:32:49 +0900138// vbmeta is the partition image that has the verification information for other partitions.
Cole Faust3552eb62024-11-06 18:07:26 -0800139func VbmetaFactory() android.Module {
Jiyong Park972e06c2021-03-15 23:32:49 +0900140 module := &vbmeta{}
141 module.AddProperties(&module.properties)
Cole Faust65cb40a2024-10-21 15:41:42 -0700142 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
Jiyong Park972e06c2021-03-15 23:32:49 +0900143 return module
144}
145
146type vbmetaDep struct {
147 blueprint.BaseDependencyTag
Jiyong Park972e06c2021-03-15 23:32:49 +0900148}
149
Cole Faustb3d6e752024-11-08 12:44:33 -0800150type chainedPartitionDep struct {
151 blueprint.BaseDependencyTag
152}
153
154var vbmetaPartitionDep = vbmetaDep{}
155var vbmetaChainedPartitionDep = chainedPartitionDep{}
Jiyong Park972e06c2021-03-15 23:32:49 +0900156
157func (v *vbmeta) DepsMutator(ctx android.BottomUpMutatorContext) {
Jihoon Kang2f0d1932025-01-17 19:22:44 +0000158 ctx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), vbmetaPartitionDep, v.properties.Partitions.GetOrDefault(ctx, nil)...)
159 ctx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), vbmetaChainedPartitionDep, v.properties.Chained_partitions...)
Jiyong Park972e06c2021-03-15 23:32:49 +0900160}
161
162func (v *vbmeta) installFileName() string {
163 return proptools.StringDefault(v.properties.Stem, v.BaseModuleName()+".img")
164}
165
166func (v *vbmeta) partitionName() string {
167 return proptools.StringDefault(v.properties.Partition_name, v.BaseModuleName())
168}
169
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900170// See external/avb/libavb/avb_slot_verify.c#VBMETA_MAX_SIZE
171const vbmetaMaxSize = 64 * 1024
172
Jiyong Park972e06c2021-03-15 23:32:49 +0900173func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Jiyong Park972e06c2021-03-15 23:32:49 +0900174 builder := android.NewRuleBuilder(pctx, ctx)
175 cmd := builder.Command().BuiltTool("avbtool").Text("make_vbmeta_image")
176
177 key := android.PathForModuleSrc(ctx, proptools.String(v.properties.Private_key))
178 cmd.FlagWithInput("--key ", key)
179
180 algorithm := proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096")
181 cmd.FlagWithArg("--algorithm ", algorithm)
182
Jihoon Kang3556c8f2025-01-15 22:32:27 +0000183 cmd.FlagWithArg("--padding_size ", "4096")
184
Jiyong Park972e06c2021-03-15 23:32:49 +0900185 cmd.FlagWithArg("--rollback_index ", v.rollbackIndexCommand(ctx))
186 ril := proptools.IntDefault(v.properties.Rollback_index_location, 0)
187 if ril < 0 {
188 ctx.PropertyErrorf("rollback_index_location", "must be 0, 1, 2, ...")
189 return
190 }
Jiyong Park972e06c2021-03-15 23:32:49 +0900191
Seungjae Yoo9f263712023-11-16 17:22:57 +0900192 for _, avb_prop := range v.properties.Avb_properties {
193 key := proptools.String(avb_prop.Key)
194 if key == "" {
195 ctx.PropertyErrorf("avb_properties", "key must be specified")
196 continue
197 }
198 value := proptools.String(avb_prop.Value)
199 if value == "" {
200 ctx.PropertyErrorf("avb_properties", "value must be specified")
201 continue
202 }
203 cmd.FlagWithArg("--prop ", key+":"+value)
204 }
205
Jiyong Park972e06c2021-03-15 23:32:49 +0900206 for _, p := range ctx.GetDirectDepsWithTag(vbmetaPartitionDep) {
207 f, ok := p.(Filesystem)
208 if !ok {
209 ctx.PropertyErrorf("partitions", "%q(type: %s) is not supported",
210 p.Name(), ctx.OtherModuleType(p))
211 continue
212 }
213 signedImage := f.SignedOutputPath()
214 if signedImage == nil {
215 ctx.PropertyErrorf("partitions", "%q(type: %s) is not signed. Use `use_avb: true`",
216 p.Name(), ctx.OtherModuleType(p))
217 continue
218 }
219 cmd.FlagWithInput("--include_descriptors_from_image ", signedImage)
220 }
221
Cole Faustb3d6e752024-11-08 12:44:33 -0800222 seenRils := make(map[int]bool)
223 for _, cp := range ctx.GetDirectDepsWithTag(vbmetaChainedPartitionDep) {
224 info, ok := android.OtherModuleProvider(ctx, cp, vbmetaPartitionProvider)
225 if !ok {
226 ctx.PropertyErrorf("chained_partitions", "Expected all modules in chained_partitions to provide vbmetaPartitionProvider, but %s did not", cp.Name())
227 continue
228 }
229 if info.Name == "" {
230 ctx.PropertyErrorf("chained_partitions", "name must be specified")
231 continue
232 }
233
234 ril := info.RollbackIndexLocation
Luca Stefani9235f4c2025-02-08 12:09:34 +0100235 if ril < 1 {
236 ctx.PropertyErrorf("chained_partitions", "rollback index location must be 1, 2, 3, ...")
Cole Faustb3d6e752024-11-08 12:44:33 -0800237 continue
238 } else if seenRils[ril] {
239 ctx.PropertyErrorf("chained_partitions", "Multiple chained partitions with the same rollback index location %d", ril)
240 continue
241 }
242 seenRils[ril] = true
243
244 publicKey := info.PublicKey
245 cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", info.Name, ril, publicKey.String()))
246 cmd.Implicit(publicKey)
247 }
248 for _, cpm := range v.properties.Chained_partition_metadata {
249 name := proptools.String(cpm.Name)
Jiyong Park972e06c2021-03-15 23:32:49 +0900250 if name == "" {
Luca Stefani9235f4c2025-02-08 12:09:34 +0100251 ctx.PropertyErrorf("chained_partition_metadata", "name must be specified")
Jiyong Park972e06c2021-03-15 23:32:49 +0900252 continue
253 }
254
Luca Stefani9235f4c2025-02-08 12:09:34 +0100255 ril := proptools.IntDefault(cpm.Rollback_index_location, 0)
256 if ril < 1 {
257 ctx.PropertyErrorf("chained_partition_metadata", "rollback index location must be 1, 2, 3, ...")
Cole Faustb3d6e752024-11-08 12:44:33 -0800258 continue
259 } else if seenRils[ril] {
260 ctx.PropertyErrorf("chained_partition_metadata", "Multiple chained partitions with the same rollback index location %d", ril)
261 continue
262 }
263 seenRils[ril] = true
264
265 var publicKey android.Path
266 if cpm.Public_key != nil {
267 publicKey = android.PathForModuleSrc(ctx, *cpm.Public_key)
268 } else if cpm.Private_key != nil {
269 privateKey := android.PathForModuleSrc(ctx, *cpm.Private_key)
270 extractedPublicKey := android.PathForModuleOut(ctx, "chained_metadata", name+".avbpubkey")
271 ctx.Build(pctx, android.BuildParams{
272 Rule: extractPublicKeyRule,
273 Input: privateKey,
274 Output: extractedPublicKey,
275 })
276 publicKey = extractedPublicKey
277 } else {
278 ctx.PropertyErrorf("public_key", "Either public_key or private_key must be specified")
Jiyong Park972e06c2021-03-15 23:32:49 +0900279 continue
280 }
281
Jiyong Park972e06c2021-03-15 23:32:49 +0900282 cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", name, ril, publicKey.String()))
283 cmd.Implicit(publicKey)
284 }
285
Cole Faust4e9f5922024-11-13 16:09:23 -0800286 output := android.PathForModuleOut(ctx, v.installFileName())
287 cmd.FlagWithOutput("--output ", output)
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900288
289 // libavb expects to be able to read the maximum vbmeta size, so we must provide a partition
290 // which matches this or the read will fail.
291 builder.Command().Text("truncate").
292 FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)).
Cole Faust4e9f5922024-11-13 16:09:23 -0800293 Output(output)
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900294
Jiyong Park972e06c2021-03-15 23:32:49 +0900295 builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
296
297 v.installDir = android.PathForModuleInstall(ctx, "etc")
Cole Faust4e9f5922024-11-13 16:09:23 -0800298 ctx.InstallFile(v.installDir, v.installFileName(), output)
mrziwang555d1332024-06-07 11:15:33 -0700299
Cole Faustb3d6e752024-11-08 12:44:33 -0800300 extractedPublicKey := android.PathForModuleOut(ctx, v.partitionName()+".avbpubkey")
301 ctx.Build(pctx, android.BuildParams{
302 Rule: extractPublicKeyRule,
303 Input: key,
304 Output: extractedPublicKey,
305 })
306
307 android.SetProvider(ctx, vbmetaPartitionProvider, vbmetaPartitionInfo{
308 Name: v.partitionName(),
309 RollbackIndexLocation: ril,
310 PublicKey: extractedPublicKey,
Spandan Dasf7098442025-01-10 22:35:53 +0000311 Output: output,
Spandan Das2e1338e2025-03-19 23:57:36 +0000312 PropFileForMiscInfo: v.buildPropFileForMiscInfo(ctx),
Cole Faustb3d6e752024-11-08 12:44:33 -0800313 })
314
Cole Faust4e9f5922024-11-13 16:09:23 -0800315 ctx.SetOutputFiles([]android.Path{output}, "")
316 v.output = output
Yu Liu0a37d422025-02-13 02:05:00 +0000317
318 setCommonFilesystemInfo(ctx, v)
Jiyong Park972e06c2021-03-15 23:32:49 +0900319}
320
Spandan Das2e1338e2025-03-19 23:57:36 +0000321func (v *vbmeta) buildPropFileForMiscInfo(ctx android.ModuleContext) android.Path {
322 var lines []string
323 addStr := func(name string, value string) {
324 lines = append(lines, fmt.Sprintf("%s=%s", name, value))
325 }
326
327 addStr(fmt.Sprintf("avb_%s_algorithm", v.partitionName()), proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096"))
328 if v.properties.Private_key != nil {
329 addStr(fmt.Sprintf("avb_%s_key_path", v.partitionName()), android.PathForModuleSrc(ctx, proptools.String(v.properties.Private_key)).String())
330 }
331 if v.properties.Rollback_index_location != nil {
332 addStr(fmt.Sprintf("avb_%s_rollback_index_location", v.partitionName()), strconv.FormatInt(*v.properties.Rollback_index_location, 10))
333 }
334
335 var partitionDepNames []string
336 ctx.VisitDirectDepsProxyWithTag(vbmetaPartitionDep, func(child android.ModuleProxy) {
337 if info, ok := android.OtherModuleProvider(ctx, child, vbmetaPartitionProvider); ok {
338 partitionDepNames = append(partitionDepNames, info.Name)
339 } else {
340 ctx.ModuleErrorf("vbmeta dep %s does not set vbmetaPartitionProvider\n", child)
341 }
342 })
343 if v.partitionName() != "vbmeta" { // skip for vbmeta to match Make's misc_info.txt
344 addStr(fmt.Sprintf("avb_%s", v.partitionName()), strings.Join(android.SortedUniqueStrings(partitionDepNames), " "))
345 }
346
347 addStr(fmt.Sprintf("avb_%s_args", v.partitionName()), fmt.Sprintf("--padding_size 4096 --rollback_index %s", v.rollbackIndexString(ctx)))
348
349 sort.Strings(lines)
350
351 propFile := android.PathForModuleOut(ctx, "prop_file_for_misc_info")
352 android.WriteFileRule(ctx, propFile, strings.Join(lines, "\n"))
353 return propFile
354}
355
Jiyong Park972e06c2021-03-15 23:32:49 +0900356// Returns the embedded shell command that prints the rollback index
357func (v *vbmeta) rollbackIndexCommand(ctx android.ModuleContext) string {
Cole Faust3552eb62024-11-06 18:07:26 -0800358 if v.properties.Rollback_index != nil {
359 return fmt.Sprintf("%d", *v.properties.Rollback_index)
Jiyong Park972e06c2021-03-15 23:32:49 +0900360 } else {
Cole Faust3552eb62024-11-06 18:07:26 -0800361 // Take the first line and remove the newline char
362 return "$(date -d 'TZ=\"GMT\" " + ctx.Config().PlatformSecurityPatch() + "' +%s | head -1 | tr -d '\n'" + ")"
Jiyong Park972e06c2021-03-15 23:32:49 +0900363 }
Jiyong Park972e06c2021-03-15 23:32:49 +0900364}
365
Spandan Das2e1338e2025-03-19 23:57:36 +0000366// Similar to rollbackIndexCommand, but guarantees that the rollback index is
367// always computed during Soong analysis, even if v.properties.Rollback_index is nil
368func (v *vbmeta) rollbackIndexString(ctx android.ModuleContext) string {
369 if v.properties.Rollback_index != nil {
370 return fmt.Sprintf("%d", *v.properties.Rollback_index)
371 } else {
372 t, _ := time.Parse(time.DateOnly, ctx.Config().PlatformSecurityPatch())
373 return fmt.Sprintf("%d", t.Unix())
374 }
375}
376
Yu Liue70976d2024-10-15 20:45:35 +0000377var _ android.AndroidMkProviderInfoProducer = (*vbmeta)(nil)
378
379func (v *vbmeta) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
mrziwang18420972024-09-03 15:12:51 -0700380 providerData := android.AndroidMkProviderInfo{
381 PrimaryInfo: android.AndroidMkInfo{
382 Class: "ETC",
383 OutputFile: android.OptionalPathForPath(v.output),
384 EntryMap: make(map[string][]string),
Jiyong Park972e06c2021-03-15 23:32:49 +0900385 },
mrziwang18420972024-09-03 15:12:51 -0700386 }
387 providerData.PrimaryInfo.SetString("LOCAL_MODULE_PATH", v.installDir.String())
388 providerData.PrimaryInfo.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
389 return &providerData
Jiyong Park972e06c2021-03-15 23:32:49 +0900390}
391
392var _ Filesystem = (*vbmeta)(nil)
393
394func (v *vbmeta) OutputPath() android.Path {
395 return v.output
396}
397
398func (v *vbmeta) SignedOutputPath() android.Path {
399 return v.OutputPath() // vbmeta is always signed
400}