afd3fd
diff --git sepolgen-1.2.3/ChangeLog sepolgen-1.2.3/ChangeLog
afd3fd
index 7cc0a18..bda7a2e 100644
afd3fd
--- sepolgen-1.2.3/ChangeLog
afd3fd
+++ sepolgen-1.2.3/ChangeLog
afd3fd
@@ -1,3 +1,6 @@
afd3fd
+	* Remove additional files when cleaning, from Nicolas Iooss.
afd3fd
+	* Add support for TYPEBOUNDS statement in INTERFACE policy files, from Miroslav Grepl.
afd3fd
+
afd3fd
 1.2.3 2016-02-23
afd3fd
 	* Support latest refpolicy interfaces, from Nicolas Iooss.
afd3fd
 	* Make sepolgen-ifgen output deterministic with Python>=3.3, from Nicolas Iooss.
afd3fd
diff --git sepolgen-1.2.3/src/sepolgen/Makefile sepolgen-1.2.3/src/sepolgen/Makefile
afd3fd
index 9ac7651..d3aa771 100644
afd3fd
--- sepolgen-1.2.3/src/sepolgen/Makefile
afd3fd
+++ sepolgen-1.2.3/src/sepolgen/Makefile
afd3fd
@@ -11,5 +11,4 @@ install: all
afd3fd
 clean:
afd3fd
 	rm -f parser.out parsetab.py
afd3fd
 	rm -f *~ *.pyc
afd3fd
-
afd3fd
-
afd3fd
+	rm -rf __pycache__
afd3fd
diff --git sepolgen-1.2.3/src/sepolgen/access.py sepolgen-1.2.3/src/sepolgen/access.py
afd3fd
index a5d8698..7606561 100644
afd3fd
--- sepolgen-1.2.3/src/sepolgen/access.py
afd3fd
+++ sepolgen-1.2.3/src/sepolgen/access.py
afd3fd
@@ -90,6 +90,8 @@ class AccessVector(util.Comparison):
afd3fd
             self.audit_msgs = []
afd3fd
             self.type = audit2why.TERULE
afd3fd
             self.data = []
afd3fd
+            self.obj_path = None
afd3fd
+            self.base_type = None
afd3fd
         # when implementing __eq__ also __hash__ is needed on py2
afd3fd
         # if object is muttable __hash__ should be None
afd3fd
         self.__hash__ = None
afd3fd
@@ -138,6 +140,29 @@ class AccessVector(util.Comparison):
afd3fd
         return "allow %s %s:%s %s;" % (self.src_type, self.tgt_type,
afd3fd
                                         self.obj_class, self.perms.to_space_str())
afd3fd
 
afd3fd
+    def base_file_type(self):
afd3fd
+        base_type_array = []
afd3fd
+        base_type_array = [self.base_type, self.tgt_type, self.src_type]
afd3fd
+        return base_type_array
afd3fd
+
afd3fd
+    def __cmp__(self, other):
afd3fd
+        if self.src_type != other.src_type:
afd3fd
+            return cmp(self.src_type, other.src_type)
afd3fd
+        if self.tgt_type != other.tgt_type:
afd3fd
+            return cmp(self.tgt_type, other.tgt_type)
afd3fd
+        if self.obj_class != self.obj_class:
afd3fd
+            return cmp(self.obj_class, other.obj_class)
afd3fd
+        if len(self.perms) != len(other.perms):
afd3fd
+            return cmp(len(self.perms), len(other.perms))
afd3fd
+        x = list(self.perms)
afd3fd
+        x.sort()
afd3fd
+        y = list(other.perms)
afd3fd
+        y.sort()
afd3fd
+        for pa, pb in zip(x, y):
afd3fd
+            if pa != pb:
afd3fd
+                return cmp(pa, pb)
afd3fd
+        return 0
afd3fd
+
afd3fd
     def _compare(self, other, method):
afd3fd
         try:
afd3fd
             x = list(self.perms)
