blob: b51ebf2370548f8a933408968b25b953d10b334f [file] [log] [blame]
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -07001from ctypes import *
2import re
3import os
Jeff Vander Stoep1fc06822017-05-31 15:36:07 -07004import sys
Jeff Vander Stoepe9777e32017-09-23 15:11:25 -07005import platform
Jeff Vander Stoep370a52f2018-02-08 09:54:59 -08006import FcSort
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -07007
Dan Cashman91d398d2017-09-26 12:58:29 -07008###
9# Check whether the regex will match a file path starting with the provided
10# prefix
11#
12# Compares regex entries in file_contexts with a path prefix. Regex entries
13# are often more specific than this file prefix. For example, the regex could
14# be /system/bin/foo\.sh and the prefix could be /system. This function
15# loops over the regex removing characters from the end until
16# 1) there is a match - return True or 2) run out of characters - return
17# False.
18#
19def MatchPathPrefix(pathregex, prefix):
20 for i in range(len(pathregex), 0, -1):
21 try:
22 pattern = re.compile('^' + pathregex[0:i] + "$")
23 except:
24 continue
25 if pattern.match(prefix):
26 return True
27 return False
28
29def MatchPathPrefixes(pathregex, Prefixes):
30 for Prefix in Prefixes:
31 if MatchPathPrefix(pathregex, Prefix):
32 return True
33 return False
34
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -070035class TERule:
36 def __init__(self, rule):
37 data = rule.split(',')
38 self.flavor = data[0]
39 self.sctx = data[1]
40 self.tctx = data[2]
41 self.tclass = data[3]
42 self.perms = set((data[4].strip()).split(' '))
43 self.rule = rule
44
45class Policy:
Dan Cashman91d398d2017-09-26 12:58:29 -070046 __ExpandedRules = set()
47 __Rules = set()
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -070048 __FcDict = None
Jeff Vander Stoep370a52f2018-02-08 09:54:59 -080049 __FcSorted = None
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -070050 __libsepolwrap = None
51 __policydbP = None
Dan Cashman91d398d2017-09-26 12:58:29 -070052 __BUFSIZE = 2048
53
Jeff Vander Stoep370a52f2018-02-08 09:54:59 -080054 def AssertPathTypesDoNotHaveAttr(self, MatchPrefix, DoNotMatchPrefix, Attr):
55 # Query policy for the types associated with Attr
56 TypesPol = self.QueryTypeAttribute(Attr, True)
57 # Search file_contexts to find types associated with input paths.
58 TypesFc = self.__GetTypesByFilePathPrefix(MatchPrefix, DoNotMatchPrefix)
59 violators = TypesFc.intersection(TypesPol)
60 ret = ""
61 if len(violators) > 0:
62 ret += "The following types on "
63 ret += " ".join(str(x) for x in sorted(MatchPrefix))
64 ret += " must not be associated with the "
65 ret += "\"" + Attr + "\" attribute: "
66 ret += " ".join(str(x) for x in sorted(violators)) + "\n"
67 return ret
68
Dan Cashman91d398d2017-09-26 12:58:29 -070069 # Check that path prefixes that match MatchPrefix, and do not Match
70 # DoNotMatchPrefix have the attribute Attr.
71 # For example assert that all types in /sys, and not in /sys/kernel/debugfs
72 # have the sysfs_type attribute.
73 def AssertPathTypesHaveAttr(self, MatchPrefix, DoNotMatchPrefix, Attr):
74 # Query policy for the types associated with Attr
75 TypesPol = self.QueryTypeAttribute(Attr, True)
76 # Search file_contexts to find paths/types that should be associated with
77 # Attr.
78 TypesFc = self.__GetTypesByFilePathPrefix(MatchPrefix, DoNotMatchPrefix)
79 violators = TypesFc.difference(TypesPol)
80
81 ret = ""
82 if len(violators) > 0:
83 ret += "The following types on "
84 ret += " ".join(str(x) for x in sorted(MatchPrefix))
85 ret += " must be associated with the "
86 ret += "\"" + Attr + "\" attribute: "
87 ret += " ".join(str(x) for x in sorted(violators)) + "\n"
88 return ret
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -070089
90 # Return all file_contexts entries that map to the input Type.
91 def QueryFc(self, Type):
92 if Type in self.__FcDict:
93 return self.__FcDict[Type]
94 else:
95 return None
96
97 # Return all attributes associated with a type if IsAttr=False or
98 # all types associated with an attribute if IsAttr=True
99 def QueryTypeAttribute(self, Type, IsAttr):
Dan Cashman91d398d2017-09-26 12:58:29 -0700100 TypeIterP = self.__libsepolwrap.init_type_iter(self.__policydbP,
101 create_string_buffer(Type), IsAttr)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700102 if (TypeIterP == None):
103 sys.exit("Failed to initialize type iterator")
Dan Cashman91d398d2017-09-26 12:58:29 -0700104 buf = create_string_buffer(self.__BUFSIZE)
105 TypeAttr = set()
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700106 while True:
Dan Cashman91d398d2017-09-26 12:58:29 -0700107 ret = self.__libsepolwrap.get_type(buf, self.__BUFSIZE,
108 self.__policydbP, TypeIterP)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700109 if ret == 0:
Dan Cashman91d398d2017-09-26 12:58:29 -0700110 TypeAttr.add(buf.value)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700111 continue
112 if ret == 1:
113 break;
114 # We should never get here.
115 sys.exit("Failed to import policy")
Dan Cashman91d398d2017-09-26 12:58:29 -0700116 self.__libsepolwrap.destroy_type_iter(TypeIterP)
117 return TypeAttr
118
119 def __TERuleMatch(self, Rule, **kwargs):
120 # Match source type
121 if ("scontext" in kwargs and
122 len(kwargs['scontext']) > 0 and
123 Rule.sctx not in kwargs['scontext']):
124 return False
125 # Match target type
126 if ("tcontext" in kwargs and
127 len(kwargs['tcontext']) > 0 and
128 Rule.tctx not in kwargs['tcontext']):
129 return False
130 # Match target class
131 if ("tclass" in kwargs and
132 len(kwargs['tclass']) > 0 and
133 not bool(set([Rule.tclass]) & kwargs['tclass'])):
134 return False
135 # Match any perms
136 if ("perms" in kwargs and
137 len(kwargs['perms']) > 0 and
138 not bool(Rule.perms & kwargs['perms'])):
139 return False
140 return True
141
142 # resolve a type to its attributes or
143 # resolve an attribute to its types and attributes
144 # For example if scontext is the domain attribute, then we need to
145 # include all types with the domain attribute such as untrusted_app and
146 # priv_app and all the attributes of those types such as appdomain.
147 def ResolveTypeAttribute(self, Type):
148 types = self.GetAllTypes(False)
149 attributes = self.GetAllTypes(True)
150
151 if Type in types:
152 return self.QueryTypeAttribute(Type, False)
153 elif Type in attributes:
154 TypesAndAttributes = set()
155 Types = self.QueryTypeAttribute(Type, True)
156 TypesAndAttributes |= Types
157 for T in Types:
158 TypesAndAttributes |= self.QueryTypeAttribute(T, False)
159 return TypesAndAttributes
160 else:
161 return set()
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700162
163 # Return all TERules that match:
164 # (any scontext) or (any tcontext) or (any tclass) or (any perms),
165 # perms.
166 # Any unspecified paramenter will match all.
167 #
168 # Example: QueryTERule(tcontext=["foo", "bar"], perms=["entrypoint"])
169 # Will return any rule with:
170 # (tcontext="foo" or tcontext="bar") and ("entrypoint" in perms)
171 def QueryTERule(self, **kwargs):
Dan Cashman91d398d2017-09-26 12:58:29 -0700172 if len(self.__Rules) == 0:
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700173 self.__InitTERules()
Dan Cashman91d398d2017-09-26 12:58:29 -0700174
175 # add any matching types and attributes for scontext and tcontext
176 if ("scontext" in kwargs and len(kwargs['scontext']) > 0):
177 scontext = set()
178 for sctx in kwargs['scontext']:
179 scontext |= self.ResolveTypeAttribute(sctx)
180 kwargs['scontext'] = scontext
181 if ("tcontext" in kwargs and len(kwargs['tcontext']) > 0):
182 tcontext = set()
183 for tctx in kwargs['tcontext']:
184 tcontext |= self.ResolveTypeAttribute(tctx)
185 kwargs['tcontext'] = tcontext
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700186 for Rule in self.__Rules:
Dan Cashman91d398d2017-09-26 12:58:29 -0700187 if self.__TERuleMatch(Rule, **kwargs):
188 yield Rule
189
190 # Same as QueryTERule but only using the expanded ruleset.
191 # i.e. all attributes have been expanded to their various types.
192 def QueryExpandedTERule(self, **kwargs):
193 if len(self.__ExpandedRules) == 0:
194 self.__InitExpandedTERules()
195 for Rule in self.__ExpandedRules:
196 if self.__TERuleMatch(Rule, **kwargs):
197 yield Rule
198
199 def GetAllTypes(self, isAttr):
200 TypeIterP = self.__libsepolwrap.init_type_iter(self.__policydbP, None, isAttr)
201 if (TypeIterP == None):
202 sys.exit("Failed to initialize type iterator")
203 buf = create_string_buffer(self.__BUFSIZE)
204 AllTypes = set()
205 while True:
206 ret = self.__libsepolwrap.get_type(buf, self.__BUFSIZE,
207 self.__policydbP, TypeIterP)
208 if ret == 0:
209 AllTypes.add(buf.value)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700210 continue
Dan Cashman91d398d2017-09-26 12:58:29 -0700211 if ret == 1:
212 break;
213 # We should never get here.
214 sys.exit("Failed to import policy")
215 self.__libsepolwrap.destroy_type_iter(TypeIterP)
216 return AllTypes
217
Jeff Vander Stoep370a52f2018-02-08 09:54:59 -0800218 def __ExactMatchPathPrefix(self, pathregex, prefix):
219 pattern = re.compile('^' + pathregex + "$")
220 if pattern.match(prefix):
221 return True
222 return False
223
224 # Return a tuple (prefix, i) where i is the index of the most specific
225 # match of prefix in the sorted file_contexts. This is useful for limiting a
226 # file_contexts search to matches that are more specific and omitting less
227 # specific matches. For example, finding all matches to prefix /data/vendor
228 # should not include /data(/.*)? if /data/vendor(/.*)? is also specified.
229 def __FcSortedIndex(self, prefix):
230 index = 0
231 for i in range(0, len(self.__FcSorted)):
232 if self.__ExactMatchPathPrefix(self.__FcSorted[i].path, prefix):
233 index = i
234 return prefix, index
235
236 # Return a tuple of (path, Type) for all matching paths. Use the sorted
237 # file_contexts and index returned from __FcSortedIndex() to limit results
238 # to results that are more specific than the prefix.
239 def __MatchPathPrefixTypes(self, prefix, index):
240 PathType = []
241 for i in range(index, len(self.__FcSorted)):
242 if MatchPathPrefix(self.__FcSorted[i].path, prefix):
243 PathType.append((self.__FcSorted[i].path, self.__FcSorted[i].Type))
244 return PathType
245
246 # Return types that match MatchPrefixes but do not match
247 # DoNotMatchPrefixes
Dan Cashman91d398d2017-09-26 12:58:29 -0700248 def __GetTypesByFilePathPrefix(self, MatchPrefixes, DoNotMatchPrefixes):
249 Types = set()
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700250
Jeff Vander Stoep370a52f2018-02-08 09:54:59 -0800251 MatchPrefixesWithIndex = []
252 for MatchPrefix in MatchPrefixes:
253 MatchPrefixesWithIndex.append(self.__FcSortedIndex(MatchPrefix))
254
255 for MatchPrefixWithIndex in MatchPrefixesWithIndex:
256 PathTypes = self.__MatchPathPrefixTypes(*MatchPrefixWithIndex)
257 for PathType in PathTypes:
258 if MatchPathPrefixes(PathType[0], DoNotMatchPrefixes):
259 continue
260 Types.add(PathType[1])
261 return Types
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700262
Dan Cashman91d398d2017-09-26 12:58:29 -0700263 def __GetTERules(self, policydbP, avtabIterP, Rules):
264 if Rules is None:
265 Rules = set()
266 buf = create_string_buffer(self.__BUFSIZE)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700267 ret = 0
268 while True:
Dan Cashman91d398d2017-09-26 12:58:29 -0700269 ret = self.__libsepolwrap.get_allow_rule(buf, self.__BUFSIZE,
270 policydbP, avtabIterP)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700271 if ret == 0:
272 Rule = TERule(buf.value)
Dan Cashman91d398d2017-09-26 12:58:29 -0700273 Rules.add(Rule)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700274 continue
275 if ret == 1:
276 break;
277 # We should never get here.
278 sys.exit("Failed to import policy")
279
280 def __InitTERules(self):
Dan Cashman91d398d2017-09-26 12:58:29 -0700281 avtabIterP = self.__libsepolwrap.init_avtab(self.__policydbP)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700282 if (avtabIterP == None):
283 sys.exit("Failed to initialize avtab")
Dan Cashman91d398d2017-09-26 12:58:29 -0700284 self.__GetTERules(self.__policydbP, avtabIterP, self.__Rules)
285 self.__libsepolwrap.destroy_avtab(avtabIterP)
286 avtabIterP = self.__libsepolwrap.init_cond_avtab(self.__policydbP)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700287 if (avtabIterP == None):
288 sys.exit("Failed to initialize conditional avtab")
Dan Cashman91d398d2017-09-26 12:58:29 -0700289 self.__GetTERules(self.__policydbP, avtabIterP, self.__Rules)
290 self.__libsepolwrap.destroy_avtab(avtabIterP)
291
292 def __InitExpandedTERules(self):
293 avtabIterP = self.__libsepolwrap.init_expanded_avtab(self.__policydbP)
294 if (avtabIterP == None):
295 sys.exit("Failed to initialize avtab")
296 self.__GetTERules(self.__policydbP, avtabIterP, self.__ExpandedRules)
297 self.__libsepolwrap.destroy_expanded_avtab(avtabIterP)
298 avtabIterP = self.__libsepolwrap.init_expanded_cond_avtab(self.__policydbP)
299 if (avtabIterP == None):
300 sys.exit("Failed to initialize conditional avtab")
301 self.__GetTERules(self.__policydbP, avtabIterP, self.__ExpandedRules)
302 self.__libsepolwrap.destroy_expanded_avtab(avtabIterP)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700303
304 # load ctypes-ified libsepol wrapper
Jeff Vander Stoep1fc06822017-05-31 15:36:07 -0700305 def __InitLibsepolwrap(self, LibPath):
Jeff Vander Stoep3ca843a2017-10-04 09:42:29 -0700306 lib = CDLL(LibPath)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700307
Dan Cashman91d398d2017-09-26 12:58:29 -0700308 # int get_allow_rule(char *out, size_t len, void *policydbp, void *avtab_iterp);
309 lib.get_allow_rule.restype = c_int
310 lib.get_allow_rule.argtypes = [c_char_p, c_size_t, c_void_p, c_void_p];
311 # void *load_policy(const char *policy_path);
312 lib.load_policy.restype = c_void_p
313 lib.load_policy.argtypes = [c_char_p]
314 # void destroy_policy(void *policydbp);
315 lib.destroy_policy.argtypes = [c_void_p]
316 # void *init_expanded_avtab(void *policydbp);
317 lib.init_expanded_avtab.restype = c_void_p
318 lib.init_expanded_avtab.argtypes = [c_void_p]
319 # void *init_expanded_cond_avtab(void *policydbp);
320 lib.init_expanded_cond_avtab.restype = c_void_p
321 lib.init_expanded_cond_avtab.argtypes = [c_void_p]
322 # void destroy_expanded_avtab(void *avtab_iterp);
323 lib.destroy_expanded_avtab.argtypes = [c_void_p]
324 # void *init_avtab(void *policydbp);
325 lib.init_avtab.restype = c_void_p
326 lib.init_avtab.argtypes = [c_void_p]
327 # void *init_cond_avtab(void *policydbp);
328 lib.init_cond_avtab.restype = c_void_p
329 lib.init_cond_avtab.argtypes = [c_void_p]
330 # void destroy_avtab(void *avtab_iterp);
331 lib.destroy_avtab.argtypes = [c_void_p]
332 # int get_type(char *out, size_t max_size, void *policydbp, void *type_iterp);
333 lib.get_type.restype = c_int
334 lib.get_type.argtypes = [c_char_p, c_size_t, c_void_p, c_void_p]
335 # void *init_type_iter(void *policydbp, const char *type, bool is_attr);
336 lib.init_type_iter.restype = c_void_p
337 lib.init_type_iter.argtypes = [c_void_p, c_char_p, c_bool]
338 # void destroy_type_iter(void *type_iterp);
339 lib.destroy_type_iter.argtypes = [c_void_p]
340
341 self.__libsepolwrap = lib
342
343
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700344 # load file_contexts
345 def __InitFC(self, FcPaths):
Dan Cashman91d398d2017-09-26 12:58:29 -0700346 if FcPaths is None:
347 return
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700348 fc = []
349 for path in FcPaths:
350 if not os.path.exists(path):
351 sys.exit("file_contexts file " + path + " does not exist.")
352 fd = open(path, "r")
353 fc += fd.readlines()
354 fd.close()
355 self.__FcDict = {}
356 for i in fc:
357 rec = i.split()
358 try:
359 t = rec[-1].split(":")[2]
360 if t in self.__FcDict:
361 self.__FcDict[t].append(rec[0])
362 else:
363 self.__FcDict[t] = [rec[0]]
364 except:
365 pass
Jeff Vander Stoep370a52f2018-02-08 09:54:59 -0800366 self.__FcSorted = FcSort.FcSort(FcPaths)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700367
368 # load policy
369 def __InitPolicy(self, PolicyPath):
Dan Cashman91d398d2017-09-26 12:58:29 -0700370 cPolicyPath = create_string_buffer(PolicyPath)
371 self.__policydbP = self.__libsepolwrap.load_policy(cPolicyPath)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700372 if (self.__policydbP is None):
373 sys.exit("Failed to load policy")
374
Jeff Vander Stoep1fc06822017-05-31 15:36:07 -0700375 def __init__(self, PolicyPath, FcPaths, LibPath):
376 self.__InitLibsepolwrap(LibPath)
Jeff Vander Stoepbdfc0302017-05-25 09:53:47 -0700377 self.__InitFC(FcPaths)
378 self.__InitPolicy(PolicyPath)
379
380 def __del__(self):
381 if self.__policydbP is not None:
Dan Cashman91d398d2017-09-26 12:58:29 -0700382 self.__libsepolwrap.destroy_policy(self.__policydbP)