231 lines
9.2 KiB
Diff
231 lines
9.2 KiB
Diff
diff --git a/sepolgen/src/sepolgen/audit.py b/sepolgen/src/sepolgen/audit.py
|
|
index 24e308e..1b0a8e5 100644
|
|
--- a/sepolgen/src/sepolgen/audit.py
|
|
+++ b/sepolgen/src/sepolgen/audit.py
|
|
@@ -68,6 +68,17 @@ def get_dmesg_msgs():
|
|
stdout=subprocess.PIPE).communicate()[0]
|
|
return output
|
|
|
|
+def get_log_msgs():
|
|
+ """Obtain all of the avc and policy load messages from /var/log/messages.
|
|
+
|
|
+ Returns:
|
|
+ string contain all of the audit messages returned by /var/log/messages.
|
|
+ """
|
|
+ import subprocess
|
|
+ output = subprocess.Popen(["/bin/grep", "avc", "/var/log/messages"],
|
|
+ stdout=subprocess.PIPE).communicate()[0]
|
|
+ return output
|
|
+
|
|
# Classes representing audit messages
|
|
|
|
class AuditMessage:
|
|
@@ -127,6 +138,9 @@ class PathMessage(AuditMessage):
|
|
if fields[0] == "path":
|
|
self.path = fields[1][1:-1]
|
|
return
|
|
+import selinux.audit2why as audit2why
|
|
+
|
|
+avcdict = {}
|
|
|
|
class AVCMessage(AuditMessage):
|
|
"""AVC message representing an access denial or granted message.
|
|
@@ -165,8 +179,11 @@ class AVCMessage(AuditMessage):
|
|
self.comm = ""
|
|
self.exe = ""
|
|
self.path = ""
|
|
+ self.name = ""
|
|
self.accesses = []
|
|
self.denial = True
|
|
+ self.type = audit2why.TERULE
|
|
+ self.bools = []
|
|
|
|
def __parse_access(self, recs, start):
|
|
# This is kind of sucky - the access that is in a space separated
|
|
@@ -223,10 +240,36 @@ class AVCMessage(AuditMessage):
|
|
self.comm = fields[1][1:-1]
|
|
elif fields[0] == "exe":
|
|
self.exe = fields[1][1:-1]
|
|
+ elif fields[0] == "name":
|
|
+ self.name = fields[1][1:-1]
|
|
|
|
if not found_src or not found_tgt or not found_class or not found_access:
|
|
raise ValueError("AVC message in invalid format [%s]\n" % self.message)
|
|
-
|
|
+ self.analyze()
|
|
+
|
|
+ def analyze(self):
|
|
+ tcontext = self.tcontext.to_string()
|
|
+ scontext = self.scontext.to_string()
|
|
+ access_tuple = tuple( self.accesses)
|
|
+ if (scontext, tcontext, self.tclass, access_tuple) in avcdict.keys():
|
|
+ self.type, self.bools = avcdict[(scontext, tcontext, self.tclass, access_tuple)]
|
|
+ else:
|
|
+ self.type, self.bools = audit2why.analyze(scontext, tcontext, self.tclass, self.accesses);
|
|
+ if self.type == audit2why.NOPOLICY:
|
|
+ self.type = audit2why.TERULE
|
|
+ if self.type == audit2why.BADTCON:
|
|
+ raise ValueError("Invalid Target Context %s\n" % tcontext)
|
|
+ if self.type == audit2why.BADSCON:
|
|
+ raise ValueError("Invalid Source Context %s\n" % scontext)
|
|
+ if self.type == audit2why.BADSCON:
|
|
+ raise ValueError("Invalid Type Class %s\n" % self.tclass)
|
|
+ if self.type == audit2why.BADPERM:
|
|
+ raise ValueError("Invalid permission %s\n" % " ".join(self.accesses))
|
|
+ if self.type == audit2why.BADCOMPUTE:
|
|
+ raise ValueError("Error during access vector computation")
|
|
+
|
|
+ avcdict[(scontext, tcontext, self.tclass, access_tuple)] = (self.type, self.bools)
|
|
+
|
|
class PolicyLoadMessage(AuditMessage):
|
|
"""Audit message indicating that the policy was reloaded."""
|
|
def __init__(self, message):
|
|
@@ -469,10 +512,10 @@ class AuditParser:
|
|
if avc_filter:
|
|
if avc_filter.filter(avc):
|
|
av_set.add(avc.scontext.type, avc.tcontext.type, avc.tclass,
|
|
- avc.accesses, avc)
|
|
+ avc.accesses, avc, avc_type=avc.type, bools=avc.bools)
|
|
else:
|
|
av_set.add(avc.scontext.type, avc.tcontext.type, avc.tclass,
|
|
- avc.accesses, avc)
|
|
+ avc.accesses, avc, avc_type=avc.type, bools=avc.bools)
|
|
return av_set
|
|
|
|
class AVCTypeFilter:
|
|
diff --git a/sepolgen/src/sepolgen/matching.py b/sepolgen/src/sepolgen/matching.py
|
|
index 1a9a3e5..d56dd92 100644
|
|
--- a/sepolgen/src/sepolgen/matching.py
|
|
+++ b/sepolgen/src/sepolgen/matching.py
|
|
@@ -50,7 +50,7 @@ class Match:
|
|
return 1
|
|
|
|
class MatchList:
|
|
- DEFAULT_THRESHOLD = 120
|
|
+ DEFAULT_THRESHOLD = 150
|
|
def __init__(self):
|
|
# Match objects that pass the threshold
|
|
self.children = []
|
|
@@ -63,14 +63,15 @@ class MatchList:
|
|
def best(self):
|
|
if len(self.children):
|
|
return self.children[0]
|
|
- else:
|
|
- return None
|
|
+ if len(self.bastards):
|
|
+ return self.bastards[0]
|
|
+ return None
|
|
|
|
def __len__(self):
|
|
# Only return the length of the matches so
|
|
# that this can be used to test if there is
|
|
# a match.
|
|
- return len(self.children)
|
|
+ return len(self.children) + len(self.bastards)
|
|
|
|
def __iter__(self):
|
|
return iter(self.children)
|
|
diff --git a/sepolgen/src/sepolgen/policygen.py b/sepolgen/src/sepolgen/policygen.py
|
|
index 0e6b502..6ce892c 100644
|
|
--- a/sepolgen/src/sepolgen/policygen.py
|
|
+++ b/sepolgen/src/sepolgen/policygen.py
|
|
@@ -29,6 +29,8 @@ import objectmodel
|
|
import access
|
|
import interfaces
|
|
import matching
|
|
+import selinux.audit2why as audit2why
|
|
+from setools import *
|
|
|
|
# Constants for the level of explanation from the generation
|
|
# routines
|
|
@@ -77,6 +79,7 @@ class PolicyGenerator:
|
|
|
|
self.dontaudit = False
|
|
|
|
+ self.domains = None
|
|
def set_gen_refpol(self, if_set=None, perm_maps=None):
|
|
"""Set whether reference policy interfaces are generated.
|
|
|
|
@@ -151,8 +154,41 @@ class PolicyGenerator:
|
|
rule = refpolicy.AVRule(av)
|
|
if self.dontaudit:
|
|
rule.rule_type = rule.DONTAUDIT
|
|
+ rule.comment = ""
|
|
if self.explain:
|
|
- rule.comment = refpolicy.Comment(explain_access(av, verbosity=self.explain))
|
|
+ rule.comment = str(refpolicy.Comment(explain_access(av, verbosity=self.explain)))
|
|
+ if av.type == audit2why.ALLOW:
|
|
+ rule.comment += "#!!!! This avc is allowed in the current policy\n"
|
|
+ if av.type == audit2why.DONTAUDIT:
|
|
+ rule.comment += "#!!!! This avc has a dontaudit rule in the current policy\n"
|
|
+
|
|
+ if av.type == audit2why.BOOLEAN:
|
|
+ if len(av.bools) > 1:
|
|
+ rule.comment += "#!!!! This avc can be allowed using one of the these booleans:\n# %s\n" % ", ".join(map(lambda x: x[0], av.bools))
|
|
+ else:
|
|
+ rule.comment += "#!!!! This avc can be allowed using the boolean '%s'\n" % av.bools[0][0]
|
|
+
|
|
+ if av.type == audit2why.CONSTRAINT:
|
|
+ rule.comment += "#!!!! This avc is a constraint violation. You will need to add an attribute to either the source or target type to make it work.\n"
|
|
+ rule.comment += "#Constraint rule: "
|
|
+
|
|
+ if av.type == audit2why.TERULE:
|
|
+ if "write" in av.perms:
|
|
+ if "dir" in av.obj_class or "open" in av.perms:
|
|
+ if not self.domains:
|
|
+ self.domains = seinfo(ATTRIBUTE, name="domain")[0]["types"]
|
|
+ types=[]
|
|
+
|
|
+ try:
|
|
+ for i in map(lambda x: x[TCONTEXT], sesearch([ALLOW], {SCONTEXT: av.src_type, CLASS: av.obj_class, PERMS: av.perms})):
|
|
+ if i not in self.domains:
|
|
+ types.append(i)
|
|
+ if len(types) == 1:
|
|
+ rule.comment += "#!!!! The source type '%s' can write to a '%s' of the following type:\n# %s\n" % ( av.src_type, av.obj_class, ", ".join(types))
|
|
+ elif len(types) >= 1:
|
|
+ rule.comment += "#!!!! The source type '%s' can write to a '%s' of the following types:\n# %s\n" % ( av.src_type, av.obj_class, ", ".join(types))
|
|
+ except:
|
|
+ pass
|
|
self.module.children.append(rule)
|
|
|
|
|
|
diff --git a/sepolgen/src/sepolgen/refparser.py b/sepolgen/src/sepolgen/refparser.py
|
|
index 1a2eec8..955784d 100644
|
|
--- a/sepolgen/src/sepolgen/refparser.py
|
|
+++ b/sepolgen/src/sepolgen/refparser.py
|
|
@@ -109,6 +109,7 @@ tokens = (
|
|
'DONTAUDIT',
|
|
'AUDITALLOW',
|
|
'NEVERALLOW',
|
|
+ 'PERMISSIVE',
|
|
'TYPE_TRANSITION',
|
|
'TYPE_CHANGE',
|
|
'TYPE_MEMBER',
|
|
@@ -170,6 +171,7 @@ reserved = {
|
|
'dontaudit' : 'DONTAUDIT',
|
|
'auditallow' : 'AUDITALLOW',
|
|
'neverallow' : 'NEVERALLOW',
|
|
+ 'permissive' : 'PERMISSIVE',
|
|
'type_transition' : 'TYPE_TRANSITION',
|
|
'type_change' : 'TYPE_CHANGE',
|
|
'type_member' : 'TYPE_MEMBER',
|
|
@@ -490,6 +492,7 @@ def p_policy_stmt(p):
|
|
| interface_call
|
|
| role_def
|
|
| role_allow
|
|
+ | permissive
|
|
| type_def
|
|
| typealias_def
|
|
| attribute_def
|
|
@@ -747,6 +750,10 @@ def p_role_allow(p):
|
|
r.tgt_roles = p[3]
|
|
p[0] = r
|
|
|
|
+def p_permissive(p):
|
|
+ 'permissive : PERMISSIVE names SEMI'
|
|
+ t.skip(1)
|
|
+
|
|
def p_avrule_def(p):
|
|
'''avrule_def : ALLOW names names COLON names names SEMI
|
|
| DONTAUDIT names names COLON names names SEMI
|