policycoreutils/selinux-python-fedora.patch
Petr Lautrbach e3a75fa174 policycoreutils-2.8-15
- 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
2019-01-21 17:56:37 +01:00

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"