summaryrefslogtreecommitdiffstats
path: root/lib/python2.7/site-packages/sepolgen/audit.py
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2016-02-04 13:27:09 -0800
committerJeff Vander Stoep <jeffv@google.com>2016-02-04 13:27:09 -0800
commit1dd717ffbacd9ef09d9c3443c82dc7ffeda83a47 (patch)
tree0b273a21aac9d863f4ea69e522a286326c21bb6c /lib/python2.7/site-packages/sepolgen/audit.py
parentf5e46605a61d63e329159ac38327b3d061277bbd (diff)
downloadplatform_prebuilts_python_linux-x86_2.7.5-1dd717ffbacd9ef09d9c3443c82dc7ffeda83a47.tar.gz
platform_prebuilts_python_linux-x86_2.7.5-1dd717ffbacd9ef09d9c3443c82dc7ffeda83a47.tar.bz2
platform_prebuilts_python_linux-x86_2.7.5-1dd717ffbacd9ef09d9c3443c82dc7ffeda83a47.zip
setools: fix sesearch, add sediff
Bug: 26480956 Change-Id: I7b493a51e2a504119d844d9bc57465b3c21bd970
Diffstat (limited to 'lib/python2.7/site-packages/sepolgen/audit.py')
-rw-r--r--lib/python2.7/site-packages/sepolgen/audit.py549
1 files changed, 0 insertions, 549 deletions
diff --git a/lib/python2.7/site-packages/sepolgen/audit.py b/lib/python2.7/site-packages/sepolgen/audit.py
deleted file mode 100644
index 56919be..0000000
--- a/lib/python2.7/site-packages/sepolgen/audit.py
+++ /dev/null
@@ -1,549 +0,0 @@
-# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
-#
-# Copyright (C) 2006 Red Hat
-# see file 'COPYING' for use and warranty information
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; version 2 only
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-
-import refpolicy
-import access
-import re
-import sys
-
-# Convenience functions
-
-def get_audit_boot_msgs():
- """Obtain all of the avc and policy load messages from the audit
- log. This function uses ausearch and requires that the current
- process have sufficient rights to run ausearch.
-
- Returns:
- string contain all of the audit messages returned by ausearch.
- """
- import subprocess
- import time
- fd=open("/proc/uptime", "r")
- off=float(fd.read().split()[0])
- fd.close
- s = time.localtime(time.time() - off)
- bootdate = time.strftime("%x", s)
- boottime = time.strftime("%X", s)
- output = subprocess.Popen(["/sbin/ausearch", "-m", "AVC,USER_AVC,MAC_POLICY_LOAD,DAEMON_START,SELINUX_ERR", "-ts", bootdate, boottime],
- stdout=subprocess.PIPE).communicate()[0]
- return output
-
-def get_audit_msgs():
- """Obtain all of the avc and policy load messages from the audit
- log. This function uses ausearch and requires that the current
- process have sufficient rights to run ausearch.
-
- Returns:
- string contain all of the audit messages returned by ausearch.
- """
- import subprocess
- output = subprocess.Popen(["/sbin/ausearch", "-m", "AVC,USER_AVC,MAC_POLICY_LOAD,DAEMON_START,SELINUX_ERR"],
- stdout=subprocess.PIPE).communicate()[0]
- return output
-
-def get_dmesg_msgs():
- """Obtain all of the avc and policy load messages from /bin/dmesg.
-
- Returns:
- string contain all of the audit messages returned by dmesg.
- """
- import subprocess
- output = subprocess.Popen(["/bin/dmesg"],
- stdout=subprocess.PIPE).communicate()[0]
- return output
-
-# Classes representing audit messages
-
-class AuditMessage:
- """Base class for all objects representing audit messages.
-
- AuditMessage is a base class for all audit messages and only
- provides storage for the raw message (as a string) and a
- parsing function that does nothing.
- """
- def __init__(self, message):
- self.message = message
- self.header = ""
-
- def from_split_string(self, recs):
- """Parse a string that has been split into records by space into
- an audit message.
-
- This method should be overridden by subclasses. Error reporting
- should be done by raise ValueError exceptions.
- """
- for msg in recs:
- fields = msg.split("=")
- if len(fields) != 2:
- if msg[:6] == "audit(":
- self.header = msg
- return
- else:
- continue
-
- if fields[0] == "msg":
- self.header = fields[1]
- return
-
-
-class InvalidMessage(AuditMessage):
- """Class representing invalid audit messages. This is used to differentiate
- between audit messages that aren't recognized (that should return None from
- the audit message parser) and a message that is recognized but is malformed
- in some way.
- """
- def __init__(self, message):
- AuditMessage.__init__(self, message)
-
-class PathMessage(AuditMessage):
- """Class representing a path message"""
- def __init__(self, message):
- AuditMessage.__init__(self, message)
- self.path = ""
-
- def from_split_string(self, recs):
- AuditMessage.from_split_string(self, recs)
-
- for msg in recs:
- fields = msg.split("=")
- if len(fields) != 2:
- continue
- 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.
-
- This is a very basic class and does not represent all possible fields
- in an avc message. Currently the fields are:
- scontext - context for the source (process) that generated the message
- tcontext - context for the target
- tclass - object class for the target (only one)
- comm - the process name
- exe - the on-disc binary
- path - the path of the target
- access - list of accesses that were allowed or denied
- denial - boolean indicating whether this was a denial (True) or granted
- (False) message.
-
- An example audit message generated from the audit daemon looks like (line breaks
- added):
- 'type=AVC msg=audit(1155568085.407:10877): avc: denied { search } for
- pid=677 comm="python" name="modules" dev=dm-0 ino=13716388
- scontext=user_u:system_r:setroubleshootd_t:s0
- tcontext=system_u:object_r:modules_object_t:s0 tclass=dir'
-
- An example audit message stored in syslog (not processed by the audit daemon - line
- breaks added):
- 'Sep 12 08:26:43 dhcp83-5 kernel: audit(1158064002.046:4): avc: denied { read }
- for pid=2 496 comm="bluez-pin" name=".gdm1K3IFT" dev=dm-0 ino=3601333
- scontext=user_u:system_r:bluetooth_helper_t:s0-s0:c0
- tcontext=system_u:object_r:xdm_tmp_t:s0 tclass=file
- """
- def __init__(self, message):
- AuditMessage.__init__(self, message)
- self.scontext = refpolicy.SecurityContext()
- self.tcontext = refpolicy.SecurityContext()
- self.tclass = ""
- self.comm = ""
- self.exe = ""
- self.path = ""
- self.name = ""
- self.accesses = []
- self.denial = True
- self.type = audit2why.TERULE
-
- def __parse_access(self, recs, start):
- # This is kind of sucky - the access that is in a space separated
- # list like '{ read write }'. This doesn't fit particularly well with splitting
- # the string on spaces. This function takes the list of recs and a starting
- # position one beyond the open brace. It then adds the accesses until it finds
- # the close brace or the end of the list (which is an error if reached without
- # seeing a close brace).
- found_close = False
- i = start
- if i == (len(recs) - 1):
- raise ValueError("AVC message in invalid format [%s]\n" % self.message)
- while i < len(recs):
- if recs[i] == "}":
- found_close = True
- break
- self.accesses.append(recs[i])
- i = i + 1
- if not found_close:
- raise ValueError("AVC message in invalid format [%s]\n" % self.message)
- return i + 1
-
-
- def from_split_string(self, recs):
- AuditMessage.from_split_string(self, recs)
- # FUTURE - fully parse avc messages and store all possible fields
- # Required fields
- found_src = False
- found_tgt = False
- found_class = False
- found_access = False
-
- for i in range(len(recs)):
- if recs[i] == "{":
- i = self.__parse_access(recs, i + 1)
- found_access = True
- continue
- elif recs[i] == "granted":
- self.denial = False
-
- fields = recs[i].split("=")
- if len(fields) != 2:
- continue
- if fields[0] == "scontext":
- self.scontext = refpolicy.SecurityContext(fields[1])
- found_src = True
- elif fields[0] == "tcontext":
- self.tcontext = refpolicy.SecurityContext(fields[1])
- found_tgt = True
- elif fields[0] == "tclass":
- self.tclass = fields[1]
- found_class = True
- elif fields[0] == "comm":
- 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)
- self.data = []
-
- if (scontext, tcontext, self.tclass, access_tuple) in avcdict.keys():
- self.type, self.data = avcdict[(scontext, tcontext, self.tclass, access_tuple)]
- else:
- self.type, self.data = 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")
-
- if self.type == audit2why.CONSTRAINT:
- self.data = [ self.data ]
- if self.scontext.user != self.tcontext.user:
- self.data.append(("user (%s)" % self.scontext.user, 'user (%s)' % self.tcontext.user))
- if self.scontext.role != self.tcontext.role and self.tcontext.role != "object_r":
- self.data.append(("role (%s)" % self.scontext.role, 'role (%s)' % self.tcontext.role))
- if self.scontext.level != self.tcontext.level:
- self.data.append(("level (%s)" % self.scontext.level, 'level (%s)' % self.tcontext.level))
-
- avcdict[(scontext, tcontext, self.tclass, access_tuple)] = (self.type, self.data)
-
-class PolicyLoadMessage(AuditMessage):
- """Audit message indicating that the policy was reloaded."""
- def __init__(self, message):
- AuditMessage.__init__(self, message)
-
-class DaemonStartMessage(AuditMessage):
- """Audit message indicating that a daemon was started."""
- def __init__(self, message):
- AuditMessage.__init__(self, message)
- self.auditd = False
-
- def from_split_string(self, recs):
- AuditMessage.from_split_string(self, recs)
- if "auditd" in recs:
- self.auditd = True
-
-
-class ComputeSidMessage(AuditMessage):
- """Audit message indicating that a sid was not valid.
-
- Compute sid messages are generated on attempting to create a security
- context that is not valid. Security contexts are invalid if the role is
- not authorized for the user or the type is not authorized for the role.
-
- This class does not store all of the fields from the compute sid message -
- just the type and role.
- """
- def __init__(self, message):
- AuditMessage.__init__(self, message)
- self.invalid_context = refpolicy.SecurityContext()
- self.scontext = refpolicy.SecurityContext()
- self.tcontext = refpolicy.SecurityContext()
- self.tclass = ""
-
- def from_split_string(self, recs):
- AuditMessage.from_split_string(self, recs)
- if len(recs) < 10:
- raise ValueError("Split string does not represent a valid compute sid message")
-
- try:
- self.invalid_context = refpolicy.SecurityContext(recs[5])
- self.scontext = refpolicy.SecurityContext(recs[7].split("=")[1])
- self.tcontext = refpolicy.SecurityContext(recs[8].split("=")[1])
- self.tclass = recs[9].split("=")[1]
- except:
- raise ValueError("Split string does not represent a valid compute sid message")
- def output(self):
- return "role %s types %s;\n" % (self.role, self.type)
-
-# Parser for audit messages
-
-class AuditParser:
- """Parser for audit messages.
-
- This class parses audit messages and stores them according to their message
- type. This is not a general purpose audit message parser - it only extracts
- selinux related messages.
-
- Each audit messages are stored in one of four lists:
- avc_msgs - avc denial or granted messages. Messages are stored in
- AVCMessage objects.
- comput_sid_messages - invalid sid messages. Messages are stored in
- ComputSidMessage objects.
- invalid_msgs - selinux related messages that are not valid. Messages
- are stored in InvalidMessageObjects.
- policy_load_messages - policy load messages. Messages are stored in
- PolicyLoadMessage objects.
-
- These lists will be reset when a policy load message is seen if
- AuditParser.last_load_only is set to true. It is assumed that messages
- are fed to the parser in chronological order - time stamps are not
- parsed.
- """
- def __init__(self, last_load_only=False):
- self.__initialize()
- self.last_load_only = last_load_only
-
- def __initialize(self):
- self.avc_msgs = []
- self.compute_sid_msgs = []
- self.invalid_msgs = []
- self.policy_load_msgs = []
- self.path_msgs = []
- self.by_header = { }
- self.check_input_file = False
-
- # Low-level parsing function - tries to determine if this audit
- # message is an SELinux related message and then parses it into
- # the appropriate AuditMessage subclass. This function deliberately
- # does not impose policy (e.g., on policy load message) or store
- # messages to make as simple and reusable as possible.
- #
- # Return values:
- # None - no recognized audit message found in this line
- #
- # InvalidMessage - a recognized but invalid message was found.
- #
- # AuditMessage (or subclass) - object representing a parsed
- # and valid audit message.
- def __parse_line(self, line):
- rec = line.split()
- for i in rec:
- found = False
- if i == "avc:" or i == "message=avc:" or i == "msg='avc:":
- msg = AVCMessage(line)
- found = True
- elif i == "security_compute_sid:":
- msg = ComputeSidMessage(line)
- found = True
- elif i == "type=MAC_POLICY_LOAD" or i == "type=1403":
- msg = PolicyLoadMessage(line)
- found = True
- elif i == "type=AVC_PATH":
- msg = PathMessage(line)
- found = True
- elif i == "type=DAEMON_START":
- msg = DaemonStartMessage(list)
- found = True
-
- if found:
- self.check_input_file = True
- try:
- msg.from_split_string(rec)
- except ValueError:
- msg = InvalidMessage(line)
- return msg
- return None
-
- # Higher-level parse function - take a line, parse it into an
- # AuditMessage object, and store it in the appropriate list.
- # This function will optionally reset all of the lists when
- # it sees a load policy message depending on the value of
- # self.last_load_only.
- def __parse(self, line):
- msg = self.__parse_line(line)
- if msg is None:
- return
-
- # Append to the correct list
- if isinstance(msg, PolicyLoadMessage):
- if self.last_load_only:
- self.__initialize()
- elif isinstance(msg, DaemonStartMessage):
- # We initialize every time the auditd is started. This
- # is less than ideal, but unfortunately it is the only
- # way to catch reboots since the initial policy load
- # by init is not stored in the audit log.
- if msg.auditd and self.last_load_only:
- self.__initialize()
- self.policy_load_msgs.append(msg)
- elif isinstance(msg, AVCMessage):
- self.avc_msgs.append(msg)
- elif isinstance(msg, ComputeSidMessage):
- self.compute_sid_msgs.append(msg)
- elif isinstance(msg, InvalidMessage):
- self.invalid_msgs.append(msg)
- elif isinstance(msg, PathMessage):
- self.path_msgs.append(msg)
-
- # Group by audit header
- if msg.header != "":
- if self.by_header.has_key(msg.header):
- self.by_header[msg.header].append(msg)
- else:
- self.by_header[msg.header] = [msg]
-
-
- # Post processing will add additional information from AVC messages
- # from related messages - only works on messages generated by
- # the audit system.
- def __post_process(self):
- for value in self.by_header.values():
- avc = []
- path = None
- for msg in value:
- if isinstance(msg, PathMessage):
- path = msg
- elif isinstance(msg, AVCMessage):
- avc.append(msg)
- if len(avc) > 0 and path:
- for a in avc:
- a.path = path.path
-
- def parse_file(self, input):
- """Parse the contents of a file object. This method can be called
- multiple times (along with parse_string)."""
- line = input.readline()
- while line:
- self.__parse(line)
- line = input.readline()
- if not self.check_input_file:
- sys.stderr.write("Nothing to do\n")
- sys.exit(0)
- self.__post_process()
-
- def parse_string(self, input):
- """Parse a string containing audit messages - messages should
- be separated by new lines. This method can be called multiple
- times (along with parse_file)."""
- lines = input.split('\n')
- for l in lines:
- self.__parse(l)
- self.__post_process()
-
- def to_role(self, role_filter=None):
- """Return RoleAllowSet statements matching the specified filter
-
- Filter out types that match the filer, or all roles
-
- Params:
- role_filter - [optional] Filter object used to filter the
- output.
- Returns:
- Access vector set representing the denied access in the
- audit logs parsed by this object.
- """
- role_types = access.RoleTypeSet()
- for cs in self.compute_sid_msgs:
- if not role_filter or role_filter.filter(cs):
- role_types.add(cs.invalid_context.role, cs.invalid_context.type)
-
- return role_types
-
- def to_access(self, avc_filter=None, only_denials=True):
- """Convert the audit logs access into a an access vector set.
-
- Convert the audit logs into an access vector set, optionally
- filtering the restults with the passed in filter object.
-
- Filter objects are object instances with a .filter method
- that takes and access vector and returns True if the message
- should be included in the final output and False otherwise.
-
- Params:
- avc_filter - [optional] Filter object used to filter the
- output.
- Returns:
- Access vector set representing the denied access in the
- audit logs parsed by this object.
- """
- av_set = access.AccessVectorSet()
- for avc in self.avc_msgs:
- if avc.denial != True and only_denials:
- continue
- if avc_filter:
- if avc_filter.filter(avc):
- av_set.add(avc.scontext.type, avc.tcontext.type, avc.tclass,
- avc.accesses, avc, avc_type=avc.type, data=avc.data)
- else:
- av_set.add(avc.scontext.type, avc.tcontext.type, avc.tclass,
- avc.accesses, avc, avc_type=avc.type, data=avc.data)
- return av_set
-
-class AVCTypeFilter:
- def __init__(self, regex):
- self.regex = re.compile(regex)
-
- def filter(self, avc):
- if self.regex.match(avc.scontext.type):
- return True
- if self.regex.match(avc.tcontext.type):
- return True
- return False
-
-class ComputeSidTypeFilter:
- def __init__(self, regex):
- self.regex = re.compile(regex)
-
- def filter(self, avc):
- if self.regex.match(avc.invalid_context.type):
- return True
- if self.regex.match(avc.scontext.type):
- return True
- if self.regex.match(avc.tcontext.type):
- return True
- return False
-
-