xref: /aosp_15_r20/build/soong/fsgen/vbmeta_partitions.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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