Home | History | Annotate | Download | only in tests
      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