blob: 75fbdf178a9d4279fd4b082056c2cc43fc5f88c7 [file] [log] [blame]
// Copyright (C) 2021 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"
"os"
"strconv"
"github.com/google/blueprint/proptools"
"android/soong/android"
)
const (
// TODO: sync with Android.mk
MlsSens = 1
MlsCats = 1024
PolicyVers = 30
)
func init() {
android.RegisterModuleType("se_policy_conf", policyConfFactory)
android.RegisterModuleType("se_policy_cil", policyCilFactory)
}
type policyConfProperties struct {
// Name of the output. Default is {module_name}
Stem *string
// Policy files to be compiled to cil file.
Srcs []string `android:"path"`
// Target build variant (user / userdebug / eng). Default follows the current lunch target
Build_variant *string
// Whether to exclude build test or not. Default is false
Exclude_build_test *bool
// Whether to include asan specific policies or not. Default follows the current lunch target
With_asan *bool
// Whether to build CTS specific policy or not. Default is false
Cts *bool
// Whether this module is directly installable to one of the partitions. Default is true
Installable *bool
}
type policyConf struct {
android.ModuleBase
properties policyConfProperties
installSource android.Path
installPath android.InstallPath
}
// se_policy_conf merges collection of policy files into a policy.conf file to be processed by
// checkpolicy.
func policyConfFactory() android.Module {
c := &policyConf{}
c.AddProperties(&c.properties)
android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
return c
}
func (c *policyConf) installable() bool {
return proptools.BoolDefault(c.properties.Installable, true)
}
func (c *policyConf) stem() string {
return proptools.StringDefault(c.properties.Stem, c.Name())
}
func (c *policyConf) buildVariant(ctx android.ModuleContext) string {
if variant := proptools.String(c.properties.Build_variant); variant != "" {
return variant
}
if ctx.Config().Eng() {
return "eng"
}
if ctx.Config().Debuggable() {
return "userdebug"
}
return "user"
}
func (c *policyConf) cts() bool {
return proptools.Bool(c.properties.Cts)
}
func (c *policyConf) withAsan(ctx android.ModuleContext) string {
isAsanDevice := android.InList("address", ctx.Config().SanitizeDevice())
return strconv.FormatBool(proptools.BoolDefault(c.properties.With_asan, isAsanDevice))
}
func (c *policyConf) sepolicySplit(ctx android.ModuleContext) string {
if c.cts() {
return "cts"
}
return strconv.FormatBool(ctx.DeviceConfig().SepolicySplit())
}
func (c *policyConf) compatibleProperty(ctx android.ModuleContext) string {
if c.cts() {
return "cts"
}
return "true"
}
func (c *policyConf) trebleSyspropNeverallow(ctx android.ModuleContext) string {
if c.cts() {
return "cts"
}
return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenTrebleSyspropNeverallow())
}
func (c *policyConf) enforceSyspropOwner(ctx android.ModuleContext) string {
if c.cts() {
return "cts"
}
return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenEnforceSyspropOwner())
}
func (c *policyConf) enforceDebugfsRestrictions(ctx android.ModuleContext) string {
if c.cts() {
return "cts"
}
return strconv.FormatBool(ctx.DeviceConfig().BuildDebugfsRestrictionsEnabled())
}
func (c *policyConf) transformPolicyToConf(ctx android.ModuleContext) android.OutputPath {
conf := android.PathForModuleOut(ctx, "conf").OutputPath
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")).
Flag("--fatal-warnings").
FlagForEachArg("-D ", ctx.DeviceConfig().SepolicyM4Defs()).
FlagWithArg("-D mls_num_sens=", strconv.Itoa(MlsSens)).
FlagWithArg("-D mls_num_cats=", strconv.Itoa(MlsCats)).
FlagWithArg("-D target_arch=", ctx.DeviceConfig().DeviceArch()).
FlagWithArg("-D target_with_asan=", c.withAsan(ctx)).
FlagWithArg("-D target_with_dexpreopt=", strconv.FormatBool(ctx.DeviceConfig().WithDexpreopt())).
FlagWithArg("-D target_with_native_coverage=", strconv.FormatBool(ctx.DeviceConfig().ClangCoverageEnabled() || ctx.DeviceConfig().GcovCoverageEnabled())).
FlagWithArg("-D target_build_variant=", c.buildVariant(ctx)).
FlagWithArg("-D target_full_treble=", c.sepolicySplit(ctx)).
FlagWithArg("-D target_compatible_property=", c.compatibleProperty(ctx)).
FlagWithArg("-D target_treble_sysprop_neverallow=", c.trebleSyspropNeverallow(ctx)).
FlagWithArg("-D target_enforce_sysprop_owner=", c.enforceSyspropOwner(ctx)).
FlagWithArg("-D target_exclude_build_test=", strconv.FormatBool(proptools.Bool(c.properties.Exclude_build_test))).
FlagWithArg("-D target_requires_insecure_execmem_for_swiftshader=", strconv.FormatBool(ctx.DeviceConfig().RequiresInsecureExecmemForSwiftshader())).
FlagWithArg("-D target_enforce_debugfs_restriction=", c.enforceDebugfsRestrictions(ctx)).
Flag("-s").
Inputs(android.PathsForModuleSrc(ctx, c.properties.Srcs)).
Text("> ").Output(conf)
rule.Build("conf", "Transform policy to conf: "+ctx.ModuleName())
return conf
}
func (c *policyConf) DepsMutator(ctx android.BottomUpMutatorContext) {
// do nothing
}
func (c *policyConf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
c.installSource = c.transformPolicyToConf(ctx)
c.installPath = android.PathForModuleInstall(ctx, "etc")
ctx.InstallFile(c.installPath, c.stem(), c.installSource)
if !c.installable() {
c.SkipInstall()
}
}
func (c *policyConf) AndroidMkEntries() []android.AndroidMkEntries {
return []android.AndroidMkEntries{android.AndroidMkEntries{
OutputFile: android.OptionalPathForPath(c.installSource),
Class: "ETC",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.installable())
entries.SetPath("LOCAL_MODULE_PATH", c.installPath.ToMakePath())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
},
},
}}
}
func (c *policyConf) OutputFiles(tag string) (android.Paths, error) {
if tag == "" {
return android.Paths{c.installSource}, nil
}
return nil, fmt.Errorf("Unknown tag %q", tag)
}
var _ android.OutputFileProducer = (*policyConf)(nil)
type policyCilProperties struct {
// Name of the output. Default is {module_name}
Stem *string
// Policy file to be compiled to cil file.
Src *string `android:"path"`
// Additional cil files to be added in the end of the output. This is to support workarounds
// which are not supported by the policy language.
Additional_cil_files []string `android:"path"`
// Cil files to be filtered out by the filter_out tool of "build_sepolicy". Used to build
// exported policies
Filter_out []string `android:"path"`
// Whether to remove line markers (denoted by ;;) out of compiled cil files. Defaults to false
Remove_line_marker *bool
// Whether to run secilc to check compiled policy or not. Defaults to true
Secilc_check *bool
// Whether to ignore neverallow when running secilc check. Defaults to
// SELINUX_IGNORE_NEVERALLOWS.
Ignore_neverallow *bool
// Whether this module is directly installable to one of the partitions. Default is true
Installable *bool
}
type policyCil struct {
android.ModuleBase
properties policyCilProperties
installSource android.Path
installPath android.InstallPath
}
// se_policy_cil compiles a policy.conf file to a cil file with checkpolicy, and optionally runs
// secilc to check the output cil file. Affected by SELINUX_IGNORE_NEVERALLOWS.
func policyCilFactory() android.Module {
c := &policyCil{}
c.AddProperties(&c.properties)
android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
return c
}
func (c *policyCil) Installable() bool {
return proptools.BoolDefault(c.properties.Installable, true)
}
func (c *policyCil) stem() string {
return proptools.StringDefault(c.properties.Stem, c.Name())
}
func (c *policyCil) compileConfToCil(ctx android.ModuleContext, conf android.Path) android.OutputPath {
cil := android.PathForModuleOut(ctx, c.stem()).OutputPath
rule := android.NewRuleBuilder(pctx, ctx)
rule.Command().BuiltTool("checkpolicy").
Flag("-C"). // Write CIL
Flag("-M"). // Enable MLS
FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
FlagWithOutput("-o ", cil).
Input(conf)
if len(c.properties.Additional_cil_files) > 0 {
rule.Command().Text("cat").
Inputs(android.PathsForModuleSrc(ctx, c.properties.Additional_cil_files)).
Text(">> ").Output(cil)
}
if len(c.properties.Filter_out) > 0 {
rule.Command().BuiltTool("build_sepolicy").
Text("filter_out").
Flag("-f").
Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)).
FlagWithOutput("-t ", cil)
}
if proptools.Bool(c.properties.Remove_line_marker) {
rule.Command().Text("grep -v").
Text(proptools.ShellEscape(";;")).
Text(cil.String()).
Text(">").
Text(cil.String() + ".tmp").
Text("&& mv").
Text(cil.String() + ".tmp").
Text(cil.String())
}
if proptools.BoolDefault(c.properties.Secilc_check, true) {
secilcCmd := rule.Command().BuiltTool("secilc").
Flag("-m"). // Multiple decls
FlagWithArg("-M ", "true"). // Enable MLS
Flag("-G"). // expand and remove auto generated attributes
FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)). // Also add cil files which are filtered out
Text(cil.String()).
FlagWithArg("-o ", os.DevNull).
FlagWithArg("-f ", os.DevNull)
if proptools.BoolDefault(c.properties.Ignore_neverallow, ctx.Config().SelinuxIgnoreNeverallows()) {
secilcCmd.Flag("-N")
}
}
rule.Build("cil", "Building cil for "+ctx.ModuleName())
return cil
}
func (c *policyCil) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if proptools.String(c.properties.Src) == "" {
ctx.PropertyErrorf("src", "must be specified")
return
}
conf := android.PathForModuleSrc(ctx, *c.properties.Src)
cil := c.compileConfToCil(ctx, conf)
if c.InstallInDebugRamdisk() {
// for userdebug_plat_sepolicy.cil
c.installPath = android.PathForModuleInstall(ctx)
} else {
c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux")
}
c.installSource = cil
ctx.InstallFile(c.installPath, c.stem(), c.installSource)
if !c.Installable() {
c.SkipInstall()
}
}
func (c *policyCil) AndroidMkEntries() []android.AndroidMkEntries {
return []android.AndroidMkEntries{android.AndroidMkEntries{
OutputFile: android.OptionalPathForPath(c.installSource),
Class: "ETC",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.Installable())
entries.SetPath("LOCAL_MODULE_PATH", c.installPath.ToMakePath())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
},
},
}}
}
func (c *policyCil) OutputFiles(tag string) (android.Paths, error) {
if tag == "" {
return android.Paths{c.installSource}, nil
}
return nil, fmt.Errorf("Unknown tag %q", tag)
}
var _ android.OutputFileProducer = (*policyCil)(nil)