e3a75fa174
- setsebool: support use of -P on SELinux-disabled hosts - sepolicy: initialize mislabeled_files in __init__() - audit2allow: use local sepolgen-ifgen-attr-helper for tests - audit2allow: allow using audit2why as non-root user - audit2allow/sepolgen-ifgen: show errors on stderr - audit2allow/sepolgen-ifgen: add missing \n to error message - sepolgen: close /etc/selinux/sepolgen.conf after parsing it - sepolicy: Make policy files sorting more robust - semanage: Load a store policy and set the store SELinux policy root
2861 lines
110 KiB
Diff
2861 lines
110 KiB
Diff
diff --git selinux-python-2.8/Makefile selinux-python-2.8/Makefile
|
|
index 80bc124..891bdee 100644
|
|
--- selinux-python-2.8/Makefile
|
|
+++ selinux-python-2.8/Makefile
|
|
@@ -1,4 +1,4 @@
|
|
-SUBDIRS = sepolicy audit2allow semanage sepolgen chcat
|
|
+SUBDIRS = sepolicy audit2allow semanage sepolgen chcat po
|
|
|
|
all install relabel clean indent:
|
|
@for subdir in $(SUBDIRS); do \
|
|
diff --git selinux-python-2.8/audit2allow/.gitignore selinux-python-2.8/audit2allow/.gitignore
|
|
index 3816d2e..2cd46af 100644
|
|
--- selinux-python-2.8/audit2allow/.gitignore
|
|
+++ selinux-python-2.8/audit2allow/.gitignore
|
|
@@ -1 +1,2 @@
|
|
sepolgen-ifgen-attr-helper
|
|
+test_dummy_policy
|
|
diff --git selinux-python-2.8/audit2allow/Makefile selinux-python-2.8/audit2allow/Makefile
|
|
index 513bb2b..06fc3b6 100644
|
|
--- selinux-python-2.8/audit2allow/Makefile
|
|
+++ selinux-python-2.8/audit2allow/Makefile
|
|
@@ -1,4 +1,5 @@
|
|
PYTHON ?= python
|
|
+SECILC ?= secilc
|
|
|
|
# Installation directories.
|
|
PREFIX ?= /usr
|
|
@@ -22,9 +23,12 @@ sepolgen-ifgen-attr-helper: sepolgen-ifgen-attr-helper.o $(LIBSEPOLA)
|
|
audit2why:
|
|
ln -sf audit2allow audit2why
|
|
|
|
-test: all
|
|
+test: all test_dummy_policy
|
|
@$(PYTHON) test_audit2allow.py -v
|
|
|
|
+test_dummy_policy: test_dummy_policy.cil
|
|
+ $(SECILC) -o $@ -f /dev/null $<
|
|
+
|
|
install: all
|
|
-mkdir -p $(DESTDIR)$(BINDIR)
|
|
install -m 755 audit2allow $(DESTDIR)$(BINDIR)
|
|
@@ -36,7 +40,7 @@ install: all
|
|
install -m 644 audit2why.1 $(DESTDIR)$(MANDIR)/man1/
|
|
|
|
clean:
|
|
- rm -f *~ *.o sepolgen-ifgen-attr-helper
|
|
+ rm -f *~ *.o sepolgen-ifgen-attr-helper test_dummy_policy
|
|
|
|
indent:
|
|
../../scripts/Lindent $(wildcard *.[ch])
|
|
diff --git selinux-python-2.8/audit2allow/audit2allow selinux-python-2.8/audit2allow/audit2allow
|
|
index 37ab23a..18fe0a5 100644
|
|
--- selinux-python-2.8/audit2allow/audit2allow
|
|
+++ selinux-python-2.8/audit2allow/audit2allow
|
|
@@ -86,6 +86,8 @@ class AuditToPolicy:
|
|
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("-x", "--xperms", action="store_true", dest="xperms",
|
|
+ default=False, help="generate extended permission rules")
|
|
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"),
|
|
@@ -240,7 +242,10 @@ class AuditToPolicy:
|
|
|
|
def __output_audit2why(self):
|
|
import selinux
|
|
- import sepolicy
|
|
+ try:
|
|
+ import sepolicy
|
|
+ except (ImportError, ValueError):
|
|
+ sepolicy = None
|
|
for i in self.__parser.avc_msgs:
|
|
rc = i.type
|
|
data = i.data
|
|
@@ -260,11 +265,13 @@ class AuditToPolicy:
|
|
if len(data) > 1:
|
|
print("\tOne of the following booleans was set incorrectly.")
|
|
for b in data:
|
|
- print("\tDescription:\n\t%s\n" % sepolicy.boolean_desc(b[0]))
|
|
+ if sepolicy is not None:
|
|
+ print("\tDescription:\n\t%s\n" % sepolicy.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" % sepolicy.boolean_desc(data[0][0]))
|
|
+ if sepolicy is not None:
|
|
+ print("\tDescription:\n\t%s\n" % sepolicy.boolean_desc(data[0][0]))
|
|
print("\tAllow access by executing:\n\t# setsebool -P %s %d" % (data[0][0], data[0][1]))
|
|
continue
|
|
|
|
@@ -314,6 +321,10 @@ class AuditToPolicy:
|
|
ifs, perm_maps = self.__load_interface_info()
|
|
g.set_gen_refpol(ifs, perm_maps)
|
|
|
|
+ # Extended permissions
|
|
+ if self.__options.xperms:
|
|
+ g.set_gen_xperms(True)
|
|
+
|
|
# Explanation
|
|
if self.__options.verbose:
|
|
g.set_gen_explain(policygen.SHORT_EXPLANATION)
|
|
diff --git selinux-python-2.8/audit2allow/audit2allow.1 selinux-python-2.8/audit2allow/audit2allow.1
|
|
index 21d286b..c61067b 100644
|
|
--- selinux-python-2.8/audit2allow/audit2allow.1
|
|
+++ selinux-python-2.8/audit2allow/audit2allow.1
|
|
@@ -85,6 +85,9 @@ This is the default behavior.
|
|
Generate reference policy using installed macros.
|
|
This attempts to match denials against interfaces and may be inaccurate.
|
|
.TP
|
|
+.B "\-x" | "\-\-xperms"
|
|
+Generate extended permission access vector rules
|
|
+.TP
|
|
.B "\-w" | "\-\-why"
|
|
Translates SELinux audit messages into a description of why the access was denied
|
|
|
|
diff --git selinux-python-2.8/audit2allow/sepolgen-ifgen selinux-python-2.8/audit2allow/sepolgen-ifgen
|
|
index acf9638..c482f22 100644
|
|
--- selinux-python-2.8/audit2allow/sepolgen-ifgen
|
|
+++ selinux-python-2.8/audit2allow/sepolgen-ifgen
|
|
@@ -56,6 +56,8 @@ def parse_options():
|
|
help="print debuging output")
|
|
parser.add_option("-d", "--debug", action="store_true", default=False,
|
|
help="extra debugging output")
|
|
+ parser.add_option("--attr-helper", default=ATTR_HELPER,
|
|
+ help="path to sepolgen-ifgen-attr-helper")
|
|
parser.add_option("--no_attrs", action="store_true", default=False,
|
|
help="do not retrieve attribute access from kernel policy")
|
|
options, args = parser.parse_args()
|
|
@@ -77,7 +79,7 @@ def get_policy():
|
|
return None
|
|
|
|
|
|
-def get_attrs(policy_path):
|
|
+def get_attrs(policy_path, attr_helper):
|
|
try:
|
|
if not policy_path:
|
|
policy_path = get_policy()
|
|
@@ -93,10 +95,10 @@ def get_attrs(policy_path):
|
|
return None
|
|
|
|
fd = open("/dev/null", "w")
|
|
- ret = subprocess.Popen([ATTR_HELPER, policy_path, outfile.name], stdout=fd).wait()
|
|
+ ret = subprocess.Popen([attr_helper, policy_path, outfile.name], stdout=fd).wait()
|
|
fd.close()
|
|
if ret != 0:
|
|
- sys.stderr.write("could not run attribute helper")
|
|
+ sys.stderr.write("could not run attribute helper\n")
|
|
return None
|
|
|
|
attrs = interfaces.AttributeSet()
|
|
@@ -127,7 +129,7 @@ def main():
|
|
# Get the attibutes from the binary
|
|
attrs = None
|
|
if not options.no_attrs:
|
|
- attrs = get_attrs(options.policy_path)
|
|
+ attrs = get_attrs(options.policy_path, options.attr_helper)
|
|
if attrs is None:
|
|
return 1
|
|
|
|
@@ -135,8 +137,7 @@ def main():
|
|
try:
|
|
headers = refparser.parse_headers(options.headers, output=log, debug=options.debug)
|
|
except ValueError as e:
|
|
- print("error parsing headers")
|
|
- print(str(e))
|
|
+ sys.stderr.write("error parsing headers: %s\n" % e)
|
|
return 1
|
|
|
|
if_set = interfaces.InterfaceSet(output=log)
|
|
diff --git selinux-python-2.8/audit2allow/test.log selinux-python-2.8/audit2allow/test.log
|
|
index 05249dc..718aca7 100644
|
|
--- selinux-python-2.8/audit2allow/test.log
|
|
+++ selinux-python-2.8/audit2allow/test.log
|
|
@@ -34,3 +34,4 @@ node=mary.example.com type=AVC msg=audit(1166023021.373:910): avc: denied { re
|
|
node=lilly.example.com type=AVC_PATH msg=audit(1164783469.561:109): path="/linuxtest/LVT/lvt/log.current"
|
|
node=lilly.example.com type=SYSCALL msg=audit(1164783469.561:109): arch=14 syscall=11 success=yes exit=0 a0=10120520 a1=10120a78 a2=10120970 a3=118 items=0 ppid=8310 pid=8311 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) comm="smbd" exe="/usr/sbin/smbd" subj=root:system_r:smbd_t:s0 key=(null)
|
|
node=lilly.example.com type=AVC msg=audit(1164783469.561:109): avc: denied { append } for pid=8311 comm="smbd" name="log.current" dev=dm-0 ino=130930 scontext=root:system_r:smbd_t:s0 tcontext=root:object_r:default_t:s0 tclass=dir
|
|
+node=lilly.example.com type=AVC msg=audit(1164783469.561:109): avc: denied { ioctl } for pid=8311 comm="smbd" name="log.current" ioctlcmd=0x2a scontext=root:system_r:smbd_t:s0 tcontext=root:object_r:default_t:s0 tclass=tcp_socket
|
|
diff --git selinux-python-2.8/audit2allow/test_audit2allow.py selinux-python-2.8/audit2allow/test_audit2allow.py
|
|
index a826a9f..87e5504 100644
|
|
--- selinux-python-2.8/audit2allow/test_audit2allow.py
|
|
+++ selinux-python-2.8/audit2allow/test_audit2allow.py
|
|
@@ -1,6 +1,7 @@
|
|
import unittest
|
|
import os
|
|
-import shutil
|
|
+import os.path
|
|
+import sys
|
|
from tempfile import mkdtemp
|
|
from subprocess import Popen, PIPE
|
|
|
|
@@ -25,15 +26,22 @@ class Audit2allowTests(unittest.TestCase):
|
|
|
|
def test_sepolgen_ifgen(self):
|
|
"Verify sepolgen-ifgen works"
|
|
- p = Popen(['sudo', 'sepolgen-ifgen'], stdout=PIPE)
|
|
+ temp_directory = mkdtemp(suffix='audit2allow_test')
|
|
+ output_file = os.path.join(temp_directory, 'interface_info')
|
|
+ p = Popen([
|
|
+ sys.executable, './sepolgen-ifgen', '-p', 'test_dummy_policy', '-o', output_file,
|
|
+ '--attr-helper', './sepolgen-ifgen-attr-helper'
|
|
+ ], stdout=PIPE)
|
|
out, err = p.communicate()
|
|
if err:
|
|
print(out, err)
|
|
self.assertSuccess("sepolgen-ifgen", p.returncode, err)
|
|
+ os.unlink(output_file)
|
|
+ os.rmdir(temp_directory)
|
|
|
|
def test_audit2allow(self):
|
|
"Verify audit2allow works"
|
|
- p = Popen(['python', './audit2allow', "-i", "test.log"], stdout=PIPE)
|
|
+ p = Popen([sys.executable, './audit2allow', '-p', 'test_dummy_policy', '-i', 'test.log'], stdout=PIPE)
|
|
out, err = p.communicate()
|
|
if err:
|
|
print(out, err)
|
|
@@ -41,11 +49,21 @@ class Audit2allowTests(unittest.TestCase):
|
|
|
|
def test_audit2why(self):
|
|
"Verify audit2why works"
|
|
- p = Popen(['python', './audit2why', "-i", "test.log"], stdout=PIPE)
|
|
+ p = Popen([sys.executable, './audit2why', '-p', 'test_dummy_policy', '-i', 'test.log'], stdout=PIPE)
|
|
out, err = p.communicate()
|
|
if err:
|
|
print(out, err)
|
|
self.assertSuccess("audit2why", p.returncode, err)
|
|
|
|
+ def test_xperms(self):
|
|
+ "Verify that xperms generation works"
|
|
+ p = Popen([sys.executable, './audit2allow', '-x', '-p', 'test_dummy_policy', '-i', 'test.log'], stdout=PIPE)
|
|
+ out, err = p.communicate()
|
|
+ if err:
|
|
+ print(out, err)
|
|
+ self.assertTrue(b"allowxperm" in out)
|
|
+ self.assertSuccess("xperms", p.returncode, err)
|
|
+
|
|
+
|
|
if __name__ == "__main__":
|
|
unittest.main()
|
|
diff --git selinux-python-2.8/audit2allow/test_dummy_policy.cil selinux-python-2.8/audit2allow/test_dummy_policy.cil
|
|
new file mode 100644
|
|
index 0000000..795fedc
|
|
--- /dev/null
|
|
+++ selinux-python-2.8/audit2allow/test_dummy_policy.cil
|
|
@@ -0,0 +1,75 @@
|
|
+; This is a dummy policy which main aim is to be compatible with test.log
|
|
+
|
|
+; Define one category and one sensitivity in order to make things work
|
|
+(mls true)
|
|
+(category c0)
|
|
+(categoryorder (c0))
|
|
+(sensitivity s0)
|
|
+(sensitivityorder (s0))
|
|
+(sensitivitycategory s0 (c0))
|
|
+
|
|
+; Define some users and roles
|
|
+(user system_u)
|
|
+(user root)
|
|
+(user unconfined_u)
|
|
+(role system_r)
|
|
+(role unconfined_r)
|
|
+(userrole root system_r)
|
|
+(userrole system_u system_r)
|
|
+(userrole unconfined_u unconfined_r)
|
|
+(userlevel system_u (s0))
|
|
+(userlevel root (s0))
|
|
+(userlevel unconfined_u (s0))
|
|
+(userrange system_u ((s0)(s0 (c0))))
|
|
+(userrange root ((s0)(s0 (c0))))
|
|
+(userrange unconfined_u ((s0)(s0 (c0))))
|
|
+
|
|
+; Define domain types
|
|
+(type automount_t)
|
|
+(type ftpd_t)
|
|
+(type httpd_t)
|
|
+(type kernel_t)
|
|
+(type nsplugin_t)
|
|
+(type postfix_local_t)
|
|
+(type qemu_t)
|
|
+(type smbd_t)
|
|
+
|
|
+(roletype system_r automount_t)
|
|
+(roletype system_r ftpd_t)
|
|
+(roletype system_r httpd_t)
|
|
+(roletype system_r kernel_t)
|
|
+(roletype system_r postfix_local_t)
|
|
+(roletype system_r qemu_t)
|
|
+(roletype system_r smbd_t)
|
|
+(roletype unconfined_r nsplugin_t)
|
|
+
|
|
+; Define file types
|
|
+(type automount_lock_t)
|
|
+(type default_t)
|
|
+(type fixed_disk_device_t)
|
|
+(type home_root_t)
|
|
+(type httpd_sys_content_t)
|
|
+(type httpd_sys_script_exec_t)
|
|
+(type mail_spool_t)
|
|
+(type ssh_home_t)
|
|
+(type usr_t)
|
|
+(type var_t)
|
|
+
|
|
+; Define port types
|
|
+(type mysqld_port_t)
|
|
+(type reserved_port_t)
|
|
+
|
|
+; Define initial SID
|
|
+(sid kernel)
|
|
+(sidorder (kernel))
|
|
+(sidcontext kernel (system_u system_r kernel_t ((s0) (s0))))
|
|
+
|
|
+; Define classes
|
|
+(class blk_file (getattr open read write))
|
|
+(class dir (append open search))
|
|
+(class file (execute execute_no_trans getattr open read write))
|
|
+(class tcp_socket (ioctl name_bind name_connect))
|
|
+(classorder (blk_file file dir tcp_socket))
|
|
+
|
|
+; The policy compiler requires at least one rule
|
|
+(allow kernel_t default_t (file (open read write)))
|
|
diff --git selinux-python-2.8/chcat/chcat selinux-python-2.8/chcat/chcat
|
|
index 4bd9fc6..27c537e 100755
|
|
--- selinux-python-2.8/chcat/chcat
|
|
+++ selinux-python-2.8/chcat/chcat
|
|
@@ -4,7 +4,7 @@
|
|
#
|
|
# chcat is a script that allows you modify the Security label on a file
|
|
#
|
|
-#` Author: Daniel Walsh <dwalsh@redhat.com>
|
|
+# Author: Daniel Walsh <dwalsh@redhat.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License as
|
|
@@ -22,19 +22,15 @@
|
|
# 02111-1307 USA
|
|
#
|
|
#
|
|
-try:
|
|
- from subprocess import getstatusoutput
|
|
-except ImportError:
|
|
- from commands import getstatusoutput
|
|
+import subprocess
|
|
import sys
|
|
import os
|
|
import pwd
|
|
-import string
|
|
import getopt
|
|
import selinux
|
|
import seobject
|
|
|
|
-PROGNAME = "policycoreutils"
|
|
+PROGNAME = "selinux-python"
|
|
try:
|
|
import gettext
|
|
kwargs = {}
|
|
@@ -44,7 +40,7 @@ try:
|
|
localedir="/usr/share/locale",
|
|
codeset='utf-8',
|
|
**kwargs)
|
|
-except:
|
|
+except ImportError:
|
|
try:
|
|
import builtins
|
|
builtins.__dict__['_'] = str
|
|
@@ -86,8 +82,7 @@ def chcat_user_add(newcat, users):
|
|
if len(serange) > 1:
|
|
top = serange[1].split(":")
|
|
if len(top) > 1:
|
|
- cats.append(top[1])
|
|
- cats = expandCats(cats)
|
|
+ cats = expandCats(top[1].split(','))
|
|
|
|
for i in newcat[1:]:
|
|
if i not in cats:
|
|
@@ -99,12 +94,12 @@ def chcat_user_add(newcat, users):
|
|
new_serange = "%s-%s" % (serange[0], top[0])
|
|
|
|
if add_ind:
|
|
- cmd = "semanage login -a -r %s -s %s %s" % (new_serange, user[0], u)
|
|
+ cmd = ["semanage", "login", "-a", "-r", new_serange, "-s", user[0], u]
|
|
else:
|
|
- cmd = "semanage login -m -r %s -s %s %s" % (new_serange, user[0], u)
|
|
- rc = getstatusoutput(cmd)
|
|
- if rc[0] != 0:
|
|
- print(rc[1])
|
|
+ cmd = ["semanage", "login", "-m", "-r", new_serange, "-s", user[0], u]
|
|
+ try:
|
|
+ subprocess.check_call(cmd, stderr=subprocess.STDOUT, shell=False)
|
|
+ except subprocess.CalledProcessError:
|
|
errors += 1
|
|
|
|
return errors
|
|
@@ -140,10 +135,11 @@ def chcat_add(orig, newcat, objects, login_ind):
|
|
cat_string = "%s,%s" % (cat_string, c)
|
|
else:
|
|
cat_string = cat
|
|
- cmd = 'chcon -l %s:%s %s' % (sensitivity, cat_string, f)
|
|
- rc = getstatusoutput(cmd)
|
|
- if rc[0] != 0:
|
|
- print(rc[1])
|
|
+
|
|
+ cmd = ["chcon", "-l", "%s:%s" % (sensitivity, cat_string), f]
|
|
+ try:
|
|
+ subprocess.check_call(cmd, stderr=subprocess.STDOUT, shell=False)
|
|
+ except subprocess.CalledProcessError:
|
|
errors += 1
|
|
return errors
|
|
|
|
@@ -166,8 +162,7 @@ def chcat_user_remove(newcat, users):
|
|
if len(serange) > 1:
|
|
top = serange[1].split(":")
|
|
if len(top) > 1:
|
|
- cats.append(top[1])
|
|
- cats = expandCats(cats)
|
|
+ cats = expandCats(top[1].split(','))
|
|
|
|
for i in newcat[1:]:
|
|
if i in cats:
|
|
@@ -179,13 +174,15 @@ def chcat_user_remove(newcat, users):
|
|
new_serange = "%s-%s" % (serange[0], top[0])
|
|
|
|
if add_ind:
|
|
- cmd = "semanage login -a -r %s -s %s %s" % (new_serange, user[0], u)
|
|
+ cmd = ["semanage", "login", "-a", "-r", new_serange, "-s", user[0], u]
|
|
else:
|
|
- cmd = "semanage login -m -r %s -s %s %s" % (new_serange, user[0], u)
|
|
- rc = getstatusoutput(cmd)
|
|
- if rc[0] != 0:
|
|
- print(rc[1])
|
|
+ cmd = ["semanage", "login", "-m", "-r", new_serange, "-s", user[0], u]
|
|
+
|
|
+ try:
|
|
+ subprocess.check_call(cmd, stderr=subprocess.STDOUT, shell=False)
|
|
+ except subprocess.CalledProcessError:
|
|
errors += 1
|
|
+
|
|
return errors
|
|
|
|
|
|
@@ -224,12 +221,14 @@ def chcat_remove(orig, newcat, objects, login_ind):
|
|
continue
|
|
|
|
if len(cat) == 0:
|
|
- cmd = 'chcon -l %s %s' % (sensitivity, f)
|
|
+ new_serange = sensitivity
|
|
else:
|
|
- cmd = 'chcon -l %s:%s %s' % (sensitivity, cat, f)
|
|
- rc = getstatusoutput(cmd)
|
|
- if rc[0] != 0:
|
|
- print(rc[1])
|
|
+ new_serange = '%s:%s' % (sensitivity, cat)
|
|
+
|
|
+ cmd = ["chcon", "-l", new_serange, f]
|
|
+ try:
|
|
+ subprocess.check_call(cmd, stderr=subprocess.STDOUT, shell=False)
|
|
+ except subprocess.CalledProcessError:
|
|
errors += 1
|
|
return errors
|
|
|
|
@@ -247,17 +246,17 @@ def chcat_user_replace(newcat, users):
|
|
add_ind = 1
|
|
user = seusers["__default__"]
|
|
serange = user[1].split("-")
|
|
- new_serange = "%s-%s:%s" % (serange[0], newcat[0], string.join(newcat[1:], ","))
|
|
+ new_serange = "%s-%s:%s" % (serange[0], newcat[0], ",".join(newcat[1:]))
|
|
if new_serange[-1:] == ":":
|
|
new_serange = new_serange[:-1]
|
|
|
|
if add_ind:
|
|
- cmd = "semanage login -a -r %s -s %s %s" % (new_serange, user[0], u)
|
|
+ cmd = ["semanage", "login", "-a", "-r", new_serange, "-s", user[0], u]
|
|
else:
|
|
- cmd = "semanage login -m -r %s -s %s %s" % (new_serange, user[0], u)
|
|
- rc = getstatusoutput(cmd)
|
|
- if rc[0] != 0:
|
|
- print(rc[1])
|
|
+ cmd = ["semanage", "login", "-m", "-r", new_serange, "-s", user[0], u]
|
|
+ try:
|
|
+ subprocess.check_call(cmd, stderr=subprocess.STDOUT, shell=False)
|
|
+ except subprocess.CalledProcessError:
|
|
errors += 1
|
|
return errors
|
|
|
|
@@ -266,21 +265,18 @@ def chcat_replace(newcat, objects, login_ind):
|
|
if login_ind == 1:
|
|
return chcat_user_replace(newcat, objects)
|
|
errors = 0
|
|
+ # newcat[0] is the sensitivity level, newcat[1:] are the categories
|
|
if len(newcat) == 1:
|
|
- sensitivity = newcat[0]
|
|
- cmd = 'chcon -l %s ' % newcat[0]
|
|
+ new_serange = newcat[0]
|
|
else:
|
|
- sensitivity = newcat[0]
|
|
- cmd = 'chcon -l %s:%s' % (sensitivity, newcat[1])
|
|
+ new_serange = "%s:%s" % (newcat[0], newcat[1])
|
|
for cat in newcat[2:]:
|
|
- cmd = '%s,%s' % (cmd, cat)
|
|
-
|
|
- for f in objects:
|
|
- cmd = "%s %s" % (cmd, f)
|
|
+ new_serange = '%s,%s' % (new_serange, cat)
|
|
|
|
- rc = getstatusoutput(cmd)
|
|
- if rc[0] != 0:
|
|
- print(rc[1])
|
|
+ cmd = ["chcon", "-l", new_serange] + objects
|
|
+ try:
|
|
+ subprocess.check_call(cmd, stderr=subprocess.STDOUT, shell=False)
|
|
+ except subprocess.CalledProcessError:
|
|
errors += 1
|
|
|
|
return errors
|
|
@@ -384,7 +380,7 @@ def listusercats(users):
|
|
if len(users) == 0:
|
|
try:
|
|
users.append(os.getlogin())
|
|
- except:
|
|
+ except OSError:
|
|
users.append(pwd.getpwuid(os.getuid()).pw_name)
|
|
|
|
verify_users(users)
|
|
@@ -401,6 +397,7 @@ def error(msg):
|
|
print("%s: %s" % (sys.argv[0], msg))
|
|
sys.exit(1)
|
|
|
|
+
|
|
if __name__ == '__main__':
|
|
if selinux.is_selinux_mls_enabled() != 1:
|
|
error("Requires a mls enabled system")
|
|
@@ -435,7 +432,7 @@ if __name__ == '__main__':
|
|
except getopt.error as error:
|
|
errorExit(_("Options Error %s ") % error.msg)
|
|
|
|
- except ValueError as e:
|
|
+ except ValueError:
|
|
usage()
|
|
|
|
if delete_ind:
|
|
diff --git selinux-python-2.8/po/Makefile selinux-python-2.8/po/Makefile
|
|
new file mode 100644
|
|
index 0000000..4e052d5
|
|
--- /dev/null
|
|
+++ selinux-python-2.8/po/Makefile
|
|
@@ -0,0 +1,83 @@
|
|
+#
|
|
+# Makefile for the PO files (translation) catalog
|
|
+#
|
|
+
|
|
+PREFIX ?= /usr
|
|
+
|
|
+# What is this package?
|
|
+NLSPACKAGE = python
|
|
+POTFILE = $(NLSPACKAGE).pot
|
|
+INSTALL = /usr/bin/install -c -p
|
|
+INSTALL_DATA = $(INSTALL) -m 644
|
|
+INSTALL_DIR = /usr/bin/install -d
|
|
+
|
|
+# destination directory
|
|
+INSTALL_NLS_DIR = $(PREFIX)/share/locale
|
|
+
|
|
+# PO catalog handling
|
|
+MSGMERGE = msgmerge
|
|
+MSGMERGE_FLAGS = -q
|
|
+XGETTEXT = xgettext --default-domain=$(NLSPACKAGE)
|
|
+MSGFMT = msgfmt
|
|
+
|
|
+# All possible linguas
|
|
+PO_LINGUAS := $(sort $(patsubst %.po,%,$(wildcard *.po)))
|
|
+
|
|
+# Only the files matching what the user has set in LINGUAS
|
|
+USER_LINGUAS := $(filter $(patsubst %,%%,$(LINGUAS)),$(PO_LINGUAS))
|
|
+
|
|
+# if no valid LINGUAS, build all languages
|
|
+USE_LINGUAS := $(if $(USER_LINGUAS),$(USER_LINGUAS),$(PO_LINGUAS))
|
|
+
|
|
+POFILES = $(patsubst %,%.po,$(USE_LINGUAS))
|
|
+MOFILES = $(patsubst %.po,%.mo,$(POFILES))
|
|
+POTFILES = $(shell cat POTFILES)
|
|
+
|
|
+#default:: clean
|
|
+
|
|
+all:: $(MOFILES)
|
|
+
|
|
+$(POTFILE): $(POTFILES)
|
|
+ $(XGETTEXT) -L Python --keyword=_ --keyword=N_ $(POTFILES)
|
|
+ $(XGETTEXT) -j --keyword=_ --keyword=N_ ../sepolicy/sepolicy/sepolicy.glade
|
|
+ @if cmp -s $(NLSPACKAGE).po $(POTFILE); then \
|
|
+ rm -f $(NLSPACKAGE).po; \
|
|
+ else \
|
|
+ mv -f $(NLSPACKAGE).po $(POTFILE); \
|
|
+ fi; \
|
|
+
|
|
+
|
|
+refresh-po: Makefile
|
|
+ for cat in $(POFILES); do \
|
|
+ lang=`basename $$cat .po`; \
|
|
+ if $(MSGMERGE) $(MSGMERGE_FLAGS) $$lang.po $(POTFILE) > $$lang.pot ; then \
|
|
+ mv -f $$lang.pot $$lang.po ; \
|
|
+ echo "$(MSGMERGE) of $$lang succeeded" ; \
|
|
+ else \
|
|
+ echo "$(MSGMERGE) of $$lang failed" ; \
|
|
+ rm -f $$lang.pot ; \
|
|
+ fi \
|
|
+ done
|
|
+
|
|
+clean:
|
|
+ @rm -fv *mo *~ .depend
|
|
+ @rm -rf tmp
|
|
+
|
|
+install: $(MOFILES)
|
|
+ @for n in $(MOFILES); do \
|
|
+ l=`basename $$n .mo`; \
|
|
+ $(INSTALL_DIR) $(DESTDIR)$(INSTALL_NLS_DIR)/$$l/LC_MESSAGES; \
|
|
+ $(INSTALL_DATA) --verbose $$n $(DESTDIR)$(INSTALL_NLS_DIR)/$$l/LC_MESSAGES/selinux-$(NLSPACKAGE).mo; \
|
|
+ done
|
|
+
|
|
+%.mo: %.po
|
|
+ $(MSGFMT) -o $@ $<
|
|
+report:
|
|
+ @for cat in $(wildcard *.po); do \
|
|
+ echo -n "$$cat: "; \
|
|
+ msgfmt -v --statistics -o /dev/null $$cat; \
|
|
+ done
|
|
+
|
|
+.PHONY: missing depend
|
|
+
|
|
+relabel:
|
|
diff --git selinux-python-2.8/po/POTFILES selinux-python-2.8/po/POTFILES
|
|
new file mode 100644
|
|
index 0000000..128eb87
|
|
--- /dev/null
|
|
+++ selinux-python-2.8/po/POTFILES
|
|
@@ -0,0 +1,10 @@
|
|
+../audit2allow/audit2allow
|
|
+../chcat/chcat
|
|
+../semanage/semanage
|
|
+../semanage/seobject.py
|
|
+../sepolgen/src/sepolgen/interfaces.py
|
|
+../sepolicy/sepolicy/generate.py
|
|
+../sepolicy/sepolicy/gui.py
|
|
+../sepolicy/sepolicy/__init__.py
|
|
+../sepolicy/sepolicy/interface.py
|
|
+../sepolicy/sepolicy.py
|
|
diff --git selinux-python-2.8/semanage/semanage selinux-python-2.8/semanage/semanage
|
|
index 8d8a086..18f4a6a 100644
|
|
--- selinux-python-2.8/semanage/semanage
|
|
+++ selinux-python-2.8/semanage/semanage
|
|
@@ -27,7 +27,7 @@ import traceback
|
|
import argparse
|
|
import seobject
|
|
import sys
|
|
-PROGNAME = "policycoreutils"
|
|
+PROGNAME = "selinux-python"
|
|
try:
|
|
import gettext
|
|
kwargs = {}
|
|
@@ -53,7 +53,7 @@ usage_fcontext = "semanage fcontext [-h] [-n] [-N] [-S STORE] ["
|
|
usage_fcontext_dict = {' --add': ('(', '-t TYPE', '-f FTYPE', '-r RANGE', '-s SEUSER', '|', '-e EQUAL', ')', 'FILE_SPEC',), ' --delete': ('(', '-t TYPE', '-f FTYPE', '|', '-e EQUAL', ')', 'FILE_SPEC',), ' --modify': ('(', '-t TYPE', '-f FTYPE', '-r RANGE', '-s SEUSER', '|', '-e EQUAL', ')', 'FILE_SPEC',), ' --list': ('[-C]',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
|
|
usage_user = "semanage user [-h] [-n] [-N] [-S STORE] ["
|
|
-usage_user_dict = {' --add': ('(', '-L LEVEL', '-R ROLES', '-r RANGE', '-s SEUSER', 'selinux_name'')'), ' --delete': ('selinux_name',), ' --modify': ('(', '-L LEVEL', '-R ROLES', '-r RANGE', '-s SEUSER', 'selinux_name', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
+usage_user_dict = {' --add': ('(', '-L LEVEL', '-R ROLES', '-r RANGE', 'SEUSER', ')'), ' --delete': ('SEUSER',), ' --modify': ('(', '-L LEVEL', '-R ROLES', '-r RANGE', '-s SEUSER', 'SEUSER', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
|
|
usage_port = "semanage port [-h] [-n] [-N] [-S STORE] ["
|
|
usage_port_dict = {' --add': ('-t TYPE', '-p PROTOCOL', '-r RANGE', '(', 'port_name', '|', 'port_range', ')'), ' --modify': ('-t TYPE', '-p PROTOCOL', '-r RANGE', '(', 'port_name', '|', 'port_range', ')'), ' --delete': ('-p PROTOCOL', '(', 'port_name', '|', 'port_range', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
@@ -62,7 +62,7 @@ usage_ibpkey = "semanage ibpkey [-h] [-n] [-N] [-s STORE] ["
|
|
usage_ibpkey_dict = {' --add': ('-t TYPE', '-x SUBNET_PREFIX', '-r RANGE', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --modify': ('-t TYPE', '-x SUBNET_PREFIX', '-r RANGE', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --delete': ('-x SUBNET_PREFIX', '(', 'ibpkey_name', '|', 'pkey_range', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
|
|
usage_ibendport = "semanage ibendport [-h] [-n] [-N] [-s STORE] ["
|
|
-usage_ibendport_dict = {' --add': ('-t TYPE', '-z IBDEV_NAME', '-r RANGE', '(', 'port', ')'), ' --modify': ('-t TYPE', '-z IBDEV_NAME', '-r RANGE', '(', 'port', ')'), ' --delete': ('-z IBDEV_NAME', '-r RANGE''(', 'port', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
+usage_ibendport_dict = {' --add': ('-t TYPE', '-z IBDEV_NAME', '-r RANGE', '(', 'port', ')'), ' --modify': ('-t TYPE', '-z IBDEV_NAME', '-r RANGE', '(', 'port', ')'), ' --delete': ('-z IBDEV_NAME', '-r RANGE', '(', 'port', ')'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
|
|
usage_node = "semanage node [-h] [-n] [-N] [-S STORE] ["
|
|
usage_node_dict = {' --add': ('-M NETMASK', '-p PROTOCOL', '-t TYPE', '-r RANGE', 'node'), ' --modify': ('-M NETMASK', '-p PROTOCOL', '-t TYPE', '-r RANGE', 'node'), ' --delete': ('-M NETMASK', '-p PROTOCOL', 'node'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
@@ -73,7 +73,7 @@ usage_interface_dict = {' --add': ('-t TYPE', '-r RANGE', 'interface'), ' --modi
|
|
usage_boolean = "semanage boolean [-h] [-n] [-N] [-S STORE] ["
|
|
usage_boolean_dict = {' --modify': ('(', '--on', '|', '--off', ')', 'boolean'), ' --list': ('-C',), ' --extract': ('',), ' --deleteall': ('',)}
|
|
|
|
-import sepolicy
|
|
+
|
|
|
|
|
|
class CheckRole(argparse.Action):
|
|
@@ -82,7 +82,12 @@ class CheckRole(argparse.Action):
|
|
newval = getattr(namespace, self.dest)
|
|
if not newval:
|
|
newval = []
|
|
- roles = sepolicy.get_all_roles()
|
|
+ try:
|
|
+ # sepolicy tries to load the SELinux policy and raises ValueError if it fails.
|
|
+ import sepolicy
|
|
+ roles = sepolicy.get_all_roles()
|
|
+ except ValueError:
|
|
+ roles = []
|
|
for v in value.split():
|
|
if v not in roles:
|
|
raise ValueError("%s must be an SELinux role:\nValid roles: %s" % (v, ", ".join(roles)))
|
|
@@ -421,7 +426,7 @@ def setupUserParser(subparsers):
|
|
userParser.add_argument('-R', '--roles', default=[],
|
|
action=CheckRole,
|
|
help=_('''
|
|
-SELinux Roles. You must enclose multiple roles within quotes, separate by spaces. Or specify -R multiple times.
|
|
+SELinux Roles. You must enclose multiple roles within quotes, separate by spaces. Or specify -R multiple times.
|
|
'''))
|
|
userParser.add_argument('-P', '--prefix', default="user", help=argparse.SUPPRESS)
|
|
userParser.add_argument('selinux_name', nargs='?', default=None, help=_('selinux_name'))
|
|
@@ -604,19 +609,19 @@ def setupInterfaceParser(subparsers):
|
|
|
|
def handleModule(args):
|
|
OBJECT = seobject.moduleRecords(args)
|
|
- if args.action == "add":
|
|
- OBJECT.add(args.module_name, args.priority)
|
|
- if args.action == "enable":
|
|
- OBJECT.set_enabled(args.module_name, True)
|
|
- if args.action == "disable":
|
|
- OBJECT.set_enabled(args.module_name, False)
|
|
- if args.action == "remove":
|
|
- OBJECT.delete(args.module_name, args.priority)
|
|
- if args.action is "deleteall":
|
|
+ if args.action_add:
|
|
+ OBJECT.add(args.action_add, args.priority)
|
|
+ if args.action_enable:
|
|
+ OBJECT.set_enabled(args.action_enable, True)
|
|
+ if args.action_disable:
|
|
+ OBJECT.set_enabled(args.action_disable, False)
|
|
+ if args.action_remove:
|
|
+ OBJECT.delete(args.action_remove, args.priority)
|
|
+ if args.action == "deleteall":
|
|
OBJECT.deleteall()
|
|
if args.action == "list":
|
|
OBJECT.list(args.noheading, args.locallist)
|
|
- if args.action is "extract":
|
|
+ if args.action == "extract":
|
|
for i in OBJECT.customized():
|
|
print("module %s" % str(i))
|
|
|
|
@@ -630,14 +635,13 @@ def setupModuleParser(subparsers):
|
|
parser_add_priority(moduleParser, "module")
|
|
|
|
mgroup = moduleParser.add_mutually_exclusive_group(required=True)
|
|
- parser_add_add(mgroup, "module")
|
|
parser_add_list(mgroup, "module")
|
|
parser_add_extract(mgroup, "module")
|
|
parser_add_deleteall(mgroup, "module")
|
|
- mgroup.add_argument('-r', '--remove', dest='action', action='store_const', const='remove', help=_("Remove a module"))
|
|
- mgroup.add_argument('-d', '--disable', dest='action', action='store_const', const='disable', help=_("Disable a module"))
|
|
- mgroup.add_argument('-e', '--enable', dest='action', action='store_const', const='enable', help=_("Enable a module"))
|
|
- moduleParser.add_argument('module_name', nargs='?', default=None, help=_('Name of the module to act on'))
|
|
+ mgroup.add_argument('-a', '--add', dest='action_add', action='store', nargs=1, metavar='module_name', help=_("Add a module"))
|
|
+ mgroup.add_argument('-r', '--remove', dest='action_remove', action='store', nargs='+', metavar='module_name', help=_("Remove a module"))
|
|
+ mgroup.add_argument('-d', '--disable', dest='action_disable', action='store', nargs='+', metavar='module_name', help=_("Disable a module"))
|
|
+ mgroup.add_argument('-e', '--enable', dest='action_enable', action='store', nargs='+', metavar='module_name', help=_("Enable a module"))
|
|
moduleParser.set_defaults(func=handleModule)
|
|
|
|
|
|
@@ -739,9 +743,7 @@ def handlePermissive(args):
|
|
if args.action is "delete":
|
|
OBJECT.delete(args.type)
|
|
else:
|
|
- args.parser.print_usage(sys.stderr)
|
|
- sys.stderr.write(_('semanage permissive: error: the following argument is required: type\n'))
|
|
- sys.exit(1)
|
|
+ args.parser.error(message=_('semanage permissive: error: the following argument is required: type\n'))
|
|
|
|
|
|
def setupPermissiveParser(subparsers):
|
|
@@ -776,7 +778,7 @@ def setupDontauditParser(subparsers):
|
|
|
|
|
|
def handleExport(args):
|
|
- manageditems = ["boolean", "login", "interface", "user", "port", "node", "fcontext", "module"]
|
|
+ manageditems = ["boolean", "login", "interface", "user", "port", "node", "fcontext", "module", "ibendport", "ibpkey"]
|
|
for i in manageditems:
|
|
print("%s -D" % i)
|
|
for i in manageditems:
|
|
diff --git selinux-python-2.8/semanage/semanage-user.8 selinux-python-2.8/semanage/semanage-user.8
|
|
index 30bc670..23fec69 100644
|
|
--- selinux-python-2.8/semanage/semanage-user.8
|
|
+++ selinux-python-2.8/semanage/semanage-user.8
|
|
@@ -2,7 +2,7 @@
|
|
.SH "NAME"
|
|
.B semanage\-user \- SELinux Policy Management SELinux User mapping tool
|
|
.SH "SYNOPSIS"
|
|
-.B semanage user [\-h] [\-n] [\-N] [\-S STORE] [ \-\-add ( \-L LEVEL \-R ROLES \-r RANGE \-s SEUSER selinux_name) | \-\-delete selinux_name | \-\-deleteall | \-\-extract | \-\-list [\-C] | \-\-modify ( \-L LEVEL \-R ROLES \-r RANGE \-s SEUSER selinux_name ) ]
|
|
+.B semanage user [\-h] [\-n] [\-N] [\-S STORE] [ \-\-add ( \-L LEVEL \-R ROLES \-r RANGE SEUSER) | \-\-delete SEUSER | \-\-deleteall | \-\-extract | \-\-list [\-C] | \-\-modify ( \-L LEVEL \-R ROLES \-r RANGE SEUSER ) ]
|
|
|
|
.SH "DESCRIPTION"
|
|
semanage is used to configure certain elements of
|
|
diff --git selinux-python-2.8/semanage/semanage.8 selinux-python-2.8/semanage/semanage.8
|
|
index 0bdb90f..0cdcfcc 100644
|
|
--- selinux-python-2.8/semanage/semanage.8
|
|
+++ selinux-python-2.8/semanage/semanage.8
|
|
@@ -57,9 +57,8 @@ to SELinux user identities (which controls the initial security context
|
|
assigned to Linux users when they login and bounds their authorized role set)
|
|
as well as security context mappings for various kinds of objects, such
|
|
as network ports, interfaces, infiniband pkeys and endports, and nodes (hosts)
|
|
-as well as the file context mapping. See the EXAMPLES section below for some
|
|
-examples of common usage. Note that the semanage login command deals with the
|
|
-mapping from Linux usernames (logins) to SELinux user identities,
|
|
+as well as the file context mapping. Note that the semanage login command deals
|
|
+with the mapping from Linux usernames (logins) to SELinux user identities,
|
|
while the semanage user command deals with the mapping from SELinux
|
|
user identities to authorized role sets. In most cases, only the
|
|
former mapping needs to be adjusted by the administrator; the latter
|
|
diff --git selinux-python-2.8/semanage/seobject.py selinux-python-2.8/semanage/seobject.py
|
|
index c76dce8..ffd3e14 100644
|
|
--- selinux-python-2.8/semanage/seobject.py
|
|
+++ selinux-python-2.8/semanage/seobject.py
|
|
@@ -30,10 +30,10 @@ import sys
|
|
import stat
|
|
import socket
|
|
from semanage import *
|
|
-PROGNAME = "policycoreutils"
|
|
+PROGNAME = "selinux-python"
|
|
import sepolicy
|
|
import setools
|
|
-from IPy import IP
|
|
+import ipaddress
|
|
|
|
try:
|
|
import gettext
|
|
@@ -101,6 +101,8 @@ ftype_to_audit = {"": "any",
|
|
|
|
try:
|
|
import audit
|
|
+ #test if audit module is enabled
|
|
+ audit.audit_close(audit.audit_open())
|
|
|
|
class logger:
|
|
|
|
@@ -138,7 +140,7 @@ try:
|
|
|
|
self.log_list = []
|
|
self.log_change_list = []
|
|
-except:
|
|
+except (OSError, ImportError):
|
|
class logger:
|
|
|
|
def __init__(self):
|
|
@@ -258,6 +260,8 @@ class semanageRecords:
|
|
if self.store == "" or self.store == localstore:
|
|
self.mylog = logger()
|
|
else:
|
|
+ sepolicy.load_store_policy(self.store)
|
|
+ selinux.selinux_set_policy_root("%s%s" % (selinux.selinux_path(), self.store))
|
|
self.mylog = nulllogger()
|
|
|
|
def set_reload(self, load):
|
|
@@ -397,6 +401,8 @@ class moduleRecords(semanageRecords):
|
|
print("%-25s %-9s %-5s %s" % (t[0], t[2], t[3], disabled))
|
|
|
|
def add(self, file, priority):
|
|
+ if type(file) == list:
|
|
+ file = file[0]
|
|
if not os.path.exists(file):
|
|
raise ValueError(_("Module does not exist: %s ") % file)
|
|
|
|
@@ -409,7 +415,9 @@ class moduleRecords(semanageRecords):
|
|
self.commit()
|
|
|
|
def set_enabled(self, module, enable):
|
|
- for m in module.split():
|
|
+ if type(module) == str:
|
|
+ module = module.split()
|
|
+ for m in module:
|
|
rc, key = semanage_module_key_create(self.sh)
|
|
if rc < 0:
|
|
raise ValueError(_("Could not create module key"))
|
|
@@ -431,7 +439,9 @@ class moduleRecords(semanageRecords):
|
|
if rc < 0:
|
|
raise ValueError(_("Invalid priority %d (needs to be between 1 and 999)") % priority)
|
|
|
|
- for m in module.split():
|
|
+ if type(module) == str:
|
|
+ module = module.split()
|
|
+ for m in module:
|
|
rc = semanage_module_remove(self.sh, m)
|
|
if rc < 0 and rc != -2:
|
|
raise ValueError(_("Could not remove module %s (remove failed)") % m)
|
|
@@ -593,7 +603,6 @@ class loginRecords(semanageRecords):
|
|
|
|
semanage_seuser_key_free(k)
|
|
semanage_seuser_free(u)
|
|
- self.mylog.log("login", name, sename=sename, serange=serange, serole=",".join(serole), oldserole=",".join(oldserole), oldsename=self.oldsename, oldserange=self.oldserange)
|
|
|
|
def add(self, name, sename, serange):
|
|
try:
|
|
@@ -601,7 +610,6 @@ class loginRecords(semanageRecords):
|
|
self.__add(name, sename, serange)
|
|
self.commit()
|
|
except ValueError as error:
|
|
- self.mylog.commit(0)
|
|
raise error
|
|
|
|
def __modify(self, name, sename="", serange=""):
|
|
@@ -653,7 +661,6 @@ class loginRecords(semanageRecords):
|
|
|
|
semanage_seuser_key_free(k)
|
|
semanage_seuser_free(u)
|
|
- self.mylog.log("login", name, sename=self.sename, serange=self.serange, serole=",".join(serole), oldserole=",".join(oldserole), oldsename=self.oldsename, oldserange=self.oldserange)
|
|
|
|
def modify(self, name, sename="", serange=""):
|
|
try:
|
|
@@ -661,7 +668,6 @@ class loginRecords(semanageRecords):
|
|
self.__modify(name, sename, serange)
|
|
self.commit()
|
|
except ValueError as error:
|
|
- self.mylog.commit(0)
|
|
raise error
|
|
|
|
def __delete(self, name):
|
|
@@ -694,8 +700,6 @@ class loginRecords(semanageRecords):
|
|
rec, self.sename, self.serange = selinux.getseuserbyname("__default__")
|
|
range, (rc, serole) = userrec.get(self.sename)
|
|
|
|
- self.mylog.log_remove("login", name, sename=self.sename, serange=self.serange, serole=",".join(serole), oldserole=",".join(oldserole), oldsename=self.oldsename, oldserange=self.oldserange)
|
|
-
|
|
def delete(self, name):
|
|
try:
|
|
self.begin()
|
|
@@ -703,7 +707,6 @@ class loginRecords(semanageRecords):
|
|
self.commit()
|
|
|
|
except ValueError as error:
|
|
- self.mylog.commit(0)
|
|
raise error
|
|
|
|
def deleteall(self):
|
|
@@ -717,7 +720,6 @@ class loginRecords(semanageRecords):
|
|
self.__delete(semanage_seuser_get_name(u))
|
|
self.commit()
|
|
except ValueError as error:
|
|
- self.mylog.commit(0)
|
|
raise error
|
|
|
|
def get_all_logins(self):
|
|
@@ -753,7 +755,10 @@ class loginRecords(semanageRecords):
|
|
l = []
|
|
ddict = self.get_all(True)
|
|
for k in sorted(ddict.keys()):
|
|
- l.append("-a -s %s -r '%s' %s" % (ddict[k][0], ddict[k][1], k))
|
|
+ if ddict[k][1]:
|
|
+ l.append("-a -s %s -r '%s' %s" % (ddict[k][0], ddict[k][1], k))
|
|
+ else:
|
|
+ l.append("-a -s %s %s" % (ddict[k][0], k))
|
|
return l
|
|
|
|
def list(self, heading=1, locallist=0):
|
|
@@ -1020,7 +1025,10 @@ class seluserRecords(semanageRecords):
|
|
l = []
|
|
ddict = self.get_all(True)
|
|
for k in sorted(ddict.keys()):
|
|
- l.append("-a -L %s -r %s -R '%s' %s" % (ddict[k][1], ddict[k][2], ddict[k][3], k))
|
|
+ if ddict[k][1] or ddict[k][2]:
|
|
+ l.append("-a -L %s -r %s -R '%s' %s" % (ddict[k][1], ddict[k][2], ddict[k][3], k))
|
|
+ else:
|
|
+ l.append("-a -R '%s' %s" % (ddict[k][3], k))
|
|
return l
|
|
|
|
def list(self, heading=1, locallist=0):
|
|
@@ -1043,13 +1051,15 @@ class seluserRecords(semanageRecords):
|
|
|
|
|
|
class portRecords(semanageRecords):
|
|
- try:
|
|
- valid_types = list(list(sepolicy.info(sepolicy.ATTRIBUTE, "port_type"))[0]["types"])
|
|
- except RuntimeError:
|
|
- valid_types = []
|
|
+
|
|
+ valid_types = []
|
|
|
|
def __init__(self, args = None):
|
|
semanageRecords.__init__(self, args)
|
|
+ try:
|
|
+ self.valid_types = list(list(sepolicy.info(sepolicy.ATTRIBUTE, "port_type"))[0]["types"])
|
|
+ except RuntimeError:
|
|
+ pass
|
|
|
|
def __genkey(self, port, proto):
|
|
if proto == "tcp":
|
|
@@ -1087,6 +1097,8 @@ class portRecords(semanageRecords):
|
|
if type == "":
|
|
raise ValueError(_("Type is required"))
|
|
|
|
+ type = sepolicy.get_real_type_name(type)
|
|
+
|
|
if type not in self.valid_types:
|
|
raise ValueError(_("Type %s is invalid, must be a port type") % type)
|
|
|
|
@@ -1151,6 +1163,7 @@ class portRecords(semanageRecords):
|
|
else:
|
|
raise ValueError(_("Requires setype"))
|
|
|
|
+ setype = sepolicy.get_real_type_name(setype)
|
|
if setype and setype not in self.valid_types:
|
|
raise ValueError(_("Type %s is invalid, must be a port type") % setype)
|
|
|
|
@@ -1295,10 +1308,11 @@ class portRecords(semanageRecords):
|
|
l = []
|
|
ddict = self.get_all(True)
|
|
for k in sorted(ddict.keys()):
|
|
- if k[0] == k[1]:
|
|
- l.append("-a -t %s -p %s %s" % (ddict[k][0], k[2], k[0]))
|
|
+ port = k[0] if k[0] == k[1] else "%s-%s" % (k[0], k[1])
|
|
+ if ddict[k][1]:
|
|
+ l.append("-a -t %s -r '%s' -p %s %s" % (ddict[k][0], ddict[k][1], k[2], port))
|
|
else:
|
|
- l.append("-a -t %s -p %s %s-%s" % (ddict[k][0], k[2], k[0], k[1]))
|
|
+ l.append("-a -t %s -p %s %s" % (ddict[k][0], k[2], port))
|
|
return l
|
|
|
|
def list(self, heading=1, locallist=0):
|
|
@@ -1317,14 +1331,16 @@ class portRecords(semanageRecords):
|
|
print(rec)
|
|
|
|
class ibpkeyRecords(semanageRecords):
|
|
- try:
|
|
- q = setools.TypeQuery(setools.SELinuxPolicy(sepolicy.get_installed_policy()), attrs=["ibpkey_type"])
|
|
- valid_types = sorted(str(t) for t in q.results())
|
|
- except:
|
|
- valid_types = []
|
|
+
|
|
+ valid_types = []
|
|
|
|
def __init__(self, args = None):
|
|
semanageRecords.__init__(self, args)
|
|
+ try:
|
|
+ q = setools.TypeQuery(setools.SELinuxPolicy(sepolicy.get_store_policy(self.store)), attrs=["ibpkey_type"])
|
|
+ self.valid_types = sorted(str(t) for t in q.results())
|
|
+ except:
|
|
+ pass
|
|
|
|
def __genkey(self, pkey, subnet_prefix):
|
|
if subnet_prefix == "":
|
|
@@ -1355,6 +1371,8 @@ class ibpkeyRecords(semanageRecords):
|
|
if type == "":
|
|
raise ValueError(_("Type is required"))
|
|
|
|
+ type = sepolicy.get_real_type_name(type)
|
|
+
|
|
if type not in self.valid_types:
|
|
raise ValueError(_("Type %s is invalid, must be a ibpkey type") % type)
|
|
|
|
@@ -1417,6 +1435,8 @@ class ibpkeyRecords(semanageRecords):
|
|
else:
|
|
raise ValueError(_("Requires setype"))
|
|
|
|
+ setype = sepolicy.get_real_type_name(setype)
|
|
+
|
|
if setype and setype not in self.valid_types:
|
|
raise ValueError(_("Type %s is invalid, must be a ibpkey type") % setype)
|
|
|
|
@@ -1548,10 +1568,11 @@ class ibpkeyRecords(semanageRecords):
|
|
ddict = self.get_all(True)
|
|
|
|
for k in sorted(ddict.keys()):
|
|
- if k[0] == k[1]:
|
|
- l.append("-a -t %s -x %s %s" % (ddict[k][0], k[2], k[0]))
|
|
+ port = k[0] if k[0] == k[1] else "%s-%s" % (k[0], k[1])
|
|
+ if ddict[k][1]:
|
|
+ l.append("-a -t %s -r '%s' -x %s %s" % (ddict[k][0], ddict[k][1], k[2], port))
|
|
else:
|
|
- l.append("-a -t %s -x %s %s-%s" % (ddict[k][0], k[2], k[0], k[1]))
|
|
+ l.append("-a -t %s -x %s %s" % (ddict[k][0], k[2], port))
|
|
return l
|
|
|
|
def list(self, heading=1, locallist=0):
|
|
@@ -1570,14 +1591,16 @@ class ibpkeyRecords(semanageRecords):
|
|
print(rec)
|
|
|
|
class ibendportRecords(semanageRecords):
|
|
- try:
|
|
- q = setools.TypeQuery(setools.SELinuxPolicy(sepolicy.get_installed_policy()), attrs=["ibendport_type"])
|
|
- valid_types = set(str(t) for t in q.results())
|
|
- except:
|
|
- valid_types = []
|
|
+
|
|
+ valid_types = []
|
|
|
|
def __init__(self, args = None):
|
|
semanageRecords.__init__(self, args)
|
|
+ try:
|
|
+ q = setools.TypeQuery(setools.SELinuxPolicy(sepolicy.get_store_policy(self.store)), attrs=["ibendport_type"])
|
|
+ self.valid_types = set(str(t) for t in q.results())
|
|
+ except:
|
|
+ pass
|
|
|
|
def __genkey(self, ibendport, ibdev_name):
|
|
if ibdev_name == "":
|
|
@@ -1603,6 +1626,8 @@ class ibendportRecords(semanageRecords):
|
|
if type == "":
|
|
raise ValueError(_("Type is required"))
|
|
|
|
+ type = sepolicy.get_real_type_name(type)
|
|
+
|
|
if type not in self.valid_types:
|
|
raise ValueError(_("Type %s is invalid, must be an ibendport type") % type)
|
|
(k, ibendport, port) = self.__genkey(ibendport, ibdev_name)
|
|
@@ -1664,6 +1689,8 @@ class ibendportRecords(semanageRecords):
|
|
else:
|
|
raise ValueError(_("Requires setype"))
|
|
|
|
+ setype = sepolicy.get_real_type_name(setype)
|
|
+
|
|
if setype and setype not in self.valid_types:
|
|
raise ValueError(_("Type %s is invalid, must be an ibendport type") % setype)
|
|
|
|
@@ -1788,7 +1815,10 @@ class ibendportRecords(semanageRecords):
|
|
ddict = self.get_all(True)
|
|
|
|
for k in sorted(ddict.keys()):
|
|
- l.append("-a -t %s -r %s -z %s %s" % (ddict[k][0], ddict[k][1], k[1], k[0]))
|
|
+ if ddict[k][1]:
|
|
+ l.append("-a -t %s -r '%s' -z %s %s" % (ddict[k][0], ddict[k][1], k[1], k[0]))
|
|
+ else:
|
|
+ l.append("-a -t %s -z %s %s" % (ddict[k][0], k[1], k[0]))
|
|
return l
|
|
|
|
def list(self, heading=1, locallist=0):
|
|
@@ -1807,14 +1837,16 @@ class ibendportRecords(semanageRecords):
|
|
print(rec)
|
|
|
|
class nodeRecords(semanageRecords):
|
|
- try:
|
|
- valid_types = list(list(sepolicy.info(sepolicy.ATTRIBUTE, "node_type"))[0]["types"])
|
|
- except RuntimeError:
|
|
- valid_types = []
|
|
+
|
|
+ valid_types = []
|
|
|
|
def __init__(self, args = None):
|
|
semanageRecords.__init__(self, args)
|
|
self.protocol = ["ipv4", "ipv6"]
|
|
+ try:
|
|
+ self.valid_types = list(list(sepolicy.info(sepolicy.ATTRIBUTE, "node_type"))[0]["types"])
|
|
+ except RuntimeError:
|
|
+ pass
|
|
|
|
def validate(self, addr, mask, protocol):
|
|
newaddr = addr
|
|
@@ -1826,13 +1858,13 @@ class nodeRecords(semanageRecords):
|
|
|
|
# verify valid comination
|
|
if len(mask) == 0 or mask[0] == "/":
|
|
- i = IP(addr + mask)
|
|
- newaddr = i.strNormal(0)
|
|
- newmask = str(i.netmask())
|
|
- if newmask == "0.0.0.0" and i.version() == 6:
|
|
+ i = ipaddress.ip_network(addr + mask)
|
|
+ newaddr = str(i.network_address)
|
|
+ newmask = str(i.netmask)
|
|
+ if newmask == "0.0.0.0" and i.version == 6:
|
|
newmask = "::"
|
|
|
|
- protocol = "ipv%d" % i.version()
|
|
+ protocol = "ipv%d" % i.version
|
|
|
|
try:
|
|
newprotocol = self.protocol.index(protocol)
|
|
@@ -1853,6 +1885,8 @@ class nodeRecords(semanageRecords):
|
|
if ctype == "":
|
|
raise ValueError(_("SELinux node type is required"))
|
|
|
|
+ ctype = sepolicy.get_real_type_name(ctype)
|
|
+
|
|
if ctype not in self.valid_types:
|
|
raise ValueError(_("Type %s is invalid, must be a node type") % ctype)
|
|
|
|
@@ -1922,6 +1956,8 @@ class nodeRecords(semanageRecords):
|
|
if serange == "" and setype == "":
|
|
raise ValueError(_("Requires setype or serange"))
|
|
|
|
+ setype = sepolicy.get_real_type_name(setype)
|
|
+
|
|
if setype and setype not in self.valid_types:
|
|
raise ValueError(_("Type %s is invalid, must be a node type") % setype)
|
|
|
|
@@ -2024,7 +2060,10 @@ class nodeRecords(semanageRecords):
|
|
l = []
|
|
ddict = self.get_all(True)
|
|
for k in sorted(ddict.keys()):
|
|
- l.append("-a -M %s -p %s -t %s %s" % (k[1], k[2], ddict[k][2], k[0]))
|
|
+ if ddict[k][3]:
|
|
+ l.append("-a -M %s -p %s -t %s -r '%s' %s" % (k[1], k[2], ddict[k][2], ddict[k][3], k[0]))
|
|
+ else:
|
|
+ l.append("-a -M %s -p %s -t %s %s" % (k[1], k[2], ddict[k][2], k[0]))
|
|
return l
|
|
|
|
def list(self, heading=1, locallist=0):
|
|
@@ -2218,7 +2257,10 @@ class interfaceRecords(semanageRecords):
|
|
l = []
|
|
ddict = self.get_all(True)
|
|
for k in sorted(ddict.keys()):
|
|
- l.append("-a -t %s %s" % (ddict[k][2], k))
|
|
+ if ddict[k][3]:
|
|
+ l.append("-a -t %s -r '%s' %s" % (ddict[k][2], ddict[k][3], k))
|
|
+ else:
|
|
+ l.append("-a -t %s %s" % (ddict[k][2], k))
|
|
return l
|
|
|
|
def list(self, heading=1, locallist=0):
|
|
@@ -2238,15 +2280,17 @@ class interfaceRecords(semanageRecords):
|
|
|
|
|
|
class fcontextRecords(semanageRecords):
|
|
- try:
|
|
- valid_types = list(list(sepolicy.info(sepolicy.ATTRIBUTE, "file_type"))[0]["types"])
|
|
- valid_types += list(list(sepolicy.info(sepolicy.ATTRIBUTE, "device_node"))[0]["types"])
|
|
- valid_types.append("<<none>>")
|
|
- except RuntimeError:
|
|
- valid_types = []
|
|
+
|
|
+ valid_types = []
|
|
|
|
def __init__(self, args = None):
|
|
semanageRecords.__init__(self, args)
|
|
+ try:
|
|
+ self.valid_types = list(list(sepolicy.info(sepolicy.ATTRIBUTE, "file_type"))[0]["types"])
|
|
+ self.valid_types += list(list(sepolicy.info(sepolicy.ATTRIBUTE, "device_node"))[0]["types"])
|
|
+ except RuntimeError:
|
|
+ pass
|
|
+
|
|
self.equiv = {}
|
|
self.equiv_dist = {}
|
|
self.equal_ind = False
|
|
@@ -2369,8 +2413,10 @@ class fcontextRecords(semanageRecords):
|
|
if type == "":
|
|
raise ValueError(_("SELinux Type is required"))
|
|
|
|
- if type not in self.valid_types:
|
|
- raise ValueError(_("Type %s is invalid, must be a file or device type") % type)
|
|
+ if type != "<<none>>":
|
|
+ type = sepolicy.get_real_type_name(type)
|
|
+ if type not in self.valid_types:
|
|
+ raise ValueError(_("Type %s is invalid, must be a file or device type") % type)
|
|
|
|
(rc, k) = semanage_fcontext_key_create(self.sh, target, file_types[ftype])
|
|
if rc < 0:
|
|
@@ -2432,8 +2478,10 @@ class fcontextRecords(semanageRecords):
|
|
def __modify(self, target, setype, ftype, serange, seuser):
|
|
if serange == "" and setype == "" and seuser == "":
|
|
raise ValueError(_("Requires setype, serange or seuser"))
|
|
- if setype and setype not in self.valid_types:
|
|
- raise ValueError(_("Type %s is invalid, must be a file or device type") % setype)
|
|
+ if setype not in ["", "<<none>>"]:
|
|
+ setype = sepolicy.get_real_type_name(setype)
|
|
+ if setype not in self.valid_types:
|
|
+ raise ValueError(_("Type %s is invalid, must be a file or device type") % setype)
|
|
|
|
self.validate(target)
|
|
|
|
@@ -2597,7 +2645,10 @@ class fcontextRecords(semanageRecords):
|
|
fcon_dict = self.get_all(True)
|
|
for k in sorted(fcon_dict.keys()):
|
|
if fcon_dict[k]:
|
|
- l.append("-a -f %s -t %s '%s'" % (file_type_str_to_option[k[1]], fcon_dict[k][2], k[0]))
|
|
+ if fcon_dict[k][3]:
|
|
+ l.append("-a -f %s -t %s -r '%s' '%s'" % (file_type_str_to_option[k[1]], fcon_dict[k][2], fcon_dict[k][3], k[0]))
|
|
+ else:
|
|
+ l.append("-a -f %s -t %s '%s'" % (file_type_str_to_option[k[1]], fcon_dict[k][2], k[0]))
|
|
|
|
if len(self.equiv):
|
|
for target in self.equiv.keys():
|
|
diff --git selinux-python-2.8/sepolgen/src/sepolgen/access.py selinux-python-2.8/sepolgen/src/sepolgen/access.py
|
|
index a5d8698..ba80f93 100644
|
|
--- selinux-python-2.8/sepolgen/src/sepolgen/access.py
|
|
+++ selinux-python-2.8/sepolgen/src/sepolgen/access.py
|
|
@@ -78,6 +78,7 @@ class AccessVector(util.Comparison):
|
|
.obj_class - The object class to which access is allowed. [String or None]
|
|
.perms - The permissions allowed to the object class. [IdSet]
|
|
.audit_msgs - The audit messages that generated this access vector [List of strings]
|
|
+ .xperms - Extended permissions attached to the AV. [Dictionary {operation: xperm set}]
|
|
"""
|
|
def __init__(self, init_list=None):
|
|
if init_list:
|
|
@@ -87,9 +88,11 @@ class AccessVector(util.Comparison):
|
|
self.tgt_type = None
|
|
self.obj_class = None
|
|
self.perms = refpolicy.IdSet()
|
|
- self.audit_msgs = []
|
|
- self.type = audit2why.TERULE
|
|
- self.data = []
|
|
+
|
|
+ self.audit_msgs = []
|
|
+ self.type = audit2why.TERULE
|
|
+ self.data = []
|
|
+ self.xperms = {}
|
|
# when implementing __eq__ also __hash__ is needed on py2
|
|
# if object is muttable __hash__ should be None
|
|
self.__hash__ = None
|
|
@@ -131,6 +134,15 @@ class AccessVector(util.Comparison):
|
|
l.extend(sorted(self.perms))
|
|
return l
|
|
|
|
+ def merge(self, av):
|
|
+ """Add permissions and extended permissions from AV"""
|
|
+ self.perms.update(av.perms)
|
|
+
|
|
+ for op in av.xperms:
|
|
+ if op not in self.xperms:
|
|
+ self.xperms[op] = refpolicy.XpermSet()
|
|
+ self.xperms[op].extend(av.xperms[op])
|
|
+
|
|
def __str__(self):
|
|
return self.to_string()
|
|
|
|
@@ -260,28 +272,28 @@ class AccessVectorSet:
|
|
def add(self, src_type, tgt_type, obj_class, perms, audit_msg=None, avc_type=audit2why.TERULE, data=[]):
|
|
"""Add an access vector to the set.
|
|
"""
|
|
- tgt = self.src.setdefault(src_type, { })
|
|
- cls = tgt.setdefault(tgt_type, { })
|
|
-
|
|
- if (obj_class, avc_type) in cls:
|
|
- access = cls[obj_class, avc_type]
|
|
- else:
|
|
- access = AccessVector()
|
|
- access.src_type = src_type
|
|
- access.tgt_type = tgt_type
|
|
- access.obj_class = obj_class
|
|
- access.data = data
|
|
- access.type = avc_type
|
|
- cls[obj_class, avc_type] = access
|
|
-
|
|
- access.perms.update(perms)
|
|
- if audit_msg:
|
|
- access.audit_msgs.append(audit_msg)
|
|
+ av = AccessVector()
|
|
+ av.src_type = src_type
|
|
+ av.tgt_type = tgt_type
|
|
+ av.obj_class = obj_class
|
|
+ av.perms = perms
|
|
+ av.data = data
|
|
+ av.type = avc_type
|
|
+
|
|
+ self.add_av(av, audit_msg)
|
|
|
|
def add_av(self, av, audit_msg=None):
|
|
"""Add an access vector to the set."""
|
|
- self.add(av.src_type, av.tgt_type, av.obj_class, av.perms)
|
|
+ tgt = self.src.setdefault(av.src_type, { })
|
|
+ cls = tgt.setdefault(av.tgt_type, { })
|
|
|
|
+ if (av.obj_class, av.type) in cls:
|
|
+ cls[av.obj_class, av.type].merge(av)
|
|
+ else:
|
|
+ cls[av.obj_class, av.type] = av
|
|
+
|
|
+ if audit_msg:
|
|
+ cls[av.obj_class, av.type].audit_msgs.append(audit_msg)
|
|
|
|
def avs_extract_types(avs):
|
|
types = refpolicy.IdSet()
|
|
diff --git selinux-python-2.8/sepolgen/src/sepolgen/audit.py selinux-python-2.8/sepolgen/src/sepolgen/audit.py
|
|
index 26ce6c9..daed58c 100644
|
|
--- selinux-python-2.8/sepolgen/src/sepolgen/audit.py
|
|
+++ selinux-python-2.8/sepolgen/src/sepolgen/audit.py
|
|
@@ -152,6 +152,7 @@ class AVCMessage(AuditMessage):
|
|
access - list of accesses that were allowed or denied
|
|
denial - boolean indicating whether this was a denial (True) or granted
|
|
(False) message.
|
|
+ ioctlcmd - ioctl 'request' parameter
|
|
|
|
An example audit message generated from the audit daemon looks like (line breaks
|
|
added):
|
|
@@ -178,6 +179,7 @@ class AVCMessage(AuditMessage):
|
|
self.name = ""
|
|
self.accesses = []
|
|
self.denial = True
|
|
+ self.ioctlcmd = None
|
|
self.type = audit2why.TERULE
|
|
|
|
def __parse_access(self, recs, start):
|
|
@@ -237,6 +239,11 @@ class AVCMessage(AuditMessage):
|
|
self.exe = fields[1][1:-1]
|
|
elif fields[0] == "name":
|
|
self.name = fields[1][1:-1]
|
|
+ elif fields[0] == "ioctlcmd":
|
|
+ try:
|
|
+ self.ioctlcmd = int(fields[1], 16)
|
|
+ except ValueError:
|
|
+ pass
|
|
|
|
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)
|
|
@@ -522,13 +529,20 @@ class AuditParser:
|
|
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)
|
|
+
|
|
+ if not avc_filter or avc_filter.filter(avc):
|
|
+ av = access.AccessVector([avc.scontext.type, avc.tcontext.type,
|
|
+ avc.tclass] + avc.accesses)
|
|
+ av.data = avc.data
|
|
+ av.type = avc.type
|
|
+
|
|
+ if avc.ioctlcmd:
|
|
+ xperm_set = refpolicy.XpermSet()
|
|
+ xperm_set.add(avc.ioctlcmd)
|
|
+ av.xperms["ioctl"] = xperm_set
|
|
+
|
|
+ av_set.add_av(av, audit_msg=avc)
|
|
+
|
|
return av_set
|
|
|
|
class AVCTypeFilter:
|
|
diff --git selinux-python-2.8/sepolgen/src/sepolgen/defaults.py selinux-python-2.8/sepolgen/src/sepolgen/defaults.py
|
|
index 9591063..e8d7b6a 100644
|
|
--- selinux-python-2.8/sepolgen/src/sepolgen/defaults.py
|
|
+++ selinux-python-2.8/sepolgen/src/sepolgen/defaults.py
|
|
@@ -32,12 +32,13 @@ class PathChoooser(object):
|
|
self.config_pathname = pathname
|
|
ignore = re.compile(r"^\s*(?:#.+)?$")
|
|
consider = re.compile(r"^\s*(\w+)\s*=\s*(.+?)\s*$")
|
|
- for lineno, line in enumerate(open(pathname)):
|
|
- if ignore.match(line): continue
|
|
- mo = consider.match(line)
|
|
- if not mo:
|
|
- raise ValueError("%s:%d: line is not in key = value format" % (pathname, lineno+1))
|
|
- self.config[mo.group(1)] = mo.group(2)
|
|
+ with open(pathname, "r") as fd:
|
|
+ for lineno, line in enumerate(fd):
|
|
+ if ignore.match(line): continue
|
|
+ mo = consider.match(line)
|
|
+ if not mo:
|
|
+ raise ValueError("%s:%d: line is not in key = value format" % (pathname, lineno+1))
|
|
+ self.config[mo.group(1)] = mo.group(2)
|
|
|
|
# We're only exporting one useful function, so why not be a function
|
|
def __call__(self, testfilename, pathset="SELINUX_DEVEL_PATH"):
|
|
diff --git selinux-python-2.8/sepolgen/src/sepolgen/policygen.py selinux-python-2.8/sepolgen/src/sepolgen/policygen.py
|
|
index ee664fb..319da15 100644
|
|
--- selinux-python-2.8/sepolgen/src/sepolgen/policygen.py
|
|
+++ selinux-python-2.8/sepolgen/src/sepolgen/policygen.py
|
|
@@ -50,10 +50,11 @@ class PolicyGenerator:
|
|
in the form of access vectors.
|
|
|
|
It generates allow rules and optionally module require
|
|
- statements and reference policy interfaces. By default
|
|
- only allow rules are generated. The methods .set_gen_refpol
|
|
- and .set_gen_requires turns on interface generation and
|
|
- requires generation respectively.
|
|
+ statements, reference policy interfaces, and extended
|
|
+ permission access vector rules. By default only allow rules
|
|
+ are generated. The methods .set_gen_refpol, .set_gen_requires
|
|
+ and .set_gen_xperms turns on interface generation,
|
|
+ requires generation, and xperms rules genration respectively.
|
|
|
|
PolicyGenerator can also optionally add comments explaining
|
|
why a particular access was allowed based on the audit
|
|
@@ -82,6 +83,7 @@ class PolicyGenerator:
|
|
self.module = refpolicy.Module()
|
|
|
|
self.dontaudit = False
|
|
+ self.xperms = False
|
|
|
|
self.domains = None
|
|
def set_gen_refpol(self, if_set=None, perm_maps=None):
|
|
@@ -120,6 +122,12 @@ class PolicyGenerator:
|
|
def set_gen_dontaudit(self, dontaudit):
|
|
self.dontaudit = dontaudit
|
|
|
|
+ def set_gen_xperms(self, xperms):
|
|
+ """Set whether extended permission access vector rules
|
|
+ are generated.
|
|
+ """
|
|
+ self.xperms = xperms
|
|
+
|
|
def __set_module_style(self):
|
|
if self.ifgen:
|
|
refpolicy = True
|
|
@@ -153,51 +161,69 @@ class PolicyGenerator:
|
|
"""Return the generated module"""
|
|
return self.module
|
|
|
|
- def __add_allow_rules(self, avs):
|
|
- for av in avs:
|
|
- rule = refpolicy.AVRule(av)
|
|
+ def __add_av_rule(self, av):
|
|
+ """Add access vector rule.
|
|
+ """
|
|
+ rule = refpolicy.AVRule(av)
|
|
+
|
|
+ if self.dontaudit:
|
|
+ rule.rule_type = rule.DONTAUDIT
|
|
+ rule.comment = ""
|
|
+ if self.explain:
|
|
+ rule.comment = str(refpolicy.Comment(explain_access(av, verbosity=self.explain)))
|
|
+
|
|
+ if av.type == audit2why.ALLOW:
|
|
+ rule.comment += "\n#!!!! This avc is allowed in the current policy"
|
|
+
|
|
+ if av.xperms:
|
|
+ rule.comment += "\n#!!!! This av rule may have been overridden by an extended permission av rule"
|
|
+
|
|
+ if av.type == audit2why.DONTAUDIT:
|
|
+ rule.comment += "\n#!!!! This avc has a dontaudit rule in the current policy"
|
|
+
|
|
+ if av.type == audit2why.BOOLEAN:
|
|
+ if len(av.data) > 1:
|
|
+ rule.comment += "\n#!!!! This avc can be allowed using one of the these booleans:\n# %s" % ", ".join([x[0] for x in av.data])
|
|
+ else:
|
|
+ rule.comment += "\n#!!!! This avc can be allowed using the boolean '%s'" % av.data[0][0]
|
|
+
|
|
+ if av.type == audit2why.CONSTRAINT:
|
|
+ rule.comment += "\n#!!!! This avc is a constraint violation. You would need to modify the attributes of either the source or target types to allow this access."
|
|
+ rule.comment += "\n#Constraint rule: "
|
|
+ rule.comment += "\n#\t" + av.data[0]
|
|
+ for reason in av.data[1:]:
|
|
+ rule.comment += "\n#\tPossible cause is the source %s and target %s are different." % reason
|
|
+
|
|
+ try:
|
|
+ if ( av.type == audit2why.TERULE and
|
|
+ "write" in av.perms and
|
|
+ ( "dir" in av.obj_class or "open" in av.perms )):
|
|
+ if not self.domains:
|
|
+ self.domains = seinfo(ATTRIBUTE, name="domain")[0]["types"]
|
|
+ types=[]
|
|
+
|
|
+ for i in [x[TCONTEXT] for x in 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 += "\n#!!!! 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 += "\n#!!!! 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)
|
|
+
|
|
+ def __add_ext_av_rules(self, av):
|
|
+ """Add extended permission access vector rules.
|
|
+ """
|
|
+ for op in av.xperms.keys():
|
|
+ extrule = refpolicy.AVExtRule(av, op)
|
|
+
|
|
if self.dontaudit:
|
|
- rule.rule_type = rule.DONTAUDIT
|
|
- rule.comment = ""
|
|
- if self.explain:
|
|
- rule.comment = str(refpolicy.Comment(explain_access(av, verbosity=self.explain)))
|
|
- if av.type == audit2why.ALLOW:
|
|
- rule.comment += "\n#!!!! This avc is allowed in the current policy"
|
|
- if av.type == audit2why.DONTAUDIT:
|
|
- rule.comment += "\n#!!!! This avc has a dontaudit rule in the current policy"
|
|
-
|
|
- if av.type == audit2why.BOOLEAN:
|
|
- if len(av.data) > 1:
|
|
- rule.comment += "\n#!!!! This avc can be allowed using one of the these booleans:\n# %s" % ", ".join([x[0] for x in av.data])
|
|
- else:
|
|
- rule.comment += "\n#!!!! This avc can be allowed using the boolean '%s'" % av.data[0][0]
|
|
-
|
|
- if av.type == audit2why.CONSTRAINT:
|
|
- rule.comment += "\n#!!!! This avc is a constraint violation. You would need to modify the attributes of either the source or target types to allow this access."
|
|
- rule.comment += "\n#Constraint rule: "
|
|
- rule.comment += "\n#\t" + av.data[0]
|
|
- for reason in av.data[1:]:
|
|
- rule.comment += "\n#\tPossible cause is the source %s and target %s are different." % reason
|
|
-
|
|
- try:
|
|
- if ( av.type == audit2why.TERULE and
|
|
- "write" in av.perms and
|
|
- ( "dir" in av.obj_class or "open" in av.perms )):
|
|
- if not self.domains:
|
|
- self.domains = seinfo(ATTRIBUTE, name="domain")[0]["types"]
|
|
- types=[]
|
|
-
|
|
- for i in [x[TCONTEXT] for x in 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 += "\n#!!!! 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 += "\n#!!!! 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)
|
|
+ extrule.rule_type = extrule.DONTAUDITXPERM
|
|
|
|
+ self.module.children.append(extrule)
|
|
|
|
def add_access(self, av_set):
|
|
"""Add the access from the access vector set to this
|
|
@@ -215,7 +241,10 @@ class PolicyGenerator:
|
|
raw_allow = av_set
|
|
|
|
# Generate the raw allow rules from the filtered list
|
|
- self.__add_allow_rules(raw_allow)
|
|
+ for av in raw_allow:
|
|
+ self.__add_av_rule(av)
|
|
+ if self.xperms and av.xperms:
|
|
+ self.__add_ext_av_rules(av)
|
|
|
|
def add_role_types(self, role_type_set):
|
|
for role_type in role_type_set:
|
|
diff --git selinux-python-2.8/sepolgen/src/sepolgen/refparser.py selinux-python-2.8/sepolgen/src/sepolgen/refparser.py
|
|
index 2cef8e8..3415aff 100644
|
|
--- selinux-python-2.8/sepolgen/src/sepolgen/refparser.py
|
|
+++ selinux-python-2.8/sepolgen/src/sepolgen/refparser.py
|
|
@@ -786,7 +786,7 @@ def p_role_allow(p):
|
|
|
|
def p_permissive(p):
|
|
'permissive : PERMISSIVE names SEMI'
|
|
- t.skip(1)
|
|
+ pass
|
|
|
|
def p_avrule_def(p):
|
|
'''avrule_def : ALLOW names names COLON names names SEMI
|
|
diff --git selinux-python-2.8/sepolgen/src/sepolgen/refpolicy.py selinux-python-2.8/sepolgen/src/sepolgen/refpolicy.py
|
|
index 352b187..c30a8c7 100644
|
|
--- selinux-python-2.8/sepolgen/src/sepolgen/refpolicy.py
|
|
+++ selinux-python-2.8/sepolgen/src/sepolgen/refpolicy.py
|
|
@@ -109,6 +109,9 @@ class Node(PolicyBase):
|
|
def avrules(self):
|
|
return filter(lambda x: isinstance(x, AVRule), walktree(self))
|
|
|
|
+ def avextrules(self):
|
|
+ return filter(lambda x: isinstance(x, AVExtRule), walktree(self))
|
|
+
|
|
def typerules(self):
|
|
return filter(lambda x: isinstance(x, TypeRule), walktree(self))
|
|
|
|
@@ -352,6 +355,65 @@ class ObjectClass(Leaf):
|
|
self.name = name
|
|
self.perms = IdSet()
|
|
|
|
+class XpermSet():
|
|
+ """Extended permission set.
|
|
+
|
|
+ This class represents one or more extended permissions
|
|
+ represented by numeric values or ranges of values. The
|
|
+ .complement attribute is used to specify all permission
|
|
+ except those specified.
|
|
+
|
|
+ Two xperm set can be merged using the .extend() method.
|
|
+ """
|
|
+ def __init__(self, complement=False):
|
|
+ self.complement = complement
|
|
+ self.ranges = []
|
|
+
|
|
+ def __normalize_ranges(self):
|
|
+ """Ensure that ranges are not overlapping.
|
|
+ """
|
|
+ self.ranges.sort()
|
|
+
|
|
+ i = 0
|
|
+ while i < len(self.ranges):
|
|
+ while i + 1 < len(self.ranges):
|
|
+ if self.ranges[i + 1][0] <= self.ranges[i][1] + 1:
|
|
+ self.ranges[i] = (self.ranges[i][0], max(self.ranges[i][1],
|
|
+ self.ranges[i + 1][1]))
|
|
+ del self.ranges[i + 1]
|
|
+ else:
|
|
+ break
|
|
+ i += 1
|
|
+
|
|
+ def extend(self, s):
|
|
+ """Add ranges from an xperm set
|
|
+ """
|
|
+ self.ranges.extend(s.ranges)
|
|
+ self.__normalize_ranges()
|
|
+
|
|
+ def add(self, minimum, maximum=None):
|
|
+ """Add value of range of values to the xperm set.
|
|
+ """
|
|
+ if maximum is None:
|
|
+ maximum = minimum
|
|
+ self.ranges.append((minimum, maximum))
|
|
+ self.__normalize_ranges()
|
|
+
|
|
+ def to_string(self):
|
|
+ if not self.ranges:
|
|
+ return ""
|
|
+
|
|
+ compl = "~ " if self.complement else ""
|
|
+
|
|
+ # print single value without braces
|
|
+ if len(self.ranges) == 1 and self.ranges[0][0] == self.ranges[0][1]:
|
|
+ return compl + str(self.ranges[0][0])
|
|
+
|
|
+ vals = map(lambda x: str(x[0]) if x[0] == x[1] else "%s-%s" % x,
|
|
+ self.ranges)
|
|
+
|
|
+ return "%s{ %s }" % (compl, " ".join(vals))
|
|
+
|
|
# Basic statements
|
|
|
|
class TypeAttribute(Leaf):
|
|
@@ -472,8 +534,10 @@ class AVRule(Leaf):
|
|
return "allow"
|
|
elif self.rule_type == self.DONTAUDIT:
|
|
return "dontaudit"
|
|
- else:
|
|
+ elif self.rule_type == self.AUDITALLOW:
|
|
return "auditallow"
|
|
+ elif self.rule_type == self.NEVERALLOW:
|
|
+ return "neverallow"
|
|
|
|
def from_av(self, av):
|
|
"""Add the access from an access vector to this allow
|
|
@@ -497,6 +561,65 @@ class AVRule(Leaf):
|
|
self.tgt_types.to_space_str(),
|
|
self.obj_classes.to_space_str(),
|
|
self.perms.to_space_str())
|
|
+
|
|
+class AVExtRule(Leaf):
|
|
+ """Extended permission access vector rule.
|
|
+
|
|
+ The AVExtRule class represents allowxperm, dontauditxperm,
|
|
+ auditallowxperm, and neverallowxperm rules.
|
|
+
|
|
+ The source and target types, and object classes are represented
|
|
+ by sets containing strings. The operation is a single string,
|
|
+ e.g. 'ioctl'. Extended permissions are represented by an XpermSet.
|
|
+ """
|
|
+ ALLOWXPERM = 0
|
|
+ DONTAUDITXPERM = 1
|
|
+ AUDITALLOWXPERM = 2
|
|
+ NEVERALLOWXPERM = 3
|
|
+
|
|
+ def __init__(self, av=None, op=None, parent=None):
|
|
+ Leaf.__init__(self, parent)
|
|
+ self.src_types = IdSet()
|
|
+ self.tgt_types = IdSet()
|
|
+ self.obj_classes = IdSet()
|
|
+ self.rule_type = self.ALLOWXPERM
|
|
+ self.xperms = XpermSet()
|
|
+ self.operation = op
|
|
+ if av:
|
|
+ self.from_av(av, op)
|
|
+
|
|
+ def __rule_type_str(self):
|
|
+ if self.rule_type == self.ALLOWXPERM:
|
|
+ return "allowxperm"
|
|
+ elif self.rule_type == self.DONTAUDITXPERM:
|
|
+ return "dontauditxperm"
|
|
+ elif self.rule_type == self.AUDITALLOWXPERM:
|
|
+ return "auditallowxperm"
|
|
+ elif self.rule_type == self.NEVERALLOWXPERM:
|
|
+ return "neverallowxperm"
|
|
+
|
|
+ def from_av(self, av, op):
|
|
+ self.src_types.add(av.src_type)
|
|
+ if av.src_type == av.tgt_type:
|
|
+ self.tgt_types.add("self")
|
|
+ else:
|
|
+ self.tgt_types.add(av.tgt_type)
|
|
+ self.obj_classes.add(av.obj_class)
|
|
+ self.operation = op
|
|
+ self.xperms = av.xperms[op]
|
|
+
|
|
+ def to_string(self):
|
|
+ """Return a string representation of the rule that is
|
|
+ a valid policy language representation (assuming that
|
|
+ the types, object class, etc. are valid).
|
|
+ """
|
|
+ return "%s %s %s:%s %s %s;" % (self.__rule_type_str(),
|
|
+ self.src_types.to_space_str(),
|
|
+ self.tgt_types.to_space_str(),
|
|
+ self.obj_classes.to_space_str(),
|
|
+ self.operation,
|
|
+ self.xperms.to_string())
|
|
+
|
|
class TypeRule(Leaf):
|
|
"""SELinux type rules.
|
|
|
|
diff --git selinux-python-2.8/sepolgen/src/sepolgen/sepolgeni18n.py selinux-python-2.8/sepolgen/src/sepolgen/sepolgeni18n.py
|
|
index 998c435..56ebd80 100644
|
|
--- selinux-python-2.8/sepolgen/src/sepolgen/sepolgeni18n.py
|
|
+++ selinux-python-2.8/sepolgen/src/sepolgen/sepolgeni18n.py
|
|
@@ -19,7 +19,7 @@
|
|
|
|
try:
|
|
import gettext
|
|
- t = gettext.translation( 'yumex' )
|
|
+ t = gettext.translation( 'selinux-python' )
|
|
_ = t.gettext
|
|
except:
|
|
def _(str):
|
|
diff --git selinux-python-2.8/sepolgen/src/sepolgen/util.py selinux-python-2.8/sepolgen/src/sepolgen/util.py
|
|
index 1fca971..b3d2616 100644
|
|
--- selinux-python-2.8/sepolgen/src/sepolgen/util.py
|
|
+++ selinux-python-2.8/sepolgen/src/sepolgen/util.py
|
|
@@ -125,7 +125,7 @@ class Comparison():
|
|
_compare function within your class."""
|
|
|
|
def _compare(self, other, method):
|
|
- raise NotImplemented
|
|
+ return NotImplemented
|
|
|
|
def __eq__(self, other):
|
|
return self._compare(other, lambda a, b: a == b)
|
|
diff --git selinux-python-2.8/sepolgen/tests/test_access.py selinux-python-2.8/sepolgen/tests/test_access.py
|
|
index d45a823..73a5407 100644
|
|
--- selinux-python-2.8/sepolgen/tests/test_access.py
|
|
+++ selinux-python-2.8/sepolgen/tests/test_access.py
|
|
@@ -32,6 +32,7 @@ class TestAccessVector(unittest.TestCase):
|
|
self.assertEqual(a.obj_class, None)
|
|
self.assertTrue(isinstance(a.perms, refpolicy.IdSet))
|
|
self.assertTrue(isinstance(a.audit_msgs, type([])))
|
|
+ self.assertTrue(isinstance(a.xperms, type({})))
|
|
self.assertEqual(len(a.audit_msgs), 0)
|
|
|
|
# Construction from a list
|
|
@@ -61,6 +62,10 @@ class TestAccessVector(unittest.TestCase):
|
|
self.assertEqual(a.obj_class, l.obj_class)
|
|
self.assertEqual(a.perms, l.perms)
|
|
|
|
+ l2 = access.AccessVector()
|
|
+ with self.assertRaises(ValueError):
|
|
+ l2.from_list(['foo', 'bar', 'file'])
|
|
+
|
|
def test_to_list(self):
|
|
a = access.AccessVector()
|
|
a.src_type = "foo"
|
|
@@ -145,7 +150,80 @@ class TestAccessVector(unittest.TestCase):
|
|
|
|
b.perms = refpolicy.IdSet(["read", "append"])
|
|
self.assertNotEqual(a, b)
|
|
+
|
|
+ def test_merge_noxperm(self):
|
|
+ """Test merging two AVs without xperms"""
|
|
+ a = access.AccessVector(["foo", "bar", "file", "read", "write"])
|
|
+ b = access.AccessVector(["foo", "bar", "file", "append"])
|
|
+
|
|
+ a.merge(b)
|
|
+ self.assertEqual(sorted(list(a.perms)), ["append", "read", "write"])
|
|
+
|
|
+ def text_merge_xperm1(self):
|
|
+ """Test merging AV that contains xperms with AV that does not"""
|
|
+ a = access.AccessVector(["foo", "bar", "file", "read"])
|
|
+ b = access.AccessVector(["foo", "bar", "file", "read"])
|
|
+ xp = refpolicy.XpermSet()
|
|
+ xp.add(42)
|
|
+ xp.add(12345)
|
|
+ b.xperms = {"ioctl": xp}
|
|
+
|
|
+ a.merge(b)
|
|
+ self.assertEqual(sorted(list(a.perms)), ["append", "read", "write"])
|
|
+ self.assertEqual(list(a.xperms.keys()), ["ioctl"])
|
|
+ self.assertEqual(a.xperms["ioctl"].to_string(), "{ 42 12345 }")
|
|
+
|
|
+ def text_merge_xperm2(self):
|
|
+ """Test merging AV that does not contain xperms with AV that does"""
|
|
+ a = access.AccessVector(["foo", "bar", "file", "read"])
|
|
+ xp = refpolicy.XpermSet()
|
|
+ xp.add(42)
|
|
+ xp.add(12345)
|
|
+ a.xperms = {"ioctl": xp}
|
|
+ b = access.AccessVector(["foo", "bar", "file", "read"])
|
|
+
|
|
+ a.merge(b)
|
|
+ self.assertEqual(sorted(list(a.perms)), ["append", "read", "write"])
|
|
+ self.assertEqual(list(a.xperms.keys()), ["ioctl"])
|
|
+ self.assertEqual(a.xperms["ioctl"].to_string(), "{ 42 12345 }")
|
|
+
|
|
+ def test_merge_xperm_diff_op(self):
|
|
+ """Test merging two AVs that contain xperms with different operation"""
|
|
+ a = access.AccessVector(["foo", "bar", "file", "read"])
|
|
+ xp1 = refpolicy.XpermSet()
|
|
+ xp1.add(23)
|
|
+ a.xperms = {"asdf": xp1}
|
|
+
|
|
+ b = access.AccessVector(["foo", "bar", "file", "read"])
|
|
+ xp2 = refpolicy.XpermSet()
|
|
+ xp2.add(42)
|
|
+ xp2.add(12345)
|
|
+ b.xperms = {"ioctl": xp2}
|
|
+
|
|
+ a.merge(b)
|
|
+ self.assertEqual(list(a.perms), ["read"])
|
|
+ self.assertEqual(sorted(list(a.xperms.keys())), ["asdf", "ioctl"])
|
|
+ self.assertEqual(a.xperms["asdf"].to_string(), "23")
|
|
+ self.assertEqual(a.xperms["ioctl"].to_string(), "{ 42 12345 }")
|
|
|
|
+ def test_merge_xperm_same_op(self):
|
|
+ """Test merging two AVs that contain xperms with same operation"""
|
|
+ a = access.AccessVector(["foo", "bar", "file", "read"])
|
|
+ xp1 = refpolicy.XpermSet()
|
|
+ xp1.add(23)
|
|
+ a.xperms = {"ioctl": xp1}
|
|
+
|
|
+ b = access.AccessVector(["foo", "bar", "file", "read"])
|
|
+ xp2 = refpolicy.XpermSet()
|
|
+ xp2.add(42)
|
|
+ xp2.add(12345)
|
|
+ b.xperms = {"ioctl": xp2}
|
|
+
|
|
+ a.merge(b)
|
|
+ self.assertEqual(list(a.perms), ["read"])
|
|
+ self.assertEqual(list(a.xperms.keys()), ["ioctl"])
|
|
+ self.assertEqual(a.xperms["ioctl"].to_string(), "{ 23 42 12345 }")
|
|
+
|
|
class TestUtilFunctions(unittest.TestCase):
|
|
def test_is_idparam(self):
|
|
self.assertTrue(access.is_idparam("$1"))
|
|
@@ -260,3 +338,53 @@ class TestAccessVectorSet(unittest.TestCase):
|
|
b = access.AccessVectorSet()
|
|
b.from_list(avl)
|
|
self.assertEqual(len(b), 3)
|
|
+
|
|
+ def test_add_av_first(self):
|
|
+ """Test adding first AV to the AV set"""
|
|
+ avs = access.AccessVectorSet()
|
|
+ av = access.AccessVector(['foo', 'bar', 'file', 'read'])
|
|
+
|
|
+ avs.add_av(av)
|
|
+
|
|
+ self.assertEqual(avs.to_list(), [['foo', 'bar', 'file', 'read']])
|
|
+
|
|
+ def test_add_av_second(self):
|
|
+ """Test adding second AV to the AV set with same source and target
|
|
+ context and class"""
|
|
+ avs = access.AccessVectorSet()
|
|
+ av1 = access.AccessVector(['foo', 'bar', 'file', 'read'])
|
|
+ av2 = access.AccessVector(['foo', 'bar', 'file', 'write'])
|
|
+
|
|
+ avs.add_av(av1)
|
|
+ avs.add_av(av2)
|
|
+
|
|
+ self.assertEqual(avs.to_list(), [['foo', 'bar', 'file', 'read',
|
|
+ 'write']])
|
|
+
|
|
+ def test_add_av_with_msg(self):
|
|
+ """Test adding audit message"""
|
|
+ avs = access.AccessVectorSet()
|
|
+ av = access.AccessVector(['foo', 'bar', 'file', 'read'])
|
|
+
|
|
+ avs.add_av(av, 'test message')
|
|
+
|
|
+ self.assertEqual(avs.src['foo']['bar']['file', av.type].audit_msgs,
|
|
+ ['test message'])
|
|
+
|
|
+ def test_add(self):
|
|
+ """Test adding AV to the set"""
|
|
+ s = access.AccessVectorSet()
|
|
+
|
|
+ def test_add_av(av, audit_msg=None):
|
|
+ self.assertEqual(av.src_type, 'foo')
|
|
+ self.assertEqual(av.tgt_type, 'bar')
|
|
+ self.assertEqual(av.obj_class, 'file')
|
|
+ self.assertEqual(list(av.perms), ['read'])
|
|
+ self.assertEqual(av.data, 'test data')
|
|
+ self.assertEqual(av.type, 42)
|
|
+ self.assertEqual(audit_msg, 'test message')
|
|
+
|
|
+ s.add_av = test_add_av
|
|
+
|
|
+ s.add("foo", "bar", "file", refpolicy.IdSet(["read"]),
|
|
+ audit_msg='test message', avc_type=42, data='test data')
|
|
diff --git selinux-python-2.8/sepolgen/tests/test_audit.py selinux-python-2.8/sepolgen/tests/test_audit.py
|
|
index 6379954..dbe6be2 100644
|
|
--- selinux-python-2.8/sepolgen/tests/test_audit.py
|
|
+++ selinux-python-2.8/sepolgen/tests/test_audit.py
|
|
@@ -56,6 +56,18 @@ type=SYSCALL msg=audit(1162852201.019:1225): arch=40000003 syscall=11 success=ye
|
|
type=AVC msg=audit(1162852201.019:1225): avc: denied { execute_no_trans } for pid=6974 comm="sh" name="sa1" dev=dm-0 ino=13061698 scontext=system_u:system_r:crond_t:s0-s0:c0.c1023 tcontext=system_u:object_r:lib_t:s0 tclass=file
|
|
type=AVC msg=audit(1162852201.019:1225): avc: denied { execute } for pid=6974 comm="sh" name="sa1" dev=dm-0 ino=13061698 scontext=system_u:system_r:crond_t:s0-s0:c0.c1023 tcontext=system_u:object_r:lib_t:s0 tclass=file"""
|
|
|
|
+xperms1 = """type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 ioctlcmd=0x42 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
|
|
+"""
|
|
+xperms2 = """type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 ioctlcmd=0x42 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
|
|
+type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 ioctlcmd=0x1234 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
|
|
+type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 ioctlcmd=0xdead scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
|
|
+type=AVC msg=audit(1516626657.910:4461): avc: denied { getattr } for pid=4310 comm="test" path="/root/test" ino=8619937 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=dir permissive=0
|
|
+"""
|
|
+xperms_invalid = """type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 ioctlcmd=asdf scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
|
|
+"""
|
|
+xperms_without = """type=AVC msg=audit(1516626657.910:4461): avc: denied { ioctl } for pid=4310 comm="test" path="/root/test" ino=8619937 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:test_file_t:s0 tclass=file permissive=0
|
|
+"""
|
|
+
|
|
class TestAVCMessage(unittest.TestCase):
|
|
def test_defs(self):
|
|
avc = sepolgen.audit.AVCMessage(audit1)
|
|
@@ -64,6 +76,7 @@ class TestAVCMessage(unittest.TestCase):
|
|
self.assertEqual(avc.tcontext, sc)
|
|
self.assertEqual(avc.tclass, "")
|
|
self.assertEqual(avc.accesses, [])
|
|
+ self.assertEqual(avc.ioctlcmd, None)
|
|
|
|
def test_granted(self):
|
|
avc = sepolgen.audit.AVCMessage(granted1)
|
|
@@ -84,6 +97,29 @@ class TestAVCMessage(unittest.TestCase):
|
|
|
|
self.assertEqual(avc.denial, False)
|
|
|
|
+ def test_xperms(self):
|
|
+ """Test that the ioctlcmd field is parsed"""
|
|
+ avc = sepolgen.audit.AVCMessage(xperms1)
|
|
+ recs = xperms1.split()
|
|
+ avc.from_split_string(recs)
|
|
+
|
|
+ self.assertEqual(avc.ioctlcmd, 66)
|
|
+
|
|
+ def test_xperms_invalid(self):
|
|
+ """Test message with invalid value in the ioctlcmd field"""
|
|
+ avc = sepolgen.audit.AVCMessage(xperms_invalid)
|
|
+ recs = xperms_invalid.split()
|
|
+ avc.from_split_string(recs)
|
|
+
|
|
+ self.assertIsNone(avc.ioctlcmd)
|
|
+
|
|
+ def test_xperms_without(self):
|
|
+ """Test message without the ioctlcmd field"""
|
|
+ avc = sepolgen.audit.AVCMessage(xperms_without)
|
|
+ recs = xperms_without.split()
|
|
+ avc.from_split_string(recs)
|
|
+
|
|
+ self.assertIsNone(avc.ioctlcmd)
|
|
|
|
def test_from_split_string(self):
|
|
# syslog message
|
|
@@ -172,6 +208,20 @@ class TestAuditParser(unittest.TestCase):
|
|
self.assertEqual(len(a.invalid_msgs), 0)
|
|
self.assertEqual(len(a.policy_load_msgs), 0)
|
|
|
|
+ def test_parse_xperms(self):
|
|
+ """ Test that correct access vectors are generated from a set of AVC
|
|
+ denial messages. """
|
|
+ a = sepolgen.audit.AuditParser()
|
|
+ a.parse_string(xperms2)
|
|
+ av_set = a.to_access()
|
|
+
|
|
+ self.assertEqual(len(av_set), 2)
|
|
+ av_list = list(sorted(av_set))
|
|
+ self.assertEqual(av_list[0].xperms, {})
|
|
+ self.assertEqual(list(av_list[1].xperms), ["ioctl"])
|
|
+ self.assertEqual(av_list[1].xperms["ioctl"].ranges, [(66,66),
|
|
+ (4660,4660), (57005,57005)])
|
|
+
|
|
class TestGeneration(unittest.TestCase):
|
|
def test_generation(self):
|
|
parser = sepolgen.audit.AuditParser()
|
|
diff --git selinux-python-2.8/sepolgen/tests/test_policygen.py selinux-python-2.8/sepolgen/tests/test_policygen.py
|
|
index 58d1adf..59496e8 100644
|
|
--- selinux-python-2.8/sepolgen/tests/test_policygen.py
|
|
+++ selinux-python-2.8/sepolgen/tests/test_policygen.py
|
|
@@ -19,13 +19,117 @@
|
|
|
|
import unittest
|
|
import sepolgen.policygen as policygen
|
|
+import sepolgen.access as access
|
|
+import sepolgen.refpolicy as refpolicy
|
|
|
|
-class PolicyGenerator(unittest.TestCase):
|
|
- def __init__(self):
|
|
- g = policygen.PolicyGenerator()
|
|
-
|
|
+class TestPolicyGenerator(unittest.TestCase):
|
|
+ def setUp(self):
|
|
+ self.g = policygen.PolicyGenerator()
|
|
|
|
+ def test_init(self):
|
|
+ """ Test that extended permission AV rules are not generated by
|
|
+ default. """
|
|
+ self.assertFalse(self.g.xperms)
|
|
|
|
+ def test_set_gen_xperms(self):
|
|
+ """ Test turning on and off generating of extended permission
|
|
+ AV rules. """
|
|
+ self.g.set_gen_xperms(True)
|
|
+ self.assertTrue(self.g.xperms)
|
|
+ self.g.set_gen_xperms(False)
|
|
+ self.assertFalse(self.g.xperms)
|
|
|
|
+ def test_av_rules(self):
|
|
+ """ Test generating of AV rules from access vectors. """
|
|
+ av1 = access.AccessVector(["test_src_t", "test_tgt_t", "file", "ioctl"])
|
|
+ av2 = access.AccessVector(["test_src_t", "test_tgt_t", "file", "open"])
|
|
+ av3 = access.AccessVector(["test_src_t", "test_tgt_t", "file", "read"])
|
|
|
|
+ avs = access.AccessVectorSet()
|
|
+ avs.add_av(av1)
|
|
+ avs.add_av(av2)
|
|
+ avs.add_av(av3)
|
|
+
|
|
+ self.g.add_access(avs)
|
|
+
|
|
+ self.assertEqual(len(self.g.module.children), 1)
|
|
+ r = self.g.module.children[0]
|
|
+ self.assertIsInstance(r, refpolicy.AVRule)
|
|
+ self.assertEqual(r.to_string(),
|
|
+ "allow test_src_t test_tgt_t:file { ioctl open read };")
|
|
+
|
|
+ def test_ext_av_rules(self):
|
|
+ """ Test generating of extended permission AV rules from access
|
|
+ vectors. """
|
|
+ self.g.set_gen_xperms(True)
|
|
+
|
|
+ av1 = access.AccessVector(["test_src_t", "test_tgt_t", "file", "ioctl"])
|
|
+ av1.xperms['ioctl'] = refpolicy.XpermSet()
|
|
+ av1.xperms['ioctl'].add(42)
|
|
+ av2 = access.AccessVector(["test_src_t", "test_tgt_t", "file", "ioctl"])
|
|
+ av2.xperms['ioctl'] = refpolicy.XpermSet()
|
|
+ av2.xperms['ioctl'].add(1234)
|
|
+ av3 = access.AccessVector(["test_src_t", "test_tgt_t", "dir", "ioctl"])
|
|
+ av3.xperms['ioctl'] = refpolicy.XpermSet()
|
|
+ av3.xperms['ioctl'].add(2345)
|
|
+
|
|
+ avs = access.AccessVectorSet()
|
|
+ avs.add_av(av1)
|
|
+ avs.add_av(av2)
|
|
+ avs.add_av(av3)
|
|
+
|
|
+ self.g.add_access(avs)
|
|
+
|
|
+ self.assertEqual(len(self.g.module.children), 4)
|
|
+
|
|
+ # we cannot sort the rules, so find all rules manually
|
|
+ av_rule1 = av_rule2 = av_ext_rule1 = av_ext_rule2 = None
|
|
+
|
|
+ for r in self.g.module.children:
|
|
+ if isinstance(r, refpolicy.AVRule):
|
|
+ if 'file' in r.obj_classes:
|
|
+ av_rule1 = r
|
|
+ else:
|
|
+ av_rule2 = r
|
|
+ elif isinstance(r, refpolicy.AVExtRule):
|
|
+ if 'file' in r.obj_classes:
|
|
+ av_ext_rule1 = r
|
|
+ else:
|
|
+ av_ext_rule2 = r
|
|
+ else:
|
|
+ self.fail("Unexpected rule type '%s'" % type(r))
|
|
+
|
|
+ # check that all rules are present
|
|
+ self.assertNotIn(None, (av_rule1, av_rule2, av_ext_rule1, av_ext_rule2))
|
|
+
|
|
+ self.assertEqual(av_rule1.rule_type, av_rule1.ALLOW)
|
|
+ self.assertEqual(av_rule1.src_types, {"test_src_t"})
|
|
+ self.assertEqual(av_rule1.tgt_types, {"test_tgt_t"})
|
|
+ self.assertEqual(av_rule1.obj_classes, {"file"})
|
|
+ self.assertEqual(av_rule1.perms, {"ioctl"})
|
|
+
|
|
+ self.assertEqual(av_ext_rule1.rule_type, av_ext_rule1.ALLOWXPERM)
|
|
+ self.assertEqual(av_ext_rule1.src_types, {"test_src_t"})
|
|
+ self.assertEqual(av_ext_rule1.tgt_types, {"test_tgt_t"})
|
|
+ self.assertEqual(av_ext_rule1.obj_classes, {"file"})
|
|
+ self.assertEqual(av_ext_rule1.operation, "ioctl")
|
|
+ xp1 = refpolicy.XpermSet()
|
|
+ xp1.add(42)
|
|
+ xp1.add(1234)
|
|
+ self.assertEqual(av_ext_rule1.xperms.ranges, xp1.ranges)
|
|
+
|
|
+ self.assertEqual(av_rule2.rule_type, av_rule2.ALLOW)
|
|
+ self.assertEqual(av_rule2.src_types, {"test_src_t"})
|
|
+ self.assertEqual(av_rule2.tgt_types, {"test_tgt_t"})
|
|
+ self.assertEqual(av_rule2.obj_classes, {"dir"})
|
|
+ self.assertEqual(av_rule2.perms, {"ioctl"})
|
|
+
|
|
+ self.assertEqual(av_ext_rule2.rule_type, av_ext_rule2.ALLOWXPERM)
|
|
+ self.assertEqual(av_ext_rule2.src_types, {"test_src_t"})
|
|
+ self.assertEqual(av_ext_rule2.tgt_types, {"test_tgt_t"})
|
|
+ self.assertEqual(av_ext_rule2.obj_classes, {"dir"})
|
|
+ self.assertEqual(av_ext_rule2.operation, "ioctl")
|
|
+ xp2 = refpolicy.XpermSet()
|
|
+ xp2.add(2345)
|
|
+ self.assertEqual(av_ext_rule2.xperms.ranges, xp2.ranges)
|
|
|
|
diff --git selinux-python-2.8/sepolgen/tests/test_refpolicy.py selinux-python-2.8/sepolgen/tests/test_refpolicy.py
|
|
index 16e6680..64c48df 100644
|
|
--- selinux-python-2.8/sepolgen/tests/test_refpolicy.py
|
|
+++ selinux-python-2.8/sepolgen/tests/test_refpolicy.py
|
|
@@ -19,6 +19,7 @@
|
|
|
|
import unittest
|
|
import sepolgen.refpolicy as refpolicy
|
|
+import sepolgen.access as access
|
|
import selinux
|
|
|
|
class TestIdSet(unittest.TestCase):
|
|
@@ -33,6 +34,74 @@ class TestIdSet(unittest.TestCase):
|
|
s.add("read")
|
|
self.assertEqual(s.to_space_str(), "read")
|
|
|
|
+class TestXpermSet(unittest.TestCase):
|
|
+ def test_init(self):
|
|
+ """ Test that all atttributes are correctly initialized. """
|
|
+ s1 = refpolicy.XpermSet()
|
|
+ self.assertEqual(s1.complement, False)
|
|
+ self.assertEqual(s1.ranges, [])
|
|
+
|
|
+ s2 = refpolicy.XpermSet(True)
|
|
+ self.assertEqual(s2.complement, True)
|
|
+ self.assertEqual(s2.ranges, [])
|
|
+
|
|
+ def test_normalize_ranges(self):
|
|
+ """ Test that ranges that are overlapping or neighboring are correctly
|
|
+ merged into one range. """
|
|
+ s = refpolicy.XpermSet()
|
|
+ s.ranges = [(1, 7), (5, 10), (100, 110), (102, 107), (200, 205),
|
|
+ (205, 210), (300, 305), (306, 310), (400, 405), (407, 410),
|
|
+ (500, 502), (504, 508), (500, 510)]
|
|
+ s._XpermSet__normalize_ranges()
|
|
+
|
|
+ i = 0
|
|
+ r = list(sorted(s.ranges))
|
|
+ while i < len(r) - 1:
|
|
+ # check that range low bound is less than equal than the upper bound
|
|
+ self.assertLessEqual(r[i][0], r[i][1])
|
|
+ # check that two ranges are not overlapping or neighboring
|
|
+ self.assertGreater(r[i + 1][0] - r[i][1], 1)
|
|
+ i += 1
|
|
+
|
|
+ def test_add(self):
|
|
+ """ Test adding new values or ranges to the set. """
|
|
+ s = refpolicy.XpermSet()
|
|
+ s.add(1, 7)
|
|
+ s.add(5, 10)
|
|
+ s.add(42)
|
|
+ self.assertEqual(s.ranges, [(1,10), (42,42)])
|
|
+
|
|
+ def test_extend(self):
|
|
+ """ Test adding ranges from another XpermSet object. """
|
|
+ a = refpolicy.XpermSet()
|
|
+ a.add(1, 7)
|
|
+
|
|
+ b = refpolicy.XpermSet()
|
|
+ b.add(5, 10)
|
|
+
|
|
+ a.extend(b)
|
|
+ self.assertEqual(a.ranges, [(1,10)])
|
|
+
|
|
+ def test_to_string(self):
|
|
+ """ Test printing the values to a string. """
|
|
+ a = refpolicy.XpermSet()
|
|
+ a.complement = False
|
|
+ self.assertEqual(a.to_string(), "")
|
|
+ a.complement = True
|
|
+ self.assertEqual(a.to_string(), "")
|
|
+ a.add(1234)
|
|
+ self.assertEqual(a.to_string(), "~ 1234")
|
|
+ a.complement = False
|
|
+ self.assertEqual(a.to_string(), "1234")
|
|
+ a.add(2345)
|
|
+ self.assertEqual(a.to_string(), "{ 1234 2345 }")
|
|
+ a.complement = True
|
|
+ self.assertEqual(a.to_string(), "~ { 1234 2345 }")
|
|
+ a.add(42,64)
|
|
+ self.assertEqual(a.to_string(), "~ { 42-64 1234 2345 }")
|
|
+ a.complement = False
|
|
+ self.assertEqual(a.to_string(), "{ 42-64 1234 2345 }")
|
|
+
|
|
class TestSecurityContext(unittest.TestCase):
|
|
def test_init(self):
|
|
sc = refpolicy.SecurityContext()
|
|
@@ -110,6 +179,76 @@ class TestAVRule(unittest.TestCase):
|
|
b.sort()
|
|
self.assertEqual(a, b)
|
|
|
|
+class TestAVExtRule(unittest.TestCase):
|
|
+ def test_init(self):
|
|
+ """ Test initialization of attributes """
|
|
+ a = refpolicy.AVExtRule()
|
|
+ self.assertEqual(a.rule_type, a.ALLOWXPERM)
|
|
+ self.assertIsInstance(a.src_types, set)
|
|
+ self.assertIsInstance(a.tgt_types, set)
|
|
+ self.assertIsInstance(a.obj_classes, set)
|
|
+ self.assertIsNone(a.operation)
|
|
+ self.assertIsInstance(a.xperms, refpolicy.XpermSet)
|
|
+
|
|
+ def test_rule_type_str(self):
|
|
+ """ Test strings returned by __rule_type_str() """
|
|
+ a = refpolicy.AVExtRule()
|
|
+ self.assertEqual(a._AVExtRule__rule_type_str(), "allowxperm")
|
|
+ a.rule_type = a.ALLOWXPERM
|
|
+ self.assertEqual(a._AVExtRule__rule_type_str(), "allowxperm")
|
|
+ a.rule_type = a.DONTAUDITXPERM
|
|
+ self.assertEqual(a._AVExtRule__rule_type_str(), "dontauditxperm")
|
|
+ a.rule_type = a.NEVERALLOWXPERM
|
|
+ self.assertEqual(a._AVExtRule__rule_type_str(), "neverallowxperm")
|
|
+ a.rule_type = a.AUDITALLOWXPERM
|
|
+ self.assertEqual(a._AVExtRule__rule_type_str(), "auditallowxperm")
|
|
+ a.rule_type = 42
|
|
+ self.assertIsNone(a._AVExtRule__rule_type_str())
|
|
+
|
|
+ def test_from_av(self):
|
|
+ """ Test creating the rule from an access vector. """
|
|
+ av = access.AccessVector(["foo", "bar", "file", "ioctl"])
|
|
+ xp = refpolicy.XpermSet()
|
|
+ av.xperms = { "ioctl": xp }
|
|
+
|
|
+ a = refpolicy.AVExtRule()
|
|
+
|
|
+ a.from_av(av, "ioctl")
|
|
+ self.assertEqual(a.src_types, {"foo"})
|
|
+ self.assertEqual(a.tgt_types, {"bar"})
|
|
+ self.assertEqual(a.obj_classes, {"file"})
|
|
+ self.assertEqual(a.operation, "ioctl")
|
|
+ self.assertIs(a.xperms, xp)
|
|
+
|
|
+ def test_from_av_self(self):
|
|
+ """ Test creating the rule from an access vector that has same
|
|
+ source and target context. """
|
|
+ av = access.AccessVector(["foo", "foo", "file", "ioctl"])
|
|
+ xp = refpolicy.XpermSet()
|
|
+ av.xperms = { "ioctl": xp }
|
|
+
|
|
+ a = refpolicy.AVExtRule()
|
|
+
|
|
+ a.from_av(av, "ioctl")
|
|
+ self.assertEqual(a.src_types, {"foo"})
|
|
+ self.assertEqual(a.tgt_types, {"self"})
|
|
+ self.assertEqual(a.obj_classes, {"file"})
|
|
+ self.assertEqual(a.operation, "ioctl")
|
|
+ self.assertIs(a.xperms, xp)
|
|
+
|
|
+ def test_to_string(self):
|
|
+ """ Test printing the rule to a string. """
|
|
+ a = refpolicy.AVExtRule()
|
|
+ a._AVExtRule__rule_type_str = lambda: "first"
|
|
+ a.src_types.to_space_str = lambda: "second"
|
|
+ a.tgt_types.to_space_str = lambda: "third"
|
|
+ a.obj_classes.to_space_str = lambda: "fourth"
|
|
+ a.operation = "fifth"
|
|
+ a.xperms.to_string = lambda: "seventh"
|
|
+
|
|
+ self.assertEqual(a.to_string(),
|
|
+ "first second third:fourth fifth seventh;")
|
|
+
|
|
class TestTypeRule(unittest.TestCase):
|
|
def test_init(self):
|
|
a = refpolicy.TypeRule()
|
|
diff --git selinux-python-2.8/sepolicy/sepolicy.py selinux-python-2.8/sepolicy/sepolicy.py
|
|
index 141f64e..5880176 100755
|
|
--- selinux-python-2.8/sepolicy/sepolicy.py
|
|
+++ selinux-python-2.8/sepolicy/sepolicy.py
|
|
@@ -27,7 +27,7 @@ import selinux
|
|
import sepolicy
|
|
from sepolicy import get_os_version, get_conditionals, get_conditionals_format_text
|
|
import argparse
|
|
-PROGNAME = "policycoreutils"
|
|
+PROGNAME = "selinux-python"
|
|
try:
|
|
import gettext
|
|
kwargs = {}
|
|
@@ -60,8 +60,6 @@ class CheckPath(argparse.Action):
|
|
class CheckType(argparse.Action):
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
- domains = sepolicy.get_all_domains()
|
|
-
|
|
if isinstance(values, str):
|
|
setattr(namespace, self.dest, values)
|
|
else:
|
|
@@ -103,6 +101,7 @@ class CheckDomain(argparse.Action):
|
|
domains = sepolicy.get_all_domains()
|
|
|
|
if isinstance(values, str):
|
|
+ values = sepolicy.get_real_type_name(values)
|
|
if values not in domains:
|
|
raise ValueError("%s must be an SELinux process domain:\nValid domains: %s" % (values, ", ".join(domains)))
|
|
setattr(namespace, self.dest, values)
|
|
@@ -112,6 +111,7 @@ class CheckDomain(argparse.Action):
|
|
newval = []
|
|
|
|
for v in values:
|
|
+ v = sepolicy.get_real_type_name(v)
|
|
if v not in domains:
|
|
raise ValueError("%s must be an SELinux process domain:\nValid domains: %s" % (v, ", ".join(domains)))
|
|
newval.append(v)
|
|
@@ -167,10 +167,11 @@ class CheckPortType(argparse.Action):
|
|
if not newval:
|
|
newval = []
|
|
for v in values:
|
|
+ v = sepolicy.get_real_type_name(v)
|
|
if v not in port_types:
|
|
raise ValueError("%s must be an SELinux port type:\nValid port types: %s" % (v, ", ".join(port_types)))
|
|
newval.append(v)
|
|
- setattr(namespace, self.dest, values)
|
|
+ setattr(namespace, self.dest, newval)
|
|
|
|
|
|
class LoadPolicy(argparse.Action):
|
|
diff --git selinux-python-2.8/sepolicy/sepolicy/__init__.py selinux-python-2.8/sepolicy/sepolicy/__init__.py
|
|
index 89346ab..1b116f6 100644
|
|
--- selinux-python-2.8/sepolicy/sepolicy/__init__.py
|
|
+++ selinux-python-2.8/sepolicy/sepolicy/__init__.py
|
|
@@ -15,7 +15,7 @@ import os
|
|
import re
|
|
import gzip
|
|
|
|
-PROGNAME = "policycoreutils"
|
|
+PROGNAME = "selinux-python"
|
|
try:
|
|
import gettext
|
|
kwargs = {}
|
|
@@ -119,16 +119,34 @@ all_allow_rules = None
|
|
all_transitions = None
|
|
|
|
|
|
+def policy_sortkey(policy_path):
|
|
+ # Parse the extension of a policy path which looks like .../policy/policy.31
|
|
+ extension = policy_path.rsplit('/policy.', 1)[1]
|
|
+ try:
|
|
+ return int(extension), policy_path
|
|
+ except ValueError:
|
|
+ # Fallback with sorting on the full path
|
|
+ return 0, policy_path
|
|
+
|
|
def get_installed_policy(root="/"):
|
|
try:
|
|
path = root + selinux.selinux_binary_policy_path()
|
|
policies = glob.glob("%s.*" % path)
|
|
- policies.sort()
|
|
+ policies.sort(key=policy_sortkey)
|
|
return policies[-1]
|
|
except:
|
|
pass
|
|
raise ValueError(_("No SELinux Policy installed"))
|
|
|
|
+def get_store_policy(store):
|
|
+ """Get the path to the policy file located in the given store name"""
|
|
+ policies = glob.glob("%s%s/policy/policy.*" %
|
|
+ (selinux.selinux_path(), store))
|
|
+ if not policies:
|
|
+ return None
|
|
+ # Return the policy with the higher version number
|
|
+ policies.sort(key=policy_sortkey)
|
|
+ return policies[-1]
|
|
|
|
def policy(policy_file):
|
|
global all_domains
|
|
@@ -156,6 +174,11 @@ def policy(policy_file):
|
|
except:
|
|
raise ValueError(_("Failed to read %s policy file") % policy_file)
|
|
|
|
+def load_store_policy(store):
|
|
+ policy_file = get_store_policy(store)
|
|
+ if not policy_file:
|
|
+ return None
|
|
+ policy(policy_file)
|
|
|
|
try:
|
|
policy_file = get_installed_policy()
|
|
@@ -168,15 +191,21 @@ except ValueError as e:
|
|
def info(setype, name=None):
|
|
if setype == TYPE:
|
|
q = setools.TypeQuery(_pol)
|
|
- if name:
|
|
- q.name = name
|
|
+ q.name = name
|
|
+ results = list(q.results())
|
|
+
|
|
+ if name and len(results) < 1:
|
|
+ # type not found, try alias
|
|
+ q.name = None
|
|
+ q.alias = name
|
|
+ results = list(q.results())
|
|
|
|
return ({
|
|
'aliases': list(map(str, x.aliases())),
|
|
'name': str(x),
|
|
'permissive': bool(x.ispermissive),
|
|
'attributes': list(map(str, x.attributes()))
|
|
- } for x in q.results())
|
|
+ } for x in results)
|
|
|
|
elif setype == ROLE:
|
|
q = setools.RoleQuery(_pol)
|
|
@@ -272,34 +301,38 @@ def _setools_rule_to_dict(rule):
|
|
'class': str(rule.tclass),
|
|
}
|
|
|
|
+ # Evaluate boolean expression associated with given rule (if there is any)
|
|
try:
|
|
- enabled = bool(rule.qpol_symbol.is_enabled(rule.policy))
|
|
+ # Get state of all booleans in the conditional expression
|
|
+ boolstate = {}
|
|
+ for boolean in rule.conditional.booleans:
|
|
+ boolstate[str(boolean)] = boolean.state
|
|
+ # evaluate if the rule is enabled
|
|
+ enabled = rule.conditional.evaluate(**boolstate) == rule.conditional_block
|
|
except AttributeError:
|
|
+ # non-conditional rules are always enabled
|
|
enabled = True
|
|
|
|
- if isinstance(rule, setools.policyrep.terule.AVRule):
|
|
- d['enabled'] = enabled
|
|
+ d['enabled'] = enabled
|
|
|
|
try:
|
|
d['permlist'] = list(map(str, rule.perms))
|
|
- except setools.policyrep.exception.RuleUseError:
|
|
+ except AttributeError:
|
|
pass
|
|
|
|
try:
|
|
d['transtype'] = str(rule.default)
|
|
- except setools.policyrep.exception.RuleUseError:
|
|
+ except AttributeError:
|
|
pass
|
|
|
|
try:
|
|
d['boolean'] = [(str(rule.conditional), enabled)]
|
|
- except (AttributeError, setools.policyrep.exception.RuleNotConditional):
|
|
+ except AttributeError:
|
|
pass
|
|
|
|
try:
|
|
d['filename'] = rule.filename
|
|
- except (AttributeError,
|
|
- setools.policyrep.exception.RuleNotConditional,
|
|
- setools.policyrep.exception.TERuleNoFilename):
|
|
+ except AttributeError:
|
|
pass
|
|
|
|
return d
|
|
@@ -334,6 +367,8 @@ def search(types, seinfo=None):
|
|
tertypes.append(NEVERALLOW)
|
|
if AUDITALLOW in types:
|
|
tertypes.append(AUDITALLOW)
|
|
+ if DONTAUDIT in types:
|
|
+ tertypes.append(DONTAUDIT)
|
|
|
|
if len(tertypes) > 0:
|
|
q = setools.TERuleQuery(_pol,
|
|
@@ -437,6 +472,20 @@ def get_file_types(setype):
|
|
return mpaths
|
|
|
|
|
|
+def get_real_type_name(name):
|
|
+ """Return the real name of a type
|
|
+
|
|
+ * If 'name' refers to a type alias, return the corresponding type name.
|
|
+ * Otherwise return the original name (even if the type does not exist).
|
|
+ """
|
|
+ if not name:
|
|
+ return name
|
|
+
|
|
+ try:
|
|
+ return next(info(TYPE, name))["name"]
|
|
+ except (RuntimeError, StopIteration):
|
|
+ return name
|
|
+
|
|
def get_writable_files(setype):
|
|
file_types = get_all_file_types()
|
|
all_writes = []
|
|
@@ -1048,6 +1097,8 @@ def _dict_has_perms(dict, perms):
|
|
def gen_short_name(setype):
|
|
all_domains = get_all_domains()
|
|
if setype.endswith("_t"):
|
|
+ # replace aliases with corresponding types
|
|
+ setype = get_real_type_name(setype)
|
|
domainname = setype[:-2]
|
|
else:
|
|
domainname = setype
|
|
@@ -1160,27 +1211,14 @@ def boolean_desc(boolean):
|
|
|
|
|
|
def get_os_version():
|
|
- os_version = ""
|
|
- pkg_name = "selinux-policy"
|
|
+ system_release = ""
|
|
try:
|
|
- try:
|
|
- from commands import getstatusoutput
|
|
- except ImportError:
|
|
- from subprocess import getstatusoutput
|
|
- rc, output = getstatusoutput("rpm -q '%s'" % pkg_name)
|
|
- if rc == 0:
|
|
- os_version = output.split(".")[-2]
|
|
- except:
|
|
- os_version = ""
|
|
-
|
|
- if os_version[0:2] == "fc":
|
|
- os_version = "Fedora" + os_version[2:]
|
|
- elif os_version[0:2] == "el":
|
|
- os_version = "RHEL" + os_version[2:]
|
|
- else:
|
|
- os_version = ""
|
|
+ with open('/etc/system-release') as f:
|
|
+ system_release = f.readline().rstrip()
|
|
+ except IOError:
|
|
+ system_release = "Misc"
|
|
|
|
- return os_version
|
|
+ return system_release
|
|
|
|
|
|
def reinit():
|
|
diff --git selinux-python-2.8/sepolicy/sepolicy/generate.py selinux-python-2.8/sepolicy/sepolicy/generate.py
|
|
index f814e27..8e53033 100644
|
|
--- selinux-python-2.8/sepolicy/sepolicy/generate.py
|
|
+++ selinux-python-2.8/sepolicy/sepolicy/generate.py
|
|
@@ -52,7 +52,7 @@ import sepolgen.defaults as defaults
|
|
##
|
|
## I18N
|
|
##
|
|
-PROGNAME = "policycoreutils"
|
|
+PROGNAME = "selinux-python"
|
|
try:
|
|
import gettext
|
|
kwargs = {}
|
|
@@ -103,7 +103,9 @@ def get_all_ports():
|
|
for p in sepolicy.info(sepolicy.PORT):
|
|
if p['type'] == "reserved_port_t" or \
|
|
p['type'] == "port_t" or \
|
|
- p['type'] == "hi_reserved_port_t":
|
|
+ p['type'] == "hi_reserved_port_t" or \
|
|
+ p['type'] == "ephemeral_port_t" or \
|
|
+ p['type'] == "unreserved_port_t":
|
|
continue
|
|
dict[(p['low'], p['high'], p['protocol'])] = (p['type'], p.get('range'))
|
|
return dict
|
|
diff --git selinux-python-2.8/sepolicy/sepolicy/gui.py selinux-python-2.8/sepolicy/sepolicy/gui.py
|
|
index 537d516..1e3c3f3 100644
|
|
--- selinux-python-2.8/sepolicy/sepolicy/gui.py
|
|
+++ selinux-python-2.8/sepolicy/sepolicy/gui.py
|
|
@@ -43,7 +43,7 @@ import os
|
|
import re
|
|
import unicodedata
|
|
|
|
-PROGNAME = "policycoreutils"
|
|
+PROGNAME = "selinux-python"
|
|
try:
|
|
import gettext
|
|
kwargs = {}
|
|
@@ -149,6 +149,7 @@ class SELinuxGui():
|
|
self.clear_entry = True
|
|
self.files_add = False
|
|
self.network_add = False
|
|
+ self.mislabeled_files = False
|
|
|
|
self.all_domains = []
|
|
self.installed_list = []
|
|
diff --git selinux-python-2.8/sepolicy/sepolicy/interface.py selinux-python-2.8/sepolicy/sepolicy/interface.py
|
|
index 18374dc..ca0122d 100644
|
|
--- selinux-python-2.8/sepolicy/sepolicy/interface.py
|
|
+++ selinux-python-2.8/sepolicy/sepolicy/interface.py
|
|
@@ -32,7 +32,7 @@ __all__ = ['get_all_interfaces', 'get_interfaces_from_xml', 'get_admin', 'get_us
|
|
##
|
|
## I18N
|
|
##
|
|
-PROGNAME = "policycoreutils"
|
|
+PROGNAME = "selinux-python"
|
|
try:
|
|
import gettext
|
|
kwargs = {}
|
|
diff --git selinux-python-2.8/sepolicy/sepolicy/manpage.py selinux-python-2.8/sepolicy/sepolicy/manpage.py
|
|
index ed8cb71..8121e5c 100755
|
|
--- selinux-python-2.8/sepolicy/sepolicy/manpage.py
|
|
+++ selinux-python-2.8/sepolicy/sepolicy/manpage.py
|
|
@@ -126,8 +126,33 @@ def gen_domains():
|
|
domains.sort()
|
|
return domains
|
|
|
|
-types = None
|
|
|
|
+exec_types = None
|
|
+
|
|
+def _gen_exec_types():
|
|
+ global exec_types
|
|
+ if exec_types is None:
|
|
+ exec_types = next(sepolicy.info(sepolicy.ATTRIBUTE, "exec_type"))["types"]
|
|
+ return exec_types
|
|
+
|
|
+entry_types = None
|
|
+
|
|
+def _gen_entry_types():
|
|
+ global entry_types
|
|
+ if entry_types is None:
|
|
+ entry_types = next(sepolicy.info(sepolicy.ATTRIBUTE, "entry_type"))["types"]
|
|
+ return entry_types
|
|
+
|
|
+mcs_constrained_types = None
|
|
+
|
|
+def _gen_mcs_constrained_types():
|
|
+ global mcs_constrained_types
|
|
+ if mcs_constrained_types is None:
|
|
+ mcs_constrained_types = next(sepolicy.info(sepolicy.ATTRIBUTE, "mcs_constrained_type"))
|
|
+ return mcs_constrained_types
|
|
+
|
|
+
|
|
+types = None
|
|
|
|
def _gen_types():
|
|
global types
|
|
@@ -150,10 +175,6 @@ def prettyprint(f, trim):
|
|
manpage_domains = []
|
|
manpage_roles = []
|
|
|
|
-fedora_releases = ["Fedora17", "Fedora18"]
|
|
-rhel_releases = ["RHEL6", "RHEL7"]
|
|
-
|
|
-
|
|
def get_alphabet_manpages(manpage_list):
|
|
alphabet_manpages = dict.fromkeys(string.ascii_letters, [])
|
|
for i in string.ascii_letters:
|
|
@@ -183,7 +204,7 @@ def convert_manpage_to_html(html_manpage, manpage):
|
|
class HTMLManPages:
|
|
|
|
"""
|
|
- Generate a HHTML Manpages on an given SELinux domains
|
|
+ Generate a HTML Manpages on an given SELinux domains
|
|
"""
|
|
|
|
def __init__(self, manpage_roles, manpage_domains, path, os_version):
|
|
@@ -191,9 +212,9 @@ class HTMLManPages:
|
|
self.manpage_domains = get_alphabet_manpages(manpage_domains)
|
|
self.os_version = os_version
|
|
self.old_path = path + "/"
|
|
- self.new_path = self.old_path + self.os_version + "/"
|
|
+ self.new_path = self.old_path
|
|
|
|
- if self.os_version in fedora_releases or self.os_version in rhel_releases:
|
|
+ if self.os_version:
|
|
self.__gen_html_manpages()
|
|
else:
|
|
print("SELinux HTML man pages can not be generated for this %s" % os_version)
|
|
@@ -202,7 +223,6 @@ class HTMLManPages:
|
|
def __gen_html_manpages(self):
|
|
self._write_html_manpage()
|
|
self._gen_index()
|
|
- self._gen_body()
|
|
self._gen_css()
|
|
|
|
def _write_html_manpage(self):
|
|
@@ -220,67 +240,21 @@ class HTMLManPages:
|
|
convert_manpage_to_html((self.new_path + r.rsplit("_selinux", 1)[0] + ".html"), self.old_path + r)
|
|
|
|
def _gen_index(self):
|
|
- index = self.old_path + "index.html"
|
|
- fd = open(index, 'w')
|
|
- fd.write("""
|
|
-<html>
|
|
-<head>
|
|
- <link rel=stylesheet type="text/css" href="style.css" title="style">
|
|
- <title>SELinux man pages online</title>
|
|
-</head>
|
|
-<body>
|
|
-<h1>SELinux man pages</h1>
|
|
-<br></br>
|
|
-Fedora or Red Hat Enterprise Linux Man Pages.</h2>
|
|
-<br></br>
|
|
-<hr>
|
|
-<h3>Fedora</h3>
|
|
-<table><tr>
|
|
-<td valign="middle">
|
|
-</td>
|
|
-</tr></table>
|
|
-<pre>
|
|
-""")
|
|
- for f in fedora_releases:
|
|
- fd.write("""
|
|
-<a href=%s/%s.html>%s</a> - SELinux man pages for %s """ % (f, f, f, f))
|
|
-
|
|
- fd.write("""
|
|
-</pre>
|
|
-<hr>
|
|
-<h3>RHEL</h3>
|
|
-<table><tr>
|
|
-<td valign="middle">
|
|
-</td>
|
|
-</tr></table>
|
|
-<pre>
|
|
-""")
|
|
- for r in rhel_releases:
|
|
- fd.write("""
|
|
-<a href=%s/%s.html>%s</a> - SELinux man pages for %s """ % (r, r, r, r))
|
|
-
|
|
- fd.write("""
|
|
-</pre>
|
|
- """)
|
|
- fd.close()
|
|
- print("%s has been created" % index)
|
|
-
|
|
- def _gen_body(self):
|
|
html = self.new_path + self.os_version + ".html"
|
|
fd = open(html, 'w')
|
|
fd.write("""
|
|
<html>
|
|
<head>
|
|
- <link rel=stylesheet type="text/css" href="../style.css" title="style">
|
|
- <title>Linux man-pages online for Fedora18</title>
|
|
+ <link rel=stylesheet type="text/css" href="style.css" title="style">
|
|
+ <title>SELinux man pages</title>
|
|
</head>
|
|
<body>
|
|
-<h1>SELinux man pages for Fedora18</h1>
|
|
+<h1>SELinux man pages for %s</h1>
|
|
<hr>
|
|
<table><tr>
|
|
<td valign="middle">
|
|
<h3>SELinux roles</h3>
|
|
-""")
|
|
+""" % self.os_version)
|
|
for letter in self.manpage_roles:
|
|
if len(self.manpage_roles[letter]):
|
|
fd.write("""
|
|
@@ -424,6 +398,9 @@ class ManPage:
|
|
self.all_file_types = sepolicy.get_all_file_types()
|
|
self.role_allows = sepolicy.get_all_role_allows()
|
|
self.types = _gen_types()
|
|
+ self.exec_types = _gen_exec_types()
|
|
+ self.entry_types = _gen_entry_types()
|
|
+ self.mcs_constrained_types = _gen_mcs_constrained_types()
|
|
|
|
if self.source_files:
|
|
self.fcpath = self.root + "file_contexts"
|
|
@@ -736,10 +713,13 @@ Default Defined Ports:""")
|
|
|
|
def _file_context(self):
|
|
flist = []
|
|
+ flist_non_exec = []
|
|
mpaths = []
|
|
for f in self.all_file_types:
|
|
if f.startswith(self.domainname):
|
|
flist.append(f)
|
|
+ if not f in self.exec_types or not f in self.entry_types:
|
|
+ flist_non_exec.append(f)
|
|
if f in self.fcdict:
|
|
mpaths = mpaths + self.fcdict[f]["regex"]
|
|
if len(mpaths) == 0:
|
|
@@ -791,19 +771,20 @@ SELinux %(domainname)s policy is very flexible allowing users to setup their %(d
|
|
.PP
|
|
""" % {'domainname': self.domainname, 'equiv': e, 'alt': e.split('/')[-1]})
|
|
|
|
- self.fd.write(r"""
|
|
+ if flist_non_exec:
|
|
+ self.fd.write(r"""
|
|
.PP
|
|
.B STANDARD FILE CONTEXT
|
|
|
|
SELinux defines the file context types for the %(domainname)s, if you wanted to
|
|
store files with these types in a diffent paths, you need to execute the semanage command to sepecify alternate labeling and then use restorecon to put the labels on disk.
|
|
|
|
-.B semanage fcontext -a -t %(type)s '/srv/%(domainname)s/content(/.*)?'
|
|
+.B semanage fcontext -a -t %(type)s '/srv/my%(domainname)s_content(/.*)?'
|
|
.br
|
|
.B restorecon -R -v /srv/my%(domainname)s_content
|
|
|
|
Note: SELinux often uses regular expressions to specify labels that match multiple files.
|
|
-""" % {'domainname': self.domainname, "type": flist[0]})
|
|
+""" % {'domainname': self.domainname, "type": flist_non_exec[-1]})
|
|
|
|
self.fd.write(r"""
|
|
.I The following file types are defined for %(domainname)s:
|
|
@@ -974,11 +955,7 @@ All executeables with the default executable label, usually stored in /usr/bin a
|
|
%s""" % ", ".join(paths))
|
|
|
|
def _mcs_types(self):
|
|
- try:
|
|
- mcs_constrained_type = next(sepolicy.info(sepolicy.ATTRIBUTE, "mcs_constrained_type"))
|
|
- except StopIteration:
|
|
- return
|
|
- if self.type not in mcs_constrained_type['types']:
|
|
+ if self.type not in self.mcs_constrained_types['types']:
|
|
return
|
|
self.fd.write ("""
|
|
.SH "MCS Constrained"
|