[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