Handle audit2allow and audit2why with the same executable Remove audit2why directory and combine this into audit2allow directory
This commit is contained in:
parent
f7d40d920c
commit
ae1cedbac8
7 changed files with 370 additions and 26 deletions
|
@ -1,4 +1,4 @@
|
|||
SUBDIRS = sepolicy setfiles semanage load_policy newrole run_init sandbox secon audit2allow audit2why sestatus semodule_package semodule semodule_link semodule_expand semodule_deps sepolgen-ifgen setsebool scripts po man gui
|
||||
SUBDIRS = sepolicy setfiles semanage load_policy newrole run_init sandbox secon audit2allow sestatus semodule_package semodule semodule_link semodule_expand semodule_deps sepolgen-ifgen setsebool scripts po man gui
|
||||
|
||||
INOTIFYH = $(shell ls /usr/include/sys/inotify.h 2>/dev/null)
|
||||
|
||||
|
|
|
@ -5,14 +5,19 @@ LIBDIR ?= $(PREFIX)/lib
|
|||
MANDIR ?= $(PREFIX)/share/man
|
||||
LOCALEDIR ?= /usr/share/locale
|
||||
|
||||
all: ;
|
||||
all: audit2why
|
||||
|
||||
audit2why:
|
||||
ln -sf audit2allow audit2why
|
||||
|
||||
install: all
|
||||
-mkdir -p $(BINDIR)
|
||||
install -m 755 audit2allow $(BINDIR)
|
||||
(cd $(BINDIR); ln -sf audit2allow audit2why)
|
||||
install -m 755 sepolgen-ifgen $(BINDIR)
|
||||
-mkdir -p $(MANDIR)/man1
|
||||
install -m 644 audit2allow.1 $(MANDIR)/man1/
|
||||
install -m 644 audit2why.1 $(MANDIR)/man1/
|
||||
|
||||
clean:
|
||||
rm -f *~
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#! /usr/bin/python -Es
|
||||
# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
|
||||
# Authors: Dan Walsh <dwalsh@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2006-2007 Red Hat
|
||||
# Copyright (C) 2006-2013 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
|
@ -18,7 +19,7 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
import sys
|
||||
import sys, os
|
||||
|
||||
import sepolgen.audit as audit
|
||||
import sepolgen.policygen as policygen
|
||||
|
@ -82,8 +83,7 @@ class AuditToPolicy:
|
|||
parser.add_option("--interface-info", dest="interface_info", help="file name of interface information")
|
||||
parser.add_option("--debug", dest="debug", action="store_true", default=False,
|
||||
help="leave generated modules for -M")
|
||||
|
||||
parser.add_option("-w", "--why", dest="audit2why", action="store_true", default=False,
|
||||
parser.add_option("-w", "--why", dest="audit2why", action="store_true", default=(os.path.basename(sys.argv[0])=="audit2why"),
|
||||
help="Translates SELinux audit messages into a description of why the access was denied")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
|
359
policycoreutils/audit2allow/audit2why
Normal file
359
policycoreutils/audit2allow/audit2why
Normal file
|
@ -0,0 +1,359 @@
|
|||
#! /usr/bin/python -Es
|
||||
# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
|
||||
# Authors: Dan Walsh <dwalsh@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2006-2013 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 sys, os
|
||||
|
||||
import sepolgen.audit as audit
|
||||
import sepolgen.policygen as policygen
|
||||
import sepolgen.interfaces as interfaces
|
||||
import sepolgen.output as output
|
||||
import sepolgen.objectmodel as objectmodel
|
||||
import sepolgen.defaults as defaults
|
||||
import sepolgen.module as module
|
||||
from sepolgen.sepolgeni18n import _
|
||||
import selinux.audit2why as audit2why
|
||||
import locale
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
|
||||
class AuditToPolicy:
|
||||
VERSION = "%prog .1"
|
||||
SYSLOG = "/var/log/messages"
|
||||
|
||||
def __init__(self):
|
||||
self.__options = None
|
||||
self.__parser = None
|
||||
self.__avs = None
|
||||
|
||||
def __parse_options(self):
|
||||
from optparse import OptionParser
|
||||
|
||||
parser = OptionParser(version=self.VERSION)
|
||||
parser.add_option("-b", "--boot", action="store_true", dest="boot", default=False,
|
||||
help="audit messages since last boot conflicts with -i")
|
||||
parser.add_option("-a", "--all", action="store_true", dest="audit", default=False,
|
||||
help="read input from audit log - conflicts with -i")
|
||||
parser.add_option("-p", "--policy", dest="policy", default=None, help="Policy file to use for analysis")
|
||||
parser.add_option("-d", "--dmesg", action="store_true", dest="dmesg", default=False,
|
||||
help="read input from dmesg - conflicts with --all and --input")
|
||||
parser.add_option("-i", "--input", dest="input",
|
||||
help="read input from <input> - conflicts with -a")
|
||||
parser.add_option("-l", "--lastreload", action="store_true", dest="lastreload", default=False,
|
||||
help="read input only after the last reload")
|
||||
parser.add_option("-r", "--requires", action="store_true", dest="requires", default=False,
|
||||
help="generate require statements for rules")
|
||||
parser.add_option("-m", "--module", dest="module",
|
||||
help="set the module name - implies --requires")
|
||||
parser.add_option("-M", "--module-package", dest="module_package",
|
||||
help="generate a module package - conflicts with -o and -m")
|
||||
parser.add_option("-o", "--output", dest="output",
|
||||
help="append output to <filename>, conflicts with -M")
|
||||
parser.add_option("-D", "--dontaudit", action="store_true",
|
||||
dest="dontaudit", default=False,
|
||||
help="generate policy with dontaudit rules")
|
||||
parser.add_option("-R", "--reference", action="store_true", dest="refpolicy",
|
||||
default=True, help="generate refpolicy style output")
|
||||
|
||||
parser.add_option("-N", "--noreference", action="store_false", dest="refpolicy",
|
||||
default=False, help="do not generate refpolicy style output")
|
||||
parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
|
||||
default=False, help="explain generated output")
|
||||
parser.add_option("-e", "--explain", action="store_true", dest="explain_long",
|
||||
default=False, help="fully explain generated output")
|
||||
parser.add_option("-t", "--type", help="only process messages with a type that matches this regex",
|
||||
dest="type")
|
||||
parser.add_option("--perm-map", dest="perm_map", help="file name of perm map")
|
||||
parser.add_option("--interface-info", dest="interface_info", help="file name of interface information")
|
||||
parser.add_option("--debug", dest="debug", action="store_true", default=False,
|
||||
help="leave generated modules for -M")
|
||||
parser.add_option("-w", "--why", dest="audit2why", action="store_true", default=(os.path.basename(sys.argv[0])=="audit2why"),
|
||||
help="Translates SELinux audit messages into a description of why the access was denied")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
|
||||
# Make -d, -a, and -i conflict
|
||||
if options.audit is True or options.boot:
|
||||
if options.input is not None:
|
||||
sys.stderr.write("error: --all/--boot conflicts with --input\n")
|
||||
if options.dmesg is True:
|
||||
sys.stderr.write("error: --all/--boot conflicts with --dmesg\n")
|
||||
if options.input is not None and options.dmesg is True:
|
||||
sys.stderr.write("error: --input conflicts with --dmesg\n")
|
||||
|
||||
# Turn on requires generation if a module name is given. Also verify
|
||||
# the module name.
|
||||
if options.module:
|
||||
name = options.module
|
||||
else:
|
||||
name = options.module_package
|
||||
if name:
|
||||
options.requires = True
|
||||
if not module.is_valid_name(name):
|
||||
sys.stderr.write('error: module names must begin with a letter, optionally followed by letters, numbers, "-", "_", "."\n')
|
||||
sys.exit(2)
|
||||
|
||||
# Make -M and -o conflict
|
||||
if options.module_package:
|
||||
if options.output:
|
||||
sys.stderr.write("error: --module-package conflicts with --output\n")
|
||||
sys.exit(2)
|
||||
if options.module:
|
||||
sys.stderr.write("error: --module-package conflicts with --module\n")
|
||||
sys.exit(2)
|
||||
|
||||
self.__options = options
|
||||
|
||||
def __read_input(self):
|
||||
parser = audit.AuditParser(last_load_only=self.__options.lastreload)
|
||||
|
||||
filename = None
|
||||
messages = None
|
||||
f = None
|
||||
|
||||
# Figure out what input we want
|
||||
if self.__options.input is not None:
|
||||
filename = self.__options.input
|
||||
elif self.__options.dmesg:
|
||||
messages = audit.get_dmesg_msgs()
|
||||
elif self.__options.audit:
|
||||
try:
|
||||
messages = audit.get_audit_msgs()
|
||||
except OSError, e:
|
||||
sys.stderr.write('could not run ausearch - "%s"\n' % str(e))
|
||||
sys.exit(1)
|
||||
elif self.__options.boot:
|
||||
try:
|
||||
messages = audit.get_audit_boot_msgs()
|
||||
except OSError, e:
|
||||
sys.stderr.write('could not run ausearch - "%s"\n' % str(e))
|
||||
sys.exit(1)
|
||||
else:
|
||||
# This is the default if no input is specified
|
||||
f = sys.stdin
|
||||
|
||||
# Get the input
|
||||
if filename is not None:
|
||||
try:
|
||||
f = open(filename)
|
||||
except IOError, e:
|
||||
sys.stderr.write('could not open file %s - "%s"\n' % (filename, str(e)))
|
||||
sys.exit(1)
|
||||
|
||||
if f is not None:
|
||||
parser.parse_file(f)
|
||||
f.close()
|
||||
|
||||
if messages is not None:
|
||||
parser.parse_string(messages)
|
||||
|
||||
self.__parser = parser
|
||||
|
||||
def __process_input(self):
|
||||
if self.__options.type:
|
||||
avcfilter = audit.AVCTypeFilter(self.__options.type)
|
||||
self.__avs = self.__parser.to_access(avcfilter)
|
||||
csfilter = audit.ComputeSidTypeFilter(self.__options.type)
|
||||
self.__role_types = self.__parser.to_role(csfilter)
|
||||
else:
|
||||
self.__avs = self.__parser.to_access()
|
||||
self.__role_types = self.__parser.to_role()
|
||||
|
||||
def __load_interface_info(self):
|
||||
# Load interface info file
|
||||
if self.__options.interface_info:
|
||||
fn = self.__options.interface_info
|
||||
else:
|
||||
fn = defaults.interface_info()
|
||||
try:
|
||||
fd = open(fn)
|
||||
except:
|
||||
sys.stderr.write("could not open interface info [%s]\n" % fn)
|
||||
sys.exit(1)
|
||||
|
||||
ifs = interfaces.InterfaceSet()
|
||||
ifs.from_file(fd)
|
||||
fd.close()
|
||||
|
||||
# Also load perm maps
|
||||
if self.__options.perm_map:
|
||||
fn = self.__options.perm_map
|
||||
else:
|
||||
fn = defaults.perm_map()
|
||||
try:
|
||||
fd = open(fn)
|
||||
except:
|
||||
sys.stderr.write("could not open perm map [%s]\n" % fn)
|
||||
sys.exit(1)
|
||||
|
||||
perm_maps = objectmodel.PermMappings()
|
||||
perm_maps.from_file(fd)
|
||||
|
||||
return (ifs, perm_maps)
|
||||
|
||||
def __output_modulepackage(self, writer, generator):
|
||||
generator.set_module_name(self.__options.module_package)
|
||||
filename = self.__options.module_package + ".te"
|
||||
packagename = self.__options.module_package + ".pp"
|
||||
|
||||
try:
|
||||
fd = open(filename, "w")
|
||||
except IOError, e:
|
||||
sys.stderr.write("could not write output file: %s\n" % str(e))
|
||||
sys.exit(1)
|
||||
|
||||
writer.write(generator.get_module(), fd)
|
||||
fd.close()
|
||||
|
||||
mc = module.ModuleCompiler()
|
||||
|
||||
try:
|
||||
mc.create_module_package(filename, self.__options.refpolicy)
|
||||
except RuntimeError, e:
|
||||
print e
|
||||
sys.exit(1)
|
||||
|
||||
sys.stdout.write(_("******************** IMPORTANT ***********************\n"))
|
||||
sys.stdout.write((_("To make this policy package active, execute:" +\
|
||||
"\n\nsemodule -i %s\n\n") % packagename))
|
||||
|
||||
def __output_audit2why(self):
|
||||
import selinux
|
||||
import seobject
|
||||
for i in self.__parser.avc_msgs:
|
||||
rc = i.type
|
||||
data = i.data
|
||||
if rc >= 0:
|
||||
print "%s\n\tWas caused by:" % i.message
|
||||
if rc == audit2why.ALLOW:
|
||||
print "\t\tUnknown - would be allowed by active policy\n",
|
||||
print "\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n"
|
||||
print "\t\tPossible mismatch between current in-memory boolean settings vs. permanent ones.\n"
|
||||
continue
|
||||
if rc == audit2why.DONTAUDIT:
|
||||
print "\t\tUnknown - should be dontaudit'd by active policy\n",
|
||||
print "\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n"
|
||||
print "\t\tPossible mismatch between current in-memory boolean settings vs. permanent ones.\n"
|
||||
continue
|
||||
if rc == audit2why.BOOLEAN:
|
||||
if len(data) > 1:
|
||||
print "\tOne of the following booleans was set incorrectly."
|
||||
for b in data:
|
||||
print "\tDescription:\n\t%s\n" % seobject.boolean_desc(b[0])
|
||||
print "\tAllow access by executing:\n\t# setsebool -P %s %d" % (b[0], b[1])
|
||||
else:
|
||||
print "\tThe boolean %s was set incorrectly. " % (data[0][0])
|
||||
print "\tDescription:\n\t%s\n" % seobject.boolean_desc(data[0][0])
|
||||
print "\tAllow access by executing:\n\t# setsebool -P %s %d" % (data[0][0], data[0][1])
|
||||
continue
|
||||
|
||||
if rc == audit2why.TERULE:
|
||||
print "\t\tMissing type enforcement (TE) allow rule.\n"
|
||||
print "\t\tYou can use audit2allow to generate a loadable module to allow this access.\n"
|
||||
continue
|
||||
|
||||
if rc == audit2why.CONSTRAINT:
|
||||
print #!!!! This avc is a constraint violation. You would need to modify the attributes of either the source or target types to allow this access.\n"
|
||||
print "#Constraint rule: \n\t" + data[0]
|
||||
for reason in data[1:]:
|
||||
print "#\tPossible cause is the source %s and target %s are different.\n\b" % reason
|
||||
|
||||
if rc == audit2why.RBAC:
|
||||
print "\t\tMissing role allow rule.\n"
|
||||
print "\t\tAdd an allow rule for the role pair.\n"
|
||||
continue
|
||||
|
||||
audit2why.finish()
|
||||
return
|
||||
|
||||
def __output(self):
|
||||
|
||||
if self.__options.audit2why:
|
||||
try:
|
||||
return self.__output_audit2why()
|
||||
except RuntimeError, e:
|
||||
print e
|
||||
sys.exit(1)
|
||||
|
||||
g = policygen.PolicyGenerator()
|
||||
|
||||
g.set_gen_dontaudit(self.__options.dontaudit)
|
||||
|
||||
if self.__options.module:
|
||||
g.set_module_name(self.__options.module)
|
||||
|
||||
# Interface generation
|
||||
if self.__options.refpolicy:
|
||||
ifs, perm_maps = self.__load_interface_info()
|
||||
g.set_gen_refpol(ifs, perm_maps)
|
||||
|
||||
# Explanation
|
||||
if self.__options.verbose:
|
||||
g.set_gen_explain(policygen.SHORT_EXPLANATION)
|
||||
if self.__options.explain_long:
|
||||
g.set_gen_explain(policygen.LONG_EXPLANATION)
|
||||
|
||||
# Requires
|
||||
if self.__options.requires:
|
||||
g.set_gen_requires(True)
|
||||
|
||||
# Generate the policy
|
||||
g.add_access(self.__avs)
|
||||
g.add_role_types(self.__role_types)
|
||||
|
||||
# Output
|
||||
writer = output.ModuleWriter()
|
||||
|
||||
# Module package
|
||||
if self.__options.module_package:
|
||||
self.__output_modulepackage(writer, g)
|
||||
else:
|
||||
# File or stdout
|
||||
if self.__options.module:
|
||||
g.set_module_name(self.__options.module)
|
||||
|
||||
if self.__options.output:
|
||||
fd = open(self.__options.output, "a")
|
||||
else:
|
||||
fd = sys.stdout
|
||||
writer.write(g.get_module(), fd)
|
||||
|
||||
def main(self):
|
||||
try:
|
||||
self.__parse_options()
|
||||
if self.__options.policy:
|
||||
audit2why.init(self.__options.policy)
|
||||
else:
|
||||
audit2why.init()
|
||||
|
||||
self.__read_input()
|
||||
self.__process_input()
|
||||
self.__output()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
except ValueError, e:
|
||||
print e
|
||||
sys.exit(1)
|
||||
except IOError, e:
|
||||
print e
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = AuditToPolicy()
|
||||
app.main()
|
|
@ -1,18 +0,0 @@
|
|||
# Installation directories.
|
||||
PREFIX ?= $(DESTDIR)/usr
|
||||
BINDIR ?= $(PREFIX)/bin
|
||||
MANDIR ?= $(PREFIX)/share/man
|
||||
|
||||
TARGETS=audit2why
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
install: all
|
||||
-mkdir -p $(BINDIR)
|
||||
install -m 755 $(TARGETS) $(BINDIR)
|
||||
-mkdir -p $(MANDIR)/man1
|
||||
install -m 644 audit2why.1 $(MANDIR)/man1/
|
||||
|
||||
clean:
|
||||
|
||||
relabel:
|
|
@ -1,2 +0,0 @@
|
|||
#!/bin/sh
|
||||
/usr/bin/audit2allow -w $*
|
Loading…
Reference in a new issue