afd3fd
@@ -257,7 +282,8 @@ class AccessVectorSet:
afd3fd
         for av in l:
afd3fd
             self.add_av(AccessVector(av))
afd3fd
 
afd3fd
-    def add(self, src_type, tgt_type, obj_class, perms, audit_msg=None, avc_type=audit2why.TERULE, data=[]):
afd3fd
+    def add(self, src_type, tgt_type, obj_class, perms, obj_path=None,
afd3fd
+            base_type=None, audit_msg=None, avc_type=audit2why.TERULE, data=[]):
afd3fd
         """Add an access vector to the set.
afd3fd
         """
afd3fd
         tgt = self.src.setdefault(src_type, { })
afd3fd
@@ -270,7 +296,9 @@ class AccessVectorSet:
afd3fd
             access.src_type = src_type
afd3fd
             access.tgt_type = tgt_type
afd3fd
             access.obj_class = obj_class
afd3fd
+            access.obj_path = obj_path
afd3fd
             access.data = data
afd3fd
+            access.base_type = base_type
afd3fd
             access.type = avc_type
afd3fd
             cls[obj_class, avc_type] = access
afd3fd
 
afd3fd
diff --git sepolgen-1.2.3/src/sepolgen/audit.py sepolgen-1.2.3/src/sepolgen/audit.py
afd3fd
index 724d3ea..ef1f6cc 100644
afd3fd
--- sepolgen-1.2.3/src/sepolgen/audit.py
afd3fd
+++ sepolgen-1.2.3/src/sepolgen/audit.py
afd3fd
@@ -176,6 +176,7 @@ class AVCMessage(AuditMessage):
afd3fd
         self.exe = ""
afd3fd
         self.path = ""
afd3fd
         self.name = ""
afd3fd
+        self.ino = ""
afd3fd
         self.accesses = []
afd3fd
         self.denial = True
afd3fd
         self.type = audit2why.TERULE
afd3fd
@@ -237,6 +238,10 @@ class AVCMessage(AuditMessage):
afd3fd
                 self.exe = fields[1][1:-1]
afd3fd
             elif fields[0] == "name":
afd3fd
                 self.name = fields[1][1:-1]
afd3fd
+            elif fields[0] == "path":
afd3fd
+                self.path = fields[1][1:-1]
afd3fd
+            elif fields[0] == "ino":
afd3fd
+                self.ino = fields[1]
afd3fd
 
afd3fd
         if not found_src or not found_tgt or not found_class or not found_access:
afd3fd
             raise ValueError("AVC message in invalid format [%s]\n" % self.message)
afd3fd
@@ -361,7 +366,9 @@ class AuditParser:
afd3fd
         self.path_msgs = []
afd3fd
         self.by_header = { }
afd3fd
         self.check_input_file = False
afd3fd
-                
afd3fd
+        self.inode_dict = { }
afd3fd
+        self.__store_base_types()
afd3fd
+
afd3fd
     # Low-level parsing function - tries to determine if this audit
afd3fd
     # message is an SELinux related message and then parses it into
afd3fd
     # the appropriate AuditMessage subclass. This function deliberately
afd3fd
@@ -376,7 +383,9 @@ class AuditParser:
afd3fd
     #   AuditMessage (or subclass) - object representing a parsed
afd3fd
     #      and valid audit message.
afd3fd
     def __parse_line(self, line):
afd3fd
-        rec = line.split()
afd3fd
+        # strip("\x1c\x1d\x1e\x85") is only needed for python2
afd3fd
+        # since str.split() in python3 already does this
afd3fd
+        rec = [x.strip("\x1c\x1d\x1e\x85") for x in line.split()]
afd3fd
         for i in rec:
afd3fd
             found = False
afd3fd
             if i == "avc:" or i == "message=avc:" or i == "msg='avc:":
afd3fd
@@ -499,6 +508,61 @@ class AuditParser:
afd3fd
         
afd3fd
         return role_types
afd3fd
 
