blob: 5de6122137b56495b7e280b0ad261b4ae5a00e29 [file] [log] [blame]
Inseob Kim619e4a72021-03-15 14:53:55 +09001// 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
Yi-Yo Chiang40073d42021-04-12 19:44:53 +080047 // SYSTEM_EXT_PUBLIC_SEPOLICY_DIR, SYSTEM_EXT_PRIVATE_SEPOLICY_DIR
Inseob Kim619e4a72021-03-15 14:53:55 +090048 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 }
Inseob Kim39fbcf72021-04-05 17:52:51 +0900191
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)...)
Inseob Kim619e4a72021-03-15 14:53:55 +0900199}