xref: /aosp_15_r20/system/sepolicy/tests/policy.py (revision e4a36f4174b17bbab9dc043f4a65dc8d87377290)
1*e4a36f41SAndroid Build Coastguard Worker# Copyright 2021 The Android Open Source Project
2*e4a36f41SAndroid Build Coastguard Worker#
3*e4a36f41SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*e4a36f41SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*e4a36f41SAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*e4a36f41SAndroid Build Coastguard Worker#
7*e4a36f41SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*e4a36f41SAndroid Build Coastguard Worker#
9*e4a36f41SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*e4a36f41SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*e4a36f41SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e4a36f41SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*e4a36f41SAndroid Build Coastguard Worker# limitations under the License.
14*e4a36f41SAndroid Build Coastguard Worker
15*e4a36f41SAndroid Build Coastguard Workerfrom ctypes import *
16*e4a36f41SAndroid Build Coastguard Workerimport re
17*e4a36f41SAndroid Build Coastguard Workerimport os
18*e4a36f41SAndroid Build Coastguard Workerimport sys
19*e4a36f41SAndroid Build Coastguard Workerimport platform
20*e4a36f41SAndroid Build Coastguard Workerimport fc_sort
21*e4a36f41SAndroid Build Coastguard Worker
22*e4a36f41SAndroid Build Coastguard Worker###
23*e4a36f41SAndroid Build Coastguard Worker# Check whether the regex will match a file path starting with the provided
24*e4a36f41SAndroid Build Coastguard Worker# prefix
25*e4a36f41SAndroid Build Coastguard Worker#
26*e4a36f41SAndroid Build Coastguard Worker# Compares regex entries in file_contexts with a path prefix. Regex entries
27*e4a36f41SAndroid Build Coastguard Worker# are often more specific than this file prefix. For example, the regex could
28*e4a36f41SAndroid Build Coastguard Worker# be /system/bin/foo\.sh and the prefix could be /system. This function
29*e4a36f41SAndroid Build Coastguard Worker# loops over the regex removing characters from the end until
30*e4a36f41SAndroid Build Coastguard Worker# 1) there is a match - return True or 2) run out of characters - return
31*e4a36f41SAndroid Build Coastguard Worker#    False.
32*e4a36f41SAndroid Build Coastguard Worker#
33*e4a36f41SAndroid Build Coastguard WorkerCOMMON_PREFIXES = {
34*e4a36f41SAndroid Build Coastguard Worker    "/(vendor|system/vendor)": ["/vendor", "/system/vendor"],
35*e4a36f41SAndroid Build Coastguard Worker    "/(odm|vendor/odm)": ["/odm", "/vendor/odm"],
36*e4a36f41SAndroid Build Coastguard Worker    "/(product|system/product)": ["/product", "/system/product"],
37*e4a36f41SAndroid Build Coastguard Worker    "/(system_ext|system/system_ext)": ["/system_ext", "/system/system_ext"],
38*e4a36f41SAndroid Build Coastguard Worker}
39*e4a36f41SAndroid Build Coastguard Worker
40*e4a36f41SAndroid Build Coastguard Workerdef MatchPathPrefix(pathregex, prefix):
41*e4a36f41SAndroid Build Coastguard Worker    # Before running regex compile loop, try two heuristics, because compiling
42*e4a36f41SAndroid Build Coastguard Worker    # regex is too expensive. These two can handle more than 90% out of all
43*e4a36f41SAndroid Build Coastguard Worker    # MatchPathPrefix calls.
44*e4a36f41SAndroid Build Coastguard Worker
45*e4a36f41SAndroid Build Coastguard Worker    # Heuristic 1: handle common prefixes for partitions
46*e4a36f41SAndroid Build Coastguard Worker    for c in COMMON_PREFIXES:
47*e4a36f41SAndroid Build Coastguard Worker        if not pathregex.startswith(c):
48*e4a36f41SAndroid Build Coastguard Worker            continue
49*e4a36f41SAndroid Build Coastguard Worker        found = False
50*e4a36f41SAndroid Build Coastguard Worker        for p in COMMON_PREFIXES[c]:
51*e4a36f41SAndroid Build Coastguard Worker            if prefix.startswith(p):
52*e4a36f41SAndroid Build Coastguard Worker                found = True
53*e4a36f41SAndroid Build Coastguard Worker                prefix = prefix[len(p):]
54*e4a36f41SAndroid Build Coastguard Worker                pathregex = pathregex[len(c):]
55*e4a36f41SAndroid Build Coastguard Worker                break
56*e4a36f41SAndroid Build Coastguard Worker        if not found:
57*e4a36f41SAndroid Build Coastguard Worker            return False
58*e4a36f41SAndroid Build Coastguard Worker
59*e4a36f41SAndroid Build Coastguard Worker    # Heuristic 2: compare normal characters as long as possible
60*e4a36f41SAndroid Build Coastguard Worker    idx = 0
61*e4a36f41SAndroid Build Coastguard Worker    while idx < len(prefix):
62*e4a36f41SAndroid Build Coastguard Worker        if idx == len(pathregex):
63*e4a36f41SAndroid Build Coastguard Worker            return False
64*e4a36f41SAndroid Build Coastguard Worker        if pathregex[idx] in fc_sort.META_CHARS or pathregex[idx] == '\\':
65*e4a36f41SAndroid Build Coastguard Worker            break
66*e4a36f41SAndroid Build Coastguard Worker        if pathregex[idx] != prefix[idx]:
67*e4a36f41SAndroid Build Coastguard Worker            return False
68*e4a36f41SAndroid Build Coastguard Worker        idx += 1
69*e4a36f41SAndroid Build Coastguard Worker    if idx == len(prefix):
70*e4a36f41SAndroid Build Coastguard Worker        return True
71*e4a36f41SAndroid Build Coastguard Worker
72*e4a36f41SAndroid Build Coastguard Worker    # Fall back to regex compile loop.
73*e4a36f41SAndroid Build Coastguard Worker    for i in range(len(pathregex), 0, -1):
74*e4a36f41SAndroid Build Coastguard Worker        try:
75*e4a36f41SAndroid Build Coastguard Worker            pattern = re.compile('^' + pathregex[0:i] + "$")
76*e4a36f41SAndroid Build Coastguard Worker        except:
77*e4a36f41SAndroid Build Coastguard Worker            continue
78*e4a36f41SAndroid Build Coastguard Worker        if pattern.match(prefix):
79*e4a36f41SAndroid Build Coastguard Worker            return True
80*e4a36f41SAndroid Build Coastguard Worker    return False
81*e4a36f41SAndroid Build Coastguard Worker
82*e4a36f41SAndroid Build Coastguard Workerdef MatchPathPrefixes(pathregex, Prefixes):
83*e4a36f41SAndroid Build Coastguard Worker    for Prefix in Prefixes:
84*e4a36f41SAndroid Build Coastguard Worker        if MatchPathPrefix(pathregex, Prefix):
85*e4a36f41SAndroid Build Coastguard Worker            return True
86*e4a36f41SAndroid Build Coastguard Worker    return False
87*e4a36f41SAndroid Build Coastguard Worker
88*e4a36f41SAndroid Build Coastguard Workerclass TERule:
89*e4a36f41SAndroid Build Coastguard Worker    def __init__(self, rule):
90*e4a36f41SAndroid Build Coastguard Worker        data = rule.split(',')
91*e4a36f41SAndroid Build Coastguard Worker        self.flavor = data[0]
92*e4a36f41SAndroid Build Coastguard Worker        self.sctx = data[1]
93*e4a36f41SAndroid Build Coastguard Worker        self.tctx = data[2]
94*e4a36f41SAndroid Build Coastguard Worker        self.tclass = data[3]
95*e4a36f41SAndroid Build Coastguard Worker        self.perms = set((data[4].strip()).split(' '))
96*e4a36f41SAndroid Build Coastguard Worker        self.rule = rule
97*e4a36f41SAndroid Build Coastguard Worker
98*e4a36f41SAndroid Build Coastguard Workerclass Policy:
99*e4a36f41SAndroid Build Coastguard Worker    __ExpandedRules = set()
100*e4a36f41SAndroid Build Coastguard Worker    __Rules = set()
101*e4a36f41SAndroid Build Coastguard Worker    __FcDict = None
102*e4a36f41SAndroid Build Coastguard Worker    __FcSorted = None
103*e4a36f41SAndroid Build Coastguard Worker    __GenfsDict = None
104*e4a36f41SAndroid Build Coastguard Worker    __libsepolwrap = None
105*e4a36f41SAndroid Build Coastguard Worker    __policydbP = None
106*e4a36f41SAndroid Build Coastguard Worker    __BUFSIZE = 2048
107*e4a36f41SAndroid Build Coastguard Worker
108*e4a36f41SAndroid Build Coastguard Worker    def AssertPathTypesDoNotHaveAttr(self, MatchPrefix, DoNotMatchPrefix, Attr, ExcludedTypes = []):
109*e4a36f41SAndroid Build Coastguard Worker        # Query policy for the types associated with Attr
110*e4a36f41SAndroid Build Coastguard Worker        TypesPol = self.QueryTypeAttribute(Attr, True) - set(ExcludedTypes)
111*e4a36f41SAndroid Build Coastguard Worker        # Search file_contexts to find types associated with input paths.
112*e4a36f41SAndroid Build Coastguard Worker        PathTypes = self.__GetTypesAndFilesByFilePathPrefix(MatchPrefix, DoNotMatchPrefix)
113*e4a36f41SAndroid Build Coastguard Worker        violators = set()
114*e4a36f41SAndroid Build Coastguard Worker        for PathType in PathTypes:
115*e4a36f41SAndroid Build Coastguard Worker            filepath, filetype = PathType
116*e4a36f41SAndroid Build Coastguard Worker            if filetype in TypesPol:
117*e4a36f41SAndroid Build Coastguard Worker                violators.add((str(filetype), str(filepath)))
118*e4a36f41SAndroid Build Coastguard Worker
119*e4a36f41SAndroid Build Coastguard Worker        ret = ""
120*e4a36f41SAndroid Build Coastguard Worker        if len(violators) > 0:
121*e4a36f41SAndroid Build Coastguard Worker            ret += "The following types on "
122*e4a36f41SAndroid Build Coastguard Worker            ret += " ".join(str(x) for x in sorted(MatchPrefix))
123*e4a36f41SAndroid Build Coastguard Worker            ret += " must not be associated with the "
124*e4a36f41SAndroid Build Coastguard Worker            ret += "\"" + Attr + "\" attribute.\n"
125*e4a36f41SAndroid Build Coastguard Worker            ret += "Violator types and corresponding paths:\n"
126*e4a36f41SAndroid Build Coastguard Worker            ret += "\n".join(str(x) for x in sorted(violators))
127*e4a36f41SAndroid Build Coastguard Worker            ret += "\n"
128*e4a36f41SAndroid Build Coastguard Worker        return ret
129*e4a36f41SAndroid Build Coastguard Worker
130*e4a36f41SAndroid Build Coastguard Worker    # Check that all types for "filesystem" have "attribute" associated with them
131*e4a36f41SAndroid Build Coastguard Worker    # for types labeled in genfs_contexts.
132*e4a36f41SAndroid Build Coastguard Worker    def AssertGenfsFilesystemTypesHaveAttr(self, Filesystem, Attr):
133*e4a36f41SAndroid Build Coastguard Worker        TypesPol = self.QueryTypeAttribute(Attr, True)
134*e4a36f41SAndroid Build Coastguard Worker        TypesGenfs = self.__GenfsDict[Filesystem]
135*e4a36f41SAndroid Build Coastguard Worker        violators = TypesGenfs.difference(TypesPol)
136*e4a36f41SAndroid Build Coastguard Worker
137*e4a36f41SAndroid Build Coastguard Worker        ret = ""
138*e4a36f41SAndroid Build Coastguard Worker        if len(violators) > 0:
139*e4a36f41SAndroid Build Coastguard Worker            ret += "The following types in " + Filesystem
140*e4a36f41SAndroid Build Coastguard Worker            ret += " must be associated with the "
141*e4a36f41SAndroid Build Coastguard Worker            ret += "\"" + Attr + "\" attribute: "
142*e4a36f41SAndroid Build Coastguard Worker            ret += " ".join(str(x) for x in sorted(violators)) + "\n"
143*e4a36f41SAndroid Build Coastguard Worker        return ret
144*e4a36f41SAndroid Build Coastguard Worker
145*e4a36f41SAndroid Build Coastguard Worker    # Check that path prefixes that match MatchPrefix, and do not Match
146*e4a36f41SAndroid Build Coastguard Worker    # DoNotMatchPrefix have the attribute Attr.
147*e4a36f41SAndroid Build Coastguard Worker    # For example assert that all types in /sys, and not in /sys/kernel/debugfs
148*e4a36f41SAndroid Build Coastguard Worker    # have the sysfs_type attribute.
149*e4a36f41SAndroid Build Coastguard Worker    def AssertPathTypesHaveAttr(self, MatchPrefix, DoNotMatchPrefix, Attr, ExcludedTypes = []):
150*e4a36f41SAndroid Build Coastguard Worker        # Query policy for the types associated with Attr
151*e4a36f41SAndroid Build Coastguard Worker        TypesPol = self.QueryTypeAttribute(Attr, True) | set(ExcludedTypes)
152*e4a36f41SAndroid Build Coastguard Worker        # Search file_contexts to find paths/types that should be associated with
153*e4a36f41SAndroid Build Coastguard Worker        # Attr.
154*e4a36f41SAndroid Build Coastguard Worker        PathTypes = self.__GetTypesAndFilesByFilePathPrefix(MatchPrefix, DoNotMatchPrefix)
155*e4a36f41SAndroid Build Coastguard Worker        violators = set()
156*e4a36f41SAndroid Build Coastguard Worker        for PathType in PathTypes:
157*e4a36f41SAndroid Build Coastguard Worker            filepath, filetype = PathType
158*e4a36f41SAndroid Build Coastguard Worker            if filetype not in TypesPol:
159*e4a36f41SAndroid Build Coastguard Worker                violators.add((str(filetype), str(filepath)))
160*e4a36f41SAndroid Build Coastguard Worker
161*e4a36f41SAndroid Build Coastguard Worker        ret = ""
162*e4a36f41SAndroid Build Coastguard Worker        if len(violators) > 0:
163*e4a36f41SAndroid Build Coastguard Worker            ret += "The following types on "
164*e4a36f41SAndroid Build Coastguard Worker            ret += " ".join(str(x) for x in sorted(MatchPrefix))
165*e4a36f41SAndroid Build Coastguard Worker            ret += " must be associated with the "
166*e4a36f41SAndroid Build Coastguard Worker            ret += "\"" + Attr + "\" attribute.\n"
167*e4a36f41SAndroid Build Coastguard Worker            ret += "Violator types and corresponding paths:\n"
168*e4a36f41SAndroid Build Coastguard Worker            ret += "\n".join(str(x) for x in sorted(violators))
169*e4a36f41SAndroid Build Coastguard Worker            ret += "\n"
170*e4a36f41SAndroid Build Coastguard Worker        return ret
171*e4a36f41SAndroid Build Coastguard Worker
172*e4a36f41SAndroid Build Coastguard Worker    def AssertPropertyOwnersAreExclusive(self):
173*e4a36f41SAndroid Build Coastguard Worker        systemProps = self.QueryTypeAttribute('system_property_type', True)
174*e4a36f41SAndroid Build Coastguard Worker        vendorProps = self.QueryTypeAttribute('vendor_property_type', True)
175*e4a36f41SAndroid Build Coastguard Worker        violators = systemProps.intersection(vendorProps)
176*e4a36f41SAndroid Build Coastguard Worker        ret = ""
177*e4a36f41SAndroid Build Coastguard Worker        if len(violators) > 0:
178*e4a36f41SAndroid Build Coastguard Worker            ret += "The following types have both system_property_type "
179*e4a36f41SAndroid Build Coastguard Worker            ret += "and vendor_property_type: "
180*e4a36f41SAndroid Build Coastguard Worker            ret += " ".join(str(x) for x in sorted(violators)) + "\n"
181*e4a36f41SAndroid Build Coastguard Worker        return ret
182*e4a36f41SAndroid Build Coastguard Worker
183*e4a36f41SAndroid Build Coastguard Worker    # Return all file_contexts entries that map to the input Type.
184*e4a36f41SAndroid Build Coastguard Worker    def QueryFc(self, Type):
185*e4a36f41SAndroid Build Coastguard Worker        if Type in self.__FcDict:
186*e4a36f41SAndroid Build Coastguard Worker            return self.__FcDict[Type]
187*e4a36f41SAndroid Build Coastguard Worker        else:
188*e4a36f41SAndroid Build Coastguard Worker            return None
189*e4a36f41SAndroid Build Coastguard Worker
190*e4a36f41SAndroid Build Coastguard Worker    # Return all attributes associated with a type if IsAttr=False or
191*e4a36f41SAndroid Build Coastguard Worker    # all types associated with an attribute if IsAttr=True
192*e4a36f41SAndroid Build Coastguard Worker    def QueryTypeAttribute(self, Type, IsAttr):
193*e4a36f41SAndroid Build Coastguard Worker        TypeIterP = self.__libsepolwrap.init_type_iter(self.__policydbP,
194*e4a36f41SAndroid Build Coastguard Worker                        create_string_buffer(Type.encode("ascii")), IsAttr)
195*e4a36f41SAndroid Build Coastguard Worker        if (TypeIterP == None):
196*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to initialize type iterator")
197*e4a36f41SAndroid Build Coastguard Worker        buf = create_string_buffer(self.__BUFSIZE)
198*e4a36f41SAndroid Build Coastguard Worker        TypeAttr = set()
199*e4a36f41SAndroid Build Coastguard Worker        while True:
200*e4a36f41SAndroid Build Coastguard Worker            ret = self.__libsepolwrap.get_type(buf, self.__BUFSIZE,
201*e4a36f41SAndroid Build Coastguard Worker                    self.__policydbP, TypeIterP)
202*e4a36f41SAndroid Build Coastguard Worker            if ret == 0:
203*e4a36f41SAndroid Build Coastguard Worker                TypeAttr.add(buf.value.decode("ascii"))
204*e4a36f41SAndroid Build Coastguard Worker                continue
205*e4a36f41SAndroid Build Coastguard Worker            if ret == 1:
206*e4a36f41SAndroid Build Coastguard Worker                break;
207*e4a36f41SAndroid Build Coastguard Worker            # We should never get here.
208*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to import policy")
209*e4a36f41SAndroid Build Coastguard Worker        self.__libsepolwrap.destroy_type_iter(TypeIterP)
210*e4a36f41SAndroid Build Coastguard Worker        return TypeAttr
211*e4a36f41SAndroid Build Coastguard Worker
212*e4a36f41SAndroid Build Coastguard Worker    def __TERuleMatch(self, Rule, **kwargs):
213*e4a36f41SAndroid Build Coastguard Worker        # Match source type
214*e4a36f41SAndroid Build Coastguard Worker        if ("scontext" in kwargs and
215*e4a36f41SAndroid Build Coastguard Worker                len(kwargs['scontext']) > 0 and
216*e4a36f41SAndroid Build Coastguard Worker                Rule.sctx not in kwargs['scontext']):
217*e4a36f41SAndroid Build Coastguard Worker            return False
218*e4a36f41SAndroid Build Coastguard Worker        # Match target type
219*e4a36f41SAndroid Build Coastguard Worker        if ("tcontext" in kwargs and
220*e4a36f41SAndroid Build Coastguard Worker                len(kwargs['tcontext']) > 0 and
221*e4a36f41SAndroid Build Coastguard Worker                Rule.tctx not in kwargs['tcontext']):
222*e4a36f41SAndroid Build Coastguard Worker            return False
223*e4a36f41SAndroid Build Coastguard Worker        # Match target class
224*e4a36f41SAndroid Build Coastguard Worker        if ("tclass" in kwargs and
225*e4a36f41SAndroid Build Coastguard Worker                len(kwargs['tclass']) > 0 and
226*e4a36f41SAndroid Build Coastguard Worker                not bool(set([Rule.tclass]) & kwargs['tclass'])):
227*e4a36f41SAndroid Build Coastguard Worker            return False
228*e4a36f41SAndroid Build Coastguard Worker        # Match any perms
229*e4a36f41SAndroid Build Coastguard Worker        if ("perms" in kwargs and
230*e4a36f41SAndroid Build Coastguard Worker                len(kwargs['perms']) > 0 and
231*e4a36f41SAndroid Build Coastguard Worker                not bool(Rule.perms & kwargs['perms'])):
232*e4a36f41SAndroid Build Coastguard Worker            return False
233*e4a36f41SAndroid Build Coastguard Worker        return True
234*e4a36f41SAndroid Build Coastguard Worker
235*e4a36f41SAndroid Build Coastguard Worker    # resolve a type to its attributes or
236*e4a36f41SAndroid Build Coastguard Worker    # resolve an attribute to its types and attributes
237*e4a36f41SAndroid Build Coastguard Worker    # For example if scontext is the domain attribute, then we need to
238*e4a36f41SAndroid Build Coastguard Worker    # include all types with the domain attribute such as untrusted_app and
239*e4a36f41SAndroid Build Coastguard Worker    # priv_app and all the attributes of those types such as appdomain.
240*e4a36f41SAndroid Build Coastguard Worker    def ResolveTypeAttribute(self, Type):
241*e4a36f41SAndroid Build Coastguard Worker        types = self.GetAllTypes(False)
242*e4a36f41SAndroid Build Coastguard Worker        attributes = self.GetAllTypes(True)
243*e4a36f41SAndroid Build Coastguard Worker
244*e4a36f41SAndroid Build Coastguard Worker        if Type in types:
245*e4a36f41SAndroid Build Coastguard Worker            return self.QueryTypeAttribute(Type, False)
246*e4a36f41SAndroid Build Coastguard Worker        elif Type in attributes:
247*e4a36f41SAndroid Build Coastguard Worker            TypesAndAttributes = set()
248*e4a36f41SAndroid Build Coastguard Worker            Types = self.QueryTypeAttribute(Type, True)
249*e4a36f41SAndroid Build Coastguard Worker            TypesAndAttributes |= Types
250*e4a36f41SAndroid Build Coastguard Worker            for T in Types:
251*e4a36f41SAndroid Build Coastguard Worker                TypesAndAttributes |= self.QueryTypeAttribute(T, False)
252*e4a36f41SAndroid Build Coastguard Worker            return TypesAndAttributes
253*e4a36f41SAndroid Build Coastguard Worker        else:
254*e4a36f41SAndroid Build Coastguard Worker            return set()
255*e4a36f41SAndroid Build Coastguard Worker
256*e4a36f41SAndroid Build Coastguard Worker    # Return all TERules that match:
257*e4a36f41SAndroid Build Coastguard Worker    # (any scontext) or (any tcontext) or (any tclass) or (any perms),
258*e4a36f41SAndroid Build Coastguard Worker    # perms.
259*e4a36f41SAndroid Build Coastguard Worker    # Any unspecified paramenter will match all.
260*e4a36f41SAndroid Build Coastguard Worker    #
261*e4a36f41SAndroid Build Coastguard Worker    # Example: QueryTERule(tcontext=["foo", "bar"], perms=["entrypoint"])
262*e4a36f41SAndroid Build Coastguard Worker    # Will return any rule with:
263*e4a36f41SAndroid Build Coastguard Worker    # (tcontext="foo" or tcontext="bar") and ("entrypoint" in perms)
264*e4a36f41SAndroid Build Coastguard Worker    def QueryTERule(self, **kwargs):
265*e4a36f41SAndroid Build Coastguard Worker        if len(self.__Rules) == 0:
266*e4a36f41SAndroid Build Coastguard Worker            self.__InitTERules()
267*e4a36f41SAndroid Build Coastguard Worker
268*e4a36f41SAndroid Build Coastguard Worker        # add any matching types and attributes for scontext and tcontext
269*e4a36f41SAndroid Build Coastguard Worker        if ("scontext" in kwargs and len(kwargs['scontext']) > 0):
270*e4a36f41SAndroid Build Coastguard Worker            scontext = set()
271*e4a36f41SAndroid Build Coastguard Worker            for sctx in kwargs['scontext']:
272*e4a36f41SAndroid Build Coastguard Worker                scontext |= self.ResolveTypeAttribute(sctx)
273*e4a36f41SAndroid Build Coastguard Worker            if (len(scontext) == 0):
274*e4a36f41SAndroid Build Coastguard Worker                return []
275*e4a36f41SAndroid Build Coastguard Worker            kwargs['scontext'] = scontext
276*e4a36f41SAndroid Build Coastguard Worker        if ("tcontext" in kwargs and len(kwargs['tcontext']) > 0):
277*e4a36f41SAndroid Build Coastguard Worker            tcontext = set()
278*e4a36f41SAndroid Build Coastguard Worker            for tctx in kwargs['tcontext']:
279*e4a36f41SAndroid Build Coastguard Worker                tcontext |= self.ResolveTypeAttribute(tctx)
280*e4a36f41SAndroid Build Coastguard Worker            if (len(tcontext) == 0):
281*e4a36f41SAndroid Build Coastguard Worker                return []
282*e4a36f41SAndroid Build Coastguard Worker            kwargs['tcontext'] = tcontext
283*e4a36f41SAndroid Build Coastguard Worker        for Rule in self.__Rules:
284*e4a36f41SAndroid Build Coastguard Worker            if self.__TERuleMatch(Rule, **kwargs):
285*e4a36f41SAndroid Build Coastguard Worker                yield Rule
286*e4a36f41SAndroid Build Coastguard Worker
287*e4a36f41SAndroid Build Coastguard Worker    # Same as QueryTERule but only using the expanded ruleset.
288*e4a36f41SAndroid Build Coastguard Worker    # i.e. all attributes have been expanded to their various types.
289*e4a36f41SAndroid Build Coastguard Worker    def QueryExpandedTERule(self, **kwargs):
290*e4a36f41SAndroid Build Coastguard Worker        if len(self.__ExpandedRules) == 0:
291*e4a36f41SAndroid Build Coastguard Worker            self.__InitExpandedTERules()
292*e4a36f41SAndroid Build Coastguard Worker        for Rule in self.__ExpandedRules:
293*e4a36f41SAndroid Build Coastguard Worker            if self.__TERuleMatch(Rule, **kwargs):
294*e4a36f41SAndroid Build Coastguard Worker                yield Rule
295*e4a36f41SAndroid Build Coastguard Worker
296*e4a36f41SAndroid Build Coastguard Worker    def GetAllTypes(self, isAttr):
297*e4a36f41SAndroid Build Coastguard Worker        TypeIterP = self.__libsepolwrap.init_type_iter(self.__policydbP, None, isAttr)
298*e4a36f41SAndroid Build Coastguard Worker        if (TypeIterP == None):
299*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to initialize type iterator")
300*e4a36f41SAndroid Build Coastguard Worker        buf = create_string_buffer(self.__BUFSIZE)
301*e4a36f41SAndroid Build Coastguard Worker        AllTypes = set()
302*e4a36f41SAndroid Build Coastguard Worker        while True:
303*e4a36f41SAndroid Build Coastguard Worker            ret = self.__libsepolwrap.get_type(buf, self.__BUFSIZE,
304*e4a36f41SAndroid Build Coastguard Worker                    self.__policydbP, TypeIterP)
305*e4a36f41SAndroid Build Coastguard Worker            if ret == 0:
306*e4a36f41SAndroid Build Coastguard Worker                AllTypes.add(buf.value.decode("ascii"))
307*e4a36f41SAndroid Build Coastguard Worker                continue
308*e4a36f41SAndroid Build Coastguard Worker            if ret == 1:
309*e4a36f41SAndroid Build Coastguard Worker                break;
310*e4a36f41SAndroid Build Coastguard Worker            # We should never get here.
311*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to import policy")
312*e4a36f41SAndroid Build Coastguard Worker        self.__libsepolwrap.destroy_type_iter(TypeIterP)
313*e4a36f41SAndroid Build Coastguard Worker        return AllTypes
314*e4a36f41SAndroid Build Coastguard Worker
315*e4a36f41SAndroid Build Coastguard Worker    def __ExactMatchPathPrefix(self, pathregex, prefix):
316*e4a36f41SAndroid Build Coastguard Worker        pattern = re.compile('^' + pathregex + "$")
317*e4a36f41SAndroid Build Coastguard Worker        if pattern.match(prefix):
318*e4a36f41SAndroid Build Coastguard Worker            return True
319*e4a36f41SAndroid Build Coastguard Worker        return False
320*e4a36f41SAndroid Build Coastguard Worker
321*e4a36f41SAndroid Build Coastguard Worker    # Return a tuple (prefix, i) where i is the index of the most specific
322*e4a36f41SAndroid Build Coastguard Worker    # match of prefix in the sorted file_contexts. This is useful for limiting a
323*e4a36f41SAndroid Build Coastguard Worker    # file_contexts search to matches that are more specific and omitting less
324*e4a36f41SAndroid Build Coastguard Worker    # specific matches. For example, finding all matches to prefix /data/vendor
325*e4a36f41SAndroid Build Coastguard Worker    # should not include /data(/.*)? if /data/vendor(/.*)? is also specified.
326*e4a36f41SAndroid Build Coastguard Worker    def __FcSortedIndex(self, prefix):
327*e4a36f41SAndroid Build Coastguard Worker        index = 0
328*e4a36f41SAndroid Build Coastguard Worker        for i in range(0, len(self.__FcSorted)):
329*e4a36f41SAndroid Build Coastguard Worker            if self.__ExactMatchPathPrefix(self.__FcSorted[i].path, prefix):
330*e4a36f41SAndroid Build Coastguard Worker                index = i
331*e4a36f41SAndroid Build Coastguard Worker        return prefix, index
332*e4a36f41SAndroid Build Coastguard Worker
333*e4a36f41SAndroid Build Coastguard Worker    # Return a tuple of (path, Type) for all matching paths. Use the sorted
334*e4a36f41SAndroid Build Coastguard Worker    # file_contexts and index returned from __FcSortedIndex() to limit results
335*e4a36f41SAndroid Build Coastguard Worker    # to results that are more specific than the prefix.
336*e4a36f41SAndroid Build Coastguard Worker    def __MatchPathPrefixTypes(self, prefix, index):
337*e4a36f41SAndroid Build Coastguard Worker        PathType = []
338*e4a36f41SAndroid Build Coastguard Worker        for i in range(index, len(self.__FcSorted)):
339*e4a36f41SAndroid Build Coastguard Worker            if MatchPathPrefix(self.__FcSorted[i].path, prefix):
340*e4a36f41SAndroid Build Coastguard Worker                PathType.append((self.__FcSorted[i].path, self.__FcSorted[i].type))
341*e4a36f41SAndroid Build Coastguard Worker        return PathType
342*e4a36f41SAndroid Build Coastguard Worker
343*e4a36f41SAndroid Build Coastguard Worker    # Return types that match MatchPrefixes but do not match
344*e4a36f41SAndroid Build Coastguard Worker    # DoNotMatchPrefixes
345*e4a36f41SAndroid Build Coastguard Worker    def __GetTypesAndFilesByFilePathPrefix(self, MatchPrefixes, DoNotMatchPrefixes):
346*e4a36f41SAndroid Build Coastguard Worker        ret = []
347*e4a36f41SAndroid Build Coastguard Worker
348*e4a36f41SAndroid Build Coastguard Worker        MatchPrefixesWithIndex = []
349*e4a36f41SAndroid Build Coastguard Worker        for MatchPrefix in MatchPrefixes:
350*e4a36f41SAndroid Build Coastguard Worker            MatchPrefixesWithIndex.append(self.__FcSortedIndex(MatchPrefix))
351*e4a36f41SAndroid Build Coastguard Worker
352*e4a36f41SAndroid Build Coastguard Worker        for MatchPrefixWithIndex in MatchPrefixesWithIndex:
353*e4a36f41SAndroid Build Coastguard Worker            PathTypes = self.__MatchPathPrefixTypes(*MatchPrefixWithIndex)
354*e4a36f41SAndroid Build Coastguard Worker            for PathType in PathTypes:
355*e4a36f41SAndroid Build Coastguard Worker                if MatchPathPrefixes(PathType[0], DoNotMatchPrefixes):
356*e4a36f41SAndroid Build Coastguard Worker                    continue
357*e4a36f41SAndroid Build Coastguard Worker                ret.append(PathType)
358*e4a36f41SAndroid Build Coastguard Worker        return ret
359*e4a36f41SAndroid Build Coastguard Worker
360*e4a36f41SAndroid Build Coastguard Worker    def __GetTERules(self, policydbP, avtabIterP, Rules):
361*e4a36f41SAndroid Build Coastguard Worker        if Rules is None:
362*e4a36f41SAndroid Build Coastguard Worker            Rules = set()
363*e4a36f41SAndroid Build Coastguard Worker        buf = create_string_buffer(self.__BUFSIZE)
364*e4a36f41SAndroid Build Coastguard Worker        ret = 0
365*e4a36f41SAndroid Build Coastguard Worker        while True:
366*e4a36f41SAndroid Build Coastguard Worker            ret = self.__libsepolwrap.get_allow_rule(buf, self.__BUFSIZE,
367*e4a36f41SAndroid Build Coastguard Worker                        policydbP, avtabIterP)
368*e4a36f41SAndroid Build Coastguard Worker            if ret == 0:
369*e4a36f41SAndroid Build Coastguard Worker                Rule = TERule(buf.value.decode("ascii"))
370*e4a36f41SAndroid Build Coastguard Worker                Rules.add(Rule)
371*e4a36f41SAndroid Build Coastguard Worker                continue
372*e4a36f41SAndroid Build Coastguard Worker            if ret == 1:
373*e4a36f41SAndroid Build Coastguard Worker                break;
374*e4a36f41SAndroid Build Coastguard Worker            # We should never get here.
375*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to import policy")
376*e4a36f41SAndroid Build Coastguard Worker
377*e4a36f41SAndroid Build Coastguard Worker    def __InitTERules(self):
378*e4a36f41SAndroid Build Coastguard Worker        avtabIterP = self.__libsepolwrap.init_avtab(self.__policydbP)
379*e4a36f41SAndroid Build Coastguard Worker        if (avtabIterP == None):
380*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to initialize avtab")
381*e4a36f41SAndroid Build Coastguard Worker        self.__GetTERules(self.__policydbP, avtabIterP, self.__Rules)
382*e4a36f41SAndroid Build Coastguard Worker        self.__libsepolwrap.destroy_avtab(avtabIterP)
383*e4a36f41SAndroid Build Coastguard Worker        avtabIterP = self.__libsepolwrap.init_cond_avtab(self.__policydbP)
384*e4a36f41SAndroid Build Coastguard Worker        if (avtabIterP == None):
385*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to initialize conditional avtab")
386*e4a36f41SAndroid Build Coastguard Worker        self.__GetTERules(self.__policydbP, avtabIterP, self.__Rules)
387*e4a36f41SAndroid Build Coastguard Worker        self.__libsepolwrap.destroy_avtab(avtabIterP)
388*e4a36f41SAndroid Build Coastguard Worker
389*e4a36f41SAndroid Build Coastguard Worker    def __InitExpandedTERules(self):
390*e4a36f41SAndroid Build Coastguard Worker        avtabIterP = self.__libsepolwrap.init_expanded_avtab(self.__policydbP)
391*e4a36f41SAndroid Build Coastguard Worker        if (avtabIterP == None):
392*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to initialize avtab")
393*e4a36f41SAndroid Build Coastguard Worker        self.__GetTERules(self.__policydbP, avtabIterP, self.__ExpandedRules)
394*e4a36f41SAndroid Build Coastguard Worker        self.__libsepolwrap.destroy_expanded_avtab(avtabIterP)
395*e4a36f41SAndroid Build Coastguard Worker        avtabIterP = self.__libsepolwrap.init_expanded_cond_avtab(self.__policydbP)
396*e4a36f41SAndroid Build Coastguard Worker        if (avtabIterP == None):
397*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to initialize conditional avtab")
398*e4a36f41SAndroid Build Coastguard Worker        self.__GetTERules(self.__policydbP, avtabIterP, self.__ExpandedRules)
399*e4a36f41SAndroid Build Coastguard Worker        self.__libsepolwrap.destroy_expanded_avtab(avtabIterP)
400*e4a36f41SAndroid Build Coastguard Worker
401*e4a36f41SAndroid Build Coastguard Worker    # load ctypes-ified libsepol wrapper
402*e4a36f41SAndroid Build Coastguard Worker    def __InitLibsepolwrap(self, LibPath):
403*e4a36f41SAndroid Build Coastguard Worker        lib = CDLL(LibPath)
404*e4a36f41SAndroid Build Coastguard Worker
405*e4a36f41SAndroid Build Coastguard Worker        # int get_allow_rule(char *out, size_t len, void *policydbp, void *avtab_iterp);
406*e4a36f41SAndroid Build Coastguard Worker        lib.get_allow_rule.restype = c_int
407*e4a36f41SAndroid Build Coastguard Worker        lib.get_allow_rule.argtypes = [c_char_p, c_size_t, c_void_p, c_void_p];
408*e4a36f41SAndroid Build Coastguard Worker        # void *load_policy(const char *policy_path);
409*e4a36f41SAndroid Build Coastguard Worker        lib.load_policy.restype = c_void_p
410*e4a36f41SAndroid Build Coastguard Worker        lib.load_policy.argtypes = [c_char_p]
411*e4a36f41SAndroid Build Coastguard Worker        # void destroy_policy(void *policydbp);
412*e4a36f41SAndroid Build Coastguard Worker        lib.destroy_policy.argtypes = [c_void_p]
413*e4a36f41SAndroid Build Coastguard Worker        # void *init_expanded_avtab(void *policydbp);
414*e4a36f41SAndroid Build Coastguard Worker        lib.init_expanded_avtab.restype = c_void_p
415*e4a36f41SAndroid Build Coastguard Worker        lib.init_expanded_avtab.argtypes = [c_void_p]
416*e4a36f41SAndroid Build Coastguard Worker        # void *init_expanded_cond_avtab(void *policydbp);
417*e4a36f41SAndroid Build Coastguard Worker        lib.init_expanded_cond_avtab.restype = c_void_p
418*e4a36f41SAndroid Build Coastguard Worker        lib.init_expanded_cond_avtab.argtypes = [c_void_p]
419*e4a36f41SAndroid Build Coastguard Worker        # void destroy_expanded_avtab(void *avtab_iterp);
420*e4a36f41SAndroid Build Coastguard Worker        lib.destroy_expanded_avtab.argtypes = [c_void_p]
421*e4a36f41SAndroid Build Coastguard Worker        # void *init_avtab(void *policydbp);
422*e4a36f41SAndroid Build Coastguard Worker        lib.init_avtab.restype = c_void_p
423*e4a36f41SAndroid Build Coastguard Worker        lib.init_avtab.argtypes = [c_void_p]
424*e4a36f41SAndroid Build Coastguard Worker        # void *init_cond_avtab(void *policydbp);
425*e4a36f41SAndroid Build Coastguard Worker        lib.init_cond_avtab.restype = c_void_p
426*e4a36f41SAndroid Build Coastguard Worker        lib.init_cond_avtab.argtypes = [c_void_p]
427*e4a36f41SAndroid Build Coastguard Worker        # void destroy_avtab(void *avtab_iterp);
428*e4a36f41SAndroid Build Coastguard Worker        lib.destroy_avtab.argtypes = [c_void_p]
429*e4a36f41SAndroid Build Coastguard Worker        # int get_type(char *out, size_t max_size, void *policydbp, void *type_iterp);
430*e4a36f41SAndroid Build Coastguard Worker        lib.get_type.restype = c_int
431*e4a36f41SAndroid Build Coastguard Worker        lib.get_type.argtypes = [c_char_p, c_size_t, c_void_p, c_void_p]
432*e4a36f41SAndroid Build Coastguard Worker        # void *init_type_iter(void *policydbp, const char *type, bool is_attr);
433*e4a36f41SAndroid Build Coastguard Worker        lib.init_type_iter.restype = c_void_p
434*e4a36f41SAndroid Build Coastguard Worker        lib.init_type_iter.argtypes = [c_void_p, c_char_p, c_bool]
435*e4a36f41SAndroid Build Coastguard Worker        # void destroy_type_iter(void *type_iterp);
436*e4a36f41SAndroid Build Coastguard Worker        lib.destroy_type_iter.argtypes = [c_void_p]
437*e4a36f41SAndroid Build Coastguard Worker        # void *init_genfs_iter(void *policydbp)
438*e4a36f41SAndroid Build Coastguard Worker        lib.init_genfs_iter.restype = c_void_p
439*e4a36f41SAndroid Build Coastguard Worker        lib.init_genfs_iter.argtypes = [c_void_p]
440*e4a36f41SAndroid Build Coastguard Worker        # int get_genfs(char *out, size_t max_size, void *genfs_iterp);
441*e4a36f41SAndroid Build Coastguard Worker        lib.get_genfs.restype = c_int
442*e4a36f41SAndroid Build Coastguard Worker        lib.get_genfs.argtypes = [c_char_p, c_size_t, c_void_p, c_void_p]
443*e4a36f41SAndroid Build Coastguard Worker        # void destroy_genfs_iter(void *genfs_iterp)
444*e4a36f41SAndroid Build Coastguard Worker        lib.destroy_genfs_iter.argtypes = [c_void_p]
445*e4a36f41SAndroid Build Coastguard Worker
446*e4a36f41SAndroid Build Coastguard Worker        self.__libsepolwrap = lib
447*e4a36f41SAndroid Build Coastguard Worker
448*e4a36f41SAndroid Build Coastguard Worker    def __GenfsDictAdd(self, Dict, buf):
449*e4a36f41SAndroid Build Coastguard Worker        fs, buf = buf.split(' ', 1)
450*e4a36f41SAndroid Build Coastguard Worker        path, context = buf.rsplit(' ', 1)
451*e4a36f41SAndroid Build Coastguard Worker        Type = context.split(":")[2]
452*e4a36f41SAndroid Build Coastguard Worker        if not fs in Dict:
453*e4a36f41SAndroid Build Coastguard Worker            Dict[fs] = {Type}
454*e4a36f41SAndroid Build Coastguard Worker        else:
455*e4a36f41SAndroid Build Coastguard Worker            Dict[fs].add(Type)
456*e4a36f41SAndroid Build Coastguard Worker
457*e4a36f41SAndroid Build Coastguard Worker    def __InitGenfsCon(self):
458*e4a36f41SAndroid Build Coastguard Worker        self.__GenfsDict = {}
459*e4a36f41SAndroid Build Coastguard Worker        GenfsIterP = self.__libsepolwrap.init_genfs_iter(self.__policydbP)
460*e4a36f41SAndroid Build Coastguard Worker        if (GenfsIterP == None):
461*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to retreive genfs entries")
462*e4a36f41SAndroid Build Coastguard Worker        buf = create_string_buffer(self.__BUFSIZE)
463*e4a36f41SAndroid Build Coastguard Worker        while True:
464*e4a36f41SAndroid Build Coastguard Worker            ret = self.__libsepolwrap.get_genfs(buf, self.__BUFSIZE,
465*e4a36f41SAndroid Build Coastguard Worker                        self.__policydbP, GenfsIterP)
466*e4a36f41SAndroid Build Coastguard Worker            if ret == 0:
467*e4a36f41SAndroid Build Coastguard Worker                self.__GenfsDictAdd(self.__GenfsDict, buf.value.decode("ascii"))
468*e4a36f41SAndroid Build Coastguard Worker                continue
469*e4a36f41SAndroid Build Coastguard Worker            if ret == 1:
470*e4a36f41SAndroid Build Coastguard Worker                self.__GenfsDictAdd(self.__GenfsDict, buf.value.decode("ascii"))
471*e4a36f41SAndroid Build Coastguard Worker                break;
472*e4a36f41SAndroid Build Coastguard Worker            # We should never get here.
473*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to get genfs entries")
474*e4a36f41SAndroid Build Coastguard Worker        self.__libsepolwrap.destroy_genfs_iter(GenfsIterP)
475*e4a36f41SAndroid Build Coastguard Worker
476*e4a36f41SAndroid Build Coastguard Worker    # load file_contexts
477*e4a36f41SAndroid Build Coastguard Worker    def __InitFC(self, FcPaths):
478*e4a36f41SAndroid Build Coastguard Worker        self.__FcDict = {}
479*e4a36f41SAndroid Build Coastguard Worker        if FcPaths is None:
480*e4a36f41SAndroid Build Coastguard Worker            return
481*e4a36f41SAndroid Build Coastguard Worker        fc = []
482*e4a36f41SAndroid Build Coastguard Worker        for path in FcPaths:
483*e4a36f41SAndroid Build Coastguard Worker            if not os.path.exists(path):
484*e4a36f41SAndroid Build Coastguard Worker                sys.exit("file_contexts file " + path + " does not exist.")
485*e4a36f41SAndroid Build Coastguard Worker            fd = open(path, "r")
486*e4a36f41SAndroid Build Coastguard Worker            fc += fd.readlines()
487*e4a36f41SAndroid Build Coastguard Worker            fd.close()
488*e4a36f41SAndroid Build Coastguard Worker        for i in fc:
489*e4a36f41SAndroid Build Coastguard Worker            rec = i.split()
490*e4a36f41SAndroid Build Coastguard Worker            try:
491*e4a36f41SAndroid Build Coastguard Worker                t = rec[-1].split(":")[2]
492*e4a36f41SAndroid Build Coastguard Worker                if t in self.__FcDict:
493*e4a36f41SAndroid Build Coastguard Worker                    self.__FcDict[t].append(rec[0])
494*e4a36f41SAndroid Build Coastguard Worker                else:
495*e4a36f41SAndroid Build Coastguard Worker                    self.__FcDict[t] = [rec[0]]
496*e4a36f41SAndroid Build Coastguard Worker            except:
497*e4a36f41SAndroid Build Coastguard Worker                pass
498*e4a36f41SAndroid Build Coastguard Worker        self.__FcSorted = fc_sort.sort(FcPaths)
499*e4a36f41SAndroid Build Coastguard Worker
500*e4a36f41SAndroid Build Coastguard Worker    # load policy
501*e4a36f41SAndroid Build Coastguard Worker    def __InitPolicy(self, PolicyPath):
502*e4a36f41SAndroid Build Coastguard Worker        cPolicyPath = create_string_buffer(PolicyPath.encode("ascii"))
503*e4a36f41SAndroid Build Coastguard Worker        self.__policydbP = self.__libsepolwrap.load_policy(cPolicyPath)
504*e4a36f41SAndroid Build Coastguard Worker        if (self.__policydbP is None):
505*e4a36f41SAndroid Build Coastguard Worker            sys.exit("Failed to load policy")
506*e4a36f41SAndroid Build Coastguard Worker
507*e4a36f41SAndroid Build Coastguard Worker    def __init__(self, PolicyPath, FcPaths, LibPath):
508*e4a36f41SAndroid Build Coastguard Worker        self.__InitLibsepolwrap(LibPath)
509*e4a36f41SAndroid Build Coastguard Worker        self.__InitFC(FcPaths)
510*e4a36f41SAndroid Build Coastguard Worker        self.__InitPolicy(PolicyPath)
511*e4a36f41SAndroid Build Coastguard Worker        self.__InitGenfsCon()
512*e4a36f41SAndroid Build Coastguard Worker
513*e4a36f41SAndroid Build Coastguard Worker    def __del__(self):
514*e4a36f41SAndroid Build Coastguard Worker        if self.__policydbP is not None:
515*e4a36f41SAndroid Build Coastguard Worker            self.__libsepolwrap.destroy_policy(self.__policydbP)
516*e4a36f41SAndroid Build Coastguard Worker
517*e4a36f41SAndroid Build Coastguard WorkercoredomainAllowlist = {
518*e4a36f41SAndroid Build Coastguard Worker        # TODO: how do we make sure vendor_init doesn't have bad coupling with
519*e4a36f41SAndroid Build Coastguard Worker        # /vendor? It is the only system process which is not coredomain.
520*e4a36f41SAndroid Build Coastguard Worker        'vendor_init',
521*e4a36f41SAndroid Build Coastguard Worker        # TODO(b/152813275): need to avoid allowlist for rootdir
522*e4a36f41SAndroid Build Coastguard Worker        "modprobe",
523*e4a36f41SAndroid Build Coastguard Worker        "slideshow",
524*e4a36f41SAndroid Build Coastguard Worker        }
525*e4a36f41SAndroid Build Coastguard Worker
526*e4a36f41SAndroid Build Coastguard Workerclass scontext:
527*e4a36f41SAndroid Build Coastguard Worker    def __init__(self):
528*e4a36f41SAndroid Build Coastguard Worker        self.fromSystem = False
529*e4a36f41SAndroid Build Coastguard Worker        self.fromVendor = False
530*e4a36f41SAndroid Build Coastguard Worker        self.coredomain = False
531*e4a36f41SAndroid Build Coastguard Worker        self.appdomain = False
532*e4a36f41SAndroid Build Coastguard Worker        self.attributes = set()
533*e4a36f41SAndroid Build Coastguard Worker        self.entrypoints = []
534*e4a36f41SAndroid Build Coastguard Worker        self.entrypointpaths = []
535*e4a36f41SAndroid Build Coastguard Worker        self.error = ""
536*e4a36f41SAndroid Build Coastguard Worker
537*e4a36f41SAndroid Build Coastguard Workerclass TestPolicy:
538*e4a36f41SAndroid Build Coastguard Worker    """A policy loaded in memory with its domains easily accessible."""
539*e4a36f41SAndroid Build Coastguard Worker
540*e4a36f41SAndroid Build Coastguard Worker    def __init__(self):
541*e4a36f41SAndroid Build Coastguard Worker        self.alldomains = {}
542*e4a36f41SAndroid Build Coastguard Worker        self.coredomains = set()
543*e4a36f41SAndroid Build Coastguard Worker        self.appdomains = set()
544*e4a36f41SAndroid Build Coastguard Worker        self.vendordomains = set()
545*e4a36f41SAndroid Build Coastguard Worker        self.pol = None
546*e4a36f41SAndroid Build Coastguard Worker
547*e4a36f41SAndroid Build Coastguard Worker        # compat vars
548*e4a36f41SAndroid Build Coastguard Worker        self.alltypes = set()
549*e4a36f41SAndroid Build Coastguard Worker        self.oldalltypes = set()
550*e4a36f41SAndroid Build Coastguard Worker        self.compatMapping = None
551*e4a36f41SAndroid Build Coastguard Worker        self.pubtypes = set()
552*e4a36f41SAndroid Build Coastguard Worker
553*e4a36f41SAndroid Build Coastguard Worker    def GetAllDomains(self):
554*e4a36f41SAndroid Build Coastguard Worker        for result in self.pol.QueryTypeAttribute("domain", True):
555*e4a36f41SAndroid Build Coastguard Worker            self.alldomains[result] = scontext()
556*e4a36f41SAndroid Build Coastguard Worker
557*e4a36f41SAndroid Build Coastguard Worker    def GetAppDomains(self):
558*e4a36f41SAndroid Build Coastguard Worker        for d in self.alldomains:
559*e4a36f41SAndroid Build Coastguard Worker            # The application of the "appdomain" attribute is trusted because core
560*e4a36f41SAndroid Build Coastguard Worker            # selinux policy contains neverallow rules that enforce that only zygote
561*e4a36f41SAndroid Build Coastguard Worker            # and runas spawned processes may transition to processes that have
562*e4a36f41SAndroid Build Coastguard Worker            # the appdomain attribute.
563*e4a36f41SAndroid Build Coastguard Worker            if "appdomain" in self.alldomains[d].attributes:
564*e4a36f41SAndroid Build Coastguard Worker                self.alldomains[d].appdomain = True
565*e4a36f41SAndroid Build Coastguard Worker                self.appdomains.add(d)
566*e4a36f41SAndroid Build Coastguard Worker
567*e4a36f41SAndroid Build Coastguard Worker    def GetCoreDomains(self):
568*e4a36f41SAndroid Build Coastguard Worker        for d in self.alldomains:
569*e4a36f41SAndroid Build Coastguard Worker            domain = self.alldomains[d]
570*e4a36f41SAndroid Build Coastguard Worker            # TestCoredomainViolations will verify if coredomain was incorrectly
571*e4a36f41SAndroid Build Coastguard Worker            # applied.
572*e4a36f41SAndroid Build Coastguard Worker            if "coredomain" in domain.attributes:
573*e4a36f41SAndroid Build Coastguard Worker                domain.coredomain = True
574*e4a36f41SAndroid Build Coastguard Worker                self.coredomains.add(d)
575*e4a36f41SAndroid Build Coastguard Worker            # check whether domains are executed off of /system or /vendor
576*e4a36f41SAndroid Build Coastguard Worker            if d in coredomainAllowlist:
577*e4a36f41SAndroid Build Coastguard Worker                continue
578*e4a36f41SAndroid Build Coastguard Worker            # TODO(b/153112003): add checks to prevent app domains from being
579*e4a36f41SAndroid Build Coastguard Worker            # incorrectly labeled as coredomain. Apps don't have entrypoints as
580*e4a36f41SAndroid Build Coastguard Worker            # they're always dynamically transitioned to by zygote.
581*e4a36f41SAndroid Build Coastguard Worker            if d in self.appdomains:
582*e4a36f41SAndroid Build Coastguard Worker                continue
583*e4a36f41SAndroid Build Coastguard Worker            # TODO(b/153112747): need to handle cases where there is a dynamic
584*e4a36f41SAndroid Build Coastguard Worker            # transition OR there happens to be no context in AOSP files.
585*e4a36f41SAndroid Build Coastguard Worker            if not domain.entrypointpaths:
586*e4a36f41SAndroid Build Coastguard Worker                continue
587*e4a36f41SAndroid Build Coastguard Worker
588*e4a36f41SAndroid Build Coastguard Worker            for path in domain.entrypointpaths:
589*e4a36f41SAndroid Build Coastguard Worker                vendor = any(MatchPathPrefix(path, prefix) for prefix in
590*e4a36f41SAndroid Build Coastguard Worker                             ["/vendor", "/odm"])
591*e4a36f41SAndroid Build Coastguard Worker                system = any(MatchPathPrefix(path, prefix) for prefix in
592*e4a36f41SAndroid Build Coastguard Worker                             ["/init", "/system_ext", "/product" ])
593*e4a36f41SAndroid Build Coastguard Worker
594*e4a36f41SAndroid Build Coastguard Worker                # only mark entrypoint as system if it is not in legacy /system/vendor
595*e4a36f41SAndroid Build Coastguard Worker                if MatchPathPrefix(path, "/system/vendor"):
596*e4a36f41SAndroid Build Coastguard Worker                    vendor = True
597*e4a36f41SAndroid Build Coastguard Worker                elif MatchPathPrefix(path, "/system"):
598*e4a36f41SAndroid Build Coastguard Worker                    system = True
599*e4a36f41SAndroid Build Coastguard Worker
600*e4a36f41SAndroid Build Coastguard Worker                if not vendor and not system:
601*e4a36f41SAndroid Build Coastguard Worker                    domain.error += "Unrecognized entrypoint for " + d + " at " + path + "\n"
602*e4a36f41SAndroid Build Coastguard Worker
603*e4a36f41SAndroid Build Coastguard Worker                domain.fromSystem = domain.fromSystem or system
604*e4a36f41SAndroid Build Coastguard Worker                domain.fromVendor = domain.fromVendor or vendor
605*e4a36f41SAndroid Build Coastguard Worker
606*e4a36f41SAndroid Build Coastguard Worker    ###
607*e4a36f41SAndroid Build Coastguard Worker    # Add the entrypoint type and path(s) to each domain.
608*e4a36f41SAndroid Build Coastguard Worker    #
609*e4a36f41SAndroid Build Coastguard Worker    def GetDomainEntrypoints(self):
610*e4a36f41SAndroid Build Coastguard Worker        for x in self.pol.QueryExpandedTERule(tclass=set(["file"]), perms=set(["entrypoint"])):
611*e4a36f41SAndroid Build Coastguard Worker            if not x.sctx in self.alldomains:
612*e4a36f41SAndroid Build Coastguard Worker                continue
613*e4a36f41SAndroid Build Coastguard Worker            self.alldomains[x.sctx].entrypoints.append(str(x.tctx))
614*e4a36f41SAndroid Build Coastguard Worker            # postinstall_file represents a special case specific to A/B OTAs.
615*e4a36f41SAndroid Build Coastguard Worker            # Update_engine mounts a partition and relabels it postinstall_file.
616*e4a36f41SAndroid Build Coastguard Worker            # There is no file_contexts entry associated with postinstall_file
617*e4a36f41SAndroid Build Coastguard Worker            # so skip the lookup.
618*e4a36f41SAndroid Build Coastguard Worker            if x.tctx == "postinstall_file":
619*e4a36f41SAndroid Build Coastguard Worker                continue
620*e4a36f41SAndroid Build Coastguard Worker            entrypointpath = self.pol.QueryFc(x.tctx)
621*e4a36f41SAndroid Build Coastguard Worker            if not entrypointpath:
622*e4a36f41SAndroid Build Coastguard Worker                continue
623*e4a36f41SAndroid Build Coastguard Worker            self.alldomains[x.sctx].entrypointpaths.extend(entrypointpath)
624*e4a36f41SAndroid Build Coastguard Worker
625*e4a36f41SAndroid Build Coastguard Worker    ###
626*e4a36f41SAndroid Build Coastguard Worker    # Get attributes associated with each domain
627*e4a36f41SAndroid Build Coastguard Worker    #
628*e4a36f41SAndroid Build Coastguard Worker    def GetAttributes(self):
629*e4a36f41SAndroid Build Coastguard Worker        for domain in self.alldomains:
630*e4a36f41SAndroid Build Coastguard Worker            for result in self.pol.QueryTypeAttribute(domain, False):
631*e4a36f41SAndroid Build Coastguard Worker                self.alldomains[domain].attributes.add(result)
632*e4a36f41SAndroid Build Coastguard Worker
633*e4a36f41SAndroid Build Coastguard Worker    def setup(self, pol):
634*e4a36f41SAndroid Build Coastguard Worker        self.pol = pol
635*e4a36f41SAndroid Build Coastguard Worker        self.GetAllDomains()
636*e4a36f41SAndroid Build Coastguard Worker        self.GetAttributes()
637*e4a36f41SAndroid Build Coastguard Worker        self.GetDomainEntrypoints()
638*e4a36f41SAndroid Build Coastguard Worker        self.GetAppDomains()
639*e4a36f41SAndroid Build Coastguard Worker        self.GetCoreDomains()
640*e4a36f41SAndroid Build Coastguard Worker
641*e4a36f41SAndroid Build Coastguard Worker    def GetAllTypes(self, basepol, oldpol):
642*e4a36f41SAndroid Build Coastguard Worker        self.alltypes = basepol.GetAllTypes(False)
643*e4a36f41SAndroid Build Coastguard Worker        self.oldalltypes = oldpol.GetAllTypes(False)
644*e4a36f41SAndroid Build Coastguard Worker
645*e4a36f41SAndroid Build Coastguard Worker    # setup for the policy compatibility tests
646*e4a36f41SAndroid Build Coastguard Worker    def compatSetup(self, basepol, oldpol, mapping, types):
647*e4a36f41SAndroid Build Coastguard Worker        self.GetAllTypes(basepol, oldpol)
648*e4a36f41SAndroid Build Coastguard Worker        self.compatMapping = mapping
649*e4a36f41SAndroid Build Coastguard Worker        self.pubtypes = types
650*e4a36f41SAndroid Build Coastguard Worker
651*e4a36f41SAndroid Build Coastguard Worker    def DomainsWithAttribute(self, attr):
652*e4a36f41SAndroid Build Coastguard Worker        domains = []
653*e4a36f41SAndroid Build Coastguard Worker        for domain in self.alldomains:
654*e4a36f41SAndroid Build Coastguard Worker            if attr in self.alldomains[domain].attributes:
655*e4a36f41SAndroid Build Coastguard Worker                domains.append(domain)
656*e4a36f41SAndroid Build Coastguard Worker        return domains
657*e4a36f41SAndroid Build Coastguard Worker
658*e4a36f41SAndroid Build Coastguard Worker    def PrintScontexts(self):
659*e4a36f41SAndroid Build Coastguard Worker        for d in sorted(self.alldomains.keys()):
660*e4a36f41SAndroid Build Coastguard Worker            sctx = self.alldomains[d]
661*e4a36f41SAndroid Build Coastguard Worker            print(d)
662*e4a36f41SAndroid Build Coastguard Worker            print("\tcoredomain="+str(sctx.coredomain))
663*e4a36f41SAndroid Build Coastguard Worker            print("\tappdomain="+str(sctx.appdomain))
664*e4a36f41SAndroid Build Coastguard Worker            print("\tfromSystem="+str(sctx.fromSystem))
665*e4a36f41SAndroid Build Coastguard Worker            print("\tfromVendor="+str(sctx.fromVendor))
666*e4a36f41SAndroid Build Coastguard Worker            print("\tattributes="+str(sctx.attributes))
667*e4a36f41SAndroid Build Coastguard Worker            print("\tentrypoints="+str(sctx.entrypoints))
668*e4a36f41SAndroid Build Coastguard Worker            print("\tentrypointpaths=")
669*e4a36f41SAndroid Build Coastguard Worker            if sctx.entrypointpaths is not None:
670*e4a36f41SAndroid Build Coastguard Worker                for path in sctx.entrypointpaths:
671*e4a36f41SAndroid Build Coastguard Worker                    print("\t\t"+str(path))
672