afd3fd
+    def __restore_path(self, name, inode):
afd3fd
+        import subprocess
afd3fd
+        import os
afd3fd
+        path = ""
afd3fd
+        # Optimizing
afd3fd
+        if name == "" or inode == "":
afd3fd
+            return path
afd3fd
+        for d in self.inode_dict:
afd3fd
+            if d == inode and self.inode_dict[d] == name:
afd3fd
+                return path
afd3fd
+            if d == inode and self.inode_dict[d] != name:
afd3fd
+                return self.inode_dict[d]
afd3fd
+        if inode not in self.inode_dict.keys():
afd3fd
+            self.inode_dict[inode] = name
afd3fd
+
afd3fd
+        command = "locate -b '\%s'" % name
afd3fd
+        try:
afd3fd
+            output = subprocess.check_output(command,
afd3fd
+                                             stderr=subprocess.STDOUT,
afd3fd
+                                             shell=True,
afd3fd
+                                             universal_newlines=True)
afd3fd
+            try:
afd3fd
+                ino = int(inode)
afd3fd
+            except ValueError:
afd3fd
+                pass
afd3fd
+            for file in output.split("\n"):
afd3fd
+                try:
afd3fd
+                    if int(os.lstat(file).st_ino) == ino:
afd3fd
+                        self.inode_dict[inode] = path = file
afd3fd
+                        return path
afd3fd
+                except:
afd3fd
+                    pass
afd3fd
+        except subprocess.CalledProcessError as e:
afd3fd
+            pass
afd3fd
+        return path
afd3fd
+
afd3fd
+    def __store_base_types(self):
afd3fd
+        import sepolicy
afd3fd
+        self.base_types = sepolicy.get_types_from_attribute("base_file_type")
afd3fd
+
afd3fd
+    def __get_base_type(self, tcontext, scontext):
afd3fd
+        import sepolicy
afd3fd
+        # Prevent unnecessary searching
afd3fd
+        if (self.old_scontext == scontext and
afd3fd
+            self.old_tcontext == tcontext):
afd3fd
+            return
afd3fd
+        self.old_scontext = scontext
afd3fd
+        self.old_tcontext = tcontext
afd3fd
+        for btype in self.base_types:
afd3fd
+            if btype == tcontext:
afd3fd
+                for writable in sepolicy.get_writable_files(scontext):
afd3fd
+                    if writable.endswith(tcontext) and writable.startswith(scontext.rstrip("_t")):
afd3fd
+                        return writable
afd3fd
+                return 0
afd3fd
+
afd3fd
     def to_access(self, avc_filter=None, only_denials=True):
afd3fd
         """Convert the audit logs access into a an access vector set.
afd3fd
 
afd3fd
@@ -517,16 +581,23 @@ class AuditParser:
afd3fd
            audit logs parsed by this object.
afd3fd
         """
afd3fd
         av_set = access.AccessVectorSet()
afd3fd
+        self.old_scontext = ""
afd3fd
+        self.old_tcontext = ""
afd3fd
         for avc in self.avc_msgs:
afd3fd
             if avc.denial != True and only_denials:
afd3fd
                 continue
afd3fd
+            base_type = self.__get_base_type(avc.tcontext.type, avc.scontext.type)
afd3fd
+            if avc.path == "":
afd3fd
+                avc.path = self.__restore_path(avc.name, avc.ino)
afd3fd
             if avc_filter:
afd3fd
                 if avc_filter.filter(avc):
afd3fd
                     av_set.add(avc.scontext.type, avc.tcontext.type, avc.tclass,
afd3fd
-                               avc.accesses, avc, avc_type=avc.type, data=avc.data)
afd3fd
+                               avc.accesses, avc.path, base_type, avc,
afd3fd
+                               avc_type=avc.type, data=avc.data)
afd3fd
             else:
