blob: cba9e39c025bc31484a79bf579a5144fa747dc18 [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()
Tri Vo438684b2018-09-29 17:47:10 -070015 self.expandtypeattributes = {}
Tri Voe3f4f772018-09-28 17:21:08 -070016 self.typeattributes = set() # attributes declared in mapping
17 self.typeattributesets = {} # sets defined in mapping
18 self.rTypeattributesets = {} # reverse mapping of above sets
19 self.apiLevel = None
20
21 with open(policyFile, 'r') as infile:
22 s = self._getNextStmt(infile)
23 while s:
24 self._parseStmt(s)
25 s = self._getNextStmt(infile)
26 fn = basename(policyFile)
27 m = re.match(r"(\d+\.\d+).+\.cil", fn)
28 if m:
29 self.apiLevel = m.group(1)
Dan Cashman91d398d2017-09-26 12:58:29 -070030
Tri Vo438684b2018-09-29 17:47:10 -070031 def unparse(self):
32 def wrapParens(stmt):
33 return "(" + stmt + ")"
34
35 def joinWrapParens(entries):
36 return wrapParens(" ".join(entries))
37
38 result = ""
39 for ty in sorted(self.types):
40 result += joinWrapParens(["type", ty]) + "\n"
41
42 for ta in sorted(self.typeattributes):
43 result += joinWrapParens(["typeattribute", ta]) + "\n"
44
45 for eta in sorted(self.expandtypeattributes.items(),
46 key=lambda x: x[0]):
47 result += joinWrapParens(
48 ["expandtypeattribute", wrapParens(eta[0]), eta[1]]) + "\n"
49
50 for tas in sorted(self.typeattributesets.items(), key=lambda x: x[0]):
51 result += joinWrapParens(
52 ["typeattributeset", tas[0],
53 joinWrapParens(sorted(tas[1]))]) + "\n"
54
55 return result
56
Dan Cashman91d398d2017-09-26 12:58:29 -070057 def _getNextStmt(self, infile):
58 parens = 0
59 s = ""
60 c = infile.read(1)
61 # get to first statement
62 while c and c != "(":
63 c = infile.read(1)
64
65 parens += 1
66 c = infile.read(1)
67 while c and parens != 0:
68 s += c
69 c = infile.read(1)
70 if c == ';':
71 # comment, get rid of rest of the line
72 while c != '\n':
73 c = infile.read(1)
74 elif c == '(':
75 parens += 1
76 elif c == ')':
77 parens -= 1
78 return s
79
80 def _parseType(self, stmt):
81 m = re.match(r"type\s+(.+)", stmt)
82 self.types.add(m.group(1))
83 return
84
Tri Vo438684b2018-09-29 17:47:10 -070085 def _parseExpandtypeattribute(self, stmt):
86 m = re.match(r"expandtypeattribute\s+\((.+)\)\s+(true|false)", stmt)
87 self.expandtypeattributes[m.group(1)] = m.group(2)
88 return
89
Dan Cashman91d398d2017-09-26 12:58:29 -070090 def _parseTypeattribute(self, stmt):
91 m = re.match(r"typeattribute\s+(.+)", stmt)
92 self.typeattributes.add(m.group(1))
93 return
94
95 def _parseTypeattributeset(self, stmt):
96 m = re.match(r"typeattributeset\s+(.+?)\s+\((.+?)\)", stmt, flags = re.M |re.S)
97 ta = m.group(1)
98 # this isn't proper expression parsing, but will do for our
99 # current use
100 tas = m.group(2).split()
101
102 if self.typeattributesets.get(ta) is None:
103 self.typeattributesets[ta] = set()
104 self.typeattributesets[ta].update(set(tas))
105 for t in tas:
106 if self.rTypeattributesets.get(t) is None:
107 self.rTypeattributesets[t] = set()
Tri Vo438684b2018-09-29 17:47:10 -0700108 self.rTypeattributesets[t].update([ta])
Dan Cashman91d398d2017-09-26 12:58:29 -0700109
110 # check to see if this typeattributeset is a versioned public type
111 pub = re.match(r"(\w+)_\d+_\d+", ta)
112 if pub is not None:
113 self.pubtypes.add(pub.group(1))
114 return
115
116 def _parseStmt(self, stmt):
117 if re.match(r"type\s+.+", stmt):
118 self._parseType(stmt)
119 elif re.match(r"typeattribute\s+.+", stmt):
120 self._parseTypeattribute(stmt)
121 elif re.match(r"typeattributeset\s+.+", stmt):
122 self._parseTypeattributeset(stmt)
Tri Vo438684b2018-09-29 17:47:10 -0700123 elif re.match(r"expandtypeattribute\s+.+", stmt):
124 self._parseExpandtypeattribute(stmt)
Dan Cashman91d398d2017-09-26 12:58:29 -0700125 return
126
Dan Cashman91d398d2017-09-26 12:58:29 -0700127if __name__ == '__main__':
128 f = sys.argv[1]
129 p = MiniCilParser(f)