| from os.path import basename |
| import re |
| import sys |
| |
| # A very limited parser whose job is to process the compatibility mapping |
| # files and retrieve type and attribute information until proper support is |
| # built into libsepol |
| |
| # get the text in the next matching parens |
| |
| class MiniCilParser: |
| def __init__(self, policyFile): |
| self.types = set() # types declared in mapping |
| self.pubtypes = set() |
| self.typeattributes = set() # attributes declared in mapping |
| self.typeattributesets = {} # sets defined in mapping |
| self.rTypeattributesets = {} # reverse mapping of above sets |
| self.apiLevel = None |
| |
| with open(policyFile, 'r') as infile: |
| s = self._getNextStmt(infile) |
| while s: |
| self._parseStmt(s) |
| s = self._getNextStmt(infile) |
| fn = basename(policyFile) |
| m = re.match(r"(\d+\.\d+).+\.cil", fn) |
| if m: |
| self.apiLevel = m.group(1) |
| |
| def _getNextStmt(self, infile): |
| parens = 0 |
| s = "" |
| c = infile.read(1) |
| # get to first statement |
| while c and c != "(": |
| c = infile.read(1) |
| |
| parens += 1 |
| c = infile.read(1) |
| while c and parens != 0: |
| s += c |
| c = infile.read(1) |
| if c == ';': |
| # comment, get rid of rest of the line |
| while c != '\n': |
| c = infile.read(1) |
| elif c == '(': |
| parens += 1 |
| elif c == ')': |
| parens -= 1 |
| return s |
| |
| def _parseType(self, stmt): |
| m = re.match(r"type\s+(.+)", stmt) |
| self.types.add(m.group(1)) |
| return |
| |
| def _parseTypeattribute(self, stmt): |
| m = re.match(r"typeattribute\s+(.+)", stmt) |
| self.typeattributes.add(m.group(1)) |
| return |
| |
| def _parseTypeattributeset(self, stmt): |
| m = re.match(r"typeattributeset\s+(.+?)\s+\((.+?)\)", stmt, flags = re.M |re.S) |
| ta = m.group(1) |
| # this isn't proper expression parsing, but will do for our |
| # current use |
| tas = m.group(2).split() |
| |
| if self.typeattributesets.get(ta) is None: |
| self.typeattributesets[ta] = set() |
| self.typeattributesets[ta].update(set(tas)) |
| for t in tas: |
| if self.rTypeattributesets.get(t) is None: |
| self.rTypeattributesets[t] = set() |
| self.rTypeattributesets[t].update(set(ta)) |
| |
| # check to see if this typeattributeset is a versioned public type |
| pub = re.match(r"(\w+)_\d+_\d+", ta) |
| if pub is not None: |
| self.pubtypes.add(pub.group(1)) |
| return |
| |
| def _parseStmt(self, stmt): |
| if re.match(r"type\s+.+", stmt): |
| self._parseType(stmt) |
| elif re.match(r"typeattribute\s+.+", stmt): |
| self._parseTypeattribute(stmt) |
| elif re.match(r"typeattributeset\s+.+", stmt): |
| self._parseTypeattributeset(stmt) |
| return |
| |
| if __name__ == '__main__': |
| f = sys.argv[1] |
| p = MiniCilParser(f) |