afd3fd
                 av_set.add(avc.scontext.type, avc.tcontext.type, avc.tclass,
afd3fd
-                           avc.accesses, avc, avc_type=avc.type, data=avc.data)
afd3fd
+                           avc.accesses, avc.path, base_type, avc,
afd3fd
+                           avc_type=avc.type, data=avc.data)
afd3fd
         return av_set
afd3fd
 
afd3fd
 class AVCTypeFilter:
afd3fd
diff --git sepolgen-1.2.3/src/sepolgen/policygen.py sepolgen-1.2.3/src/sepolgen/policygen.py
afd3fd
index 34c8401..f374132 100644
afd3fd
--- sepolgen-1.2.3/src/sepolgen/policygen.py
afd3fd
+++ sepolgen-1.2.3/src/sepolgen/policygen.py
afd3fd
@@ -82,8 +82,9 @@ class PolicyGenerator:
afd3fd
             self.module = refpolicy.Module()
afd3fd
 
afd3fd
         self.dontaudit = False
afd3fd
-
afd3fd
+        self.mislabled = None
afd3fd
         self.domains = None
afd3fd
+
afd3fd
     def set_gen_refpol(self, if_set=None, perm_maps=None):
afd3fd
         """Set whether reference policy interfaces are generated.
afd3fd
 
afd3fd
@@ -153,6 +154,18 @@ class PolicyGenerator:
afd3fd
         """Return the generated module"""
afd3fd
         return self.module
afd3fd
 
afd3fd
+    def __restore_label(self, av):
afd3fd
+        import selinux
afd3fd
+        try:
afd3fd
+            context = selinux.matchpathcon(av.obj_path, 0)
afd3fd
+            split = context[1].split(":")[2]
afd3fd
+            if split != av.tgt_type:
afd3fd
+                self.mislabled = split
afd3fd
+                return
afd3fd
+        except OSError:
afd3fd
+            pass
afd3fd
+        self.mislabled = None
afd3fd
+
afd3fd
     def __add_allow_rules(self, avs):
afd3fd
         for av in avs:
afd3fd
             rule = refpolicy.AVRule(av)
afd3fd
@@ -161,6 +174,34 @@ class PolicyGenerator:
afd3fd
             rule.comment = ""
afd3fd
             if self.explain:
afd3fd
                 rule.comment = str(refpolicy.Comment(explain_access(av, verbosity=self.explain)))
afd3fd
+            # base_type[0] == 0 means there exists a base type but not the path
afd3fd
+            # base_type[0] == None means user isn't using base type
afd3fd
+            # base_type[1] contains the target context
afd3fd
+            # base_type[2] contains the source type
afd3fd
+            base_type = av.base_file_type()
afd3fd
+            if base_type[0] == 0 and av.type != audit2why.ALLOW:
afd3fd
+                  rule.comment += "\n#!!!! WARNING: '%s' is a base type." % "".join(base_type[1])
afd3fd
+            for perm in av.perms:
afd3fd
+                if perm == "write" or perm == "create":
afd3fd
+                    permission = True
afd3fd
+                    break
afd3fd
+                else:
afd3fd
+                    permission = False
afd3fd
+
afd3fd
+            # Catch perms 'write' and 'create' for base types
afd3fd
+            if (base_type[0] is not None and base_type[0] != 0
afd3fd
+                and permission and av.type != audit2why.ALLOW):
afd3fd
+                if av.obj_class == dir:
afd3fd
+                    comp = "(/.*?)"
afd3fd
+                else:
afd3fd
+                    comp = ""
afd3fd
+                rule.comment += "\n#!!!! WARNING '%s' is not allowed to write or create to %s.  Change the label to %s." % ("".join(base_type[2]), "".join(base_type[1]), "".join(base_type[0]))
afd3fd
+                if av.obj_path != "":
afd3fd
+                    rule.comment += "\n#!!!! $ semanage fcontext -a -t %s %s%s   \n#!!!! $ restorecon -R -v %s" % ("".join(base_type[0]), "".join(av.obj_path), "".join(comp) ,"".join(av.obj_path))
afd3fd
+
afd3fd
+            self.__restore_label(av)
afd3fd
+            if self.mislabled is not None and av.type != audit2why.ALLOW:
afd3fd
+                rule.comment += "\n#!!!! The file '%s' is mislabeled on your system.  \n#!!!! Fix with $ restorecon -R -v %s" % ("".join(av.obj_path), "".join(av.obj_path))
afd3fd
             if av.type == audit2why.ALLOW:
afd3fd
                 rule.comment += "\n#!!!! This avc is allowed in the current policy"
afd3fd
             if av.type == audit2why.DONTAUDIT:
afd3fd
diff --git sepolgen-1.2.3/src/sepolgen/refparser.py sepolgen-1.2.3/src/sepolgen/refparser.py
afd3fd
index 9b1d0c8..2cef8e8 100644
afd3fd
--- sepolgen-1.2.3/src/sepolgen/refparser.py
afd3fd
+++ sepolgen-1.2.3/src/sepolgen/refparser.py
afd3fd
@@ -113,6 +113,7 @@ tokens = (
afd3fd
     'AUDITALLOW',
afd3fd
     'NEVERALLOW',
afd3fd
     'PERMISSIVE',
afd3fd
+    'TYPEBOUNDS',
afd3fd
     'TYPE_TRANSITION',
afd3fd
     'TYPE_CHANGE',
afd3fd
     'TYPE_MEMBER',
afd3fd
@@ -178,6 +179,7 @@ reserved = {
afd3fd
     'auditallow' : 'AUDITALLOW',
afd3fd
     'neverallow' : 'NEVERALLOW',
afd3fd
     'permissive' : 'PERMISSIVE',
afd3fd
+    'typebounds' : 'TYPEBOUNDS',
afd3fd
     'type_transition' : 'TYPE_TRANSITION',
afd3fd
     'type_change' : 'TYPE_CHANGE',
afd3fd
     'type_member' : 'TYPE_MEMBER',
afd3fd
@@ -502,6 +504,7 @@ def p_policy_stmt(p):
afd3fd
     '''policy_stmt : gen_require
afd3fd
                    | avrule_def
afd3fd
                    | typerule_def
afd3fd
+                   | typebound_def
afd3fd
                    | typeattribute_def
afd3fd
                    | roleattribute_def
afd3fd
                    | interface_call
afd3fd
@@ -823,6 +826,13 @@ def p_typerule_def(p):
afd3fd
     t.file_name = p[7]
afd3fd
     p[0] = t
afd3fd
 
afd3fd
+def p_typebound_def(p):
afd3fd
+    '''typebound_def : TYPEBOUNDS IDENTIFIER comma_list SEMI'''
afd3fd
+    t = refpolicy.TypeBound()
afd3fd
+    t.type = p[2]
afd3fd
+    t.tgt_types.update(p[3])
afd3fd
+    p[0] = t
afd3fd
+
afd3fd
 def p_bool(p):
afd3fd
     '''bool : BOOL IDENTIFIER TRUE SEMI
afd3fd
             | BOOL IDENTIFIER FALSE SEMI'''
afd3fd
diff --git sepolgen-1.2.3/src/sepolgen/refpolicy.py sepolgen-1.2.3/src/sepolgen/refpolicy.py
afd3fd
index 31b40d8..352b187 100644
afd3fd
--- sepolgen-1.2.3/src/sepolgen/refpolicy.py
afd3fd
+++ sepolgen-1.2.3/src/sepolgen/refpolicy.py
afd3fd
@@ -112,6 +112,9 @@ class Node(PolicyBase):
afd3fd
     def typerules(self):
afd3fd
         return filter(lambda x: isinstance(x, TypeRule), walktree(self))
afd3fd
 
afd3fd
+    def typebounds(self):
afd3fd
+        return filter(lambda x: isinstance(x, TypeBound), walktree(self))
afd3fd
+
afd3fd
     def typeattributes(self):
afd3fd
         """Iterate over all of the TypeAttribute children of this Interface."""
afd3fd
         return filter(lambda x: isinstance(x, TypeAttribute), walktree(self))
afd3fd
@@ -281,6 +284,11 @@ class SecurityContext(Leaf):
afd3fd
 
afd3fd
         Raises ValueError if the string is not parsable as a security context.
afd3fd
         """
