mini_parser.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. from os.path import basename
  2. import re
  3. import sys
  4. # A very limited parser whose job is to process the compatibility mapping
  5. # files and retrieve type and attribute information until proper support is
  6. # built into libsepol
  7. # get the text in the next matching parens
  8. class MiniCilParser:
  9. def __init__(self, policyFile):
  10. self.types = set() # types declared in mapping
  11. self.pubtypes = set()
  12. self.expandtypeattributes = {}
  13. self.typeattributes = set() # attributes declared in mapping
  14. self.typeattributesets = {} # sets defined in mapping
  15. self.rTypeattributesets = {} # reverse mapping of above sets
  16. self.apiLevel = None
  17. with open(policyFile, 'r') as infile:
  18. s = self._getNextStmt(infile)
  19. while s:
  20. self._parseStmt(s)
  21. s = self._getNextStmt(infile)
  22. fn = basename(policyFile)
  23. m = re.match(r"(\d+\.\d+).+\.cil", fn)
  24. if m:
  25. self.apiLevel = m.group(1)
  26. def unparse(self):
  27. def wrapParens(stmt):
  28. return "(" + stmt + ")"
  29. def joinWrapParens(entries):
  30. return wrapParens(" ".join(entries))
  31. result = ""
  32. for ty in sorted(self.types):
  33. result += joinWrapParens(["type", ty]) + "\n"
  34. for ta in sorted(self.typeattributes):
  35. result += joinWrapParens(["typeattribute", ta]) + "\n"
  36. for eta in sorted(self.expandtypeattributes.items(),
  37. key=lambda x: x[0]):
  38. result += joinWrapParens(
  39. ["expandtypeattribute", wrapParens(eta[0]), eta[1]]) + "\n"
  40. for tas in sorted(self.typeattributesets.items(), key=lambda x: x[0]):
  41. result += joinWrapParens(
  42. ["typeattributeset", tas[0],
  43. joinWrapParens(sorted(tas[1]))]) + "\n"
  44. return result
  45. def _getNextStmt(self, infile):
  46. parens = 0
  47. s = ""
  48. c = infile.read(1)
  49. # get to first statement
  50. while c and c != "(":
  51. c = infile.read(1)
  52. parens += 1
  53. c = infile.read(1)
  54. while c and parens != 0:
  55. s += c
  56. c = infile.read(1)
  57. if c == ';':
  58. # comment, get rid of rest of the line
  59. while c != '\n':
  60. c = infile.read(1)
  61. elif c == '(':
  62. parens += 1
  63. elif c == ')':
  64. parens -= 1
  65. return s
  66. def _parseType(self, stmt):
  67. m = re.match(r"type\s+(.+)", stmt)
  68. self.types.add(m.group(1))
  69. return
  70. def _parseExpandtypeattribute(self, stmt):
  71. m = re.match(r"expandtypeattribute\s+\((.+)\)\s+(true|false)", stmt)
  72. self.expandtypeattributes[m.group(1)] = m.group(2)
  73. return
  74. def _parseTypeattribute(self, stmt):
  75. m = re.match(r"typeattribute\s+(.+)", stmt)
  76. self.typeattributes.add(m.group(1))
  77. return
  78. def _parseTypeattributeset(self, stmt):
  79. m = re.match(r"typeattributeset\s+(.+?)\s+\((.+?)\)", stmt, flags = re.M |re.S)
  80. ta = m.group(1)
  81. # this isn't proper expression parsing, but will do for our
  82. # current use
  83. tas = m.group(2).split()
  84. if self.typeattributesets.get(ta) is None:
  85. self.typeattributesets[ta] = set()
  86. self.typeattributesets[ta].update(set(tas))
  87. for t in tas:
  88. if self.rTypeattributesets.get(t) is None:
  89. self.rTypeattributesets[t] = set()
  90. self.rTypeattributesets[t].update([ta])
  91. # check to see if this typeattributeset is a versioned public type
  92. pub = re.match(r"(\w+)_\d+_\d+", ta)
  93. if pub is not None:
  94. self.pubtypes.add(pub.group(1))
  95. return
  96. def _parseStmt(self, stmt):
  97. if re.match(r"type\s+.+", stmt):
  98. self._parseType(stmt)
  99. elif re.match(r"typeattribute\s+.+", stmt):
  100. self._parseTypeattribute(stmt)
  101. elif re.match(r"typeattributeset\s+.+", stmt):
  102. self._parseTypeattributeset(stmt)
  103. elif re.match(r"expandtypeattribute\s+.+", stmt):
  104. self._parseExpandtypeattribute(stmt)
  105. return
  106. if __name__ == '__main__':
  107. f = sys.argv[1]
  108. p = MiniCilParser(f)