1// Copyright (C) 2021 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package selinux 16 17import ( 18 "fmt" 19 "os" 20 "strconv" 21 22 "github.com/google/blueprint/proptools" 23 24 "android/soong/android" 25) 26 27func init() { 28 android.RegisterModuleType("se_versioned_policy", versionedPolicyFactory) 29} 30 31type versionedPolicyProperties struct { 32 // Base cil file for versioning. 33 Base *string `android:"path"` 34 35 // Output file name. Defaults to {name} if target_policy is set, {version}.cil if mapping is set 36 Stem *string 37 38 // Target sepolicy version. Can be a specific version number (e.g. "30.0" for R) or "current" 39 // (PLATFORM_SEPOLICY_VERSION). Defaults to "current" 40 Version *string 41 42 // If true, generate mapping file from given base cil file. Cannot be set with target_policy. 43 Mapping *bool 44 45 // If given, version target policy file according to base policy. Cannot be set with mapping. 46 Target_policy *string `android:"path"` 47 48 // Cil files to be filtered out by the filter_out tool of "build_sepolicy". 49 Filter_out []string `android:"path"` 50 51 // Cil files to which this mapping file depends. If specified, secilc checks whether the output 52 // file can be merged with specified cil files or not. 53 Dependent_cils []string `android:"path"` 54 55 // Whether this module is directly installable to one of the partitions. Default is true 56 Installable *bool 57 58 // install to a subdirectory of the default install path for the module 59 Relative_install_path *string 60} 61 62type versionedPolicy struct { 63 android.ModuleBase 64 65 properties versionedPolicyProperties 66 67 installSource android.Path 68 installPath android.InstallPath 69} 70 71// se_versioned_policy generates versioned cil file with "version_policy". This can generate either 72// mapping file for public plat policies, or associate a target policy file with the version that 73// non-platform policy targets. 74func versionedPolicyFactory() android.Module { 75 m := &versionedPolicy{} 76 m.AddProperties(&m.properties) 77 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 78 return m 79} 80 81func (m *versionedPolicy) installable() bool { 82 return proptools.BoolDefault(m.properties.Installable, true) 83} 84 85func (m *versionedPolicy) DepsMutator(ctx android.BottomUpMutatorContext) { 86 // do nothing 87} 88 89func (m *versionedPolicy) GenerateAndroidBuildActions(ctx android.ModuleContext) { 90 version := proptools.StringDefault(m.properties.Version, "current") 91 if version == "current" { 92 version = ctx.DeviceConfig().PlatformSepolicyVersion() 93 } 94 95 var stem string 96 if s := proptools.String(m.properties.Stem); s != "" { 97 stem = s 98 } else if proptools.Bool(m.properties.Mapping) { 99 stem = version + ".cil" 100 } else { 101 stem = ctx.ModuleName() 102 } 103 104 out := android.PathForModuleOut(ctx, stem) 105 rule := android.NewRuleBuilder(pctx, ctx) 106 107 if proptools.String(m.properties.Base) == "" { 108 ctx.PropertyErrorf("base", "must be specified") 109 return 110 } 111 112 versionCmd := rule.Command().BuiltTool("version_policy"). 113 FlagWithInput("-b ", android.PathForModuleSrc(ctx, *m.properties.Base)). 114 FlagWithArg("-n ", version). 115 FlagWithOutput("-o ", out) 116 117 if proptools.Bool(m.properties.Mapping) && proptools.String(m.properties.Target_policy) != "" { 118 ctx.ModuleErrorf("Can't set both mapping and target_policy") 119 return 120 } 121 122 if proptools.Bool(m.properties.Mapping) { 123 versionCmd.Flag("-m") 124 } else if target := proptools.String(m.properties.Target_policy); target != "" { 125 versionCmd.FlagWithInput("-t ", android.PathForModuleSrc(ctx, target)) 126 } else { 127 ctx.ModuleErrorf("Either mapping or target_policy must be set") 128 return 129 } 130 131 if len(m.properties.Filter_out) > 0 { 132 rule.Command().BuiltTool("build_sepolicy"). 133 Text("filter_out"). 134 Flag("-f"). 135 Inputs(android.PathsForModuleSrc(ctx, m.properties.Filter_out)). 136 FlagWithOutput("-t ", out) 137 } 138 139 if len(m.properties.Dependent_cils) > 0 { 140 rule.Command().BuiltTool("secilc"). 141 Flag("-m"). 142 FlagWithArg("-M ", "true"). 143 Flag("-G"). 144 Flag("-N"). 145 FlagWithArg("-c ", strconv.Itoa(PolicyVers)). 146 Inputs(android.PathsForModuleSrc(ctx, m.properties.Dependent_cils)). 147 Text(out.String()). 148 FlagWithArg("-o ", os.DevNull). 149 FlagWithArg("-f ", os.DevNull) 150 } 151 152 rule.Build("mapping", "Versioning mapping file "+ctx.ModuleName()) 153 154 m.installSource = out 155 m.installPath = android.PathForModuleInstall(ctx, "etc", "selinux") 156 if subdir := proptools.String(m.properties.Relative_install_path); subdir != "" { 157 m.installPath = m.installPath.Join(ctx, subdir) 158 } 159 ctx.InstallFile(m.installPath, m.installSource.Base(), m.installSource) 160 161 if !m.installable() { 162 m.SkipInstall() 163 } 164} 165 166func (m *versionedPolicy) AndroidMkEntries() []android.AndroidMkEntries { 167 return []android.AndroidMkEntries{android.AndroidMkEntries{ 168 OutputFile: android.OptionalPathForPath(m.installSource), 169 Class: "ETC", 170 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 171 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 172 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !m.installable()) 173 entries.SetPath("LOCAL_MODULE_PATH", m.installPath.ToMakePath()) 174 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", m.installSource.Base()) 175 }, 176 }, 177 }} 178} 179 180func (m *versionedPolicy) OutputFiles(tag string) (android.Paths, error) { 181 if tag == "" { 182 return android.Paths{m.installSource}, nil 183 } 184 return nil, fmt.Errorf("Unknown tag %q", tag) 185} 186 187var _ android.OutputFileProducer = (*policyConf)(nil) 188