afd3fd
+        # try to translate the context string to raw form
afd3fd
+        raw = selinux.selinux_trans_to_raw_context(context)
afd3fd
+        if raw[0] == 0:
afd3fd
+            context = raw[1]
afd3fd
+
afd3fd
         fields = context.split(":")
afd3fd
         if len(fields) < 3:
afd3fd
             raise ValueError("context string [%s] not in a valid format" % context)
afd3fd
@@ -522,6 +530,19 @@ class TypeRule(Leaf):
afd3fd
                                      self.tgt_types.to_space_str(),
afd3fd
                                      self.obj_classes.to_space_str(),
afd3fd
                                      self.dest_type)
afd3fd
+class TypeBound(Leaf):
afd3fd
+    """SElinux typebound statement.
afd3fd
+
afd3fd
+    This class represents a typebound statement.
afd3fd
+    """
afd3fd
+    def __init__(self, parent=None):
afd3fd
+        Leaf.__init__(self, parent)
afd3fd
+        self.type = ""
afd3fd
+        self.tgt_types = IdSet()
afd3fd
+
afd3fd
+    def to_string(self):
afd3fd
+        return "typebounds %s %s;" % (self.type, self.tgt_types.to_comma_str())
afd3fd
+
afd3fd
 
afd3fd
 class RoleAllow(Leaf):
