152 lines
5.7 KiB
Go
152 lines
5.7 KiB
Go
// Copyright (C) 2024 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package filesystem
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"android/soong/android"
|
|
|
|
"github.com/google/blueprint/proptools"
|
|
)
|
|
|
|
type fsverityProperties struct {
|
|
// Patterns of files for fsverity metadata generation. For each matched file, a .fsv_meta file
|
|
// will be generated and included to the filesystem image.
|
|
// etc/security/fsverity/BuildManifest.apk will also be generated which contains information
|
|
// about generated .fsv_meta files.
|
|
Inputs proptools.Configurable[[]string]
|
|
|
|
// APK libraries to link against, for etc/security/fsverity/BuildManifest.apk
|
|
Libs proptools.Configurable[[]string] `android:"path"`
|
|
}
|
|
|
|
func (f *filesystem) writeManifestGeneratorListFile(ctx android.ModuleContext, outputPath android.WritablePath, matchedSpecs []android.PackagingSpec, rebasedDir android.OutputPath) {
|
|
var buf strings.Builder
|
|
for _, spec := range matchedSpecs {
|
|
buf.WriteString(rebasedDir.Join(ctx, spec.RelPathInPackage()).String())
|
|
buf.WriteRune('\n')
|
|
}
|
|
android.WriteFileRuleVerbatim(ctx, outputPath, buf.String())
|
|
}
|
|
|
|
func (f *filesystem) buildFsverityMetadataFiles(ctx android.ModuleContext, builder *android.RuleBuilder, specs map[string]android.PackagingSpec, rootDir android.OutputPath, rebasedDir android.OutputPath) {
|
|
match := func(path string) bool {
|
|
for _, pattern := range f.properties.Fsverity.Inputs.GetOrDefault(ctx, nil) {
|
|
if matched, err := filepath.Match(pattern, path); matched {
|
|
return true
|
|
} else if err != nil {
|
|
ctx.PropertyErrorf("fsverity.inputs", "bad pattern %q", pattern)
|
|
return false
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
var matchedSpecs []android.PackagingSpec
|
|
for _, relPath := range android.SortedKeys(specs) {
|
|
if match(relPath) {
|
|
matchedSpecs = append(matchedSpecs, specs[relPath])
|
|
}
|
|
}
|
|
|
|
if len(matchedSpecs) == 0 {
|
|
return
|
|
}
|
|
|
|
fsverityPath := ctx.Config().HostToolPath(ctx, "fsverity")
|
|
|
|
// STEP 1: generate .fsv_meta
|
|
var sb strings.Builder
|
|
sb.WriteString("set -e\n")
|
|
for _, spec := range matchedSpecs {
|
|
// srcPath is copied by CopySpecsToDir()
|
|
srcPath := rebasedDir.Join(ctx, spec.RelPathInPackage())
|
|
destPath := rebasedDir.Join(ctx, spec.RelPathInPackage()+".fsv_meta")
|
|
builder.Command().
|
|
BuiltTool("fsverity_metadata_generator").
|
|
FlagWithInput("--fsverity-path ", fsverityPath).
|
|
FlagWithArg("--signature ", "none").
|
|
FlagWithArg("--hash-alg ", "sha256").
|
|
FlagWithArg("--output ", destPath.String()).
|
|
Text(srcPath.String())
|
|
f.appendToEntry(ctx, destPath)
|
|
}
|
|
|
|
// STEP 2: generate signed BuildManifest.apk
|
|
// STEP 2-1: generate build_manifest.pb
|
|
manifestGeneratorListPath := android.PathForModuleOut(ctx, "fsverity_manifest.list")
|
|
f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath, matchedSpecs, rebasedDir)
|
|
assetsPath := android.PathForModuleOut(ctx, "fsverity_manifest/assets")
|
|
manifestPbPath := assetsPath.Join(ctx, "build_manifest.pb")
|
|
builder.Command().Text("rm -rf " + assetsPath.String())
|
|
builder.Command().Text("mkdir -p " + assetsPath.String())
|
|
builder.Command().
|
|
BuiltTool("fsverity_manifest_generator").
|
|
FlagWithInput("--fsverity-path ", fsverityPath).
|
|
FlagWithArg("--base-dir ", rootDir.String()).
|
|
FlagWithArg("--output ", manifestPbPath.String()).
|
|
FlagWithInput("@", manifestGeneratorListPath)
|
|
|
|
f.appendToEntry(ctx, manifestPbPath)
|
|
f.appendToEntry(ctx, manifestGeneratorListPath)
|
|
|
|
// STEP 2-2: generate BuildManifest.apk (unsigned)
|
|
apkNameSuffix := ""
|
|
if f.PartitionType() == "system_ext" {
|
|
//https://source.corp.google.com/h/googleplex-android/platform/build/+/e392d2b486c2d4187b20a72b1c67cc737ecbcca5:core/Makefile;l=3410;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b;bpv=1;bpt=0
|
|
apkNameSuffix = "SystemExt"
|
|
}
|
|
apkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk", apkNameSuffix))
|
|
idsigPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk.idsig", apkNameSuffix))
|
|
manifestTemplatePath := android.PathForSource(ctx, "system/security/fsverity/AndroidManifest.xml")
|
|
libs := android.PathsForModuleSrc(ctx, f.properties.Fsverity.Libs.GetOrDefault(ctx, nil))
|
|
|
|
minSdkVersion := ctx.Config().PlatformSdkCodename()
|
|
if minSdkVersion == "REL" {
|
|
minSdkVersion = ctx.Config().PlatformSdkVersion().String()
|
|
}
|
|
|
|
unsignedApkCommand := builder.Command().
|
|
BuiltTool("aapt2").
|
|
Text("link").
|
|
FlagWithOutput("-o ", apkPath).
|
|
FlagWithArg("-A ", assetsPath.String())
|
|
for _, lib := range libs {
|
|
unsignedApkCommand.FlagWithInput("-I ", lib)
|
|
}
|
|
unsignedApkCommand.
|
|
FlagWithArg("--min-sdk-version ", minSdkVersion).
|
|
FlagWithArg("--version-code ", ctx.Config().PlatformSdkVersion().String()).
|
|
FlagWithArg("--version-name ", ctx.Config().AppsDefaultVersionName()).
|
|
FlagWithInput("--manifest ", manifestTemplatePath).
|
|
Text(" --rename-manifest-package com.android.security.fsverity_metadata." + f.partitionName())
|
|
|
|
f.appendToEntry(ctx, apkPath)
|
|
|
|
// STEP 2-3: sign BuildManifest.apk
|
|
pemPath, keyPath := ctx.Config().DefaultAppCertificate(ctx)
|
|
builder.Command().
|
|
BuiltTool("apksigner").
|
|
Text("sign").
|
|
FlagWithArg("--in ", apkPath.String()).
|
|
FlagWithInput("--cert ", pemPath).
|
|
FlagWithInput("--key ", keyPath).
|
|
ImplicitOutput(idsigPath)
|
|
|
|
f.appendToEntry(ctx, idsigPath)
|
|
}
|