#! /usr/bin/python3 # ------------------------------------------------------------------ # # Copyright (C) 2011-2015 Canonical Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public # License published by the Free Software Foundation. # # ------------------------------------------------------------------ import glob import json import optparse import os import shutil import sys import tempfile import unittest import apparmor.easyprof as easyprof topdir = None debugging = False def recursive_rm(dirPath, contents_only=False): '''recursively remove directory''' names = os.listdir(dirPath) for name in names: path = os.path.join(dirPath, name) if os.path.islink(path) or not os.path.isdir(path): os.unlink(path) else: recursive_rm(path) if contents_only == False: os.rmdir(dirPath) # From Lib/test/test_optparse.py from python 2.7.4 class InterceptedError(Exception): def __init__(self, error_message=None, exit_status=None, exit_message=None): self.error_message = error_message self.exit_status = exit_status self.exit_message = exit_message def __str__(self): return self.error_message or self.exit_message or "intercepted error" class InterceptingOptionParser(optparse.OptionParser): def exit(self, status=0, msg=None): raise InterceptedError(exit_status=status, exit_message=msg) def error(self, msg): raise InterceptedError(error_message=msg) class Manifest(object): def __init__(self, profile_name): self.security = dict() self.security['profiles'] = dict() self.profile_name = profile_name self.security['profiles'][self.profile_name] = dict() def add_policygroups(self, policy_list): self.security['profiles'][self.profile_name]['policy_groups'] = policy_list.split(",") def add_author(self, author): self.security['profiles'][self.profile_name]['author'] = author def add_copyright(self, copyright): self.security['profiles'][self.profile_name]['copyright'] = copyright def add_comment(self, comment): self.security['profiles'][self.profile_name]['comment'] = comment def add_binary(self, binary): self.security['profiles'][self.profile_name]['binary'] = binary def add_template(self, template): self.security['profiles'][self.profile_name]['template'] = template def add_template_variable(self, name, value): if not 'template_variables' in self.security['profiles'][self.profile_name]: self.security['profiles'][self.profile_name]['template_variables'] = dict() self.security['profiles'][self.profile_name]['template_variables'][name] = value def emit_json(self, use_security_prefix=True): manifest = dict() manifest['security'] = self.security if use_security_prefix: dumpee = manifest else: dumpee = self.security return json.dumps(dumpee, indent=2) # # Our test class # class T(unittest.TestCase): # work around UsrMove ls = os.path.realpath('/bin/ls') def setUp(self): '''Setup for tests''' global topdir self.tmpdir = os.path.realpath(tempfile.mkdtemp(prefix='test-aa-easyprof')) # Copy everything into place for d in ['easyprof/policygroups', 'easyprof/templates']: shutil.copytree(os.path.join(topdir, d), os.path.join(self.tmpdir, os.path.basename(d))) # Create a test template self.test_template = "test-template" contents = '''# vim:syntax=apparmor # %s # AppArmor policy for ###NAME### # ###AUTHOR### # ###COPYRIGHT### # ###COMMENT### #include ###VAR### ###PROFILEATTACH### { #include ###ABSTRACTIONS### ###POLICYGROUPS### ###READS### ###WRITES### } ''' % (self.test_template) open(os.path.join(self.tmpdir, 'templates', self.test_template), 'w').write(contents) # Create a test policygroup self.test_policygroup = "test-policygroup" contents = ''' # %s #include #include ''' % (self.test_policygroup) open(os.path.join(self.tmpdir, 'policygroups', self.test_policygroup), 'w').write(contents) # setup our conffile self.conffile = os.path.join(self.tmpdir, 'easyprof.conf') contents = ''' POLICYGROUPS_DIR="%s/policygroups" TEMPLATES_DIR="%s/templates" ''' % (self.tmpdir, self.tmpdir) open(self.conffile, 'w').write(contents) self.binary = "/opt/bin/foo" self.full_args = ['-c', self.conffile, self.binary] # Check __AA_BASEDIR, which may be set by the Makefile, to see if # we should use a non-default base directory path to find # abstraction files # # NOTE: Individual tests can append another --base path to the # args list and override a base path set here base = os.getenv('__AA_BASEDIR') if base: self.full_args.append('--base=%s' % base) # Check __AA_PARSER, which may be set by the Makefile, to see if # we should use a non-default apparmor_parser path to verify # policy parser = os.getenv('__AA_PARSER') if parser: self.full_args.append('--parser=%s' % parser) if debugging: self.full_args.append('-d') (self.options, self.args) = easyprof.parse_args(self.full_args + [self.binary]) # Now create some differently prefixed files in the include-dir self.test_include_dir = os.path.join(self.tmpdir, 'include-dir') os.mkdir(self.test_include_dir) os.mkdir(os.path.join(self.test_include_dir, "templates")) os.mkdir(os.path.join(self.test_include_dir, "policygroups")) for d in ['policygroups', 'templates']: for f in easyprof.get_directory_contents(os.path.join( self.tmpdir, d)): shutil.copy(f, os.path.join(self.test_include_dir, d, "inc_%s" % os.path.basename(f))) def tearDown(self): '''Teardown for tests''' if os.path.exists(self.tmpdir): if debugging: sys.stdout.write("%s\n" % self.tmpdir) else: recursive_rm(self.tmpdir) # # config file tests # def test_configuration_file_p_invalid(self): '''Test config parsing (invalid POLICYGROUPS_DIR)''' contents = ''' POLICYGROUPS_DIR= TEMPLATES_DIR="%s/templates" ''' % (self.tmpdir) open(self.conffile, 'w').write(contents) try: easyprof.AppArmorEasyProfile(self.binary, self.options) except easyprof.AppArmorException: return except Exception: raise raise Exception ("File should have been invalid") def test_configuration_file_p_empty(self): '''Test config parsing (empty POLICYGROUPS_DIR)''' contents = ''' POLICYGROUPS_DIR="%s" TEMPLATES_DIR="%s/templates" ''' % ('', self.tmpdir) open(self.conffile, 'w').write(contents) try: easyprof.AppArmorEasyProfile(self.binary, self.options) except easyprof.AppArmorException: return except Exception: raise raise Exception ("File should have been invalid") def test_configuration_file_p_nonexistent(self): '''Test config parsing (nonexistent POLICYGROUPS_DIR)''' contents = ''' POLICYGROUPS_DIR="%s/policygroups" TEMPLATES_DIR="%s/templates" ''' % ('/nonexistent', self.tmpdir) open(self.conffile, 'w').write(contents) try: easyprof.AppArmorEasyProfile(self.binary, self.options) except easyprof.AppArmorException: return except Exception: raise raise Exception ("File should have been invalid") def test_policygroups_dir_relative(self): '''Test --policy-groups-dir (relative DIR)''' os.chdir(self.tmpdir) rel = os.path.join(self.tmpdir, 'relative') os.mkdir(rel) shutil.copy(os.path.join(self.tmpdir, 'policygroups', self.test_policygroup), os.path.join(rel, self.test_policygroup)) args = self.full_args args += ['--policy-groups-dir', './relative', '--show-policy-group', '--policy-groups=%s' % self.test_policygroup] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(self.binary, self.options) # no fallback self.assertTrue(easyp.dirs['policygroups'] == rel, "Not using specified --policy-groups-dir\n" + "Specified dir: %s\nActual dir: %s" % (rel, str(easyp.dirs['policygroups']))) self.assertFalse(easyp.get_policy_groups() == None, "Could not find policy-groups") def test_policygroups_dir_nonexistent(self): '''Test --policy-groups-dir (nonexistent DIR)''' os.chdir(self.tmpdir) rel = os.path.join(self.tmpdir, 'nonexistent') args = self.full_args args += ['--policy-groups-dir', rel, '--show-policy-group', '--policy-groups=%s' % self.test_policygroup] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(self.binary, self.options) # test if using fallback self.assertFalse(easyp.dirs['policygroups'] == rel, "Using nonexistent --policy-groups-dir") # test fallback self.assertTrue(easyp.get_policy_groups() != None, "Found policy-groups when shouldn't have") def test_policygroups_dir_valid(self): '''Test --policy-groups-dir (valid DIR)''' os.chdir(self.tmpdir) valid = os.path.join(self.tmpdir, 'valid') os.mkdir(valid) shutil.copy(os.path.join(self.tmpdir, 'policygroups', self.test_policygroup), os.path.join(valid, self.test_policygroup)) args = self.full_args args += ['--policy-groups-dir', valid, '--show-policy-group', '--policy-groups=%s' % self.test_policygroup] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(self.binary, self.options) # no fallback self.assertTrue(easyp.dirs['policygroups'] == valid, "Not using specified --policy-groups-dir") self.assertFalse(easyp.get_policy_groups() == None, "Could not find policy-groups") def test_policygroups_dir_valid_with_vendor(self): '''Test --policy-groups-dir (valid DIR with vendor)''' os.chdir(self.tmpdir) valid = os.path.join(self.tmpdir, 'valid') os.mkdir(valid) shutil.copy(os.path.join(self.tmpdir, 'policygroups', self.test_policygroup), os.path.join(valid, self.test_policygroup)) vendor = "ubuntu" version = "1.0" valid_distro = os.path.join(valid, vendor, version) os.mkdir(os.path.join(valid, vendor)) os.mkdir(valid_distro) shutil.copy(os.path.join(self.tmpdir, 'policygroups', self.test_policygroup), valid_distro) args = self.full_args args += ['--policy-groups-dir', valid, '--show-policy-group', '--policy-groups=%s' % self.test_policygroup] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(self.binary, self.options) self.assertTrue(easyp.dirs['policygroups'] == valid, "Not using specified --policy-groups-dir") self.assertFalse(easyp.get_policy_groups() == None, "Could not find policy-groups") for f in easyp.get_policy_groups(): self.assertFalse(os.path.basename(f) == vendor, "Found '%s' in %s" % (vendor, f)) def test_configuration_file_t_invalid(self): '''Test config parsing (invalid TEMPLATES_DIR)''' contents = ''' TEMPLATES_DIR= POLICYGROUPS_DIR="%s/templates" ''' % (self.tmpdir) open(self.conffile, 'w').write(contents) try: easyprof.AppArmorEasyProfile(self.binary, self.options) except easyprof.AppArmorException: return except Exception: raise raise Exception ("File should have been invalid") def test_configuration_file_t_empty(self): '''Test config parsing (empty TEMPLATES_DIR)''' contents = ''' TEMPLATES_DIR="%s" POLICYGROUPS_DIR="%s/templates" ''' % ('', self.tmpdir) open(self.conffile, 'w').write(contents) try: easyprof.AppArmorEasyProfile(self.binary, self.options) except easyprof.AppArmorException: return except Exception: raise raise Exception ("File should have been invalid") def test_configuration_file_t_nonexistent(self): '''Test config parsing (nonexistent TEMPLATES_DIR)''' contents = ''' TEMPLATES_DIR="%s/policygroups" POLICYGROUPS_DIR="%s/templates" ''' % ('/nonexistent', self.tmpdir) open(self.conffile, 'w').write(contents) try: easyprof.AppArmorEasyProfile(self.binary, self.options) except easyprof.AppArmorException: return except Exception: raise raise Exception ("File should have been invalid") def test_templates_dir_relative(self): '''Test --templates-dir (relative DIR)''' os.chdir(self.tmpdir) rel = os.path.join(self.tmpdir, 'relative') os.mkdir(rel) shutil.copy(os.path.join(self.tmpdir, 'templates', self.test_template), os.path.join(rel, self.test_template)) args = self.full_args args += ['--templates-dir', './relative', '--show-template', '--template=%s' % self.test_template] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(self.binary, self.options) # no fallback self.assertTrue(easyp.dirs['templates'] == rel, "Not using specified --template-dir\n" + "Specified dir: %s\nActual dir: %s" % (rel, str(easyp.dirs['templates']))) self.assertFalse(easyp.get_templates() == None, "Could not find templates") def test_templates_dir_nonexistent(self): '''Test --templates-dir (nonexistent DIR)''' os.chdir(self.tmpdir) rel = os.path.join(self.tmpdir, 'nonexistent') args = self.full_args args += ['--templates-dir', rel, '--show-template', '--template=%s' % self.test_template] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(self.binary, self.options) # test if using fallback self.assertFalse(easyp.dirs['templates'] == rel, "Using nonexistent --template-dir") # test fallback self.assertTrue(easyp.get_templates() != None, "Found templates when shouldn't have") def test_templates_dir_valid(self): '''Test --templates-dir (valid DIR)''' os.chdir(self.tmpdir) valid = os.path.join(self.tmpdir, 'valid') os.mkdir(valid) shutil.copy(os.path.join(self.tmpdir, 'templates', self.test_template), os.path.join(valid, self.test_template)) args = self.full_args args += ['--templates-dir', valid, '--show-template', '--template=%s' % self.test_template] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(self.binary, self.options) # no fallback self.assertTrue(easyp.dirs['templates'] == valid, "Not using specified --template-dir") self.assertFalse(easyp.get_templates() == None, "Could not find templates") def test_templates_dir_valid_with_vendor(self): '''Test --templates-dir (valid DIR with vendor)''' os.chdir(self.tmpdir) valid = os.path.join(self.tmpdir, 'valid') os.mkdir(valid) shutil.copy(os.path.join(self.tmpdir, 'templates', self.test_template), os.path.join(valid, self.test_template)) vendor = "ubuntu" version = "1.0" valid_distro = os.path.join(valid, vendor, version) os.mkdir(os.path.join(valid, vendor)) os.mkdir(valid_distro) shutil.copy(os.path.join(self.tmpdir, 'templates', self.test_template), valid_distro) args = self.full_args args += ['--templates-dir', valid, '--show-template', '--template=%s' % self.test_template] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(self.binary, self.options) self.assertTrue(easyp.dirs['templates'] == valid, "Not using specified --template-dir") self.assertFalse(easyp.get_templates() == None, "Could not find templates") for f in easyp.get_templates(): self.assertFalse(os.path.basename(f) == vendor, "Found '%s' in %s" % (vendor, f)) # # Binary file tests # def test_binary_without_profile_name(self): '''Test binary ( { })''' easyprof.AppArmorEasyProfile(self.ls, self.options) def test_binary_with_profile_name(self): '''Test binary (profile { })''' args = self.full_args args += ['--profile-name=some-profile-name'] (self.options, self.args) = easyprof.parse_args(args) easyprof.AppArmorEasyProfile(self.ls, self.options) def test_binary_omitted_with_profile_name(self): '''Test binary (profile { })''' args = self.full_args args += ['--profile-name=some-profile-name'] (self.options, self.args) = easyprof.parse_args(args) easyprof.AppArmorEasyProfile(None, self.options) def test_binary_nonexistent(self): '''Test binary (nonexistent)''' easyprof.AppArmorEasyProfile(os.path.join(self.tmpdir, 'nonexistent'), self.options) def test_binary_relative(self): '''Test binary (relative)''' try: easyprof.AppArmorEasyProfile('./foo', self.options) except easyprof.AppArmorException: return except Exception: raise raise Exception ("Binary should have been invalid") def test_binary_symlink(self): '''Test binary (symlink)''' exe = os.path.join(self.tmpdir, 'exe') open(exe, 'a').close() symlink = exe + ".lnk" os.symlink(exe, symlink) try: easyprof.AppArmorEasyProfile(symlink, self.options) except easyprof.AppArmorException: return except Exception: raise raise Exception ("Binary should have been invalid") # # Templates tests # def test_templates_list(self): '''Test templates (list)''' args = self.full_args args.append('--list-templates') (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) for i in easyp.get_templates(): self.assertTrue(os.path.exists(i), "Could not find '%s'" % i) def test_templates_show(self): '''Test templates (show)''' files = [] for f in glob.glob("%s/templates/*" % self.tmpdir): files.append(f) for f in files: args = self.full_args args += ['--show-template', '--template', f] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) path = os.path.join(easyp.dirs['templates'], f) self.assertTrue(os.path.exists(path), "Could not find '%s'" % path) open(path).read() def test_templates_list_include(self): '''Test templates (list with --include-templates-dir)''' args = self.full_args args.append('--list-templates') (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) orig_templates = easyp.get_templates() args = self.full_args args.append('--list-templates') args.append('--include-templates-dir=%s' % os.path.join(self.test_include_dir, 'templates')) (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) inc_templates = easyp.get_templates() self.assertTrue(len(inc_templates) == len(orig_templates) * 2, "templates missing: %s" % inc_templates) for i in inc_templates: self.assertTrue(os.path.exists(i), "Could not find '%s'" % i) def test_templates_show_include(self): '''Test templates (show with --include-templates-dir)''' files = [] for f in glob.glob("%s/templates/*" % self.test_include_dir): files.append(f) for f in files: args = self.full_args args += ['--show-template', '--template', f, '--include-templates-dir=%s' % os.path.join(self.test_include_dir, 'templates')] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) path = os.path.join(easyp.dirs['templates_include'], f) self.assertTrue(os.path.exists(path), "Could not find '%s'" % path) open(path).read() bn = os.path.basename(f) # setup() copies everything in the include prefixed with inc_ self.assertTrue(bn.startswith('inc_'), "'%s' does not start with 'inc_'" % bn) # # Policygroups tests # def test_policygroups_list(self): '''Test policygroups (list)''' args = self.full_args args.append('--list-policy-groups') (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) for i in easyp.get_policy_groups(): self.assertTrue(os.path.exists(i), "Could not find '%s'" % i) def test_policygroups_show(self): '''Test policygroups (show)''' files = [] for f in glob.glob("%s/policygroups/*" % self.tmpdir): files.append(f) for f in files: args = self.full_args args += ['--show-policy-group', '--policy-groups', os.path.basename(f)] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) path = os.path.join(easyp.dirs['policygroups'], f) self.assertTrue(os.path.exists(path), "Could not find '%s'" % path) open(path).read() def test_policygroups_list_include(self): '''Test policygroups (list with --include-policy-groups-dir)''' args = self.full_args args.append('--list-policy-groups') (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) orig_policy_groups = easyp.get_policy_groups() args = self.full_args args.append('--list-policy-groups') args.append('--include-policy-groups-dir=%s' % os.path.join(self.test_include_dir, 'policygroups')) (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) inc_policy_groups = easyp.get_policy_groups() self.assertTrue(len(inc_policy_groups) == len(orig_policy_groups) * 2, "policy_groups missing: %s" % inc_policy_groups) for i in inc_policy_groups: self.assertTrue(os.path.exists(i), "Could not find '%s'" % i) def test_policygroups_show_include(self): '''Test policygroups (show with --include-policy-groups-dir)''' files = [] for f in glob.glob("%s/policygroups/*" % self.test_include_dir): files.append(f) for f in files: args = self.full_args args += ['--show-policy-group', '--policy-groups', os.path.basename(f), '--include-policy-groups-dir=%s' % os.path.join(self.test_include_dir, 'policygroups')] (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) path = os.path.join(easyp.dirs['policygroups_include'], f) self.assertTrue(os.path.exists(path), "Could not find '%s'" % path) open(path).read() bn = os.path.basename(f) # setup() copies everything in the include prefixed with inc_ self.assertTrue(bn.startswith('inc_'), "'%s' does not start with 'inc_'" % bn) # # Manifest file argument tests # def test_manifest_argument(self): '''Test manifest argument''' # setup our manifest self.manifest = os.path.join(self.tmpdir, 'manifest.json') contents = ''' {"security": {"domain.reverse.appname": {"name": "simple-app"}}} ''' open(self.manifest, 'w').write(contents) args = self.full_args args.extend(['--manifest', self.manifest]) easyprof.parse_args(args) def _manifest_conflicts(self, opt, value): '''Helper for conflicts tests''' # setup our manifest self.manifest = os.path.join(self.tmpdir, 'manifest.json') contents = ''' {"security": {"domain.reverse.appname": {"binary": /nonexistent"}}} ''' open(self.manifest, 'w').write(contents) # opt first args = self.full_args args.extend([opt, value, '--manifest', self.manifest]) raised = False try: easyprof.parse_args(args, InterceptingOptionParser()) except InterceptedError: raised = True self.assertTrue(raised, msg="%s and manifest arguments did not " \ "raise a parse error" % opt) # manifest first args = self.full_args args.extend(['--manifest', self.manifest, opt, value]) raised = False try: easyprof.parse_args(args, InterceptingOptionParser()) except InterceptedError: raised = True self.assertTrue(raised, msg="%s and manifest arguments did not " \ "raise a parse error" % opt) def test_manifest_conflicts_profilename(self): '''Test manifest arg conflicts with profile_name arg''' self._manifest_conflicts("--profile-name", "simple-app") def test_manifest_conflicts_copyright(self): '''Test manifest arg conflicts with copyright arg''' self._manifest_conflicts("--copyright", "2013-01-01") def test_manifest_conflicts_author(self): '''Test manifest arg conflicts with author arg''' self._manifest_conflicts("--author", "Foo Bar") def test_manifest_conflicts_comment(self): '''Test manifest arg conflicts with comment arg''' self._manifest_conflicts("--comment", "some comment") def test_manifest_conflicts_abstractions(self): '''Test manifest arg conflicts with abstractions arg''' self._manifest_conflicts("--abstractions", "base") def test_manifest_conflicts_read_path(self): '''Test manifest arg conflicts with read-path arg''' self._manifest_conflicts("--read-path", "/etc/passwd") def test_manifest_conflicts_write_path(self): '''Test manifest arg conflicts with write-path arg''' self._manifest_conflicts("--write-path", "/tmp/foo") def test_manifest_conflicts_policy_groups(self): '''Test manifest arg conflicts with policy-groups arg''' self._manifest_conflicts("--policy-groups", "opt-application") def test_manifest_conflicts_name(self): '''Test manifest arg conflicts with name arg''' self._manifest_conflicts("--name", "foo") def test_manifest_conflicts_template_var(self): '''Test manifest arg conflicts with template-var arg''' self._manifest_conflicts("--template-var", "foo") def test_manifest_conflicts_policy_version(self): '''Test manifest arg conflicts with policy-version arg''' self._manifest_conflicts("--policy-version", "1.0") def test_manifest_conflicts_policy_vendor(self): '''Test manifest arg conflicts with policy-vendor arg''' self._manifest_conflicts("--policy-vendor", "somevendor") # # Test genpolicy # def _gen_policy(self, name=None, template=None, extra_args=[]): '''Generate a policy''' # Build up our args args = self.full_args if template == None: args.append('--template=%s' % self.test_template) else: args.append('--template=%s' % template) if name != None: args.append('--name=%s' % name) if len(extra_args) > 0: args += extra_args args.append(self.binary) # Now parse our args (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(self.binary, self.options) params = easyprof.gen_policy_params(self.binary, self.options) p = easyp.gen_policy(**params) # We always need to check for these search_terms = [self.binary] if name != None: search_terms.append(name) if template == None: search_terms.append(self.test_template) for s in search_terms: self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) # ###NAME### should be replaced with self.binary or 'name'. Check for that inv_s = '###NAME###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) if debugging: sys.stdout.write("%s\n" % p) return p def _gen_manifest_policy(self, manifest, use_security_prefix=True): # Build up our args args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, self.options) = easyprof.parse_manifest(manifest.emit_json(use_security_prefix), self.options)[0] easyp = easyprof.AppArmorEasyProfile(binary, self.options) params = easyprof.gen_policy_params(binary, self.options) p = easyp.gen_policy(**params) # ###NAME### should be replaced with self.binary or 'name'. Check for that inv_s = '###NAME###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) if debugging: sys.stdout.write("%s\n" % p) return p def test__is_safe(self): '''Test _is_safe()''' bad = [ "/../../../../etc/passwd", "abstraction with spaces", "semicolon;bad", "bad\x00baz", "foo/bar", "foo'bar", 'foo"bar', ] for s in bad: self.assertFalse(easyprof._is_safe(s), "'%s' should be bad" %s) def test_genpolicy_templates_abspath(self): '''Test genpolicy (abspath to template)''' # create a new template template = os.path.join(self.tmpdir, "test-abspath-template") shutil.copy(os.path.join(self.tmpdir, 'templates', self.test_template), template) contents = open(template).read() test_string = "#teststring" open(template, 'w').write(contents + "\n%s\n" % test_string) p = self._gen_policy(template=template) for s in [self.test_template, test_string]: self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) def test_genpolicy_templates_system(self): '''Test genpolicy (system template)''' self._gen_policy() def test_genpolicy_templates_nonexistent(self): '''Test genpolicy (nonexistent template)''' try: self._gen_policy(template=os.path.join(self.tmpdir, "/nonexistent")) except easyprof.AppArmorException: return except Exception: raise raise Exception ("template should be invalid") def test_genpolicy_name(self): '''Test genpolicy (name)''' self._gen_policy(name='test-foo') def test_genpolicy_comment(self): '''Test genpolicy (comment)''' s = "test comment" p = self._gen_policy(extra_args=['--comment=%s' % s]) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###COMMENT###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_author(self): '''Test genpolicy (author)''' s = "Archibald Poindexter" p = self._gen_policy(extra_args=['--author=%s' % s]) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###AUTHOR###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_copyright(self): '''Test genpolicy (copyright)''' s = "2112/01/01" p = self._gen_policy(extra_args=['--copyright=%s' % s]) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###COPYRIGHT###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_abstractions(self): '''Test genpolicy (single abstraction)''' s = "nameservice" p = self._gen_policy(extra_args=['--abstractions=%s' % s]) search = "#include " % s self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###ABSTRACTIONS###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_abstractions_multiple(self): '''Test genpolicy (multiple abstractions)''' abstractions = "authentication,X,user-tmp" p = self._gen_policy(extra_args=['--abstractions=%s' % abstractions]) for s in abstractions.split(','): search = "#include " % s self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###ABSTRACTIONS###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_abstractions_bad(self): '''Test genpolicy (abstractions - bad values)''' bad = [ "nonexistent", "/../../../../etc/passwd", "abstraction with spaces", ] for s in bad: try: self._gen_policy(extra_args=['--abstractions=%s' % s]) except easyprof.AppArmorException: continue except Exception: raise raise Exception ("abstraction '%s' should be invalid" % s) def _create_tmp_base_dir(self, prefix='', abstractions=[], tunables=[]): '''Create a temporary base dir layout''' base_name = 'apparmor.d' if prefix: base_name = '%s-%s' % (prefix, base_name) base_dir = os.path.join(self.tmpdir, base_name) abstractions_dir = os.path.join(base_dir, 'abstractions') tunables_dir = os.path.join(base_dir, 'tunables') os.mkdir(base_dir) os.mkdir(abstractions_dir) os.mkdir(tunables_dir) for f in abstractions: contents = ''' # Abstraction file for testing /%s r, ''' % (f) open(os.path.join(abstractions_dir, f), 'w').write(contents) for f in tunables: contents = ''' # Tunable file for testing @{AA_TEST_%s}=foo ''' % (f) open(os.path.join(tunables_dir, f), 'w').write(contents) return base_dir def test_genpolicy_abstractions_custom_base(self): '''Test genpolicy (custom base dir)''' abstraction = "custom-base-dir-test-abstraction" # The default template #includes the base abstraction and global # tunable so we need to create placeholders base = self._create_tmp_base_dir(abstractions=['base', abstraction], tunables=['global']) args = ['--abstractions=%s' % abstraction, '--base=%s' % base] p = self._gen_policy(extra_args=args) search = "#include " % abstraction self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###ABSTRACTIONS###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_abstractions_custom_base_bad(self): '''Test genpolicy (custom base dir - bad base dirs)''' abstraction = "custom-base-dir-test-abstraction" bad = [ None, '/etc/apparmor.d', '/' ] for base in bad: try: args = ['--abstractions=%s' % abstraction] if base: args.append('--base=%s' % base) self._gen_policy(extra_args=args) except easyprof.AppArmorException: continue except Exception: raise raise Exception ("abstraction '%s' should be invalid" % abstraction) def test_genpolicy_abstractions_custom_include(self): '''Test genpolicy (custom include dir)''' abstraction = "custom-include-dir-test-abstraction" # No need to create placeholders for the base abstraction or global # tunable since we're not adjusting the base directory include = self._create_tmp_base_dir(abstractions=[abstraction]) args = ['--abstractions=%s' % abstraction, '--Include=%s' % include] p = self._gen_policy(extra_args=args) search = "#include " % abstraction self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###ABSTRACTIONS###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_abstractions_custom_include_bad(self): '''Test genpolicy (custom include dir - bad include dirs)''' abstraction = "custom-include-dir-test-abstraction" bad = [ None, '/etc/apparmor.d', '/' ] for include in bad: try: args = ['--abstractions=%s' % abstraction] if include: args.append('--Include=%s' % include) self._gen_policy(extra_args=args) except easyprof.AppArmorException: continue except Exception: raise raise Exception ("abstraction '%s' should be invalid" % abstraction) def test_genpolicy_profile_name_bad(self): '''Test genpolicy (profile name - bad values)''' bad = [ "/../../../../etc/passwd", "../../../../etc/passwd", "profile name with spaces", ] for s in bad: try: self._gen_policy(extra_args=['--profile-name=%s' % s]) except easyprof.AppArmorException: continue except Exception: raise raise Exception ("profile_name '%s' should be invalid" % s) def test_genpolicy_policy_group_bad(self): '''Test genpolicy (policy group - bad values)''' bad = [ "/../../../../etc/passwd", "../../../../etc/passwd", "profile name with spaces", ] for s in bad: try: self._gen_policy(extra_args=['--policy-groups=%s' % s]) except easyprof.AppArmorException: continue except Exception: raise raise Exception ("policy group '%s' should be invalid" % s) def test_genpolicy_policygroups(self): '''Test genpolicy (single policygroup)''' groups = self.test_policygroup p = self._gen_policy(extra_args=['--policy-groups=%s' % groups]) for s in ['#include ', '#include ']: self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###POLICYGROUPS###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_policygroups_multiple(self): '''Test genpolicy (multiple policygroups)''' test_policygroup2 = "test-policygroup2" contents = ''' # %s #include #include ''' % (self.test_policygroup) open(os.path.join(self.tmpdir, 'policygroups', test_policygroup2), 'w').write(contents) groups = "%s,%s" % (self.test_policygroup, test_policygroup2) p = self._gen_policy(extra_args=['--policy-groups=%s' % groups]) for s in ['#include ', '#include ', '#include ', '#include ']: self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###POLICYGROUPS###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_policygroups_nonexistent(self): '''Test genpolicy (nonexistent policygroup)''' try: self._gen_policy(extra_args=['--policy-groups=nonexistent']) except easyprof.AppArmorException: return except Exception: raise raise Exception ("policygroup should be invalid") def test_genpolicy_readpath_file(self): '''Test genpolicy (read-path file)''' s = "/opt/test-foo" p = self._gen_policy(extra_args=['--read-path=%s' % s]) search = "%s rk," % s self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_readpath_home_file(self): '''Test genpolicy (read-path file in /home)''' s = "/home/*/test-foo" p = self._gen_policy(extra_args=['--read-path=%s' % s]) search = "owner %s rk," % s self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_readpath_homevar_file(self): '''Test genpolicy (read-path file in @{HOME})''' s = "@{HOME}/test-foo" p = self._gen_policy(extra_args=['--read-path=%s' % s]) search = "owner %s rk," % s self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_readpath_homedirs_file(self): '''Test genpolicy (read-path file in @{HOMEDIRS})''' s = "@{HOMEDIRS}/test-foo" p = self._gen_policy(extra_args=['--read-path=%s' % s]) search = "owner %s rk," % s self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_readpath_dir(self): '''Test genpolicy (read-path directory/)''' s = "/opt/test-foo-dir/" p = self._gen_policy(extra_args=['--read-path=%s' % s]) search_terms = ["%s rk," % s, "%s** rk," % s] for search in search_terms: self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_readpath_dir_glob(self): '''Test genpolicy (read-path directory/*)''' s = "/opt/test-foo-dir/*" p = self._gen_policy(extra_args=['--read-path=%s' % s]) search_terms = ["%s rk," % os.path.dirname(s), "%s rk," % s] for search in search_terms: self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_readpath_dir_glob_all(self): '''Test genpolicy (read-path directory/**)''' s = "/opt/test-foo-dir/**" p = self._gen_policy(extra_args=['--read-path=%s' % s]) search_terms = ["%s rk," % os.path.dirname(s), "%s rk," % s] for search in search_terms: self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_readpath_multiple(self): '''Test genpolicy (read-path multiple)''' paths = ["/opt/test-foo", "/home/*/test-foo", "@{HOME}/test-foo", "@{HOMEDIRS}/test-foo", "/opt/test-foo-dir/", "/opt/test-foo-dir/*", "/opt/test-foo-dir/**"] args = [] search_terms = [] for s in paths: args.append('--read-path=%s' % s) # This mimics easyprof.gen_path_rule() owner = "" if s.startswith('/home/') or s.startswith("@{HOME"): owner = "owner " if s.endswith('/'): search_terms.append("%s rk," % (s)) search_terms.append("%s%s** rk," % (owner, s)) elif s.endswith('/**') or s.endswith('/*'): search_terms.append("%s rk," % (os.path.dirname(s))) search_terms.append("%s%s rk," % (owner, s)) else: search_terms.append("%s%s rk," % (owner, s)) p = self._gen_policy(extra_args=args) for search in search_terms: self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_readpath_bad(self): '''Test genpolicy (read-path bad)''' s = "bar" try: self._gen_policy(extra_args=['--read-path=%s' % s]) except easyprof.AppArmorException: return except Exception: raise raise Exception ("read-path should be invalid") def test_genpolicy_writepath_file(self): '''Test genpolicy (write-path file)''' s = "/opt/test-foo" p = self._gen_policy(extra_args=['--write-path=%s' % s]) search = "%s rwk," % s self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_writepath_home_file(self): '''Test genpolicy (write-path file in /home)''' s = "/home/*/test-foo" p = self._gen_policy(extra_args=['--write-path=%s' % s]) search = "owner %s rwk," % s self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_writepath_homevar_file(self): '''Test genpolicy (write-path file in @{HOME})''' s = "@{HOME}/test-foo" p = self._gen_policy(extra_args=['--write-path=%s' % s]) search = "owner %s rwk," % s self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_writepath_homedirs_file(self): '''Test genpolicy (write-path file in @{HOMEDIRS})''' s = "@{HOMEDIRS}/test-foo" p = self._gen_policy(extra_args=['--write-path=%s' % s]) search = "owner %s rwk," % s self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_writepath_dir(self): '''Test genpolicy (write-path directory/)''' s = "/opt/test-foo-dir/" p = self._gen_policy(extra_args=['--write-path=%s' % s]) search_terms = ["%s rwk," % s, "%s** rwk," % s] for search in search_terms: self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_writepath_dir_glob(self): '''Test genpolicy (write-path directory/*)''' s = "/opt/test-foo-dir/*" p = self._gen_policy(extra_args=['--write-path=%s' % s]) search_terms = ["%s rwk," % os.path.dirname(s), "%s rwk," % s] for search in search_terms: self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_writepath_dir_glob_all(self): '''Test genpolicy (write-path directory/**)''' s = "/opt/test-foo-dir/**" p = self._gen_policy(extra_args=['--write-path=%s' % s]) search_terms = ["%s rwk," % os.path.dirname(s), "%s rwk," % s] for search in search_terms: self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_writepath_multiple(self): '''Test genpolicy (write-path multiple)''' paths = ["/opt/test-foo", "/home/*/test-foo", "@{HOME}/test-foo", "@{HOMEDIRS}/test-foo", "/opt/test-foo-dir/", "/opt/test-foo-dir/*", "/opt/test-foo-dir/**"] args = [] search_terms = [] for s in paths: args.append('--write-path=%s' % s) # This mimics easyprof.gen_path_rule() owner = "" if s.startswith('/home/') or s.startswith("@{HOME"): owner = "owner " if s.endswith('/'): search_terms.append("%s rwk," % (s)) search_terms.append("%s%s** rwk," % (owner, s)) elif s.endswith('/**') or s.endswith('/*'): search_terms.append("%s rwk," % (os.path.dirname(s))) search_terms.append("%s%s rwk," % (owner, s)) else: search_terms.append("%s%s rwk," % (owner, s)) p = self._gen_policy(extra_args=args) for search in search_terms: self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p)) inv_s = '###READPATH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_writepath_bad(self): '''Test genpolicy (write-path bad)''' s = "bar" try: self._gen_policy(extra_args=['--write-path=%s' % s]) except easyprof.AppArmorException: return except Exception: raise raise Exception ("write-path should be invalid") def test_genpolicy_templatevar(self): '''Test genpolicy (template-var single)''' s = "@{FOO}=bar" p = self._gen_policy(extra_args=['--template-var=%s' % s]) k, v = s.split('=') s = '%s="%s"' % (k, v) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###TEMPLATEVAR###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_templatevar_multiple(self): '''Test genpolicy (template-var multiple)''' variables = ['@{FOO}=bar', '@{BAR}=baz'] args = [] for s in variables: args.append('--template-var=%s' % s) p = self._gen_policy(extra_args=args) for s in variables: k, v = s.split('=') s = '%s="%s"' % (k, v) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###TEMPLATEVAR###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_templatevar_bad(self): '''Test genpolicy (template-var - bad values)''' bad = [ "{FOO}=bar", "@FOO}=bar", "@{FOO=bar", "FOO=bar", "@FOO=bar", "@{FOO}=/../../../etc/passwd", "@{FOO}=bar=foo", "@{FOO;BAZ}=bar", '@{FOO}=bar"baz', ] for s in bad: try: self._gen_policy(extra_args=['--template-var=%s' % s]) except easyprof.AppArmorException: continue except Exception: raise raise Exception ("template-var should be invalid") def test_genpolicy_invalid_template_policy(self): '''Test genpolicy (invalid template policy)''' # create a new template template = os.path.join(self.tmpdir, "test-invalid-template") shutil.copy(os.path.join(self.tmpdir, 'templates', self.test_template), template) contents = open(template).read() bad_pol = "" bad_string = "bzzzt" for line in contents.splitlines(): if '}' in line: bad_pol += bad_string else: bad_pol += line bad_pol += "\n" open(template, 'w').write(bad_pol) try: self._gen_policy(template=template) except easyprof.AppArmorException: return except Exception: raise raise Exception ("policy should be invalid") def test_genpolicy_no_binary_without_profile_name(self): '''Test genpolicy (no binary with no profile name)''' try: easyprof.gen_policy_params(None, self.options) except easyprof.AppArmorException: return except Exception: raise raise Exception ("No binary or profile name should have been invalid") def test_genpolicy_with_binary_with_profile_name(self): '''Test genpolicy (binary with profile name)''' profile_name = "some-profile-name" p = self._gen_policy(extra_args=['--profile-name=%s' % profile_name]) s = 'profile "%s" "%s" {' % (profile_name, self.binary) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###PROFILEATTACH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_with_binary_without_profile_name(self): '''Test genpolicy (binary without profile name)''' p = self._gen_policy() s = '"%s" {' % (self.binary) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###PROFILEATTACH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_genpolicy_without_binary_with_profile_name(self): '''Test genpolicy (no binary with profile name)''' profile_name = "some-profile-name" args = self.full_args args.append('--profile-name=%s' % profile_name) (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(None, self.options) params = easyprof.gen_policy_params(None, self.options) p = easyp.gen_policy(**params) s = 'profile "%s" {' % (profile_name) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###PROFILEATTACH###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) # manifest tests def test_gen_manifest_policy_with_binary_with_profile_name(self): '''Test gen_manifest_policy (binary with profile name)''' m = Manifest("test_gen_manifest_policy") m.add_binary(self.ls) self._gen_manifest_policy(m) def test_gen_manifest_policy_without_binary_with_profile_name(self): '''Test gen_manifest_policy (no binary with profile name)''' m = Manifest("test_gen_manifest_policy") self._gen_manifest_policy(m) def test_gen_manifest_policy_templates_system(self): '''Test gen_manifest_policy (system template)''' m = Manifest("test_gen_manifest_policy") m.add_template(self.test_template) self._gen_manifest_policy(m) def test_gen_manifest_policy_templates_system_noprefix(self): '''Test gen_manifest_policy (system template, no security prefix)''' m = Manifest("test_gen_manifest_policy") m.add_template(self.test_template) self._gen_manifest_policy(m, use_security_prefix=False) def test_gen_manifest_abs_path_template(self): '''Test gen_manifest_policy (abs path template)''' m = Manifest("test_gen_manifest_policy") m.add_template("/etc/shadow") try: self._gen_manifest_policy(m) except easyprof.AppArmorException: return except Exception: raise raise Exception ("abs path template name should be invalid") def test_gen_manifest_escape_path_templates(self): '''Test gen_manifest_policy (esc path template)''' m = Manifest("test_gen_manifest_policy") m.add_template("../../../../../../../../etc/shadow") try: self._gen_manifest_policy(m) except easyprof.AppArmorException: return except Exception: raise raise Exception ("../ template name should be invalid") def test_gen_manifest_policy_templates_nonexistent(self): '''Test gen manifest policy (nonexistent template)''' m = Manifest("test_gen_manifest_policy") m.add_template("nonexistent") try: self._gen_manifest_policy(m) except easyprof.AppArmorException: return except Exception: raise raise Exception ("template should be invalid") def test_gen_manifest_policy_comment(self): '''Test gen manifest policy (comment)''' s = "test comment" m = Manifest("test_gen_manifest_policy") m.add_comment(s) p = self._gen_manifest_policy(m) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###COMMENT###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_gen_manifest_policy_author(self): '''Test gen manifest policy (author)''' s = "Archibald Poindexter" m = Manifest("test_gen_manifest_policy") m.add_author(s) p = self._gen_manifest_policy(m) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###AUTHOR###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_gen_manifest_policy_copyright(self): '''Test genpolicy (copyright)''' s = "2112/01/01" m = Manifest("test_gen_manifest_policy") m.add_copyright(s) p = self._gen_manifest_policy(m) self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###COPYRIGHT###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_gen_manifest_policy_policygroups(self): '''Test gen manifest policy (single policygroup)''' groups = self.test_policygroup m = Manifest("test_gen_manifest_policy") m.add_policygroups(groups) p = self._gen_manifest_policy(m) for s in ['#include ', '#include ']: self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###POLICYGROUPS###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_gen_manifest_policy_policygroups_multiple(self): '''Test genpolicy (multiple policygroups)''' test_policygroup2 = "test-policygroup2" contents = ''' # %s #include #include ''' % (self.test_policygroup) open(os.path.join(self.tmpdir, 'policygroups', test_policygroup2), 'w').write(contents) groups = "%s,%s" % (self.test_policygroup, test_policygroup2) m = Manifest("test_gen_manifest_policy") m.add_policygroups(groups) p = self._gen_manifest_policy(m) for s in ['#include ', '#include ', '#include ', '#include ']: self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###POLICYGROUPS###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_gen_manifest_policy_policygroups_nonexistent(self): '''Test gen manifest policy (nonexistent policygroup)''' groups = "nonexistent" m = Manifest("test_gen_manifest_policy") m.add_policygroups(groups) try: self._gen_manifest_policy(m) except easyprof.AppArmorException: return except Exception: raise raise Exception ("policygroup should be invalid") def test_gen_manifest_policy_templatevar(self): '''Test gen manifest policy (template-var single)''' m = Manifest("test_gen_manifest_policy") m.add_template_variable("FOO", "bar") p = self._gen_manifest_policy(m) s = '@{FOO}="bar"' self.assertTrue(s in p, "Could not find '%s' in:\n%s" % (s, p)) inv_s = '###TEMPLATEVAR###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_gen_manifest_policy_templatevar_multiple(self): '''Test gen manifest policy (template-var multiple)''' variables = [["FOO", "bar"], ["BAR", "baz"]] m = Manifest("test_gen_manifest_policy") for s in variables: m.add_template_variable(s[0], s[1]) p = self._gen_manifest_policy(m) for s in variables: str_s = '@{%s}="%s"' % (s[0], s[1]) self.assertTrue(str_s in p, "Could not find '%s' in:\n%s" % (str_s, p)) inv_s = '###TEMPLATEVAR###' self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p)) def test_gen_manifest_policy_invalid_keys(self): '''Test gen manifest policy (invalid keys)''' keys = ['config_file', 'debug', 'help', 'list-templates', 'list_templates', 'show-template', 'show_template', 'list-policy-groups', 'list_policy_groups', 'show-policy-group', 'show_policy_group', 'templates-dir', 'templates_dir', 'policy-groups-dir', 'policy_groups_dir', 'nonexistent', 'no_verify', ] args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) for k in keys: security = dict() security["profile_name"] = "test-app" security[k] = "bad" j = json.dumps(security, indent=2) try: easyprof.parse_manifest(j, self.options) except easyprof.AppArmorException: continue raise Exception ("'%s' should be invalid" % k) def test_gen_manifest(self): '''Test gen_manifest''' # this should come from manpage m = '''{ "security": { "profiles": { "com.example.foo": { "abstractions": [ "audio", "gnome" ], "author": "Your Name", "binary": "/opt/foo/**", "comment": "Unstructured single-line comment", "copyright": "Unstructured single-line copyright statement", "name": "My Foo App", "policy_groups": [ "opt-application", "user-application" ], "policy_vendor": "somevendor", "policy_version": 1.0, "read_path": [ "/tmp/foo_r", "/tmp/bar_r/" ], "template": "user-application", "template_variables": { "APPNAME": "foo", "VAR1": "bar", "VAR2": "baz" }, "write_path": [ "/tmp/foo_w", "/tmp/bar_w/" ] } } } }''' for d in ['policygroups', 'templates']: shutil.copytree(os.path.join(self.tmpdir, d), os.path.join(self.tmpdir, d, "somevendor/1.0")) args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, self.options) = easyprof.parse_manifest(m, self.options)[0] easyp = easyprof.AppArmorEasyProfile(binary, self.options) params = easyprof.gen_policy_params(binary, self.options) # verify we get the same manifest back man_new = easyp.gen_manifest(params) self.assertEquals(m, man_new) def test_gen_manifest_ubuntu(self): '''Test gen_manifest (ubuntu)''' # this should be based on the manpage (but use existing policy_groups # and template m = '''{ "security": { "profiles": { "com.ubuntu.developer.myusername.MyCoolApp": { "name": "MyCoolApp", "policy_groups": [ "opt-application", "user-application" ], "policy_vendor": "ubuntu", "policy_version": 1.0, "template": "user-application", "template_variables": { "APPNAME": "MyCoolApp", "APPVERSION": "0.1.2" } } } } }''' for d in ['policygroups', 'templates']: shutil.copytree(os.path.join(self.tmpdir, d), os.path.join(self.tmpdir, d, "ubuntu/1.0")) args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, self.options) = easyprof.parse_manifest(m, self.options)[0] easyp = easyprof.AppArmorEasyProfile(binary, self.options) params = easyprof.gen_policy_params(binary, self.options) # verify we get the same manifest back man_new = easyp.gen_manifest(params) self.assertEquals(m, man_new) def test_parse_manifest_no_version(self): '''Test parse_manifest (vendor with no version)''' # this should come from manpage m = '''{ "security": { "profiles": { "com.ubuntu.developer.myusername.MyCoolApp": { "policy_groups": [ "opt-application", "user-application" ], "policy_vendor": "ubuntu", "template": "user-application", "template_variables": { "APPNAME": "MyCoolApp", "APPVERSION": "0.1.2" } } } } }''' args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, self.options) = easyprof.parse_manifest(m, self.options)[0] try: easyprof.AppArmorEasyProfile(binary, self.options) except easyprof.AppArmorException: return raise Exception ("Should have failed on missing version") def test_parse_manifest_no_vendor(self): '''Test parse_manifest (version with no vendor)''' # this should come from manpage m = '''{ "security": { "profiles": { "com.ubuntu.developer.myusername.MyCoolApp": { "policy_groups": [ "opt-application", "user-application" ], "policy_version": 1.0, "template": "user-application", "template_variables": { "APPNAME": "MyCoolApp", "APPVERSION": "0.1.2" } } } } }''' args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, self.options) = easyprof.parse_manifest(m, self.options)[0] try: easyprof.AppArmorEasyProfile(binary, self.options) except easyprof.AppArmorException: return raise Exception ("Should have failed on missing vendor") def test_parse_manifest_multiple(self): '''Test parse_manifest_multiple''' m = '''{ "security": { "profiles": { "com.example.foo": { "abstractions": [ "audio", "gnome" ], "author": "Your Name", "binary": "/opt/foo/**", "comment": "Unstructured single-line comment", "copyright": "Unstructured single-line copyright statement", "name": "My Foo App", "policy_groups": [ "opt-application", "user-application" ], "read_path": [ "/tmp/foo_r", "/tmp/bar_r/" ], "template": "user-application", "template_variables": { "APPNAME": "foo", "VAR1": "bar", "VAR2": "baz" }, "write_path": [ "/tmp/foo_w", "/tmp/bar_w/" ] }, "com.ubuntu.developer.myusername.MyCoolApp": { "policy_groups": [ "opt-application" ], "policy_vendor": "ubuntu", "policy_version": 1.0, "template": "user-application", "template_variables": { "APPNAME": "MyCoolApp", "APPVERSION": "0.1.2" } } } } }''' for d in ['policygroups', 'templates']: shutil.copytree(os.path.join(self.tmpdir, d), os.path.join(self.tmpdir, d, "ubuntu/1.0")) args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) profiles = easyprof.parse_manifest(m, self.options) for (binary, options) in profiles: easyp = easyprof.AppArmorEasyProfile(binary, options) params = easyprof.gen_policy_params(binary, options) easyp.gen_manifest(params) easyp.gen_policy(**params) # verify manifest tests def _verify_manifest(self, m, expected, invalid=False): args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) try: (binary, options) = easyprof.parse_manifest(m, self.options)[0] except easyprof.AppArmorException: if invalid: return raise params = easyprof.gen_policy_params(binary, options) if expected: self.assertTrue(easyprof.verify_manifest(params, args), "params=%s\nmanifest=%s" % (params,m)) else: self.assertFalse(easyprof.verify_manifest(params, args), "params=%s\nmanifest=%s" % (params,m)) def test_verify_manifest_full(self): '''Test verify_manifest (full)''' m = '''{ "security": { "profiles": { "com.example.foo": { "abstractions": [ "base" ], "author": "Your Name", "binary": "/opt/com.example/foo/**", "comment": "some free-form single-line comment", "copyright": "Unstructured single-line copyright statement", "name": "foo", "policy_groups": [ "user-application", "opt-application" ], "template": "user-application", "template_variables": { "OK1": "foo", "OK2": "com.example.foo" } } } } }''' self._verify_manifest(m, expected=True) def test_verify_manifest_full_bad(self): '''Test verify_manifest (full bad)''' m = '''{ "security": { "profiles": { "/com.example.foo": { "abstractions": [ "audio", "gnome" ], "author": "Your Name", "binary": "/usr/foo/**", "comment": "some free-form single-line comment", "copyright": "Unstructured single-line copyright statement", "name": "foo", "policy_groups": [ "user-application", "opt-application" ], "read_path": [ "/tmp/foo_r", "/tmp/bar_r/" ], "template": "user-application", "template_variables": { "VAR1": "f*o", "VAR2": "*foo", "VAR3": "fo*", "VAR4": "b{ar", "VAR5": "b{a,r}", "VAR6": "b}ar", "VAR7": "bar[0-9]", "VAR8": "b{ar", "VAR9": "/tmp/../etc/passwd" }, "write_path": [ "/tmp/foo_w", "/tmp/bar_w/" ] } } } }''' self._verify_manifest(m, expected=False, invalid=True) def test_verify_manifest_binary(self): '''Test verify_manifest (binary in /usr)''' m = '''{ "security": { "profiles": { "com.example.foo": { "binary": "/usr/foo/**", "template": "user-application" } } } }''' self._verify_manifest(m, expected=True) def test_verify_manifest_profile_profile_name_bad(self): '''Test verify_manifest (bad profile_name)''' m = '''{ "security": { "profiles": { "/foo": { "binary": "/opt/com.example/foo/**", "template": "user-application" } } } }''' self._verify_manifest(m, expected=False, invalid=True) m = '''{ "security": { "profiles": { "bin/*": { "binary": "/opt/com.example/foo/**", "template": "user-application" } } } }''' self._verify_manifest(m, expected=False) def test_verify_manifest_profile_profile_name(self): '''Test verify_manifest (profile_name)''' m = '''{ "security": { "profiles": { "com.example.foo": { "binary": "/opt/com.example/foo/**", "template": "user-application" } } } }''' self._verify_manifest(m, expected=True) def test_verify_manifest_profile_abstractions(self): '''Test verify_manifest (abstractions)''' m = '''{ "security": { "profiles": { "com.example.foo": { "binary": "/opt/com.example/foo/**", "template": "user-application", "abstractions": [ "base" ] } } } }''' self._verify_manifest(m, expected=True) def test_verify_manifest_profile_abstractions_bad(self): '''Test verify_manifest (bad abstractions)''' m = '''{ "security": { "profiles": { "com.example.foo": { "binary": "/opt/com.example/foo/**", "template": "user-application", "abstractions": [ "user-tmp" ] } } } }''' self._verify_manifest(m, expected=False) def test_verify_manifest_profile_template_var(self): '''Test verify_manifest (good template_var)''' m = '''{ "security": { "profiles": { "com.example.foo": { "binary": "/opt/com.example/something with spaces/**", "template": "user-application", "template_variables": { "OK1": "foo", "OK2": "com.example.foo", "OK3": "something with spaces" } } } } }''' self._verify_manifest(m, expected=True) def test_verify_manifest_profile_template_var_bad(self): '''Test verify_manifest (bad template_var)''' for v in ['"VAR1": "f*o"', '"VAR2": "*foo"', '"VAR3": "fo*"', '"VAR4": "b{ar"', '"VAR5": "b{a,r}"', '"VAR6": "b}ar"', '"VAR7": "bar[0-9]"', '"VAR8": "b{ar"', '"VAR9": "foo/bar"' # this is valid, but potentially unsafe ]: m = '''{ "security": { "profiles": { "com.example.foo": { "binary": "/opt/com.example/foo/**", "template": "user-application", "template_variables": { %s } } } } }''' % v self._verify_manifest(m, expected=False) def test_manifest_invalid(self): '''Test invalid manifest (parse error)''' m = '''{ "security": { "com.example.foo": { "binary": "/opt/com.example/foo/**", "template": "user-application", "abstractions": [ "base" ] }''' self._verify_manifest(m, expected=False, invalid=True) def test_manifest_invalid2(self): '''Test invalid manifest (profile_name is not key)''' m = '''{ "security": { "binary": "/opt/com.example/foo/**", "template": "user-application", "abstractions": [ "base" ] } }''' self._verify_manifest(m, expected=False, invalid=True) def test_manifest_invalid3(self): '''Test invalid manifest (profile_name in dict)''' m = '''{ "security": { "binary": "/opt/com.example/foo/**", "template": "user-application", "abstractions": [ "base" ], "profile_name": "com.example.foo" } }''' self._verify_manifest(m, expected=False, invalid=True) def test_manifest_invalid4(self): '''Test invalid manifest (bad path in template var)''' for v in ['"VAR1": "/tmp/../etc/passwd"', '"VAR2": "./"', '"VAR3": "foo\"bar"', '"VAR4": "foo//bar"', ]: m = '''{ "security": { "profiles": { "com.example.foo": { "binary": "/opt/com.example/foo/**", "template": "user-application", "template_variables": { %s } } } } }''' % v args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, options) = easyprof.parse_manifest(m, self.options)[0] params = easyprof.gen_policy_params(binary, options) try: easyprof.verify_manifest(params) except easyprof.AppArmorException: return raise Exception ("Should have failed with invalid variable declaration") # policy version tests def test_policy_vendor_manifest_nonexistent(self): '''Test policy vendor via manifest (nonexistent)''' m = '''{ "security": { "profiles": { "com.example.foo": { "policy_vendor": "nonexistent", "policy_version": 1.0, "binary": "/opt/com.example/foo/**", "template": "user-application" } } } }''' # Build up our args args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, self.options) = easyprof.parse_manifest(m, self.options)[0] try: easyprof.AppArmorEasyProfile(binary, self.options) except easyprof.AppArmorException: return raise Exception ("Should have failed with non-existent directory") def test_policy_version_manifest(self): '''Test policy version via manifest (good)''' policy_vendor = "somevendor" policy_version = "1.0" policy_subdir = "%s/%s" % (policy_vendor, policy_version) m = '''{ "security": { "profiles": { "com.example.foo": { "policy_vendor": "%s", "policy_version": %s, "binary": "/opt/com.example/foo/**", "template": "user-application" } } } }''' % (policy_vendor, policy_version) for d in ['policygroups', 'templates']: shutil.copytree(os.path.join(self.tmpdir, d), os.path.join(self.tmpdir, d, policy_subdir)) # Build up our args args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, self.options) = easyprof.parse_manifest(m, self.options)[0] easyp = easyprof.AppArmorEasyProfile(binary, self.options) tdir = os.path.join(self.tmpdir, 'templates', policy_subdir) for t in easyp.get_templates(): self.assertTrue(t.startswith(tdir)) pdir = os.path.join(self.tmpdir, 'policygroups', policy_subdir) for p in easyp.get_policy_groups(): self.assertTrue(p.startswith(pdir)) params = easyprof.gen_policy_params(binary, self.options) easyp.gen_policy(**params) def test_policy_vendor_version_args(self): '''Test policy vendor and version via command line args (good)''' policy_version = "1.0" policy_vendor = "somevendor" policy_subdir = "%s/%s" % (policy_vendor, policy_version) # Create the directories for d in ['policygroups', 'templates']: shutil.copytree(os.path.join(self.tmpdir, d), os.path.join(self.tmpdir, d, policy_subdir)) # Build up our args args = self.full_args args.append("--policy-version=%s" % policy_version) args.append("--policy-vendor=%s" % policy_vendor) (self.options, self.args) = easyprof.parse_args(args) (self.options, self.args) = easyprof.parse_args(self.full_args + [self.binary]) easyp = easyprof.AppArmorEasyProfile(self.binary, self.options) tdir = os.path.join(self.tmpdir, 'templates', policy_subdir) for t in easyp.get_templates(): self.assertTrue(t.startswith(tdir), \ "'%s' does not start with '%s'" % (t, tdir)) pdir = os.path.join(self.tmpdir, 'policygroups', policy_subdir) for p in easyp.get_policy_groups(): self.assertTrue(p.startswith(pdir), \ "'%s' does not start with '%s'" % (p, pdir)) params = easyprof.gen_policy_params(self.binary, self.options) easyp.gen_policy(**params) def test_policy_vendor_args_nonexistent(self): '''Test policy vendor via command line args (nonexistent)''' policy_vendor = "nonexistent" policy_version = "1.0" args = self.full_args args.append("--policy-version=%s" % policy_version) args.append("--policy-vendor=%s" % policy_vendor) (self.options, self.args) = easyprof.parse_args(args) (self.options, self.args) = easyprof.parse_args(self.full_args + [self.binary]) try: easyprof.AppArmorEasyProfile(self.binary, self.options) except easyprof.AppArmorException: return raise Exception ("Should have failed with non-existent directory") def test_policy_version_args_bad(self): '''Test policy version via command line args (bad)''' bad = [ "../../../../../../etc", "notanumber", "v1.0a", "-1", ] for policy_version in bad: args = self.full_args args.append("--policy-version=%s" % policy_version) args.append("--policy-vendor=somevendor") (self.options, self.args) = easyprof.parse_args(args) (self.options, self.args) = easyprof.parse_args(self.full_args + [self.binary]) try: easyprof.AppArmorEasyProfile(self.binary, self.options) except easyprof.AppArmorException: continue raise Exception ("Should have failed with bad version") def test_policy_vendor_args_bad(self): '''Test policy vendor via command line args (bad)''' bad = [ "../../../../../../etc", "vendor with space", "semicolon;isbad", ] for policy_vendor in bad: args = self.full_args args.append("--policy-vendor=%s" % policy_vendor) args.append("--policy-version=1.0") (self.options, self.args) = easyprof.parse_args(args) (self.options, self.args) = easyprof.parse_args(self.full_args + [self.binary]) try: easyprof.AppArmorEasyProfile(self.binary, self.options) except easyprof.AppArmorException: continue raise Exception ("Should have failed with bad vendor") # output_directory tests def test_output_directory_multiple(self): '''Test output_directory (multiple)''' files = dict() files["com.example.foo"] = "com.example.foo" files["com.ubuntu.developer.myusername.MyCoolApp"] = "com.ubuntu.developer.myusername.MyCoolApp" files["usr.bin.baz"] = "/usr/bin/baz" m = '''{ "security": { "profiles": { "%s": { "abstractions": [ "audio", "gnome" ], "author": "Your Name", "binary": "/opt/foo/**", "comment": "Unstructured single-line comment", "copyright": "Unstructured single-line copyright statement", "name": "My Foo App", "policy_groups": [ "opt-application", "user-application" ], "read_path": [ "/tmp/foo_r", "/tmp/bar_r/" ], "template": "user-application", "template_variables": { "APPNAME": "foo", "VAR1": "bar", "VAR2": "baz" }, "write_path": [ "/tmp/foo_w", "/tmp/bar_w/" ] }, "%s": { "policy_groups": [ "opt-application", "user-application" ], "template": "user-application", "template_variables": { "APPNAME": "MyCoolApp", "APPVERSION": "0.1.2" } }, "%s": { "abstractions": [ "gnome" ], "policy_groups": [ "user-application" ], "template_variables": { "APPNAME": "baz" } } } } }''' % (files["com.example.foo"], files["com.ubuntu.developer.myusername.MyCoolApp"], files["usr.bin.baz"]) out_dir = os.path.join(self.tmpdir, "output") args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) profiles = easyprof.parse_manifest(m, self.options) for (binary, options) in profiles: easyp = easyprof.AppArmorEasyProfile(binary, options) params = easyprof.gen_policy_params(binary, options) easyp.output_policy(params, dir=out_dir) for fn in files: f = os.path.join(out_dir, fn) self.assertTrue(os.path.exists(f), "Could not find '%s'" % f) def test_output_directory_single(self): '''Test output_directory (single)''' files = dict() files["com.example.foo"] = "com.example.foo" m = '''{ "security": { "profiles": { "%s": { "abstractions": [ "audio", "gnome" ], "author": "Your Name", "binary": "/opt/foo/**", "comment": "Unstructured single-line comment", "copyright": "Unstructured single-line copyright statement", "name": "My Foo App", "policy_groups": [ "opt-application", "user-application" ], "read_path": [ "/tmp/foo_r", "/tmp/bar_r/" ], "template": "user-application", "template_variables": { "APPNAME": "foo", "VAR1": "bar", "VAR2": "baz" }, "write_path": [ "/tmp/foo_w", "/tmp/bar_w/" ] } } } }''' % (files["com.example.foo"]) out_dir = os.path.join(self.tmpdir, "output") args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) profiles = easyprof.parse_manifest(m, self.options) for (binary, options) in profiles: easyp = easyprof.AppArmorEasyProfile(binary, options) params = easyprof.gen_policy_params(binary, options) easyp.output_policy(params, dir=out_dir) for fn in files: f = os.path.join(out_dir, fn) self.assertTrue(os.path.exists(f), "Could not find '%s'" % f) def test_output_directory_invalid(self): '''Test output_directory (output directory exists as file)''' files = dict() files["usr.bin.baz"] = "/usr/bin/baz" m = '''{ "security": { "profiles": { "%s": { "abstractions": [ "gnome" ], "policy_groups": [ "user-application" ], "template_variables": { "APPNAME": "baz" } } } } }''' % files["usr.bin.baz"] out_dir = os.path.join(self.tmpdir, "output") open(out_dir, 'w').close() args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, options) = easyprof.parse_manifest(m, self.options)[0] easyp = easyprof.AppArmorEasyProfile(binary, options) params = easyprof.gen_policy_params(binary, options) try: easyp.output_policy(params, dir=out_dir) except easyprof.AppArmorException: return raise Exception ("Should have failed with 'is not a directory'") def test_output_directory_invalid_params(self): '''Test output_directory (no binary or profile_name)''' files = dict() files["usr.bin.baz"] = "/usr/bin/baz" m = '''{ "security": { "profiles": { "%s": { "abstractions": [ "gnome" ], "policy_groups": [ "user-application" ], "template_variables": { "APPNAME": "baz" } } } } }''' % files["usr.bin.baz"] out_dir = os.path.join(self.tmpdir, "output") args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, options) = easyprof.parse_manifest(m, self.options)[0] easyp = easyprof.AppArmorEasyProfile(binary, options) params = easyprof.gen_policy_params(binary, options) del params['binary'] try: easyp.output_policy(params, dir=out_dir) except easyprof.AppArmorException: return raise Exception ("Should have failed with 'Must specify binary and/or profile name'") def test_output_directory_invalid2(self): '''Test output_directory (profile exists)''' files = dict() files["usr.bin.baz"] = "/usr/bin/baz" m = '''{ "security": { "profiles": { "%s": { "abstractions": [ "gnome" ], "policy_groups": [ "user-application" ], "template_variables": { "APPNAME": "baz" } } } } }''' % files["usr.bin.baz"] out_dir = os.path.join(self.tmpdir, "output") os.mkdir(out_dir) open(os.path.join(out_dir, "usr.bin.baz"), 'w').close() args = self.full_args args.append("--manifest=/dev/null") (self.options, self.args) = easyprof.parse_args(args) (binary, options) = easyprof.parse_manifest(m, self.options)[0] easyp = easyprof.AppArmorEasyProfile(binary, options) params = easyprof.gen_policy_params(binary, options) try: easyp.output_policy(params, dir=out_dir) except easyprof.AppArmorException: return raise Exception ("Should have failed with 'already exists'") def test_output_directory_args(self): '''Test output_directory (args)''' files = dict() files["usr.bin.baz"] = "/usr/bin/baz" # Build up our args args = self.full_args args.append('--template=%s' % self.test_template) args.append('--name=%s' % 'foo') args.append(files["usr.bin.baz"]) out_dir = os.path.join(self.tmpdir, "output") # Now parse our args (self.options, self.args) = easyprof.parse_args(args) easyp = easyprof.AppArmorEasyProfile(files["usr.bin.baz"], self.options) params = easyprof.gen_policy_params(files["usr.bin.baz"], self.options) easyp.output_policy(params, dir=out_dir) for fn in files: f = os.path.join(out_dir, fn) self.assertTrue(os.path.exists(f), "Could not find '%s'" % f) # # utility classes # def test_valid_profile_name(self): '''Test valid_profile_name''' names = ['foo', 'com.example.foo', '/usr/bin/foo', 'com.example.app_myapp_1:2.3+ab12~foo', ] for n in names: self.assertTrue(easyprof.valid_profile_name(n), "'%s' should be valid" % n) def test_valid_profile_name_invalid(self): '''Test valid_profile_name (invalid)''' names = ['fo/o', '/../../etc/passwd', '../../etc/passwd', './../etc/passwd', './etc/passwd', '/usr/bin//foo', '/usr/bin/./foo', 'foo`', 'foo!', 'foo@', 'foo$', 'foo#', 'foo%', 'foo^', 'foo&', 'foo*', 'foo(', 'foo)', 'foo=', 'foo{', 'foo}', 'foo[', 'foo]', 'foo|', 'foo/', 'foo\\', 'foo;', 'foo\'', 'foo"', 'foo<', 'foo>', 'foo?', 'foo\/', 'foo,', '_foo', ] for n in names: self.assertFalse(easyprof.valid_profile_name(n), "'%s' should be invalid" % n) def test_valid_path(self): '''Test valid_path''' names = ['/bin/bar', '/etc/apparmor.d/com.example.app_myapp_1:2.3+ab12~foo', ] names_rel = ['bin/bar', 'apparmor.d/com.example.app_myapp_1:2.3+ab12~foo', 'com.example.app_myapp_1:2.3+ab12~foo', ] for n in names: self.assertTrue(easyprof.valid_path(n), "'%s' should be valid" % n) for n in names_rel: self.assertTrue(easyprof.valid_path(n, relative_ok=True), "'%s' should be valid" % n) def test_zz_valid_path_invalid(self): '''Test valid_path (invalid)''' names = ['/bin//bar', 'bin/bar', '/../etc/passwd', './bin/bar', './', ] names_rel = ['bin/../bar', 'apparmor.d/../passwd', 'com.example.app_"myapp_1:2.3+ab12~foo', ] for n in names: self.assertFalse(easyprof.valid_path(n, relative_ok=False), "'%s' should be invalid" % n) for n in names_rel: self.assertFalse(easyprof.valid_path(n, relative_ok=True), "'%s' should be invalid" % n) # # End test class # # # Main # if __name__ == '__main__': absfn = os.path.abspath(sys.argv[0]) topdir = os.path.dirname(os.path.dirname(absfn)) if len(sys.argv) > 1 and (sys.argv[1] == '-d' or sys.argv[1] == '--debug'): debugging = True # run the tests suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(T)) rc = unittest.TextTestRunner(verbosity=1).run(suite) if not rc.wasSuccessful(): sys.exit(1)