1*333d2b36SAndroid Build Coastguard Worker// Copyright (C) 2024 The Android Open Source Project 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage fsgen 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 19*333d2b36SAndroid Build Coastguard Worker "android/soong/filesystem" 20*333d2b36SAndroid Build Coastguard Worker "slices" 21*333d2b36SAndroid Build Coastguard Worker "strconv" 22*333d2b36SAndroid Build Coastguard Worker "strings" 23*333d2b36SAndroid Build Coastguard Worker 24*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/proptools" 25*333d2b36SAndroid Build Coastguard Worker) 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Workertype vbmetaModuleInfo struct { 28*333d2b36SAndroid Build Coastguard Worker // The name of the generated vbmeta module 29*333d2b36SAndroid Build Coastguard Worker moduleName string 30*333d2b36SAndroid Build Coastguard Worker // The name of the module that avb understands. This is the name passed to --chain_partition, 31*333d2b36SAndroid Build Coastguard Worker // and also the basename of the output file. (the output file is called partitionName + ".img") 32*333d2b36SAndroid Build Coastguard Worker partitionName string 33*333d2b36SAndroid Build Coastguard Worker} 34*333d2b36SAndroid Build Coastguard Worker 35*333d2b36SAndroid Build Coastguard Worker// Creates the vbmeta partition and the chained vbmeta partitions. Returns the list of module names 36*333d2b36SAndroid Build Coastguard Worker// that the function created. May return nil if the product isn't using avb. 37*333d2b36SAndroid Build Coastguard Worker// 38*333d2b36SAndroid Build Coastguard Worker// AVB is Android Verified Boot: https://source.android.com/docs/security/features/verifiedboot 39*333d2b36SAndroid Build Coastguard Worker// It works by signing all the partitions, but then also including an extra metadata paritition 40*333d2b36SAndroid Build Coastguard Worker// called vbmeta that depends on all the other signed partitions. This creates a requirement 41*333d2b36SAndroid Build Coastguard Worker// that you update all those partitions and the vbmeta partition together, so in order to relax 42*333d2b36SAndroid Build Coastguard Worker// that requirement products can set up "chained" vbmeta partitions, where a chained partition 43*333d2b36SAndroid Build Coastguard Worker// like vbmeta_system might contain the avb metadata for just a few products. In cuttlefish 44*333d2b36SAndroid Build Coastguard Worker// vbmeta_system contains metadata about product, system, and system_ext. Using chained partitions, 45*333d2b36SAndroid Build Coastguard Worker// that group of partitions can be updated independently from the other signed partitions. 46*333d2b36SAndroid Build Coastguard Workerfunc createVbmetaPartitions(ctx android.LoadHookContext, generatedPartitionTypes []string) []vbmetaModuleInfo { 47*333d2b36SAndroid Build Coastguard Worker partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 48*333d2b36SAndroid Build Coastguard Worker // Some products seem to have BuildingVbmetaImage as true even when BoardAvbEnable is false 49*333d2b36SAndroid Build Coastguard Worker if !partitionVars.BuildingVbmetaImage || !partitionVars.BoardAvbEnable { 50*333d2b36SAndroid Build Coastguard Worker return nil 51*333d2b36SAndroid Build Coastguard Worker } 52*333d2b36SAndroid Build Coastguard Worker 53*333d2b36SAndroid Build Coastguard Worker var result []vbmetaModuleInfo 54*333d2b36SAndroid Build Coastguard Worker 55*333d2b36SAndroid Build Coastguard Worker var chainedPartitions []string 56*333d2b36SAndroid Build Coastguard Worker var partitionTypesHandledByChainedPartitions []string 57*333d2b36SAndroid Build Coastguard Worker for _, chainedName := range android.SortedKeys(partitionVars.ChainedVbmetaPartitions) { 58*333d2b36SAndroid Build Coastguard Worker props := partitionVars.ChainedVbmetaPartitions[chainedName] 59*333d2b36SAndroid Build Coastguard Worker chainedName = "vbmeta_" + chainedName 60*333d2b36SAndroid Build Coastguard Worker if len(props.Partitions) == 0 { 61*333d2b36SAndroid Build Coastguard Worker continue 62*333d2b36SAndroid Build Coastguard Worker } 63*333d2b36SAndroid Build Coastguard Worker if len(props.Key) == 0 { 64*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("No key found for chained avb partition %q", chainedName) 65*333d2b36SAndroid Build Coastguard Worker continue 66*333d2b36SAndroid Build Coastguard Worker } 67*333d2b36SAndroid Build Coastguard Worker if len(props.Algorithm) == 0 { 68*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("No algorithm found for chained avb partition %q", chainedName) 69*333d2b36SAndroid Build Coastguard Worker continue 70*333d2b36SAndroid Build Coastguard Worker } 71*333d2b36SAndroid Build Coastguard Worker if len(props.RollbackIndex) == 0 { 72*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("No rollback index found for chained avb partition %q", chainedName) 73*333d2b36SAndroid Build Coastguard Worker continue 74*333d2b36SAndroid Build Coastguard Worker } 75*333d2b36SAndroid Build Coastguard Worker ril, err := strconv.ParseInt(props.RollbackIndexLocation, 10, 32) 76*333d2b36SAndroid Build Coastguard Worker if err != nil { 77*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("Rollback index location must be an int, got %q", props.RollbackIndexLocation) 78*333d2b36SAndroid Build Coastguard Worker continue 79*333d2b36SAndroid Build Coastguard Worker } 80*333d2b36SAndroid Build Coastguard Worker // The default is to use the PlatformSecurityPatch, and a lot of product config files 81*333d2b36SAndroid Build Coastguard Worker // just set it to the platform security patch, so detect that and don't set the property 82*333d2b36SAndroid Build Coastguard Worker // in soong. 83*333d2b36SAndroid Build Coastguard Worker var rollbackIndex *int64 84*333d2b36SAndroid Build Coastguard Worker if props.RollbackIndex != ctx.Config().PlatformSecurityPatch() { 85*333d2b36SAndroid Build Coastguard Worker i, err := strconv.ParseInt(props.RollbackIndex, 10, 32) 86*333d2b36SAndroid Build Coastguard Worker if err != nil { 87*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("Rollback index must be an int, got %q", props.RollbackIndex) 88*333d2b36SAndroid Build Coastguard Worker continue 89*333d2b36SAndroid Build Coastguard Worker } 90*333d2b36SAndroid Build Coastguard Worker rollbackIndex = &i 91*333d2b36SAndroid Build Coastguard Worker } 92*333d2b36SAndroid Build Coastguard Worker 93*333d2b36SAndroid Build Coastguard Worker var partitionModules []string 94*333d2b36SAndroid Build Coastguard Worker for _, partition := range props.Partitions { 95*333d2b36SAndroid Build Coastguard Worker partitionTypesHandledByChainedPartitions = append(partitionTypesHandledByChainedPartitions, partition) 96*333d2b36SAndroid Build Coastguard Worker if !slices.Contains(generatedPartitionTypes, partition) { 97*333d2b36SAndroid Build Coastguard Worker // The partition is probably unsupported. 98*333d2b36SAndroid Build Coastguard Worker continue 99*333d2b36SAndroid Build Coastguard Worker } 100*333d2b36SAndroid Build Coastguard Worker partitionModules = append(partitionModules, generatedModuleNameForPartition(ctx.Config(), partition)) 101*333d2b36SAndroid Build Coastguard Worker } 102*333d2b36SAndroid Build Coastguard Worker 103*333d2b36SAndroid Build Coastguard Worker name := generatedModuleName(ctx.Config(), chainedName) 104*333d2b36SAndroid Build Coastguard Worker ctx.CreateModuleInDirectory( 105*333d2b36SAndroid Build Coastguard Worker filesystem.VbmetaFactory, 106*333d2b36SAndroid Build Coastguard Worker ".", // Create in the root directory for now so its easy to get the key 107*333d2b36SAndroid Build Coastguard Worker &filesystem.VbmetaProperties{ 108*333d2b36SAndroid Build Coastguard Worker Partition_name: proptools.StringPtr(chainedName), 109*333d2b36SAndroid Build Coastguard Worker Stem: proptools.StringPtr(chainedName + ".img"), 110*333d2b36SAndroid Build Coastguard Worker Private_key: proptools.StringPtr(props.Key), 111*333d2b36SAndroid Build Coastguard Worker Algorithm: &props.Algorithm, 112*333d2b36SAndroid Build Coastguard Worker Rollback_index: rollbackIndex, 113*333d2b36SAndroid Build Coastguard Worker Rollback_index_location: &ril, 114*333d2b36SAndroid Build Coastguard Worker Partitions: proptools.NewSimpleConfigurable(partitionModules), 115*333d2b36SAndroid Build Coastguard Worker }, &struct { 116*333d2b36SAndroid Build Coastguard Worker Name *string 117*333d2b36SAndroid Build Coastguard Worker }{ 118*333d2b36SAndroid Build Coastguard Worker Name: &name, 119*333d2b36SAndroid Build Coastguard Worker }, 120*333d2b36SAndroid Build Coastguard Worker ).HideFromMake() 121*333d2b36SAndroid Build Coastguard Worker 122*333d2b36SAndroid Build Coastguard Worker chainedPartitions = append(chainedPartitions, name) 123*333d2b36SAndroid Build Coastguard Worker 124*333d2b36SAndroid Build Coastguard Worker result = append(result, vbmetaModuleInfo{ 125*333d2b36SAndroid Build Coastguard Worker moduleName: name, 126*333d2b36SAndroid Build Coastguard Worker partitionName: chainedName, 127*333d2b36SAndroid Build Coastguard Worker }) 128*333d2b36SAndroid Build Coastguard Worker } 129*333d2b36SAndroid Build Coastguard Worker 130*333d2b36SAndroid Build Coastguard Worker vbmetaModuleName := generatedModuleName(ctx.Config(), "vbmeta") 131*333d2b36SAndroid Build Coastguard Worker 132*333d2b36SAndroid Build Coastguard Worker var algorithm *string 133*333d2b36SAndroid Build Coastguard Worker var ri *int64 134*333d2b36SAndroid Build Coastguard Worker var key *string 135*333d2b36SAndroid Build Coastguard Worker if len(partitionVars.BoardAvbKeyPath) == 0 { 136*333d2b36SAndroid Build Coastguard Worker // Match make's defaults: https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4568;drc=5b55f926830963c02ab1d2d91e46442f04ba3af0 137*333d2b36SAndroid Build Coastguard Worker key = proptools.StringPtr("external/avb/test/data/testkey_rsa4096.pem") 138*333d2b36SAndroid Build Coastguard Worker algorithm = proptools.StringPtr("SHA256_RSA4096") 139*333d2b36SAndroid Build Coastguard Worker } else { 140*333d2b36SAndroid Build Coastguard Worker key = proptools.StringPtr(partitionVars.BoardAvbKeyPath) 141*333d2b36SAndroid Build Coastguard Worker algorithm = proptools.StringPtr(partitionVars.BoardAvbAlgorithm) 142*333d2b36SAndroid Build Coastguard Worker } 143*333d2b36SAndroid Build Coastguard Worker if len(partitionVars.BoardAvbRollbackIndex) > 0 { 144*333d2b36SAndroid Build Coastguard Worker parsedRi, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 32) 145*333d2b36SAndroid Build Coastguard Worker if err != nil { 146*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("Rollback index location must be an int, got %q", partitionVars.BoardAvbRollbackIndex) 147*333d2b36SAndroid Build Coastguard Worker } 148*333d2b36SAndroid Build Coastguard Worker ri = &parsedRi 149*333d2b36SAndroid Build Coastguard Worker } 150*333d2b36SAndroid Build Coastguard Worker 151*333d2b36SAndroid Build Coastguard Worker var partitionModules []string 152*333d2b36SAndroid Build Coastguard Worker for _, partitionType := range generatedPartitionTypes { 153*333d2b36SAndroid Build Coastguard Worker if slices.Contains(partitionTypesHandledByChainedPartitions, partitionType) { 154*333d2b36SAndroid Build Coastguard Worker // Already handled by a chained vbmeta partition 155*333d2b36SAndroid Build Coastguard Worker continue 156*333d2b36SAndroid Build Coastguard Worker } 157*333d2b36SAndroid Build Coastguard Worker if strings.Contains(partitionType, "ramdisk") || strings.Contains(partitionType, "boot") { 158*333d2b36SAndroid Build Coastguard Worker // ramdisk is never signed with avb information 159*333d2b36SAndroid Build Coastguard Worker // boot partitions just have the avb footer, and don't have a corresponding vbmeta 160*333d2b36SAndroid Build Coastguard Worker // partition. 161*333d2b36SAndroid Build Coastguard Worker continue 162*333d2b36SAndroid Build Coastguard Worker } 163*333d2b36SAndroid Build Coastguard Worker partitionModules = append(partitionModules, generatedModuleNameForPartition(ctx.Config(), partitionType)) 164*333d2b36SAndroid Build Coastguard Worker } 165*333d2b36SAndroid Build Coastguard Worker 166*333d2b36SAndroid Build Coastguard Worker ctx.CreateModuleInDirectory( 167*333d2b36SAndroid Build Coastguard Worker filesystem.VbmetaFactory, 168*333d2b36SAndroid Build Coastguard Worker ".", // Create in the root directory for now so its easy to get the key 169*333d2b36SAndroid Build Coastguard Worker &filesystem.VbmetaProperties{ 170*333d2b36SAndroid Build Coastguard Worker Stem: proptools.StringPtr("vbmeta.img"), 171*333d2b36SAndroid Build Coastguard Worker Algorithm: algorithm, 172*333d2b36SAndroid Build Coastguard Worker Private_key: key, 173*333d2b36SAndroid Build Coastguard Worker Rollback_index: ri, 174*333d2b36SAndroid Build Coastguard Worker Chained_partitions: chainedPartitions, 175*333d2b36SAndroid Build Coastguard Worker Partitions: proptools.NewSimpleConfigurable(partitionModules), 176*333d2b36SAndroid Build Coastguard Worker }, &struct { 177*333d2b36SAndroid Build Coastguard Worker Name *string 178*333d2b36SAndroid Build Coastguard Worker }{ 179*333d2b36SAndroid Build Coastguard Worker Name: &vbmetaModuleName, 180*333d2b36SAndroid Build Coastguard Worker }, 181*333d2b36SAndroid Build Coastguard Worker ).HideFromMake() 182*333d2b36SAndroid Build Coastguard Worker 183*333d2b36SAndroid Build Coastguard Worker result = append(result, vbmetaModuleInfo{ 184*333d2b36SAndroid Build Coastguard Worker moduleName: vbmetaModuleName, 185*333d2b36SAndroid Build Coastguard Worker partitionName: "vbmeta", 186*333d2b36SAndroid Build Coastguard Worker }) 187*333d2b36SAndroid Build Coastguard Worker return result 188*333d2b36SAndroid Build Coastguard Worker} 189