blob: 9182c5d1e40f0a17b057e9ef56793d6a11ba1207 [file] [log] [blame]
Dan Cashman91d398d2017-09-26 12:58:29 -07001from os.path import basename
2import re
3import 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
11class MiniCilParser:
Tri Voe3f4f772018-09-28 17:21:08 -070012 def __init__(self, policyFile):
13 self.types = set() # types declared in mapping
14 self.pubtypes = set()
15 self.typeattributes = set() # attributes declared in mapping
16 self.typeattributesets = {} # sets defined in mapping
17 self.rTypeattributesets = {} # reverse mapping of above sets
18 self.apiLevel = None
19
20 with open(policyFile, 'r') as infile:
21 s = self._getNextStmt(infile)
22 while s:
23 self._parseStmt(s)
24 s = self._getNextStmt(infile)
25 fn = basename(policyFile)
26 m = re.match(r"(\d+\.\d+).+\.cil", fn)
27 if m:
28 self.apiLevel = m.group(1)
Dan Cashman91d398d2017-09-26 12:58:29 -070029
30 def _getNextStmt(self, infile):
31 parens = 0
32 s = ""
33 c = infile.read(1)
34 # get to first statement
35 while c and c != "(":
36 c = infile.read(1)
37
38 parens += 1
39 c = infile.read(1)
40 while c and parens != 0:
41 s += c
42 c = infile.read(1)
43 if c == ';':
44 # comment, get rid of rest of the line
45 while c != '\n':
46 c = infile.read(1)
47 elif c == '(':
48 parens += 1
49 elif c == ')':
50 parens -= 1
51 return s
52
53 def _parseType(self, stmt):
54 m = re.match(r"type\s+(.+)", stmt)
55 self.types.add(m.group(1))
56 return
57
58 def _parseTypeattribute(self, stmt):
59 m = re.match(r"typeattribute\s+(.+)", stmt)
60 self.typeattributes.add(m.group(1))
61 return
62
63 def _parseTypeattributeset(self, stmt):
64 m = re.match(r"typeattributeset\s+(.+?)\s+\((.+?)\)", stmt, flags = re.M |re.S)
65 ta = m.group(1)
66 # this isn't proper expression parsing, but will do for our
67 # current use
68 tas = m.group(2).split()
69
70 if self.typeattributesets.get(ta) is None:
71 self.typeattributesets[ta] = set()
72 self.typeattributesets[ta].update(set(tas))
73 for t in tas:
74 if self.rTypeattributesets.get(t) is None:
75 self.rTypeattributesets[t] = set()
76 self.rTypeattributesets[t].update(set(ta))
77
78 # check to see if this typeattributeset is a versioned public type
79 pub = re.match(r"(\w+)_\d+_\d+", ta)
80 if pub is not None:
81 self.pubtypes.add(pub.group(1))
82 return
83
84 def _parseStmt(self, stmt):
85 if re.match(r"type\s+.+", stmt):
86 self._parseType(stmt)
87 elif re.match(r"typeattribute\s+.+", stmt):
88 self._parseTypeattribute(stmt)
89 elif re.match(r"typeattributeset\s+.+", stmt):
90 self._parseTypeattributeset(stmt)
Dan Cashman91d398d2017-09-26 12:58:29 -070091 return
92
Dan Cashman91d398d2017-09-26 12:58:29 -070093if __name__ == '__main__':
94 f = sys.argv[1]
95 p = MiniCilParser(f)