1 from ctypes import * 2 import re 3 import os 4 import sys 5 6 ### 7 # Check whether the regex will match a file path starting with the provided 8 # prefix 9 # 10 # Compares regex entries in file_contexts with a path prefix. Regex entries 11 # are often more specific than this file prefix. For example, the regex could 12 # be /system/bin/foo\.sh and the prefix could be /system. This function 13 # loops over the regex removing characters from the end until 14 # 1) there is a match - return True or 2) run out of characters - return 15 # False. 16 # 17 def MatchPathPrefix(pathregex, prefix): 18 for i in range(len(pathregex), 0, -1): 19 try: 20 pattern = re.compile('^' + pathregex[0:i] + "$") 21 except: 22 continue 23 if pattern.match(prefix): 24 return True 25 return False 26 27 def MatchPathPrefixes(pathregex, Prefixes): 28 for Prefix in Prefixes: 29 if MatchPathPrefix(pathregex, Prefix): 30 return True 31 return False 32 33 class TERule: 34 def __init__(self, rule): 35 data = rule.split(',') 36 self.flavor = data[0] 37 self.sctx = data[1] 38 self.tctx = data[2] 39 self.tclass = data[3] 40 self.perms = set((data[4].strip()).split(' ')) 41 self.rule = rule 42 43 class Policy: 44 __Rules = None 45 __FcDict = None 46 __libsepolwrap = None 47 __policydbP = None 48 __BUFSIZE = 2048 49 50 # Check that path prefixes that match MatchPrefix, and do not Match 51 # DoNotMatchPrefix have the attribute Attr. 52 # For example assert that all types in /sys, and not in /sys/kernel/debugfs 53 # have the sysfs_type attribute. 54 def AssertPathTypesHaveAttr(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 paths/types that should be associated with 58 # Attr. 59 TypesFc = self.__GetTypesByFilePathPrefix(MatchPrefix, DoNotMatchPrefix) 60 violators = TypesFc.difference(TypesPol) 61 62 ret = "" 63 if len(violators) > 0: 64 ret += "The following types on " 65 ret += " ".join(str(x) for x in sorted(MatchPrefix)) 66 ret += " must be associated with the " 67 ret += "\"" + Attr + "\" attribute: " 68 ret += " ".join(str(x) for x in sorted(violators)) + "\n" 69 return ret 70 71 # Return all file_contexts entries that map to the input Type. 72 def QueryFc(self, Type): 73 if Type in self.__FcDict: 74 return self.__FcDict[Type] 75 else: 76 return None 77 78 # Return all attributes associated with a type if IsAttr=False or 79 # all types associated with an attribute if IsAttr=True 80 def QueryTypeAttribute(self, Type, IsAttr): 81 TypeIterP = self.__libsepolwrap.init_type_iter(self.__policydbP, 82 create_string_buffer(Type), IsAttr) 83 if (TypeIterP == None): 84 sys.exit("Failed to initialize type iterator") 85 buf = create_string_buffer(self.__BUFSIZE) 86 TypeAttr = set() 87 while True: 88 ret = self.__libsepolwrap.get_type(buf, self.__BUFSIZE, 89 self.__policydbP, TypeIterP) 90 if ret == 0: 91 TypeAttr.add(buf.value) 92 continue 93 if ret == 1: 94 break; 95 # We should never get here. 96 sys.exit("Failed to import policy") 97 self.__libsepolwrap.destroy_type_iter(TypeIterP) 98 return TypeAttr 99 100 # Return all TERules that match: 101 # (any scontext) or (any tcontext) or (any tclass) or (any perms), 102 # perms. 103 # Any unspecified paramenter will match all. 104 # 105 # Example: QueryTERule(tcontext=["foo", "bar"], perms=["entrypoint"]) 106 # Will return any rule with: 107 # (tcontext="foo" or tcontext="bar") and ("entrypoint" in perms) 108 def QueryTERule(self, **kwargs): 109 if self.__Rules is None: 110 self.__InitTERules() 111 for Rule in self.__Rules: 112 # Match source type 113 if "scontext" in kwargs and Rule.sctx not in kwargs['scontext']: 114 continue 115 # Match target type 116 if "tcontext" in kwargs and Rule.tctx not in kwargs['tcontext']: 117 continue 118 # Match target class 119 if "tclass" in kwargs and Rule.tclass not in kwargs['tclass']: 120 continue 121 # Match any perms 122 if "perms" in kwargs and not bool(Rule.perms & set(kwargs['perms'])): 123 continue 124 yield Rule 125 126 127 def GetAllTypes(self, isAttr): 128 TypeIterP = self.__libsepolwrap.init_type_iter(self.__policydbP, None, isAttr) 129 if (TypeIterP == None): 130 sys.exit("Failed to initialize type iterator") 131 buf = create_string_buffer(self.__BUFSIZE) 132 AllTypes = set() 133 while True: 134 ret = self.__libsepolwrap.get_type(buf, self.__BUFSIZE, 135 self.__policydbP, TypeIterP) 136 if ret == 0: 137 AllTypes.add(buf.value) 138 continue 139 if ret == 1: 140 break; 141 # We should never get here. 142 sys.exit("Failed to import policy") 143 self.__libsepolwrap.destroy_type_iter(TypeIterP) 144 return AllTypes 145 146 def __GetTypesByFilePathPrefix(self, MatchPrefixes, DoNotMatchPrefixes): 147 Types = set() 148 for Type in self.__FcDict: 149 for pathregex in self.__FcDict[Type]: 150 if not MatchPathPrefixes(pathregex, MatchPrefixes): 151 continue 152 if MatchPathPrefixes(pathregex, DoNotMatchPrefixes): 153 continue 154 Types.add(Type) 155 return Types 156 157 158 def __GetTERules(self, policydbP, avtabIterP): 159 if self.__Rules is None: 160 self.__Rules = set() 161 buf = create_string_buffer(self.__BUFSIZE) 162 ret = 0 163 while True: 164 ret = self.__libsepolwrap.get_allow_rule(buf, self.__BUFSIZE, 165 policydbP, avtabIterP) 166 if ret == 0: 167 Rule = TERule(buf.value) 168 self.__Rules.add(Rule) 169 continue 170 if ret == 1: 171 break; 172 # We should never get here. 173 sys.exit("Failed to import policy") 174 175 def __InitTERules(self): 176 avtabIterP = self.__libsepolwrap.init_avtab(self.__policydbP) 177 if (avtabIterP == None): 178 sys.exit("Failed to initialize avtab") 179 self.__GetTERules(self.__policydbP, avtabIterP) 180 self.__libsepolwrap.destroy_avtab(avtabIterP) 181 avtabIterP = self.__libsepolwrap.init_cond_avtab(self.__policydbP) 182 if (avtabIterP == None): 183 sys.exit("Failed to initialize conditional avtab") 184 self.__GetTERules(self.__policydbP, avtabIterP) 185 self.__libsepolwrap.destroy_avtab(avtabIterP) 186 187 # load ctypes-ified libsepol wrapper 188 def __InitLibsepolwrap(self, LibPath): 189 if "linux" in sys.platform: 190 lib = CDLL(LibPath + "/libsepolwrap.so") 191 elif "darwin" in sys.platform: 192 lib = CDLL(LibPath + "/libsepolwrap.dylib") 193 else: 194 sys.exit("only Linux and Mac currrently supported") 195 196 # int get_allow_rule(char *out, size_t len, void *policydbp, void *avtab_iterp); 197 lib.get_allow_rule.restype = c_int 198 lib.get_allow_rule.argtypes = [c_char_p, c_size_t, c_void_p, c_void_p]; 199 # void *load_policy(const char *policy_path); 200 lib.load_policy.restype = c_void_p 201 lib.load_policy.argtypes = [c_char_p] 202 # void destroy_policy(void *policydbp); 203 lib.destroy_policy.argtypes = [c_void_p] 204 # void *init_avtab(void *policydbp); 205 lib.init_avtab.restype = c_void_p 206 lib.init_avtab.argtypes = [c_void_p] 207 # void *init_cond_avtab(void *policydbp); 208 lib.init_cond_avtab.restype = c_void_p 209 lib.init_cond_avtab.argtypes = [c_void_p] 210 # void destroy_avtab(void *avtab_iterp); 211 lib.destroy_avtab.argtypes = [c_void_p] 212 # int get_type(char *out, size_t max_size, void *policydbp, void *type_iterp); 213 lib.get_type.restype = c_int 214 lib.get_type.argtypes = [c_char_p, c_size_t, c_void_p, c_void_p] 215 # void *init_type_iter(void *policydbp, const char *type, bool is_attr); 216 lib.init_type_iter.restype = c_void_p 217 lib.init_type_iter.argtypes = [c_void_p, c_char_p, c_bool] 218 # void destroy_type_iter(void *type_iterp); 219 lib.destroy_type_iter.argtypes = [c_void_p] 220 221 self.__libsepolwrap = lib 222 223 224 # load file_contexts 225 def __InitFC(self, FcPaths): 226 if FcPaths is None: 227 return 228 fc = [] 229 for path in FcPaths: 230 if not os.path.exists(path): 231 sys.exit("file_contexts file " + path + " does not exist.") 232 fd = open(path, "r") 233 fc += fd.readlines() 234 fd.close() 235 self.__FcDict = {} 236 for i in fc: 237 rec = i.split() 238 try: 239 t = rec[-1].split(":")[2] 240 if t in self.__FcDict: 241 self.__FcDict[t].append(rec[0]) 242 else: 243 self.__FcDict[t] = [rec[0]] 244 except: 245 pass 246 247 # load policy 248 def __InitPolicy(self, PolicyPath): 249 cPolicyPath = create_string_buffer(PolicyPath) 250 self.__policydbP = self.__libsepolwrap.load_policy(cPolicyPath) 251 if (self.__policydbP is None): 252 sys.exit("Failed to load policy") 253 254 def __init__(self, PolicyPath, FcPaths, LibPath): 255 self.__InitLibsepolwrap(LibPath) 256 self.__InitFC(FcPaths) 257 self.__InitPolicy(PolicyPath) 258 259 def __del__(self): 260 if self.__policydbP is not None: 261 self.__libsepolwrap.destroy_policy(self.__policydbP) 262