[apparmor] Proposal for rule class
Christian Boltz
apparmor at cboltz.de
Sun Oct 26 12:25:18 UTC 2014
Hello,
I have a first proposal for the rule class interface :-)
The code below is basically a python skeleton with lots of comments,
but also contains some pseudocode or implicit code (like variables that
are "just there" without being set before - however their name should
indicate what they mean ;-)
I'm quite sure this is not the final interface, but I think it's something
that should at least work in theory ;-)
Do you like my proposal or do you want something totally different?
Did I include something that will explode in practise?
What's your opinion on the questions I included in the comments?
Feedback welcome! ;-)
BTW: This is the first public version, but my personal version counter
is > 10. To simplify things, let's just use the date as version ;-)
# proposal for a rule class (v2014-10-26)
# the interface should be (nearly) the same for all rule types
# aa[profile][hat]['netdomain'] = networkrule
# ^^^^
# - allow/deny handled inside the class
# - only one instance of the class per profile, with all rules of the same type in it
class aarule
global_profiles = None
global_abstractions = None
# need to be set when creating the instance of the class
#
# needed for handling of #include - global_profiles and global_abstractions should contain _references_
# (not a copy! we always need the latest version!) to all profiles and all available abstractions.
# (I first thought about using global variables, but this might cause problems if we want to have more
# than one set of profiles loaded at once, especially when it comes to includes (aa-mergeprof?).)
#
# In theory global_profiles[profile][hat] would be enough, but there might be cases where knowing the
# list of all profiles is useful, for example when proposing *x rules it could be helpful if the target
# profile exists
# (if we do this, rename global_profiles to full_profile and drop the profile and hat variables)
profile = ''
hat = ''
# need to be set when creating the instance of the class
#
# needed when checking global_profiles for includes etc.
# (or we need to hand over the includes at various points, which would make the class more stand-alone,
# but annoying to use)
#
# should be private to the class (outside users know this by the position in the global profiles variable)
rules = []
# TODO: decide about internal structure
# - class contains both allow and deny rules
# - probably some nested dicts, but not hasher() ;-)
# - different for each rule type, but should be consistent as much as possible
#
# each rule should
# - have a 'changed' flag
# - maybe even have a 'deleted' flag so that we can easily track deleted rules
# (for 3-way merge or generating diffs internally)
# - store the raw rule as found in the profile file (to write a profile in original formatting)
# - store the comment line(s) above
# - store the comment at the end of the line
#
# I'm also thinking about the internal order - do we want to keep [allow/deny][path][permissions]
# or is [path][allow/deny][permissions] easier to handle?
#
# should be read-only for "outside" users (needed for checking the rules in #include files!)
canglob = 1
# decides if the (G)lob and Glob w/ (E)xt options are displayed
#
# Possible values:
# - 2 - glob + glob with extension (for file rules)
# - 1 - just normal glob, for example for network rules
# - 0 - for rule types that don't support globbing
#
# should be read-only for "outside" users
last_proposal = None
# cache last proposal by _propose_rules (used by add_proposed_rule)
# should be private to the class
def __init__(self, profile, hat, global_profiles, global_abstractions)
self.profile = profile
self.hat = hat
self.global_profiles = global_profiles
self.global_abstractions = global_abstractions
def initrule()
# called by add() to initialize the internal structure of a new rules
# (internal use only)
def add(rawrule)
# parse rawrule (from profile file) and store it in a structured way
def add_proposed_rule(proposal_number, chosen_action)
# like add, but takes one of the last_proposed rules as input
# - proposal_number is the number of the proposed rule, for example "[1] /foo r"
# - chosen_action is the selected "button", for example "(A)llow"
def get_raw()
# return all raw rules (if possible/not modified) as previously added with add(),
# and of couse also all added rules
# (as array of lines, without leading whitespace - or add a 'whitespace' parameter)
# replaces write_$ruletype() (in non-clean mode)
def get_clean()
# get "clean" rules
# replaces write_$ruletype() (in clean mode)
def covered(rawrule)
# return true if covered by existing rules (which means aa-logprof doesn't need to ask), otherwise false
# needs the includes from global_profiles
def covered_from_log(log_entry)
# like covered, but takes a log entry as input
def get_glob(path_or_rule)
# returns the next possible glob
def get_glob_ext(path_or_rule)
# returns the next possible glob with extension (for file rules only)
def propose_rules(rawrule)
# returns _propose_rules() result for usage in aa-mergeprof
# PARAM rawrule: raw rule from other profile
return _propose_rules(parsed_rawrule)
def propose_rules_from_log(log_entry)
# returns _propose_rules() result for usage in aa-logprof
# PARAM log_entry: log entry
# wildcards etc. in filenames need to be escaped before calling _propose_rules()!
return _propose_rules(parsed_and_escaped_log_entry)
def _propose_rules(parsed_rule)
# returns an array of
# - array with proposed rules (including globs from logprof.conf etc. and abstractions)
# - can_glob (see explanation in class header)
# - if all proposals are already "globbed to the end", should we return 0 for can_glob?
# (for example if we only offer bare "network," and an abstraction)
# - or go a step further and return an array with available_buttons instead of only can_glob?
# that would mean just allow/deny, audit and maybe glob for many cases, but for file rules
# it could also include the various *x options
#
# PARAM parsed_rule: pre-parsed rule (rawrule or log_entry)
# needs the list of all available abstractions from global_abstractions
this.last_proposal = proposal # needed by add_proposed_rule()
return proposal, can_glob
def delete_duplicates()
# does exactly that ;-)
# needs the profile's includes from global_profiles
def get_diff()
# just dreaming ;-)
# (but it should be possible based on the information inside the class)
Regards,
Christian Boltz
--
[Passwörter] Ich suche nach einem Mittelweg zwischen maximaler
Sicherheit und Zumutbarkeit für den Benutzer (ein Pferd mit Hufen,
dem unsere Admin-Tastaturen viel zu klein sind :-)).
[Manfred Rebentisch in suse-linux]
More information about the AppArmor
mailing list