• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     def __init__(self, policyFile):
13         self.types = set() # types declared in mapping
14         self.pubtypes = set()
15         self.expandtypeattributes = {}
16         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)
30 
31     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 
57     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 
85     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 
90     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()
108             self.rTypeattributesets[t].update([ta])
109 
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)
123         elif re.match(r"expandtypeattribute\s+.+", stmt):
124             self._parseExpandtypeattribute(stmt)
125         return
126 
127 if __name__ == '__main__':
128     f = sys.argv[1]
129     p = MiniCilParser(f)
130