blob: 5f51d34debd2a71c1063d28e107d682941f8fbd7 [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)
Cole Faustb3d6e752024-11-08 12:44:33 -080029 pctx.HostBinToolVariable("avbtool", "avbtool")
Jiyong Park972e06c2021-03-15 23:32:49 +090030}
31
Cole Faustb3d6e752024-11-08 12:44:33 -080032var (
33 extractPublicKeyRule = pctx.AndroidStaticRule("avb_extract_public_key",
34 blueprint.RuleParams{
35 Command: `${avbtool} extract_public_key --key $in --output $out`,
36 CommandDeps: []string{
37 "${avbtool}",
38 },
39 })
40)
41
Jiyong Park972e06c2021-03-15 23:32:49 +090042type vbmeta struct {
43 android.ModuleBase
44
Cole Faust3552eb62024-11-06 18:07:26 -080045 properties VbmetaProperties
Jiyong Park972e06c2021-03-15 23:32:49 +090046
Cole Faust4e9f5922024-11-13 16:09:23 -080047 output android.Path
Jiyong Park972e06c2021-03-15 23:32:49 +090048 installDir android.InstallPath
49}
50
Cole Faust3552eb62024-11-06 18:07:26 -080051type VbmetaProperties struct {
Jiyong Park972e06c2021-03-15 23:32:49 +090052 // Name of the partition stored in vbmeta desc. Defaults to the name of this module.
53 Partition_name *string
54
55 // Set the name of the output. Defaults to <module_name>.img.
56 Stem *string
57
58 // Path to the private key that avbtool will use to sign this vbmeta image.
59 Private_key *string `android:"path"`
60
61 // Algorithm that avbtool will use to sign this vbmeta image. Default is SHA256_RSA4096.
62 Algorithm *string
63
Cole Faust3552eb62024-11-06 18:07:26 -080064 // The rollback index. If unspecified, the rollback index is from PLATFORM_SECURITY_PATCH
65 Rollback_index *int64
Jiyong Park972e06c2021-03-15 23:32:49 +090066
67 // Rollback index location of this vbmeta image. Must be 0, 1, 2, etc. Default is 0.
68 Rollback_index_location *int64
69
70 // List of filesystem modules that this vbmeta has descriptors for. The filesystem modules
71 // have to be signed (use_avb: true).
Inseob Kim4daca6b2024-07-26 11:17:52 +090072 Partitions proptools.Configurable[[]string]
Jiyong Park972e06c2021-03-15 23:32:49 +090073
Cole Faustb3d6e752024-11-08 12:44:33 -080074 // Metadata about the chained partitions that this vbmeta delegates the verification.
75 // This is an alternative to chained_partitions, using chained_partitions instead is simpler
76 // in most cases. However, this property allows building this vbmeta partition without
77 // its chained partitions existing in this build.
78 Chained_partition_metadata []ChainedPartitionProperties
79
80 // List of chained partitions that this vbmeta delegates the verification. They are the
81 // names of other vbmeta modules.
82 Chained_partitions []string
Seungjae Yoo9f263712023-11-16 17:22:57 +090083
84 // List of key-value pair of avb properties
85 Avb_properties []avbProperty
86}
87
88type avbProperty struct {
89 // Key of given avb property
90 Key *string
91
92 // Value of given avb property
93 Value *string
Jiyong Park972e06c2021-03-15 23:32:49 +090094}
95
Cole Faust3552eb62024-11-06 18:07:26 -080096type ChainedPartitionProperties struct {
Jiyong Park972e06c2021-03-15 23:32:49 +090097 // Name of the chained partition
98 Name *string
99
100 // Rollback index location of the chained partition. Must be 0, 1, 2, etc. Default is the
101 // index of this partition in the list + 1.
102 Rollback_index_location *int64
103
104 // Path to the public key that the chained partition is signed with. If this is specified,
105 // private_key is ignored.
106 Public_key *string `android:"path"`
107
108 // Path to the private key that the chained partition is signed with. If this is specified,
109 // and public_key is not specified, a public key is extracted from this private key and
110 // the extracted public key is embedded in the vbmeta image.
111 Private_key *string `android:"path"`
112}
113
Cole Faustb3d6e752024-11-08 12:44:33 -0800114type vbmetaPartitionInfo struct {
115 // Name of the partition
116 Name string
117
118 // Rollback index location, non-negative int
119 RollbackIndexLocation int
120
121 // The path to the public key of the private key used to sign this partition. Derived from
122 // the private key.
123 PublicKey android.Path
Spandan Dasf7098442025-01-10 22:35:53 +0000124
125 // The output of the vbmeta module
126 Output android.Path
Cole Faustb3d6e752024-11-08 12:44:33 -0800127}
128
129var vbmetaPartitionProvider = blueprint.NewProvider[vbmetaPartitionInfo]()
130
Jiyong Park972e06c2021-03-15 23:32:49 +0900131// vbmeta is the partition image that has the verification information for other partitions.
Cole Faust3552eb62024-11-06 18:07:26 -0800132func VbmetaFactory() android.Module {
Jiyong Park972e06c2021-03-15 23:32:49 +0900133 module := &vbmeta{}
134 module.AddProperties(&module.properties)
Cole Faust65cb40a2024-10-21 15:41:42 -0700135 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
Jiyong Park972e06c2021-03-15 23:32:49 +0900136 return module
137}
138
139type vbmetaDep struct {
140 blueprint.BaseDependencyTag
Jiyong Park972e06c2021-03-15 23:32:49 +0900141}
142
Cole Faustb3d6e752024-11-08 12:44:33 -0800143type chainedPartitionDep struct {
144 blueprint.BaseDependencyTag
145}
146
147var vbmetaPartitionDep = vbmetaDep{}
148var vbmetaChainedPartitionDep = chainedPartitionDep{}
Jiyong Park972e06c2021-03-15 23:32:49 +0900149
150func (v *vbmeta) DepsMutator(ctx android.BottomUpMutatorContext) {
Cole Faustbf1d92a2024-07-29 12:24:25 -0700151 ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions.GetOrDefault(ctx, nil)...)
Cole Faustb3d6e752024-11-08 12:44:33 -0800152 ctx.AddDependency(ctx.Module(), vbmetaChainedPartitionDep, v.properties.Chained_partitions...)
Jiyong Park972e06c2021-03-15 23:32:49 +0900153}
154
155func (v *vbmeta) installFileName() string {
156 return proptools.StringDefault(v.properties.Stem, v.BaseModuleName()+".img")
157}
158
159func (v *vbmeta) partitionName() string {
160 return proptools.StringDefault(v.properties.Partition_name, v.BaseModuleName())
161}
162
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900163// See external/avb/libavb/avb_slot_verify.c#VBMETA_MAX_SIZE
164const vbmetaMaxSize = 64 * 1024
165
Jiyong Park972e06c2021-03-15 23:32:49 +0900166func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Jiyong Park972e06c2021-03-15 23:32:49 +0900167 builder := android.NewRuleBuilder(pctx, ctx)
168 cmd := builder.Command().BuiltTool("avbtool").Text("make_vbmeta_image")
169
170 key := android.PathForModuleSrc(ctx, proptools.String(v.properties.Private_key))
171 cmd.FlagWithInput("--key ", key)
172
173 algorithm := proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096")
174 cmd.FlagWithArg("--algorithm ", algorithm)
175
Jihoon Kang3556c8f2025-01-15 22:32:27 +0000176 cmd.FlagWithArg("--padding_size ", "4096")
177
Jiyong Park972e06c2021-03-15 23:32:49 +0900178 cmd.FlagWithArg("--rollback_index ", v.rollbackIndexCommand(ctx))
179 ril := proptools.IntDefault(v.properties.Rollback_index_location, 0)
180 if ril < 0 {
181 ctx.PropertyErrorf("rollback_index_location", "must be 0, 1, 2, ...")
182 return
183 }
184 cmd.FlagWithArg("--rollback_index_location ", strconv.Itoa(ril))
185
Seungjae Yoo9f263712023-11-16 17:22:57 +0900186 for _, avb_prop := range v.properties.Avb_properties {
187 key := proptools.String(avb_prop.Key)
188 if key == "" {
189 ctx.PropertyErrorf("avb_properties", "key must be specified")
190 continue
191 }
192 value := proptools.String(avb_prop.Value)
193 if value == "" {
194 ctx.PropertyErrorf("avb_properties", "value must be specified")
195 continue
196 }
197 cmd.FlagWithArg("--prop ", key+":"+value)
198 }
199
Jiyong Park972e06c2021-03-15 23:32:49 +0900200 for _, p := range ctx.GetDirectDepsWithTag(vbmetaPartitionDep) {
201 f, ok := p.(Filesystem)
202 if !ok {
203 ctx.PropertyErrorf("partitions", "%q(type: %s) is not supported",
204 p.Name(), ctx.OtherModuleType(p))
205 continue
206 }
207 signedImage := f.SignedOutputPath()
208 if signedImage == nil {
209 ctx.PropertyErrorf("partitions", "%q(type: %s) is not signed. Use `use_avb: true`",
210 p.Name(), ctx.OtherModuleType(p))
211 continue
212 }
213 cmd.FlagWithInput("--include_descriptors_from_image ", signedImage)
214 }
215
Cole Faustb3d6e752024-11-08 12:44:33 -0800216 seenRils := make(map[int]bool)
217 for _, cp := range ctx.GetDirectDepsWithTag(vbmetaChainedPartitionDep) {
218 info, ok := android.OtherModuleProvider(ctx, cp, vbmetaPartitionProvider)
219 if !ok {
220 ctx.PropertyErrorf("chained_partitions", "Expected all modules in chained_partitions to provide vbmetaPartitionProvider, but %s did not", cp.Name())
221 continue
222 }
223 if info.Name == "" {
224 ctx.PropertyErrorf("chained_partitions", "name must be specified")
225 continue
226 }
227
228 ril := info.RollbackIndexLocation
229 if ril < 0 {
230 ctx.PropertyErrorf("chained_partitions", "rollback index location must be 0, 1, 2, ...")
231 continue
232 } else if seenRils[ril] {
233 ctx.PropertyErrorf("chained_partitions", "Multiple chained partitions with the same rollback index location %d", ril)
234 continue
235 }
236 seenRils[ril] = true
237
238 publicKey := info.PublicKey
239 cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", info.Name, ril, publicKey.String()))
240 cmd.Implicit(publicKey)
241 }
242 for _, cpm := range v.properties.Chained_partition_metadata {
243 name := proptools.String(cpm.Name)
Jiyong Park972e06c2021-03-15 23:32:49 +0900244 if name == "" {
245 ctx.PropertyErrorf("chained_partitions", "name must be specified")
246 continue
247 }
248
Cole Faustb3d6e752024-11-08 12:44:33 -0800249 ril := proptools.IntDefault(cpm.Rollback_index_location, -1)
Jiyong Park972e06c2021-03-15 23:32:49 +0900250 if ril < 0 {
Cole Faustb3d6e752024-11-08 12:44:33 -0800251 ctx.PropertyErrorf("chained_partition_metadata", "rollback index location must be 0, 1, 2, ...")
252 continue
253 } else if seenRils[ril] {
254 ctx.PropertyErrorf("chained_partition_metadata", "Multiple chained partitions with the same rollback index location %d", ril)
255 continue
256 }
257 seenRils[ril] = true
258
259 var publicKey android.Path
260 if cpm.Public_key != nil {
261 publicKey = android.PathForModuleSrc(ctx, *cpm.Public_key)
262 } else if cpm.Private_key != nil {
263 privateKey := android.PathForModuleSrc(ctx, *cpm.Private_key)
264 extractedPublicKey := android.PathForModuleOut(ctx, "chained_metadata", name+".avbpubkey")
265 ctx.Build(pctx, android.BuildParams{
266 Rule: extractPublicKeyRule,
267 Input: privateKey,
268 Output: extractedPublicKey,
269 })
270 publicKey = extractedPublicKey
271 } else {
272 ctx.PropertyErrorf("public_key", "Either public_key or private_key must be specified")
Jiyong Park972e06c2021-03-15 23:32:49 +0900273 continue
274 }
275
Jiyong Park972e06c2021-03-15 23:32:49 +0900276 cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", name, ril, publicKey.String()))
277 cmd.Implicit(publicKey)
278 }
279
Cole Faust4e9f5922024-11-13 16:09:23 -0800280 output := android.PathForModuleOut(ctx, v.installFileName())
281 cmd.FlagWithOutput("--output ", output)
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900282
283 // libavb expects to be able to read the maximum vbmeta size, so we must provide a partition
284 // which matches this or the read will fail.
285 builder.Command().Text("truncate").
286 FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)).
Cole Faust4e9f5922024-11-13 16:09:23 -0800287 Output(output)
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900288
Jihoon Kang9e087002025-01-08 19:12:23 +0000289 if !ctx.Config().KatiEnabled() {
290 copyImageFileToProductOut(ctx, builder, v.partitionName(), output)
291 }
292
Jiyong Park972e06c2021-03-15 23:32:49 +0900293 builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
294
295 v.installDir = android.PathForModuleInstall(ctx, "etc")
Cole Faust4e9f5922024-11-13 16:09:23 -0800296 ctx.InstallFile(v.installDir, v.installFileName(), output)
mrziwang555d1332024-06-07 11:15:33 -0700297
Cole Faustb3d6e752024-11-08 12:44:33 -0800298 extractedPublicKey := android.PathForModuleOut(ctx, v.partitionName()+".avbpubkey")
299 ctx.Build(pctx, android.BuildParams{
300 Rule: extractPublicKeyRule,
301 Input: key,
302 Output: extractedPublicKey,
303 })
304
305 android.SetProvider(ctx, vbmetaPartitionProvider, vbmetaPartitionInfo{
306 Name: v.partitionName(),
307 RollbackIndexLocation: ril,
308 PublicKey: extractedPublicKey,
Spandan Dasf7098442025-01-10 22:35:53 +0000309 Output: output,
Cole Faustb3d6e752024-11-08 12:44:33 -0800310 })
311
Cole Faust4e9f5922024-11-13 16:09:23 -0800312 ctx.SetOutputFiles([]android.Path{output}, "")
313 v.output = output
Jiyong Park972e06c2021-03-15 23:32:49 +0900314}
315
316// Returns the embedded shell command that prints the rollback index
317func (v *vbmeta) rollbackIndexCommand(ctx android.ModuleContext) string {
Cole Faust3552eb62024-11-06 18:07:26 -0800318 if v.properties.Rollback_index != nil {
319 return fmt.Sprintf("%d", *v.properties.Rollback_index)
Jiyong Park972e06c2021-03-15 23:32:49 +0900320 } else {
Cole Faust3552eb62024-11-06 18:07:26 -0800321 // Take the first line and remove the newline char
322 return "$(date -d 'TZ=\"GMT\" " + ctx.Config().PlatformSecurityPatch() + "' +%s | head -1 | tr -d '\n'" + ")"
Jiyong Park972e06c2021-03-15 23:32:49 +0900323 }
Jiyong Park972e06c2021-03-15 23:32:49 +0900324}
325
Yu Liue70976d2024-10-15 20:45:35 +0000326var _ android.AndroidMkProviderInfoProducer = (*vbmeta)(nil)
327
328func (v *vbmeta) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
mrziwang18420972024-09-03 15:12:51 -0700329 providerData := android.AndroidMkProviderInfo{
330 PrimaryInfo: android.AndroidMkInfo{
331 Class: "ETC",
332 OutputFile: android.OptionalPathForPath(v.output),
333 EntryMap: make(map[string][]string),
Jiyong Park972e06c2021-03-15 23:32:49 +0900334 },
mrziwang18420972024-09-03 15:12:51 -0700335 }
336 providerData.PrimaryInfo.SetString("LOCAL_MODULE_PATH", v.installDir.String())
337 providerData.PrimaryInfo.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
338 return &providerData
Jiyong Park972e06c2021-03-15 23:32:49 +0900339}
340
341var _ Filesystem = (*vbmeta)(nil)
342
343func (v *vbmeta) OutputPath() android.Path {
344 return v.output
345}
346
347func (v *vbmeta) SignedOutputPath() android.Path {
348 return v.OutputPath() // vbmeta is always signed
349}