blob: 25018a76d7dd307656661029b0574bbf06deeeed [file] [log] [blame]
ThiƩbaud Weksteenf24b4572021-11-26 09:12:41 +11001# Copyright 2021 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Dan Cashman91d398d2017-09-26 12:58:29 -070015from os.path import basename
16import re
17import sys
18
19# A very limited parser whose job is to process the compatibility mapping
20# files and retrieve type and attribute information until proper support is
21# built into libsepol
22
Dan Cashman91d398d2017-09-26 12:58:29 -070023class MiniCilParser:
Tri Voe3f4f772018-09-28 17:21:08 -070024 def __init__(self, policyFile):
25 self.types = set() # types declared in mapping
26 self.pubtypes = set()
Tri Vo438684b2018-09-29 17:47:10 -070027 self.expandtypeattributes = {}
Tri Voe3f4f772018-09-28 17:21:08 -070028 self.typeattributes = set() # attributes declared in mapping
29 self.typeattributesets = {} # sets defined in mapping
30 self.rTypeattributesets = {} # reverse mapping of above sets
31 self.apiLevel = None
32
33 with open(policyFile, 'r') as infile:
34 s = self._getNextStmt(infile)
35 while s:
36 self._parseStmt(s)
37 s = self._getNextStmt(infile)
38 fn = basename(policyFile)
39 m = re.match(r"(\d+\.\d+).+\.cil", fn)
40 if m:
41 self.apiLevel = m.group(1)
Dan Cashman91d398d2017-09-26 12:58:29 -070042
Tri Vo438684b2018-09-29 17:47:10 -070043 def unparse(self):
44 def wrapParens(stmt):
45 return "(" + stmt + ")"
46
47 def joinWrapParens(entries):
48 return wrapParens(" ".join(entries))
49
50 result = ""
51 for ty in sorted(self.types):
52 result += joinWrapParens(["type", ty]) + "\n"
53
54 for ta in sorted(self.typeattributes):
55 result += joinWrapParens(["typeattribute", ta]) + "\n"
56
57 for eta in sorted(self.expandtypeattributes.items(),
58 key=lambda x: x[0]):
59 result += joinWrapParens(
60 ["expandtypeattribute", wrapParens(eta[0]), eta[1]]) + "\n"
61
62 for tas in sorted(self.typeattributesets.items(), key=lambda x: x[0]):
63 result += joinWrapParens(
64 ["typeattributeset", tas[0],
65 joinWrapParens(sorted(tas[1]))]) + "\n"
66
67 return result
68
Dan Cashman91d398d2017-09-26 12:58:29 -070069 def _getNextStmt(self, infile):
70 parens = 0
71 s = ""
72 c = infile.read(1)
73 # get to first statement
74 while c and c != "(":
75 c = infile.read(1)
76
77 parens += 1
78 c = infile.read(1)
79 while c and parens != 0:
80 s += c
81 c = infile.read(1)
82 if c == ';':
83 # comment, get rid of rest of the line
84 while c != '\n':
85 c = infile.read(1)
86 elif c == '(':
87 parens += 1
88 elif c == ')':
89 parens -= 1
90 return s
91
92 def _parseType(self, stmt):
93 m = re.match(r"type\s+(.+)", stmt)
94 self.types.add(m.group(1))
95 return
96
Tri Vo438684b2018-09-29 17:47:10 -070097 def _parseExpandtypeattribute(self, stmt):
98 m = re.match(r"expandtypeattribute\s+\((.+)\)\s+(true|false)", stmt)
99 self.expandtypeattributes[m.group(1)] = m.group(2)
100 return
101
Dan Cashman91d398d2017-09-26 12:58:29 -0700102 def _parseTypeattribute(self, stmt):
103 m = re.match(r"typeattribute\s+(.+)", stmt)
104 self.typeattributes.add(m.group(1))
105 return
106
107 def _parseTypeattributeset(self, stmt):
108 m = re.match(r"typeattributeset\s+(.+?)\s+\((.+?)\)", stmt, flags = re.M |re.S)
109 ta = m.group(1)
110 # this isn't proper expression parsing, but will do for our
111 # current use
112 tas = m.group(2).split()
113
114 if self.typeattributesets.get(ta) is None:
115 self.typeattributesets[ta] = set()
116 self.typeattributesets[ta].update(set(tas))
117 for t in tas:
118 if self.rTypeattributesets.get(t) is None:
119 self.rTypeattributesets[t] = set()
Tri Vo438684b2018-09-29 17:47:10 -0700120 self.rTypeattributesets[t].update([ta])
Dan Cashman91d398d2017-09-26 12:58:29 -0700121
122 # check to see if this typeattributeset is a versioned public type
123 pub = re.match(r"(\w+)_\d+_\d+", ta)
124 if pub is not None:
125 self.pubtypes.add(pub.group(1))
126 return
127
128 def _parseStmt(self, stmt):
129 if re.match(r"type\s+.+", stmt):
130 self._parseType(stmt)
131 elif re.match(r"typeattribute\s+.+", stmt):
132 self._parseTypeattribute(stmt)
133 elif re.match(r"typeattributeset\s+.+", stmt):
134 self._parseTypeattributeset(stmt)
Tri Vo438684b2018-09-29 17:47:10 -0700135 elif re.match(r"expandtypeattribute\s+.+", stmt):
136 self._parseExpandtypeattribute(stmt)
Dan Cashman91d398d2017-09-26 12:58:29 -0700137 return
138
Dan Cashman91d398d2017-09-26 12:58:29 -0700139if __name__ == '__main__':
140 f = sys.argv[1]
141 p = MiniCilParser(f)