1// Copyright 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 "path/filepath" 20 "sort" 21 "strings" 22 23 "android/soong/android" 24) 25 26func init() { 27 android.RegisterModuleType("se_build_files", buildFilesFactory) 28} 29 30// se_build_files gathers policy files from sepolicy dirs, and acts like a filegroup. A tag with 31// partition(plat, system_ext, product) and scope(public, private) is used to select directories. 32// Supported tags are: "plat", "plat_public", "system_ext", "system_ext_public", "product", 33// "product_public", and "reqd_mask". 34func buildFilesFactory() android.Module { 35 module := &buildFiles{} 36 module.AddProperties(&module.properties) 37 android.InitAndroidModule(module) 38 return module 39} 40 41type buildFilesProperties struct { 42 // list of source file suffixes used to collect selinux policy files. 43 // Source files will be looked up in the following local directories: 44 // system/sepolicy/{public, private, vendor, reqd_mask} 45 // and directories specified by following config variables: 46 // BOARD_SEPOLICY_DIRS, BOARD_ODM_SEPOLICY_DIRS 47 // SYSTEM_EXT_PUBLIC_SEPOLICY_DIR, SYSTEM_EXT_PRIVATE_SEPOLICY_DIR 48 Srcs []string 49} 50 51type buildFiles struct { 52 android.ModuleBase 53 properties buildFilesProperties 54 55 srcs map[string]android.Paths 56} 57 58func (b *buildFiles) findSrcsInDirs(ctx android.ModuleContext, dirs ...string) android.Paths { 59 result := android.Paths{} 60 for _, file := range b.properties.Srcs { 61 for _, dir := range dirs { 62 path := filepath.Join(dir, file) 63 files, err := ctx.GlobWithDeps(path, nil) 64 if err != nil { 65 ctx.ModuleErrorf("glob: %s", err.Error()) 66 } 67 for _, f := range files { 68 result = append(result, android.PathForSource(ctx, f)) 69 } 70 } 71 } 72 return result 73} 74 75func (b *buildFiles) DepsMutator(ctx android.BottomUpMutatorContext) { 76 // do nothing 77} 78 79func (b *buildFiles) OutputFiles(tag string) (android.Paths, error) { 80 if paths, ok := b.srcs[tag]; ok { 81 return paths, nil 82 } 83 84 return nil, fmt.Errorf("unknown tag %q. Supported tags are: %q", tag, strings.Join(android.SortedStringKeys(b.srcs), " ")) 85} 86 87var _ android.OutputFileProducer = (*buildFiles)(nil) 88 89type partition int 90 91const ( 92 system partition = iota 93 system_ext 94 product 95) 96 97type scope int 98 99const ( 100 public scope = iota 101 private 102) 103 104type sepolicyDir struct { 105 partition partition 106 scope scope 107 paths []string 108} 109 110func (p partition) String() string { 111 switch p { 112 case system: 113 return "plat" 114 case system_ext: 115 return "system_ext" 116 case product: 117 return "product" 118 default: 119 panic(fmt.Sprintf("Unknown partition %#v", p)) 120 } 121} 122 123func (b *buildFiles) GenerateAndroidBuildActions(ctx android.ModuleContext) { 124 // Sepolicy directories should be included in the following order. 125 // - system_public 126 // - system_private 127 // - system_ext_public 128 // - system_ext_private 129 // - product_public 130 // - product_private 131 dirs := []sepolicyDir{ 132 sepolicyDir{partition: system, scope: public, paths: []string{filepath.Join(ctx.ModuleDir(), "public")}}, 133 sepolicyDir{partition: system, scope: private, paths: []string{filepath.Join(ctx.ModuleDir(), "private")}}, 134 sepolicyDir{partition: system_ext, scope: public, paths: ctx.DeviceConfig().SystemExtPublicSepolicyDirs()}, 135 sepolicyDir{partition: system_ext, scope: private, paths: ctx.DeviceConfig().SystemExtPrivateSepolicyDirs()}, 136 sepolicyDir{partition: product, scope: public, paths: ctx.Config().ProductPublicSepolicyDirs()}, 137 sepolicyDir{partition: product, scope: private, paths: ctx.Config().ProductPrivateSepolicyDirs()}, 138 } 139 140 if !sort.SliceIsSorted(dirs, func(i, j int) bool { 141 if dirs[i].partition != dirs[j].partition { 142 return dirs[i].partition < dirs[j].partition 143 } 144 145 return dirs[i].scope < dirs[j].scope 146 }) { 147 panic("dirs is not sorted") 148 } 149 150 // Exported cil policy files are built with the following policies. 151 // 152 // - plat_pub_policy.cil: exported 'system' 153 // - system_ext_pub_policy.cil: exported 'system' and 'system_ext' 154 // - pub_policy.cil: exported 'system', 'system_ext', and 'product' 155 // 156 // cil policy files are built with the following policies. 157 // 158 // - plat_policy.cil: 'system', including private 159 // - system_ext_policy.cil: 'system_ext', including private 160 // - product_sepolicy.cil: 'product', including private 161 // 162 // gatherDirsFor collects all needed directories for given partition and scope. For example, 163 // 164 // - gatherDirsFor(system_ext, private) will return system + system_ext (including private) 165 // - gatherDirsFor(product, public) will return system + system_ext + product (public only) 166 // 167 // "dirs" should be sorted before calling this. 168 gatherDirsFor := func(p partition, s scope) []string { 169 var ret []string 170 171 for _, d := range dirs { 172 if d.partition <= p && d.scope <= s { 173 ret = append(ret, d.paths...) 174 } 175 } 176 177 return ret 178 } 179 180 reqdMaskDir := filepath.Join(ctx.ModuleDir(), "reqd_mask") 181 182 b.srcs = make(map[string]android.Paths) 183 b.srcs[".reqd_mask"] = b.findSrcsInDirs(ctx, reqdMaskDir) 184 185 for _, p := range []partition{system, system_ext, product} { 186 b.srcs["."+p.String()] = b.findSrcsInDirs(ctx, gatherDirsFor(p, private)...) 187 188 // reqd_mask is needed for public policies 189 b.srcs["."+p.String()+"_public"] = b.findSrcsInDirs(ctx, append(gatherDirsFor(p, public), reqdMaskDir)...) 190 } 191 192 // A special tag, "plat_vendor", includes minimized vendor policies required to boot. 193 // - system/sepolicy/public 194 // - system/sepolicy/reqd_mask 195 // - system/sepolicy/vendor 196 // This is for minimized vendor partition, e.g. microdroid's vendor 197 platVendorDir := filepath.Join(ctx.ModuleDir(), "vendor") 198 b.srcs[".plat_vendor"] = b.findSrcsInDirs(ctx, append(gatherDirsFor(system, public), reqdMaskDir, platVendorDir)...) 199} 200