complete infrastructure support for building modules

This commit is contained in:
Chris PeBenito 2005-08-22 17:07:17 +00:00
parent db93d707c5
commit c04f2abe88
6 changed files with 314 additions and 28 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -12,6 +12,8 @@ define(`policy_module',`
ifdef(`monolithic_policy',`',`
module $1 $2;
')
require { all_kernel_class_perms }
')
##############################

View File

@ -0,0 +1,284 @@
#!/usr/bin/python
# Author: Donald Miner <dminer@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)))