Home | History | Annotate | Download | only in tests
      1 from os.path import basename
      2 import re
      3 import sys
      4 
      5 # A very limited parser whose job is to process the compatibility mapping
      6 # files and retrieve type and attribute information until proper support is
      7 # built into libsepol
      8 
      9 # get the text in the next matching parens
     10 
     11 class MiniCilParser:
     12     types = set() # types declared in mapping
     13     pubtypes = set()
     14     typeattributes = set() # attributes declared in mapping
     15     typeattributesets = {} # sets defined in mapping
     16     rTypeattributesets = {} # reverse mapping of above sets
     17     apiLevel = None
     18 
     19     def _getNextStmt(self, infile):
     20         parens = 0
     21         s = ""
     22         c = infile.read(1)
     23         # get to first statement
     24         while c and c != "(":
     25             c = infile.read(1)
     26 
     27         parens += 1
     28         c = infile.read(1)
     29         while c and parens != 0:
     30             s += c
     31             c = infile.read(1)
     32             if c == ';':
     33                 # comment, get rid of rest of the line
     34                 while c != '\n':
     35                     c = infile.read(1)
     36             elif c == '(':
     37                 parens += 1
     38             elif c == ')':
     39                 parens -= 1
     40         return s
     41 
     42     def _parseType(self, stmt):
     43         m = re.match(r"type\s+(.+)", stmt)
     44         self.types.add(m.group(1))
     45         return
     46 
     47     def _parseTypeattribute(self, stmt):
     48         m = re.match(r"typeattribute\s+(.+)", stmt)
     49         self.typeattributes.add(m.group(1))
     50         return
     51 
     52     def _parseTypeattributeset(self, stmt):
     53         m = re.match(r"typeattributeset\s+(.+?)\s+\((.+?)\)", stmt, flags = re.M |re.S)
     54         ta = m.group(1)
     55         # this isn't proper expression parsing, but will do for our
     56         # current use
     57         tas = m.group(2).split()
     58 
     59         if self.typeattributesets.get(ta) is None:
     60             self.typeattributesets[ta] = set()
     61         self.typeattributesets[ta].update(set(tas))
     62         for t in tas:
     63             if self.rTypeattributesets.get(t) is None:
     64                 self.rTypeattributesets[t] = set()
     65             self.rTypeattributesets[t].update(set(ta))
     66 
     67         # check to see if this typeattributeset is a versioned public type
     68         pub = re.match(r"(\w+)_\d+_\d+", ta)
     69         if pub is not None:
     70             self.pubtypes.add(pub.group(1))
     71         return
     72 
     73     def _parseStmt(self, stmt):
     74         if re.match(r"type\s+.+", stmt):
     75             self._parseType(stmt)
     76         elif re.match(r"typeattribute\s+.+", stmt):
     77             self._parseTypeattribute(stmt)
     78         elif re.match(r"typeattributeset\s+.+", stmt):
     79             self._parseTypeattributeset(stmt)
     80         else:
     81             m = re.match(r"(\w+)\s+.+", stmt)
     82             ret = "Warning: Unknown statement type (" + m.group(1) + ") in "
     83             ret += "mapping file, perhaps consider adding support for it in "
     84             ret += "system/sepolicy/tests/mini_parser.py!\n"
     85             print ret
     86         return
     87 
     88     def __init__(self, policyFile):
     89         with open(policyFile, 'r') as infile:
     90             s = self._getNextStmt(infile)
     91             while s:
     92                 self._parseStmt(s)
     93                 s = self._getNextStmt(infile)
     94         fn = basename(policyFile)
     95         m = re.match(r"(\d+\.\d+).+\.cil", fn)
     96         self.apiLevel = m.group(1)
     97 
     98 if __name__ == '__main__':
     99     f = sys.argv[1]
    100     p = MiniCilParser(f)
    101