vbmeta.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // 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. package filesystem
  15. import (
  16. "fmt"
  17. "strconv"
  18. "github.com/google/blueprint"
  19. "github.com/google/blueprint/proptools"
  20. "android/soong/android"
  21. )
  22. func init() {
  23. android.RegisterModuleType("vbmeta", vbmetaFactory)
  24. }
  25. type vbmeta struct {
  26. android.ModuleBase
  27. properties vbmetaProperties
  28. output android.OutputPath
  29. installDir android.InstallPath
  30. }
  31. type vbmetaProperties struct {
  32. // Name of the partition stored in vbmeta desc. Defaults to the name of this module.
  33. Partition_name *string
  34. // Set the name of the output. Defaults to <module_name>.img.
  35. Stem *string
  36. // Path to the private key that avbtool will use to sign this vbmeta image.
  37. Private_key *string `android:"path"`
  38. // Algorithm that avbtool will use to sign this vbmeta image. Default is SHA256_RSA4096.
  39. Algorithm *string
  40. // File whose content will provide the rollback index. If unspecified, the rollback index
  41. // is from PLATFORM_SECURITY_PATCH
  42. Rollback_index_file *string `android:"path"`
  43. // Rollback index location of this vbmeta image. Must be 0, 1, 2, etc. Default is 0.
  44. Rollback_index_location *int64
  45. // List of filesystem modules that this vbmeta has descriptors for. The filesystem modules
  46. // have to be signed (use_avb: true).
  47. Partitions []string
  48. // List of chained partitions that this vbmeta deletages the verification.
  49. Chained_partitions []chainedPartitionProperties
  50. }
  51. type chainedPartitionProperties struct {
  52. // Name of the chained partition
  53. Name *string
  54. // Rollback index location of the chained partition. Must be 0, 1, 2, etc. Default is the
  55. // index of this partition in the list + 1.
  56. Rollback_index_location *int64
  57. // Path to the public key that the chained partition is signed with. If this is specified,
  58. // private_key is ignored.
  59. Public_key *string `android:"path"`
  60. // Path to the private key that the chained partition is signed with. If this is specified,
  61. // and public_key is not specified, a public key is extracted from this private key and
  62. // the extracted public key is embedded in the vbmeta image.
  63. Private_key *string `android:"path"`
  64. }
  65. // vbmeta is the partition image that has the verification information for other partitions.
  66. func vbmetaFactory() android.Module {
  67. module := &vbmeta{}
  68. module.AddProperties(&module.properties)
  69. android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
  70. return module
  71. }
  72. type vbmetaDep struct {
  73. blueprint.BaseDependencyTag
  74. kind string
  75. }
  76. var vbmetaPartitionDep = vbmetaDep{kind: "partition"}
  77. func (v *vbmeta) DepsMutator(ctx android.BottomUpMutatorContext) {
  78. ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions...)
  79. }
  80. func (v *vbmeta) installFileName() string {
  81. return proptools.StringDefault(v.properties.Stem, v.BaseModuleName()+".img")
  82. }
  83. func (v *vbmeta) partitionName() string {
  84. return proptools.StringDefault(v.properties.Partition_name, v.BaseModuleName())
  85. }
  86. // See external/avb/libavb/avb_slot_verify.c#VBMETA_MAX_SIZE
  87. const vbmetaMaxSize = 64 * 1024
  88. func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) {
  89. extractedPublicKeys := v.extractPublicKeys(ctx)
  90. v.output = android.PathForModuleOut(ctx, v.installFileName()).OutputPath
  91. builder := android.NewRuleBuilder(pctx, ctx)
  92. cmd := builder.Command().BuiltTool("avbtool").Text("make_vbmeta_image")
  93. key := android.PathForModuleSrc(ctx, proptools.String(v.properties.Private_key))
  94. cmd.FlagWithInput("--key ", key)
  95. algorithm := proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096")
  96. cmd.FlagWithArg("--algorithm ", algorithm)
  97. cmd.FlagWithArg("--rollback_index ", v.rollbackIndexCommand(ctx))
  98. ril := proptools.IntDefault(v.properties.Rollback_index_location, 0)
  99. if ril < 0 {
  100. ctx.PropertyErrorf("rollback_index_location", "must be 0, 1, 2, ...")
  101. return
  102. }
  103. cmd.FlagWithArg("--rollback_index_location ", strconv.Itoa(ril))
  104. for _, p := range ctx.GetDirectDepsWithTag(vbmetaPartitionDep) {
  105. f, ok := p.(Filesystem)
  106. if !ok {
  107. ctx.PropertyErrorf("partitions", "%q(type: %s) is not supported",
  108. p.Name(), ctx.OtherModuleType(p))
  109. continue
  110. }
  111. signedImage := f.SignedOutputPath()
  112. if signedImage == nil {
  113. ctx.PropertyErrorf("partitions", "%q(type: %s) is not signed. Use `use_avb: true`",
  114. p.Name(), ctx.OtherModuleType(p))
  115. continue
  116. }
  117. cmd.FlagWithInput("--include_descriptors_from_image ", signedImage)
  118. }
  119. for i, cp := range v.properties.Chained_partitions {
  120. name := proptools.String(cp.Name)
  121. if name == "" {
  122. ctx.PropertyErrorf("chained_partitions", "name must be specified")
  123. continue
  124. }
  125. ril := proptools.IntDefault(cp.Rollback_index_location, i+1)
  126. if ril < 0 {
  127. ctx.PropertyErrorf("chained_partitions", "must be 0, 1, 2, ...")
  128. continue
  129. }
  130. var publicKey android.Path
  131. if cp.Public_key != nil {
  132. publicKey = android.PathForModuleSrc(ctx, proptools.String(cp.Public_key))
  133. } else {
  134. publicKey = extractedPublicKeys[name]
  135. }
  136. cmd.FlagWithArg("--chain_partition ", fmt.Sprintf("%s:%d:%s", name, ril, publicKey.String()))
  137. cmd.Implicit(publicKey)
  138. }
  139. cmd.FlagWithOutput("--output ", v.output)
  140. // libavb expects to be able to read the maximum vbmeta size, so we must provide a partition
  141. // which matches this or the read will fail.
  142. builder.Command().Text("truncate").
  143. FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)).
  144. Output(v.output)
  145. builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
  146. v.installDir = android.PathForModuleInstall(ctx, "etc")
  147. ctx.InstallFile(v.installDir, v.installFileName(), v.output)
  148. }
  149. // Returns the embedded shell command that prints the rollback index
  150. func (v *vbmeta) rollbackIndexCommand(ctx android.ModuleContext) string {
  151. var cmd string
  152. if v.properties.Rollback_index_file != nil {
  153. f := android.PathForModuleSrc(ctx, proptools.String(v.properties.Rollback_index_file))
  154. cmd = "cat " + f.String()
  155. } else {
  156. cmd = "date -d 'TZ=\"GMT\" " + ctx.Config().PlatformSecurityPatch() + "' +%s"
  157. }
  158. // Take the first line and remove the newline char
  159. return "$(" + cmd + " | head -1 | tr -d '\n'" + ")"
  160. }
  161. // Extract public keys from chained_partitions.private_key. The keys are indexed with the partition
  162. // name.
  163. func (v *vbmeta) extractPublicKeys(ctx android.ModuleContext) map[string]android.OutputPath {
  164. result := make(map[string]android.OutputPath)
  165. builder := android.NewRuleBuilder(pctx, ctx)
  166. for _, cp := range v.properties.Chained_partitions {
  167. if cp.Private_key == nil {
  168. continue
  169. }
  170. name := proptools.String(cp.Name)
  171. if name == "" {
  172. ctx.PropertyErrorf("chained_partitions", "name must be specified")
  173. continue
  174. }
  175. if _, ok := result[name]; ok {
  176. ctx.PropertyErrorf("chained_partitions", "name %q is duplicated", name)
  177. continue
  178. }
  179. privateKeyFile := android.PathForModuleSrc(ctx, proptools.String(cp.Private_key))
  180. publicKeyFile := android.PathForModuleOut(ctx, name+".avbpubkey").OutputPath
  181. builder.Command().
  182. BuiltTool("avbtool").
  183. Text("extract_public_key").
  184. FlagWithInput("--key ", privateKeyFile).
  185. FlagWithOutput("--output ", publicKeyFile)
  186. result[name] = publicKeyFile
  187. }
  188. builder.Build("vbmeta_extract_public_key", fmt.Sprintf("Extract public keys for %s", ctx.ModuleName()))
  189. return result
  190. }
  191. var _ android.AndroidMkEntriesProvider = (*vbmeta)(nil)
  192. // Implements android.AndroidMkEntriesProvider
  193. func (v *vbmeta) AndroidMkEntries() []android.AndroidMkEntries {
  194. return []android.AndroidMkEntries{android.AndroidMkEntries{
  195. Class: "ETC",
  196. OutputFile: android.OptionalPathForPath(v.output),
  197. ExtraEntries: []android.AndroidMkExtraEntriesFunc{
  198. func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
  199. entries.SetString("LOCAL_MODULE_PATH", v.installDir.String())
  200. entries.SetString("LOCAL_INSTALLED_MODULE_STEM", v.installFileName())
  201. },
  202. },
  203. }}
  204. }
  205. var _ Filesystem = (*vbmeta)(nil)
  206. func (v *vbmeta) OutputPath() android.Path {
  207. return v.output
  208. }
  209. func (v *vbmeta) SignedOutputPath() android.Path {
  210. return v.OutputPath() // vbmeta is always signed
  211. }
  212. var _ android.OutputFileProducer = (*vbmeta)(nil)
  213. // Implements android.OutputFileProducer
  214. func (v *vbmeta) OutputFiles(tag string) (android.Paths, error) {
  215. if tag == "" {
  216. return []android.Path{v.output}, nil
  217. }
  218. return nil, fmt.Errorf("unsupported module reference tag %q", tag)
  219. }