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), "current" 39 // (PLATFORM_SEPOLICY_VERSION), or "vendor" (BOARD_SEPOLICY_VERS). 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 } else if version == "vendor" { 94 version = ctx.DeviceConfig().BoardSepolicyVers() 95 } 96 97 var stem string 98 if s := proptools.String(m.properties.Stem); s != "" { 99 stem = s 100 } else if proptools.Bool(m.properties.Mapping) { 101 stem = version + ".cil" 102 } else { 103 stem = ctx.ModuleName() 104 } 105 106 out := android.PathForModuleOut(ctx, stem) 107 rule := android.NewRuleBuilder(pctx, ctx) 108 109 if proptools.String(m.properties.Base) == "" { 110 ctx.PropertyErrorf("base", "must be specified") 111 return 112 } 113 114 versionCmd := rule.Command().BuiltTool("version_policy"). 115 FlagWithInput("-b ", android.PathForModuleSrc(ctx, *m.properties.Base)). 116 FlagWithArg("-n ", version). 117 FlagWithOutput("-o ", out) 118 119 if proptools.Bool(m.properties.Mapping) && proptools.String(m.properties.Target_policy) != "" { 120 ctx.ModuleErrorf("Can't set both mapping and target_policy") 121 return 122 } 123 124 if proptools.Bool(m.properties.Mapping) { 125 versionCmd.Flag("-m") 126 } else if target := proptools.String(m.properties.Target_policy); target != "" { 127 versionCmd.FlagWithInput("-t ", android.PathForModuleSrc(ctx, target)) 128 } else { 129 ctx.ModuleErrorf("Either mapping or target_policy must be set") 130 return 131 } 132 133 if len(m.properties.Filter_out) > 0 { 134 rule.Command().BuiltTool("build_sepolicy"). 135 Text("filter_out"). 136 Flag("-f"). 137 Inputs(android.PathsForModuleSrc(ctx, m.properties.Filter_out)). 138 FlagWithOutput("-t ", out) 139 } 140 141 if len(m.properties.Dependent_cils) > 0 { 142 rule.Command().BuiltTool("secilc"). 143 Flag("-m"). 144 FlagWithArg("-M ", "true"). 145 Flag("-G"). 146 Flag("-N"). 147 FlagWithArg("-c ", strconv.Itoa(PolicyVers)). 148 Inputs(android.PathsForModuleSrc(ctx, m.properties.Dependent_cils)). 149 Text(out.String()). 150 FlagWithArg("-o ", os.DevNull). 151 FlagWithArg("-f ", os.DevNull) 152 } 153 154 rule.Build("mapping", "Versioning mapping file "+ctx.ModuleName()) 155 156 if !m.installable() { 157 m.SkipInstall() 158 } 159 160 m.installSource = out 161 m.installPath = android.PathForModuleInstall(ctx, "etc", "selinux") 162 if subdir := proptools.String(m.properties.Relative_install_path); subdir != "" { 163 m.installPath = m.installPath.Join(ctx, subdir) 164 } 165 ctx.InstallFile(m.installPath, m.installSource.Base(), m.installSource) 166} 167 168func (m *versionedPolicy) AndroidMkEntries() []android.AndroidMkEntries { 169 return []android.AndroidMkEntries{android.AndroidMkEntries{ 170 OutputFile: android.OptionalPathForPath(m.installSource), 171 Class: "ETC", 172 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 173 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 174 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !m.installable()) 175 entries.SetPath("LOCAL_MODULE_PATH", m.installPath) 176 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", m.installSource.Base()) 177 }, 178 }, 179 }} 180} 181 182func (m *versionedPolicy) OutputFiles(tag string) (android.Paths, error) { 183 if tag == "" { 184 return android.Paths{m.installSource}, nil 185 } 186 return nil, fmt.Errorf("Unknown tag %q", tag) 187} 188 189var _ android.OutputFileProducer = (*policyConf)(nil) 190