Build contexts files with Soong
This is to migrate sepolicy Makefiles into Soong. For the first part,
file_contexts, hwservice_contexts, property_contexts, and
service_contexts are migrated. Build-time tests for contexts files are
still in Makefile; they will also be done with Soong after porting the
module sepolicy.
The motivation of migrating is based on generating property_contexts
dynamically: if we were to amend contexts files at build time in the
future, it would be nicer to manage them in Soong. To do that, building
contexts files with Soong can be very helpful.
Bug: 127949646
Bug: 129377144
Test: 1) Build blueline-userdebug, flash, and boot.
Test: 2) Build blueline-userdebug with TARGET_FLATTEN_APEX=true, flash,
and boot.
Test: 3) Build aosp_arm-userdebug.
Change-Id: I576f6f20686f6f2121204f76657274696d652121
2019-04-15 13:10:46 +02:00
|
|
|
// Copyright (C) 2019 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 selinux
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
|
|
|
|
"android/soong/android"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
coreMode = "core"
|
|
|
|
recoveryMode = "recovery"
|
|
|
|
)
|
|
|
|
|
|
|
|
type selinuxContextsProperties struct {
|
|
|
|
// Filenames under sepolicy directories, which will be used to generate contexts file.
|
|
|
|
Srcs []string `android:"path"`
|
|
|
|
|
|
|
|
Product_variables struct {
|
|
|
|
Debuggable struct {
|
|
|
|
Srcs []string
|
|
|
|
}
|
|
|
|
|
|
|
|
Address_sanitize struct {
|
|
|
|
Srcs []string
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Whether reqd_mask directory is included to sepolicy directories or not.
|
|
|
|
Reqd_mask *bool
|
|
|
|
|
|
|
|
// Whether the comments in generated contexts file will be removed or not.
|
|
|
|
Remove_comment *bool
|
|
|
|
|
|
|
|
// Whether the result context file is sorted with fc_sort or not.
|
|
|
|
Fc_sort *bool
|
|
|
|
|
|
|
|
// Make this module available when building for recovery
|
|
|
|
Recovery_available *bool
|
|
|
|
|
|
|
|
InRecovery bool `blueprint:"mutated"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type fileContextsProperties struct {
|
|
|
|
// flatten_apex can be used to specify additional sources of file_contexts.
|
|
|
|
// Apex paths, /system/apex/{apex_name}, will be amended to the paths of file_contexts
|
|
|
|
// entries.
|
|
|
|
Flatten_apex struct {
|
|
|
|
Srcs []string
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type selinuxContextsModule struct {
|
|
|
|
android.ModuleBase
|
|
|
|
|
|
|
|
properties selinuxContextsProperties
|
|
|
|
fileContextsProperties fileContextsProperties
|
|
|
|
build func(ctx android.ModuleContext, inputs android.Paths)
|
|
|
|
outputPath android.ModuleGenPath
|
|
|
|
installPath android.OutputPath
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
reuseContextsDepTag = dependencyTag{name: "reuseContexts"}
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
pctx.HostBinToolVariable("fc_sort", "fc_sort")
|
|
|
|
|
|
|
|
android.RegisterModuleType("file_contexts", fileFactory)
|
|
|
|
android.RegisterModuleType("hwservice_contexts", hwServiceFactory)
|
|
|
|
android.RegisterModuleType("property_contexts", propertyFactory)
|
|
|
|
android.RegisterModuleType("service_contexts", serviceFactory)
|
|
|
|
|
|
|
|
android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
|
|
|
ctx.BottomUp("selinux_contexts", selinuxContextsMutator).Parallel()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *selinuxContextsModule) inRecovery() bool {
|
|
|
|
return m.properties.InRecovery || m.ModuleBase.InstallInRecovery()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *selinuxContextsModule) onlyInRecovery() bool {
|
|
|
|
return m.ModuleBase.InstallInRecovery()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *selinuxContextsModule) InstallInRecovery() bool {
|
|
|
|
return m.inRecovery()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *selinuxContextsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
|
|
if m.InstallInRecovery() {
|
|
|
|
// Workaround for installing context files at the root of the recovery partition
|
|
|
|
m.installPath = android.PathForOutput(ctx,
|
|
|
|
"target", "product", ctx.Config().DeviceName(), "recovery", "root")
|
|
|
|
} else {
|
|
|
|
m.installPath = android.PathForModuleInstall(ctx, "etc", "selinux")
|
|
|
|
}
|
|
|
|
|
|
|
|
if m.inRecovery() && !m.onlyInRecovery() {
|
|
|
|
dep := ctx.GetDirectDepWithTag(m.Name(), reuseContextsDepTag)
|
|
|
|
|
|
|
|
if reuseDeps, ok := dep.(*selinuxContextsModule); ok {
|
|
|
|
m.outputPath = reuseDeps.outputPath
|
|
|
|
ctx.InstallFile(m.installPath, m.Name(), m.outputPath)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var inputs android.Paths
|
|
|
|
|
|
|
|
ctx.VisitDirectDepsWithTag(android.SourceDepTag, func(dep android.Module) {
|
|
|
|
segroup, ok := dep.(*fileGroup)
|
|
|
|
if !ok {
|
|
|
|
ctx.ModuleErrorf("srcs dependency %q is not an selinux filegroup",
|
|
|
|
ctx.OtherModuleName(dep))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if ctx.ProductSpecific() {
|
|
|
|
inputs = append(inputs, segroup.ProductPrivateSrcs()...)
|
|
|
|
} else if ctx.SocSpecific() {
|
|
|
|
inputs = append(inputs, segroup.SystemVendorSrcs()...)
|
|
|
|
inputs = append(inputs, segroup.VendorSrcs()...)
|
|
|
|
} else if ctx.DeviceSpecific() {
|
|
|
|
inputs = append(inputs, segroup.OdmSrcs()...)
|
2019-09-09 16:04:06 +02:00
|
|
|
} else if ctx.SystemExtSpecific() {
|
|
|
|
inputs = append(inputs, segroup.SystemExtPrivateSrcs()...)
|
Build contexts files with Soong
This is to migrate sepolicy Makefiles into Soong. For the first part,
file_contexts, hwservice_contexts, property_contexts, and
service_contexts are migrated. Build-time tests for contexts files are
still in Makefile; they will also be done with Soong after porting the
module sepolicy.
The motivation of migrating is based on generating property_contexts
dynamically: if we were to amend contexts files at build time in the
future, it would be nicer to manage them in Soong. To do that, building
contexts files with Soong can be very helpful.
Bug: 127949646
Bug: 129377144
Test: 1) Build blueline-userdebug, flash, and boot.
Test: 2) Build blueline-userdebug with TARGET_FLATTEN_APEX=true, flash,
and boot.
Test: 3) Build aosp_arm-userdebug.
Change-Id: I576f6f20686f6f2121204f76657274696d652121
2019-04-15 13:10:46 +02:00
|
|
|
} else {
|
|
|
|
inputs = append(inputs, segroup.SystemPrivateSrcs()...)
|
|
|
|
|
|
|
|
if ctx.Config().ProductCompatibleProperty() {
|
|
|
|
inputs = append(inputs, segroup.SystemPublicSrcs()...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if proptools.Bool(m.properties.Reqd_mask) {
|
|
|
|
inputs = append(inputs, segroup.SystemReqdMaskSrcs()...)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
for _, src := range m.properties.Srcs {
|
|
|
|
// Module sources are handled above with VisitDirectDepsWithTag
|
|
|
|
if android.SrcIsModule(src) == "" {
|
|
|
|
inputs = append(inputs, android.PathForModuleSrc(ctx, src))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m.build(ctx, inputs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func newModule() *selinuxContextsModule {
|
|
|
|
m := &selinuxContextsModule{}
|
|
|
|
m.AddProperties(
|
|
|
|
&m.properties,
|
|
|
|
)
|
|
|
|
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
|
|
|
|
android.AddLoadHook(m, func(ctx android.LoadHookContext) {
|
|
|
|
m.selinuxContextsHook(ctx)
|
|
|
|
})
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *selinuxContextsModule) selinuxContextsHook(ctx android.LoadHookContext) {
|
|
|
|
// TODO: clean this up to use build/soong/android/variable.go after b/79249983
|
|
|
|
var srcs []string
|
|
|
|
|
|
|
|
if ctx.Config().Debuggable() {
|
|
|
|
srcs = append(srcs, m.properties.Product_variables.Debuggable.Srcs...)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, sanitize := range ctx.Config().SanitizeDevice() {
|
|
|
|
if sanitize == "address" {
|
|
|
|
srcs = append(srcs, m.properties.Product_variables.Address_sanitize.Srcs...)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m.properties.Srcs = append(m.properties.Srcs, srcs...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *selinuxContextsModule) AndroidMk() android.AndroidMkData {
|
|
|
|
return android.AndroidMkData{
|
|
|
|
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
|
|
|
|
nameSuffix := ""
|
|
|
|
if m.inRecovery() && !m.onlyInRecovery() {
|
|
|
|
nameSuffix = ".recovery"
|
|
|
|
}
|
|
|
|
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
|
|
|
|
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
|
|
|
|
fmt.Fprintln(w, "LOCAL_MODULE :=", name+nameSuffix)
|
|
|
|
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
|
|
|
|
if m.Owner() != "" {
|
|
|
|
fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", m.Owner())
|
|
|
|
}
|
|
|
|
fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
|
|
|
|
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", m.outputPath.String())
|
|
|
|
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(OUT_DIR)/"+m.installPath.RelPathString())
|
|
|
|
fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", name)
|
|
|
|
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func selinuxContextsMutator(ctx android.BottomUpMutatorContext) {
|
|
|
|
m, ok := ctx.Module().(*selinuxContextsModule)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var coreVariantNeeded bool = true
|
|
|
|
var recoveryVariantNeeded bool = false
|
|
|
|
if proptools.Bool(m.properties.Recovery_available) {
|
|
|
|
recoveryVariantNeeded = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if m.ModuleBase.InstallInRecovery() {
|
|
|
|
recoveryVariantNeeded = true
|
|
|
|
coreVariantNeeded = false
|
|
|
|
}
|
|
|
|
|
|
|
|
var variants []string
|
|
|
|
if coreVariantNeeded {
|
|
|
|
variants = append(variants, coreMode)
|
|
|
|
}
|
|
|
|
if recoveryVariantNeeded {
|
|
|
|
variants = append(variants, recoveryMode)
|
|
|
|
}
|
|
|
|
mod := ctx.CreateVariations(variants...)
|
|
|
|
|
|
|
|
for i, v := range variants {
|
|
|
|
if v == recoveryMode {
|
|
|
|
m := mod[i].(*selinuxContextsModule)
|
|
|
|
m.properties.InRecovery = true
|
|
|
|
|
|
|
|
if coreVariantNeeded {
|
|
|
|
ctx.AddInterVariantDependency(reuseContextsDepTag, m, mod[i-1])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *selinuxContextsModule) buildGeneralContexts(ctx android.ModuleContext, inputs android.Paths) {
|
|
|
|
m.outputPath = android.PathForModuleGen(ctx, ctx.ModuleName()+"_m4out")
|
|
|
|
|
|
|
|
rule := android.NewRuleBuilder()
|
|
|
|
|
|
|
|
rule.Command().
|
2019-06-19 19:52:50 +02:00
|
|
|
Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")).
|
|
|
|
Text("--fatal-warnings -s").
|
Build contexts files with Soong
This is to migrate sepolicy Makefiles into Soong. For the first part,
file_contexts, hwservice_contexts, property_contexts, and
service_contexts are migrated. Build-time tests for contexts files are
still in Makefile; they will also be done with Soong after porting the
module sepolicy.
The motivation of migrating is based on generating property_contexts
dynamically: if we were to amend contexts files at build time in the
future, it would be nicer to manage them in Soong. To do that, building
contexts files with Soong can be very helpful.
Bug: 127949646
Bug: 129377144
Test: 1) Build blueline-userdebug, flash, and boot.
Test: 2) Build blueline-userdebug with TARGET_FLATTEN_APEX=true, flash,
and boot.
Test: 3) Build aosp_arm-userdebug.
Change-Id: I576f6f20686f6f2121204f76657274696d652121
2019-04-15 13:10:46 +02:00
|
|
|
FlagForEachArg("-D", ctx.DeviceConfig().SepolicyM4Defs()).
|
|
|
|
Inputs(inputs).
|
|
|
|
FlagWithOutput("> ", m.outputPath)
|
|
|
|
|
|
|
|
if proptools.Bool(m.properties.Remove_comment) {
|
|
|
|
rule.Temporary(m.outputPath)
|
|
|
|
|
|
|
|
remove_comment_output := android.PathForModuleGen(ctx, ctx.ModuleName()+"_remove_comment")
|
|
|
|
|
|
|
|
rule.Command().
|
|
|
|
Text("sed -e 's/#.*$//' -e '/^$/d'").
|
|
|
|
Input(m.outputPath).
|
|
|
|
FlagWithOutput("> ", remove_comment_output)
|
|
|
|
|
|
|
|
m.outputPath = remove_comment_output
|
|
|
|
}
|
|
|
|
|
|
|
|
if proptools.Bool(m.properties.Fc_sort) {
|
|
|
|
rule.Temporary(m.outputPath)
|
|
|
|
|
|
|
|
sorted_output := android.PathForModuleGen(ctx, ctx.ModuleName()+"_sorted")
|
|
|
|
|
|
|
|
rule.Command().
|
|
|
|
Tool(ctx.Config().HostToolPath(ctx, "fc_sort")).
|
|
|
|
FlagWithInput("-i ", m.outputPath).
|
|
|
|
FlagWithOutput("-o ", sorted_output)
|
|
|
|
|
|
|
|
m.outputPath = sorted_output
|
|
|
|
}
|
|
|
|
|
|
|
|
rule.Build(pctx, ctx, "selinux_contexts", m.Name())
|
|
|
|
|
|
|
|
rule.DeleteTemporaryFiles()
|
|
|
|
|
|
|
|
ctx.InstallFile(m.installPath, ctx.ModuleName(), m.outputPath)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *selinuxContextsModule) buildFileContexts(ctx android.ModuleContext, inputs android.Paths) {
|
|
|
|
if m.properties.Fc_sort == nil {
|
|
|
|
m.properties.Fc_sort = proptools.BoolPtr(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
rule := android.NewRuleBuilder()
|
|
|
|
|
|
|
|
if ctx.Config().FlattenApex() {
|
|
|
|
for _, src := range m.fileContextsProperties.Flatten_apex.Srcs {
|
|
|
|
if m := android.SrcIsModule(src); m != "" {
|
|
|
|
ctx.ModuleErrorf(
|
|
|
|
"Module srcs dependency %q is not supported for flatten_apex.srcs", m)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, path := range android.PathsForModuleSrcExcludes(ctx, []string{src}, nil) {
|
|
|
|
out := android.PathForModuleGen(ctx, "flattened_apex", path.Rel())
|
|
|
|
apex_path := "/system/apex/" + strings.Replace(
|
|
|
|
strings.TrimSuffix(path.Base(), "-file_contexts"),
|
|
|
|
".", "\\\\.", -1)
|
|
|
|
|
|
|
|
rule.Command().
|
|
|
|
Text("awk '/object_r/{printf(\""+apex_path+"%s\\n\",$0)}'").
|
|
|
|
Input(path).
|
|
|
|
FlagWithOutput("> ", out)
|
|
|
|
|
|
|
|
inputs = append(inputs, out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rule.Build(pctx, ctx, m.Name(), "flattened_apex_file_contexts")
|
|
|
|
m.buildGeneralContexts(ctx, inputs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func fileFactory() android.Module {
|
|
|
|
m := newModule()
|
|
|
|
m.AddProperties(&m.fileContextsProperties)
|
|
|
|
m.build = m.buildFileContexts
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *selinuxContextsModule) buildHwServiceContexts(ctx android.ModuleContext, inputs android.Paths) {
|
|
|
|
if m.properties.Remove_comment == nil {
|
|
|
|
m.properties.Remove_comment = proptools.BoolPtr(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
m.buildGeneralContexts(ctx, inputs)
|
|
|
|
}
|
|
|
|
|
|
|
|
func hwServiceFactory() android.Module {
|
|
|
|
m := newModule()
|
|
|
|
m.build = m.buildHwServiceContexts
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
|
|
|
func propertyFactory() android.Module {
|
|
|
|
m := newModule()
|
|
|
|
m.build = m.buildGeneralContexts
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
|
|
|
func serviceFactory() android.Module {
|
|
|
|
m := newModule()
|
|
|
|
m.build = m.buildGeneralContexts
|
|
|
|
return m
|
|
|
|
}
|