[selinux-policy: 581/3172] complete infrastructure support for building modules
Daniel J Walsh
dwalsh at fedoraproject.org
Thu Oct 7 19:54:50 UTC 2010
commit c04f2abe8815fc3e18ecd03f43e947545c4c7e05
Author: Chris PeBenito <cpebenito at tresys.com>
Date: Mon Aug 22 17:07:17 2005 +0000
complete infrastructure support for building modules
refpolicy/Changelog | 2 +
refpolicy/Makefile | 10 +-
refpolicy/Rules.modular | 42 ++---
refpolicy/Rules.monolithic | 2 +-
refpolicy/policy/support/loadable_module.spt | 2 +
refpolicy/support/genclassperms.py | 284 ++++++++++++++++++++++++++
6 files changed, 314 insertions(+), 28 deletions(-)
---
diff --git a/refpolicy/Changelog b/refpolicy/Changelog
index b8eaac6..751bfb8 100644
--- a/refpolicy/Changelog
+++ b/refpolicy/Changelog
@@ -1,4 +1,6 @@
* Add Makefile support for building loadable modules.
+ * Add genclassperms.py tool to add require blocks
+ for loadable modules.
* Change sedoctool to make required modules part of base
by default, otherwise make as modules, in modules.conf.
* Fix segenxml to handle modules with no interfaces.
diff --git a/refpolicy/Makefile b/refpolicy/Makefile
index 42e3757..7025fce 100644
--- a/refpolicy/Makefile
+++ b/refpolicy/Makefile
@@ -73,14 +73,18 @@ XMLLINT := $(BINDIR)/xmllint
CFLAGS := -Wall
# policy source layout
-POLDIR = policy
-MODDIR = $(POLDIR)/modules
-FLASKDIR = $(POLDIR)/flask
+POLDIR := policy
+MODDIR := $(POLDIR)/modules
+FLASKDIR := $(POLDIR)/flask
+SECCLASS := $(FLASKDIR)/security_classes
+ISIDS := $(FLASKDIR)/initial_sids
+AVS := $(FLASKDIR)/access_vectors
# policy building support tools
SUPPORT := support
GENXML := $(SUPPORT)/segenxml.py
GENDOC := $(SUPPORT)/sedoctool.py
+GENPERM := $(SUPPORT)/genclassperms.py
FCSORT := $(SUPPORT)/fc_sort
SETTUN := $(SUPPORT)/set_tunables
diff --git a/refpolicy/Rules.modular b/refpolicy/Rules.modular
index b24297c..a8eef96 100644
--- a/refpolicy/Rules.modular
+++ b/refpolicy/Rules.modular
@@ -11,13 +11,18 @@ BASE_FC := base.fc
BASE_SECTIONS := tmp/pre_te_files.conf tmp/generated_definitions.conf tmp/all_interfaces.conf tmp/all_attrs_types.conf $(GLOBALTUN) tmp/only_te_rules.conf tmp/all_post.conf
-BASE_PRE_TE_FILES := $(addprefix $(FLASKDIR)/,security_classes initial_sids access_vectors) $(M4SUPPORT) $(POLDIR)/mls
+BASE_PRE_TE_FILES := $(SECCLASS) $(ISIDS) $(AVS) $(M4SUPPORT) $(POLDIR)/mls
BASE_TE_FILES := $(BASE_MODS)
BASE_POST_TE_FILES := $(POLDIR)/users $(POLDIR)/constraints
BASE_FC_FILES := $(BASE_MODS:.te=.fc)
MOD_MODULES := $(MOD_MODS:.te=.mod)
-MOD_PKGS := $(MOD_MODS:.te=.pp)
+MOD_PKGS := $(notdir $(MOD_MODS:.te=.pp))
+
+# search layer dirs for source files
+vpath %.te $(ALL_LAYERS)
+vpath %.if $(ALL_LAYERS)
+vpath %.fc $(ALL_LAYERS)
########################################
#
@@ -68,14 +73,9 @@ tmp/pre_te_files.conf: $(BASE_PRE_TE_FILES)
$(QUIET) cat $^ > $@
tmp/generated_definitions.conf: $(ALL_LAYERS) $(BASE_TE_FILES)
-# per-userdomain templates:
@test -d tmp || mkdir -p tmp
- $(QUIET) echo "define(\`per_userdomain_templates',\`" > $@
- $(QUIET) for i in $(patsubst %.te,%,$(notdir $(BASE_TE_FILES))); do \
- echo "ifdef(\`""$$i""_per_userdomain_template',\`""$$i""_per_userdomain_template("'$$1'")')" \
- >> $@ ;\
- done
- $(QUIET) echo "')" >> $@
+# define all available object classes
+ $(QUIET) $(GENPERM) $(AVS) $(SECCLASS) > $@
# define foo.te
$(QUIET) for i in $(notdir $(BASE_TE_FILES)); do \
echo "define(\`$$i')" >> $@ ;\
@@ -131,20 +131,16 @@ endif
########################################
#
-# Build modules packages
+# Build module packages
#
-%.pp: %.mod %.fc
- @echo "Creating $(NAME) $(@F) package"
- $(QUIET) $(SEMOD_PKG) $@ %^
+tmp/%.mod: $(M4SUPPORT) tmp/generated_definitions.conf tmp/all_interfaces.conf %.te
+ @echo "Compliling $(NAME) $(@F) module"
+ $(QUIET) m4 $(M4PARAM) -s $^ > $(@:.mod=.tmp)
+ $(QUIET) $(CHECKMODULE) -m $(@:.mod=.tmp) -o $@
-########################################
-#
-# Compile modules
-#
-%.mod: $(M4SUPPORT) tmp/all_interfaces.conf %.te
- @echo "Compiling $(NAME) $(@F) module"
- $(QUIET) m4 $(M4PARAM) -s $^ > tmp/$(@F).tmp
- $(QUIET) $(CHECKMODULE) -m tmp/$(@F).tmp -o $@
+%.pp: tmp/%.mod %.fc
+ @echo "Creating $(NAME) $(@F) policy package"
+ $(QUIET) $(SEMOD_PKG) $@ $^
########################################
#
@@ -153,8 +149,6 @@ endif
clean:
rm -fR tmp
rm -f base.conf
- rm -f $(BASE_PKG)
- find . -iname "*.mod" | xargs rm -f
- find . -iname "*.pp" | xargs rm -f
+ rm -f *.pp
.PHONY: default base modules clean
diff --git a/refpolicy/Rules.monolithic b/refpolicy/Rules.monolithic
index 404ef7f..d2a2f1e 100644
--- a/refpolicy/Rules.monolithic
+++ b/refpolicy/Rules.monolithic
@@ -18,7 +18,7 @@ ALL_INTERFACES := $(ALL_MODULES:.te=.if)
ALL_TE_FILES := $(ALL_MODULES)
ALL_FC_FILES := $(ALL_MODULES:.te=.fc)
-PRE_TE_FILES := $(addprefix $(FLASKDIR)/,security_classes initial_sids access_vectors) $(M4SUPPORT) $(POLDIR)/mls
+PRE_TE_FILES := $(SECCLASS) $(ISIDS) $(AVS) $(M4SUPPORT) $(POLDIR)/mls
POST_TE_FILES := $(POLDIR)/users $(POLDIR)/constraints
POLICY_SECTIONS := tmp/pre_te_files.conf tmp/generated_definitions.conf tmp/all_interfaces.conf tmp/all_attrs_types.conf $(GLOBALTUN) tmp/only_te_rules.conf tmp/all_post.conf
diff --git a/refpolicy/policy/support/loadable_module.spt b/refpolicy/policy/support/loadable_module.spt
index 479ece7..dfa28ce 100644
--- a/refpolicy/policy/support/loadable_module.spt
+++ b/refpolicy/policy/support/loadable_module.spt
@@ -12,6 +12,8 @@ define(`policy_module',`
ifdef(`monolithic_policy',`',`
module $1 $2;
')
+
+ require { all_kernel_class_perms }
')
##############################
diff --git a/refpolicy/support/genclassperms.py b/refpolicy/support/genclassperms.py
new file mode 100755
index 0000000..9ddae68
--- /dev/null
+++ b/refpolicy/support/genclassperms.py
@@ -0,0 +1,284 @@
+#!/usr/bin/python
+
+# Author: Donald Miner <dminer at tresys.com>
+#
+# Copyright (C) 2003 - 2005 Tresys Technology, LLC
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, version 2.
+
+
+"""
+ This script generates an object class perm definition file.
+"""
+
+import sys
+
+USERSPACE_CLASS = "userspace"
+
+class Class:
+ """
+ This object stores an access vector class.
+ """
+
+ def __init__(self, name, perms, common):
+ # The name of the class.
+ self.name = name
+
+ # A list of permissions the class contains.
+ self.perms = perms
+
+ # True if the class is declared as common, False if not.
+ self.common = common
+
+def get_perms(name, av_db):
+ """
+ Returns the list of permissions contained within an access vector
+ class that is stored in the access vector database av_db.
+ Returns an empty list if the object name is not found.
+ """
+
+ # Traverse through the access vector database and try to find the
+ # object with the name passed.
+ for obj in av_db:
+ if obj.name == name:
+ return obj.perms
+
+ return []
+
+def get_av_db(file_name):
+ """
+ Returns an access vector database generated from the file file_name.
+ """
+
+ av_file = open(file_name, "r")
+ av_data = []
+ # Read the file and strip out comments on the way.
+ # At the end of the loop, av_data will contain a list of individual
+ # words. i.e. ['common', 'file', '{', ...]. All comments and whitespace
+ # will be gone.
+ while True:
+ av_line = av_file.readline()
+
+ # If EOF has been reached:
+ if not av_line:
+ break
+
+ # Check if there is a comment, and if there is, remove it.
+ comment_index = av_line.find("#")
+ if comment_index != -1:
+ av_line = av_line[:comment_index]
+
+ # Pad the braces with whitespace so that they are split into
+ # their own word. It doesn't matter if there will be extra
+ # white space, it'll get thrown away when the string is split.
+ av_line.replace("{"," { ")
+ av_line.replace("}"," } ")
+
+ # Split up the words on the line and add it to av_data.
+ av_data += av_line.split()
+
+ av_file.close()
+
+ # Parsing the file:
+ # The implementation of this parse is a queue. We use the list of words
+ # from av_data and use the front element, then dequeue it. Each
+ # loop of this while is a common or class declaration. Several
+ # expected tokens are parsed and dequeued out of av_data for each loop.
+ # Dequeue from the beginning of the list until av_data is empty:
+ database = []
+ while len(av_data) != 0:
+ # At the beginning of every loop, the next word should be
+ # "common" or "class", meaning that each loop is a common
+ # or class declaration.
+ # av_data = av_data[1:] removes the first element in the
+ # list, this is what is dequeueing data.
+
+ # Figure out whether the next class will be a common or a class.
+ if av_data[0] == "class":
+ common = False
+ elif av_data[0] == "common":
+ common = True
+ else:
+ error("Unexpected token in file " + file_name + ": "\
+ + av_data[0] + ".")
+
+ # Dequeue the "class" or "common" key word.
+ av_data = av_data[1:]
+
+ if len(av_data) == 0:
+ error("Missing token in file " + file_name + ".")
+
+ # Get and dequeue the name of the class or common.
+ name = av_data[0]
+ av_data = av_data[1:]
+
+ # Retrieve the permissions inherited from a common set:
+ perms = []
+ # If the object we are working with is a class, since only
+ # classes inherit:
+ if common == False:
+ if len(av_data) == 0:
+ error("Missing token in file " + file_name + ".")
+
+ # If the class inherits from something else:
+ if av_data[0] == "inherits":
+ # Dequeue the "inherits" key word.
+ av_data = av_data[1:]
+
+ if len(av_data) == 0:
+ error("Missing token in file "\
+ + file_name + " for " +\
+ keyword + " " + name + ".")
+
+ # av_data[0] is the name of the parent.
+ # Append the permissions of the parent to
+ # the current class' permissions.
+ perms += get_perms(av_data[0], database)
+ # Dequeue the name of the parent.
+ av_data = av_data[1:]
+
+ # Retrieve the permissions defined with this set.
+ if len(av_data) > 0 and av_data[0] == "{":
+ # Dequeue the "{"
+ av_data = av_data[1:]
+
+ # Keep appending permissions until a close brace is
+ # found.
+ while av_data[0] != "}":
+ if av_data[0] == "{":
+ error("Extra '{' in file " +\
+ file_name + ".")
+
+ # Add the permission name.
+ perms.append(av_data[0])
+
+ # Dequeue the permission name.
+ av_data = av_data[1:]
+
+ if len(av_data) == 0:
+ error("Missing token '}' in file "\
+ + file_name + ".")
+
+ # Dequeue the "}"
+ av_data = av_data[1:]
+
+ # Add the new access vector class to the database.
+ database.append(Class(name, perms, common))
+
+ return database
+
+def get_sc_db(file_name):
+ """
+ Returns a security class database generated from the file file_name.
+ """
+
+ # Read the file then close it.
+ sc_file = open(file_name)
+ sc_data = sc_file.readlines()
+ sc_file.close()
+
+ # For each line in the security classes file, add the name of the class
+ # and whether it is a userspace class or not to the security class
+ # database.
+ database = []
+ for line in sc_data:
+ line = line.lstrip()
+ # If the line is empty or the entire line is a comment, skip.
+ if line == "" or line[0] == "#":
+ continue
+
+ # Check if the comment to the right of the permission matches
+ # USERSPACE_CLASS.
+ comment_index = line.find("#")
+ if comment_index != -1 and line[comment_index+1:].strip() == USERSPACE_CLASS:
+ userspace = True
+ else:
+ userspace = False
+
+ # All lines should be in the format "class NAME", meaning
+ # it should have two tokens and the first token should be
+ # "class".
+ split_line = line.split()
+ if len(split_line) < 2 or split_line[0] != "class":
+ error("Wrong syntax: " + line)
+
+ # Add the class's name (split_line[1]) and whether it is a
+ # userspace class or not to the database.
+ # This is appending a tuple of (NAME,USERSPACE), where NAME is
+ # the name of the security class and USERSPACE is True if
+ # if it has "# USERSPACE_CLASS" on the end of the line, False
+ # if not.
+ database.append((split_line[1], userspace))
+
+ return database
+
+def gen_class_perms(av_db, sc_db):
+ """
+ Generates a class permissions document and returns it.
+ """
+
+ # Define class template:
+ class_perms_line = "define(`all_%s_perms',`{ %s}')\n"
+
+ # Generate the defines for the individual class permissions.
+ class_perms = ""
+ for obj in av_db:
+ # Don't output commons
+ if obj.common == True:
+ continue
+
+ # Get the list of permissions.
+ perms = get_perms(obj.name, av_db)
+
+ # Merge all the permissions into one string with one space
+ # padding.
+ perm_str = ""
+ for perm in perms:
+ perm_str += perm + " "
+
+ # Add the line to the class_perms
+ class_perms += class_perms_line % (obj.name, perm_str)
+ class_perms += "\n"
+
+ # Generate the kernel_class_perms and userspace_class_perms sets.
+ class_line = "\tclass %s all_%s_perms;\n"
+ kernel_class_perms = "define(`all_kernel_class_perms',`\n"
+ userspace_class_perms = "define(`all_userspace_class_perms',`\n"
+ # For each (NAME,USERSPACE) tuple, add the class to the appropriate
+ # class permission set.
+ for name, userspace in sc_db:
+ if userspace:
+ userspace_class_perms += class_line % (name, name)
+ else:
+ kernel_class_perms += class_line % (name, name)
+ kernel_class_perms += "')\n\n"
+ userspace_class_perms += "')\n"
+
+ # Throw all the strings together and return the string.
+ return class_perms + kernel_class_perms + userspace_class_perms
+
+def error(error):
+ """
+ Print an error message and exit.
+ """
+
+ sys.stderr.write("%s exiting for: " % sys.argv[0])
+ sys.stderr.write("%s\n" % error)
+ sys.stderr.flush()
+ sys.exit(1)
+
+# MAIN PROGRAM
+app_name = sys.argv[0]
+
+if len(sys.argv) != 3:
+ error("Incorrect input.\nUsage: " + sys.argv[0] + " access_vectors security_classes" )
+
+# argv[1] is the access vector file.
+av_file = sys.argv[1]
+
+# argv[2] is the security class file.
+sc_file = sys.argv[2]
+
+# Output the class permissions document.
+sys.stdout.write(gen_class_perms(get_av_db(av_file), get_sc_db(sc_file)))
More information about the scm-commits
mailing list