blob: 6a47859331b4e2aaa19d1bcd4a4e02414d9aae8d [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
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 builder := android.NewRuleBuilder(pctx, ctx)
165 cmd := builder.Command().BuiltTool("avbtool").Text("make_vbmeta_image")
166
167 key := android.PathForModuleSrc(ctx, proptools.String(v.properties.Private_key))
168 cmd.FlagWithInput("--key ", key)
169
170 algorithm := proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096")
171 cmd.FlagWithArg("--algorithm ", algorithm)
172
173 cmd.FlagWithArg("--rollback_index ", v.rollbackIndexCommand(ctx))
174 ril := proptools.IntDefault(v.properties.Rollback_index_location, 0)
175 if ril < 0 {
176 ctx.PropertyErrorf("rollback_index_location", "must be 0, 1, 2, ...")
177 return
178 }
179 cmd.FlagWithArg("--rollback_index_location ", strconv.Itoa(ril))
180
Seungjae Yoo9f263712023-11-16 17:22:57 +0900181 for _, avb_prop := range v.properties.Avb_properties {
182 key := proptools.String(avb_prop.Key)
183 if key == "" {
184 ctx.PropertyErrorf("avb_properties", "key must be specified")
185 continue
186 }
187 value := proptools.String(avb_prop.Value)
188 if value == "" {
189 ctx.PropertyErrorf("avb_properties", "value must be specified")
190 continue
191 }
192 cmd.FlagWithArg("--prop ", key+":"+value)
193 }
194
Jiyong Park972e06c2021-03-15 23:32:49 +0900195 for _, p := range ctx.GetDirectDepsWithTag(vbmetaPartitionDep) {
196 f, ok := p.(Filesystem)
197 if !ok {
198 ctx.PropertyErrorf("partitions", "%q(type: %s) is not supported",
199 p.Name(), ctx.OtherModuleType(p))
200 continue
201 }
202 signedImage := f.SignedOutputPath()
203 if signedImage == nil {
204 ctx.PropertyErrorf("partitions", "%q(type: %s) is not signed. Use `use_avb: true`",
205 p.Name(), ctx.OtherModuleType(p))
206 continue
207 }
208 cmd.FlagWithInput("--include_descriptors_from_image ", signedImage)
209 }
210
Cole Faustb3d6e752024-11-08 12:44:33 -0800211 seenRils := make(map[int]bool)
212 for _, cp := range ctx.GetDirectDepsWithTag(vbmetaChainedPartitionDep) {
213 info, ok := android.OtherModuleProvider(ctx, cp, vbmetaPartitionProvider)
214 if !ok {
215 ctx.PropertyErrorf("chained_partitions", "Expected all modules in chained_partitions to provide vbmetaPartitionProvider, but %s did not", cp.Name())
216 continue
217 }
218 if info.Name == "" {
219 ctx.PropertyErrorf("chained_partitions", "name must be specified")
220 continue
221 }
222
223 ril := info.RollbackIndexLocation
224 if ril < 0 {
225 ctx.PropertyErrorf("chained_partitions", "rollback index location must be 0, 1, 2, ...")
226 continue
227 } else if seenRils[ril] {
228 ctx.PropertyErrorf("chained_partitions", "Multiple chained partitions with the same rollback index location %d", ril)
229 continue
230 }
231 seenRils[ril] = true
232
233 publicKey := info.PublicKey
234 cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", info.Name, ril, publicKey.String()))
235 cmd.Implicit(publicKey)
236 }
237 for _, cpm := range v.properties.Chained_partition_metadata {
238 name := proptools.String(cpm.Name)
Jiyong Park972e06c2021-03-15 23:32:49 +0900239 if name == "" {
240 ctx.PropertyErrorf("chained_partitions", "name must be specified")
241 continue
242 }
243
Cole Faustb3d6e752024-11-08 12:44:33 -0800244 ril := proptools.IntDefault(cpm.Rollback_index_location, -1)
Jiyong Park972e06c2021-03-15 23:32:49 +0900245 if ril < 0 {
Cole Faustb3d6e752024-11-08 12:44:33 -0800246 ctx.PropertyErrorf("chained_partition_metadata", "rollback index location must be 0, 1, 2, ...")
247 continue
248 } else if seenRils[ril] {
249 ctx.PropertyErrorf("chained_partition_metadata", "Multiple chained partitions with the same rollback index location %d", ril)
250 continue
251 }
252 seenRils[ril] = true
253
254 var publicKey android.Path
255 if cpm.Public_key != nil {
256 publicKey = android.PathForModuleSrc(ctx, *cpm.Public_key)
257 } else if cpm.Private_key != nil {
258 privateKey := android.PathForModuleSrc(ctx, *cpm.Private_key)
259 extractedPublicKey := android.PathForModuleOut(ctx, "chained_metadata", name+".avbpubkey")
260 ctx.Build(pctx, android.BuildParams{
261 Rule: extractPublicKeyRule,
262 Input: privateKey,
263 Output: extractedPublicKey,
264 })
265 publicKey = extractedPublicKey
266 } else {
267 ctx.PropertyErrorf("public_key", "Either public_key or private_key must be specified")
Jiyong Park972e06c2021-03-15 23:32:49 +0900268 continue
269 }
270
Jiyong Park972e06c2021-03-15 23:32:49 +0900271 cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", name, ril, publicKey.String()))
272 cmd.Implicit(publicKey)
273 }
274
Cole Faust4e9f5922024-11-13 16:09:23 -0800275 output := android.PathForModuleOut(ctx, v.installFileName())
276 cmd.FlagWithOutput("--output ", output)
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900277
278 // libavb expects to be able to read the maximum vbmeta size, so we must provide a partition
279 // which matches this or the read will fail.
280 builder.Command().Text("truncate").
281 FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)).
Cole Faust4e9f5922024-11-13 16:09:23 -0800282 Output(output)
Jiyong Parkda2d6ee2021-04-14 16:42:24 +0900283
Jiyong Park972e06c2021-03-15 23:32:49 +0900284 builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
285
286 v.installDir = android.PathForModuleInstall(ctx, "etc")
Cole Faust4e9f5922024-11-13 16:09:23 -0800287 ctx.InstallFile(v.installDir, v.installFileName(), output)
mrziwang555d1332024-06-07 11:15:33 -0700288
Cole Faustb3d6e752024-11-08 12:44:33 -0800289 extractedPublicKey := android.PathForModuleOut(ctx, v.partitionName()+".avbpubkey")
290 ctx.Build(pctx, android.BuildParams{
291 Rule: extractPublicKeyRule,
292 Input: key,
293 Output: extractedPublicKey,
294 })
295
296 android.SetProvider(ctx, vbmetaPartitionProvider, vbmetaPartitionInfo{
297 Name: v.partitionName(),
298 RollbackIndexLocation: ril,
299 PublicKey: extractedPublicKey,
300 })
301
Cole Faust4e9f5922024-11-13 16:09:23 -0800302 ctx.SetOutputFiles([]android.Path{output}, "")
303 v.output = 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}