afd3fd
     def __init__(self, parent=None):
afd3fd
diff --git sepolgen-1.2.3/tests/.gitignore sepolgen-1.2.3/tests/.gitignore
afd3fd
new file mode 100644
afd3fd
index 0000000..c120af8
afd3fd
--- /dev/null
afd3fd
+++ sepolgen-1.2.3/tests/.gitignore
afd3fd
@@ -0,0 +1,4 @@
afd3fd
+module_compile_test.fc
afd3fd
+module_compile_test.if
afd3fd
+output
afd3fd
+tmp/
afd3fd
diff --git sepolgen-1.2.3/tests/Makefile sepolgen-1.2.3/tests/Makefile
afd3fd
index 924a9be..e17eef2 100644
afd3fd
--- sepolgen-1.2.3/tests/Makefile
afd3fd
+++ sepolgen-1.2.3/tests/Makefile
afd3fd
@@ -4,8 +4,11 @@ clean:
afd3fd
 	rm -f *~ *.pyc
afd3fd
 	rm -f parser.out parsetab.py
afd3fd
 	rm -f out.txt
afd3fd
+	rm -f module_compile_test.fc
afd3fd
+	rm -f module_compile_test.if
afd3fd
 	rm -f module_compile_test.pp
afd3fd
 	rm -f output
afd3fd
+	rm -rf __pycache__ tmp
afd3fd
 
afd3fd
 test:
afd3fd
 	$(PYTHON) run-tests.py
afd3fd
diff --git sepolgen-1.2.3/tests/module_compile_test.te sepolgen-1.2.3/tests/module_compile_test.te
afd3fd
index 446c8dc..b365448 100644
afd3fd
--- sepolgen-1.2.3/tests/module_compile_test.te
afd3fd
+++ sepolgen-1.2.3/tests/module_compile_test.te
afd3fd
@@ -1,8 +1,8 @@
afd3fd
-module foo 1.0;
afd3fd
+module module_compile_test 1.0;
afd3fd
 
afd3fd
 require {
afd3fd
 	type foo, bar;
afd3fd
 	class file { read write };
afd3fd
 }
afd3fd
 
afd3fd
-allow foo bar : file { read write };
afd3fd
\ No newline at end of file
afd3fd
+allow foo bar : file { read write };