blob: ebb3ff9517c885a9949ff01d19a8bab8de378665 [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
47 output android.OutputPath
48 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
124}
125
126var vbmetaPartitionProvider = blueprint.NewProvider[vbmetaPartitionInfo]()
127
Jiyong Park972e06c2021-03-15 23:32:49 +0900128// vbmeta is the partition image that has the verification information for other partitions.
Cole Faust3552eb62024-11-06 18:07:26 -0800129func VbmetaFactory() android.Module {
Jiyong Park972e06c2021-03-15 23:32:49 +0900130 module := &vbmeta{}
131 module.AddProperties(&module.properties)
Cole Faust65cb40a2024-10-21 15:41:42 -0700132 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
Jiyong Park972e06c2021-03-15 23:32:49 +0900133 return module
134}
135
136type vbmetaDep struct {
137 blueprint.BaseDependencyTag
Jiyong Park972e06c2021-03-15 23:32:49 +0900138}
139
Cole Faustb3d6e752024-11-08 12:44:33 -0800140type chainedPartitionDep struct {
141 blueprint.BaseDependencyTag
142}
143
144var vbmetaPartitionDep = vbmetaDep{}
145var vbmetaChainedPartitionDep = chainedPartitionDep{}
Jiyong Park972e06c2021-03-15 23:32:49 +0900146
147func (v *vbmeta) DepsMutator(ctx android.BottomUpMutatorContext) {
Cole Faustbf1d92a2024-07-29 12:24:25 -0700148 ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions.GetOrDefault(ctx, nil)...)
Cole Faustb3d6e752024-11-08 12:44:33 -0800149 ctx.AddDependency(ctx.Module(), vbmetaChainedPartitionDep, v.properties.Chained_partitions...)
Jiyong Park972e06c2021-03-15 23:32:49 +0900150}
151
152func (v *vbmeta) installFileName() string {
153 return proptools.StringDefault(v.properties.Stem, v.BaseModuleName()+".img")
154}
155
156func (v *vbmeta) partitionName() string {
157 return proptools.StringDefault(v.properties.Partition_name, v.BaseModuleName())
158}
159
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900160// See external/avb/libavb/avb_slot_verify.c#VBMETA_MAX_SIZE
161const vbmetaMaxSize = 64 * 1024
162
Jiyong Park972e06c2021-03-15 23:32:49 +0900163func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Jiyong Park972e06c2021-03-15 23:32:49 +0900164 v.output = android.PathForModuleOut(ctx, v.installFileName()).OutputPath
165
166 builder := android.NewRuleBuilder(pctx, ctx)
167 cmd := builder.Command().BuiltTool("avbtool").Text("make_vbmeta_image")
168
169 key := android.PathForModuleSrc(ctx, proptools.String(v.properties.Private_key))
170 cmd.FlagWithInput("--key ", key)
171
172 algorithm := proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096")
173 cmd.FlagWithArg("--algorithm ", algorithm)
174
175 cmd.FlagWithArg("--rollback_index ", v.rollbackIndexCommand(ctx))
176 ril := proptools.IntDefault(v.properties.Rollback_index_location, 0)
177 if ril < 0 {
178 ctx.PropertyErrorf("rollback_index_location", "must be 0, 1, 2, ...")
179 return
180 }
181 cmd.FlagWithArg("--rollback_index_location ", strconv.Itoa(ril))
182
Seungjae Yoo9f263712023-11-16 17:22:57 +0900183 for _, avb_prop := range v.properties.Avb_properties {
184 key := proptools.String(avb_prop.Key)
185 if key == "" {
186 ctx.PropertyErrorf("avb_properties", "key must be specified")
187 continue
188 }
189 value := proptools.String(avb_prop.Value)
190 if value == "" {
191 ctx.PropertyErrorf("avb_properties", "value must be specified")
192 continue
193 }
194 cmd.FlagWithArg("--prop ", key+":"+value)
195 }
196
Jiyong Park972e06c2021-03-15 23:32:49 +0900197 for _, p := range ctx.GetDirectDepsWithTag(vbmetaPartitionDep) {
198 f, ok := p.(Filesystem)
199 if !ok {
200 ctx.PropertyErrorf("partitions", "%q(type: %s) is not supported",
201 p.Name(), ctx.OtherModuleType(p))
202 continue
203 }
204 signedImage := f.SignedOutputPath()
205 if signedImage == nil {
206 ctx.PropertyErrorf("partitions", "%q(type: %s) is not signed. Use `use_avb: true`",
207 p.Name(), ctx.OtherModuleType(p))
208 continue
209 }
210 cmd.FlagWithInput("--include_descriptors_from_image ", signedImage)
211 }
212
Cole Faustb3d6e752024-11-08 12:44:33 -0800213 seenRils := make(map[int]bool)
214 for _, cp := range ctx.GetDirectDepsWithTag(vbmetaChainedPartitionDep) {
215 info, ok := android.OtherModuleProvider(ctx, cp, vbmetaPartitionProvider)
216 if !ok {
217 ctx.PropertyErrorf("chained_partitions", "Expected all modules in chained_partitions to provide vbmetaPartitionProvider, but %s did not", cp.Name())
218 continue
219 }
220 if info.Name == "" {
221 ctx.PropertyErrorf("chained_partitions", "name must be specified")
222 continue
223 }
224
225 ril := info.RollbackIndexLocation
226 if ril < 0 {
227 ctx.PropertyErrorf("chained_partitions", "rollback index location must be 0, 1, 2, ...")
228 continue
229 } else if seenRils[ril] {
230 ctx.PropertyErrorf("chained_partitions", "Multiple chained partitions with the same rollback index location %d", ril)
231 continue
232 }
233 seenRils[ril] = true
234
235 publicKey := info.PublicKey
236 cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", info.Name, ril, publicKey.String()))
237 cmd.Implicit(publicKey)
238 }
239 for _, cpm := range v.properties.Chained_partition_metadata {
240 name := proptools.String(cpm.Name)
Jiyong Park972e06c2021-03-15 23:32:49 +0900241 if name == "" {
242 ctx.PropertyErrorf("chained_partitions", "name must be specified")
243 continue
244 }
245
Cole Faustb3d6e752024-11-08 12:44:33 -0800246 ril := proptools.IntDefault(cpm.Rollback_index_location, -1)
Jiyong Park972e06c2021-03-15 23:32:49 +0900247 if ril < 0 {
Cole Faustb3d6e752024-11-08 12:44:33 -0800248 ctx.PropertyErrorf("chained_partition_metadata", "rollback index location must be 0, 1, 2, ...")
249 continue
250 } else if seenRils[ril] {
251 ctx.PropertyErrorf("chained_partition_metadata", "Multiple chained partitions with the same rollback index location %d", ril)
252 continue
253 }
254 seenRils[ril] = true
255
256 var publicKey android.Path
257 if cpm.Public_key != nil {
258 publicKey = android.PathForModuleSrc(ctx, *cpm.Public_key)
259 } else if cpm.Private_key != nil {
260 privateKey := android.PathForModuleSrc(ctx, *cpm.Private_key)
261 extractedPublicKey := android.PathForModuleOut(ctx, "chained_metadata", name+".avbpubkey")
262 ctx.Build(pctx, android.BuildParams{
263 Rule: extractPublicKeyRule,
264 Input: privateKey,
265 Output: extractedPublicKey,
266 })
267 publicKey = extractedPublicKey
268 } else {
269 ctx.PropertyErrorf("public_key", "Either public_key or private_key must be specified")
Jiyong Park972e06c2021-03-15 23:32:49 +0900270 continue
271 }
272
Jiyong Park972e06c2021-03-15 23:32:49 +0900273 cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", name, ril, publicKey.String()))
274 cmd.Implicit(publicKey)
275 }
276
277 cmd.FlagWithOutput("--output ", v.output)
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900278
279 // libavb expects to be able to read the maximum vbmeta size, so we must provide a partition
280 // which matches this or the read will fail.
281 builder.Command().Text("truncate").
282 FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)).
283 Output(v.output)
284
Jiyong Park972e06c2021-03-15 23:32:49 +0900285 builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
286
287 v.installDir = android.PathForModuleInstall(ctx, "etc")
288 ctx.InstallFile(v.installDir, v.installFileName(), v.output)
mrziwang555d1332024-06-07 11:15:33 -0700289
Cole Faustb3d6e752024-11-08 12:44:33 -0800290 extractedPublicKey := android.PathForModuleOut(ctx, v.partitionName()+".avbpubkey")
291 ctx.Build(pctx, android.BuildParams{
292 Rule: extractPublicKeyRule,
293 Input: key,
294 Output: extractedPublicKey,
295 })
296
297 android.SetProvider(ctx, vbmetaPartitionProvider, vbmetaPartitionInfo{
298 Name: v.partitionName(),
299 RollbackIndexLocation: ril,
300 PublicKey: extractedPublicKey,
301 })
302
mrziwang555d1332024-06-07 11:15:33 -0700303 ctx.SetOutputFiles([]android.Path{v.output}, "")
Jiyong Park972e06c2021-03-15 23:32:49 +0900304}
305
306// Returns the embedded shell command that prints the rollback index
307func (v *vbmeta) rollbackIndexCommand(ctx android.ModuleContext) string {
Cole Faust3552eb62024-11-06 18:07:26 -0800308 if v.properties.Rollback_index != nil {
309 return fmt.Sprintf("%d", *v.properties.Rollback_index)
Jiyong Park972e06c2021-03-15 23:32:49 +0900310 } else {
Cole Faust3552eb62024-11-06 18:07:26 -0800311 // Take the first line and remove the newline char
312 return "$(date -d 'TZ=\"GMT\" " + ctx.Config().PlatformSecurityPatch() + "' +%s | head -1 | tr -d '\n'" + ")"
Jiyong Park972e06c2021-03-15 23:32:49 +0900313 }
Jiyong Park972e06c2021-03-15 23:32:49 +0900314}
315
Yu Liue70976d2024-10-15 20:45:35 +0000316var _ android.AndroidMkProviderInfoProducer = (*vbmeta)(nil)
317
318func (v *vbmeta) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
mrziwang18420972024-09-03 15:12:51 -0700319 providerData := android.AndroidMkProviderInfo{
320 PrimaryInfo: android.AndroidMkInfo{
321 Class: "ETC",
322 OutputFile: android.OptionalPathForPath(v.output),
323 EntryMap: make(map[string][]string),
Jiyong Park972e06c2021-03-15 23:32:49 +0900324 },
mrziwang18420972024-09-03 15:12:51 -0700325 }
326 providerData.PrimaryInfo.SetString("LOCAL_MODULE_PATH", v.installDir.String())
327 providerData.PrimaryInfo.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
328 return &providerData
Jiyong Park972e06c2021-03-15 23:32:49 +0900329}
330
331var _ Filesystem = (*vbmeta)(nil)
332
333func (v *vbmeta) OutputPath() android.Path {
334 return v.output
335}
336
337func (v *vbmeta) SignedOutputPath() android.Path {
338 return v.OutputPath() // vbmeta is always signed
339}