On Tue, May 26, 2015 at 12:41:19AM +0200, Christian Boltz wrote: > Am Dienstag, 26. Mai 2015 schrieb Christian Boltz: > > $subject. > > > > This time we "only" have 98% coverage (2 missing, 3 partial) because > > I didn't find corner cases that raise some exceptions ;-) > > (maybe we can even drop those checks if they are never hit?) > > Here's the patch again, but without linebreaks caused by my mail client:
> [ 42-add-tests-for-rlimit-rule.diff ] > > === modified file utils/test/test-rlimit.py > --- utils/test/test-rlimit.py 2015-05-25 23:59:49.484474818 +0200 > +++ utils/test/test-rlimit.py 2015-05-25 23:35:41.919727344 +0200 > @@ -0,0 +1,468 @@ > +#!/usr/bin/env python > +# ---------------------------------------------------------------------- > +# Copyright (C) 2015 Christian Boltz <[email protected]> > +# > +# 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 as published by the Free Software Foundation. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# ---------------------------------------------------------------------- > + > +import unittest > +from collections import namedtuple > +from common_test import AATest, setup_all_loops > + > +from apparmor.rule.rlimit import RlimitRule, RlimitRuleset, split_unit > +from apparmor.rule import BaseRule > +from apparmor.common import AppArmorException, AppArmorBug > +#from apparmor.logparser import ReadLog > +from apparmor.translations import init_translation > +_ = init_translation() > + > +exp = namedtuple('exp', ['audit', 'allow_keyword', 'deny', 'comment', > + 'rlimit', 'value', 'all_values']) > + > +# --- tests for single RlimitRule --- # > + > +class RlimitTest(AATest): > + def _compare_obj(self, obj, expected): > + self.assertEqual(expected.allow_keyword, obj.allow_keyword) > + self.assertEqual(expected.audit, obj.audit) > + self.assertEqual(expected.rlimit, obj.rlimit) > + self.assertEqual(expected.value, obj.value) > + self.assertEqual(expected.all_values, obj.all_values) > + self.assertEqual(expected.deny, obj.deny) > + self.assertEqual(expected.comment, obj.comment) > + > +class RlimitTestParse(RlimitTest): > + tests = [ > + # rawrule audit allow deny > comment rlimit value all/infinity? > + ('set rlimit as <= 2047MB,' , exp(False, False, False, '' > , 'as' , '2047MB' , False)), > + ('set rlimit cpu <= 1024,' , exp(False, False, False, '' > , 'cpu' , '1024' , False)), > + ('set rlimit stack <= 1024GB,' , exp(False, False, False, '' > , 'stack' , '1024GB' , False)), > + ('set rlimit rtprio <= 10, # comment' , exp(False, False, False, ' > # comment' , 'rtprio' , '10' , False)), > + ('set rlimit core <= 44444KB,' , exp(False, False, False, '' > , 'core' , '44444KB' , False)), > + ('set rlimit rttime <= 60ms,' , exp(False, False, False, '' > , 'rttime' , '60ms' , False)), > + ('set rlimit cpu <= infinity,' , exp(False, False, False, '' > , 'cpu' , None , True )), > + ('set rlimit nofile <= 256,' , exp(False, False, False, '' > , 'nofile' , '256' , False)), > + ('set rlimit data <= 4095KB,' , exp(False, False, False, '' > , 'data' , '4095KB' , False)), > + ('set rlimit cpu <= 12, # cmt' , exp(False, False, False, ' > # cmt' , 'cpu' , '12' , False)), > + ('set rlimit ofile <= 1234,' , exp(False, False, False, '' > , 'ofile' , '1234' , False)), > + ('set rlimit msgqueue <= 4444,' , exp(False, False, False, '' > , 'msgqueue' , '4444' , False)), > + ('set rlimit nice <= -10,' , exp(False, False, False, '' > , 'nice' , '-10' , False)), > + ('set rlimit rttime <= 60minutes,' , exp(False, False, False, '' > , 'rttime' , '60minutes' , False)), > + ('set rlimit fsize <= 1023MB,' , exp(False, False, False, '' > , 'fsize' , '1023MB' , False)), > + ('set rlimit nproc <= 1,' , exp(False, False, False, '' > , 'nproc' , '1' , False)), > + ('set rlimit rss <= infinity, # cmt' , exp(False, False, False, ' > # cmt' , 'rss' , None , True )), > + ('set rlimit memlock <= 10240,' , exp(False, False, False, '' > , 'memlock' , '10240' , False)), > + ('set rlimit sigpending <= 42,' , exp(False, False, False, '' > , 'sigpending' , '42' , False)), > + ] > + > + def _run_test(self, rawrule, expected): > + self.assertTrue(RlimitRule.match(rawrule)) > + obj = RlimitRule.parse(rawrule) > + self.assertEqual(rawrule.strip(), obj.raw_rule) > + self._compare_obj(obj, expected) > + > +class RlimitTestParseInvalid(RlimitTest): > + tests = [ > + ('set rlimit,' , AppArmorException), # missing > parts > + ('set rlimit <= 5,' , AppArmorException), > + ('set rlimit cpu <= ,' , AppArmorException), > + ('set rlimit foo <= 5,' , AppArmorException), # unknown > rlimit > + ('set rlimit rttime <= 60m,' , AppArmorException), # 'm' > could mean 'ms' or 'minutes' > + ('set rlimit nice <= 20MB,' , AppArmorException), # invalid > unit for this rlimit type > + ('set rlimit cpu <= 20MB,' , AppArmorException), > + ('set rlimit data <= 20seconds,' , AppArmorException), > + ('set rlimit locks <= 20seconds,' , AppArmorException), > + ] > + > + def _run_test(self, rawrule, expected): > + #self.assertFalse(RlimitRule.match(rawrule)) # the main regex isn't > very strict > + with self.assertRaises(expected): > + RlimitRule.parse(rawrule) > + > +class RlimitTestParseFromLog(RlimitTest): > + pass > + # def test_net_from_log(self): > + # parser = ReadLog('', '', '', '', '') > + > + # event = 'type=AVC ...' > + > + # parsed_event = parser.parse_event(event) > + > + # self.assertEqual(parsed_event, { > + # ... > + # }) > + > + # obj = RlimitRule(RlimitRule.ALL, parsed_event['name2'], > log_event=parsed_event) > + > + # # audit allow deny comment rlimit value > all? > + # expected = exp(False, False, False, '' , None, > '/foo/rename', False) > + > + # self._compare_obj(obj, expected) > + > + # self.assertEqual(obj.get_raw(1), ' rlimit -> /foo/rename,') > + > + > +class RlimitFromInit(RlimitTest): > + tests = [ > + # RlimitRule object audit allow > deny comment rlimit value all/infinity? > + (RlimitRule('as', '2047MB') , exp(False, False, > False, '' , 'as' , '2047MB' , False)), > + (RlimitRule('cpu', '1024') , exp(False, False, > False, '' , 'cpu' , '1024' , False)), > + (RlimitRule('rttime', '60minutes') , exp(False, False, > False, '' , 'rttime' , '60minutes', False)), > + (RlimitRule('nice', '-10') , exp(False, False, > False, '' , 'nice' , '-10' , False)), > + (RlimitRule('rss', RlimitRule.ALL) , exp(False, False, > False, '' , 'rss' , None , True )), > + ] > + > + def _run_test(self, obj, expected): > + self._compare_obj(obj, expected) > + > + > +class InvalidRlimitInit(AATest): > + tests = [ > + # init params expected exception > + (['as' , '' ] , AppArmorBug), # empty value > + (['' , '1024' ] , AppArmorException), # empty rlimit > + ([' ', '1024' ] , AppArmorException), # whitespace > rlimit > + (['as' , ' ' ] , AppArmorBug), # whitespace value > + (['xyxy', '1024' ] , AppArmorException), # invalid > rlimit > + ([dict(), '1024' ] , AppArmorBug), # wrong type for > rlimit > + ([None , '1024' ] , AppArmorBug), # wrong type for > rlimit > + (['as' , dict() ] , AppArmorBug), # wrong type for > value > + (['as' , None ] , AppArmorBug), # wrong type for > value > + ] > + > + def _run_test(self, params, expected): > + with self.assertRaises(expected): > + RlimitRule(params[0], params[1]) > + > + def test_missing_params_1(self): > + with self.assertRaises(TypeError): > + RlimitRule() > + > + def test_missing_params_2(self): > + with self.assertRaises(TypeError): > + RlimitRule('as') > + > + def test_allow_keyword(self): > + with self.assertRaises(AppArmorBug): > + RlimitRule('as', '1024MB', allow_keyword=True) > + > + def test_deny_keyword(self): > + with self.assertRaises(AppArmorBug): > + RlimitRule('as', '1024MB', deny=True) > + > + def test_audit_keyword(self): > + with self.assertRaises(AppArmorBug): > + RlimitRule('as', '1024MB', audit=True) > + > + > +class InvalidRlimitTest(AATest): > + def _check_invalid_rawrule(self, rawrule): > + obj = None > + self.assertFalse(RlimitRule.match(rawrule)) > + with self.assertRaises(AppArmorException): > + obj = RlimitRule(RlimitRule.parse(rawrule)) > + > + self.assertIsNone(obj, 'RlimitRule handed back an object > unexpectedly') > + > + def test_invalid_net_missing_comma(self): > + self._check_invalid_rawrule('rlimit') # missing comma > + > + def test_invalid_net_non_RlimitRule(self): > + self._check_invalid_rawrule('dbus,') # not a rlimit rule > + > + def test_empty_net_data_1(self): > + obj = RlimitRule('as', '1024MB') > + obj.rlimit = '' > + # no rlimit set, and ALL not set > + with self.assertRaises(AppArmorBug): > + obj.get_clean(1) > + > + def test_empty_net_data_2(self): > + obj = RlimitRule('as', '1024MB') > + obj.value = '' > + # no value set, and ALL not set > + with self.assertRaises(AppArmorBug): > + obj.get_clean(1) > + > + > +class WriteRlimitTest(AATest): > + tests = [ > + # raw rule > clean rule > + (' set rlimit cpu <= 1024 , # foo ' > , 'set rlimit cpu <= 1024, # foo'), > + (' set rlimit stack <= 1024GB ,' > , 'set rlimit stack <= 1024GB,'), > + (' set rlimit rttime <= 100ms , # foo bar' , 'set rlimit > rttime <= 100ms, # foo bar'), > + (' set rlimit cpu <= infinity , ' , 'set rlimit > cpu <= infinity,'), > + (' set rlimit msgqueue <= 4444 , ' , 'set rlimit > msgqueue <= 4444,'), > + (' set rlimit nice <= 5 , # foo bar' , 'set rlimit > nice <= 5, # foo bar'), > + (' set rlimit nice <= -5 , # cmt' , 'set rlimit > nice <= -5, # cmt'), > + ] > + > + def _run_test(self, rawrule, expected): > + self.assertTrue(RlimitRule.match(rawrule)) > + obj = RlimitRule.parse(rawrule) > + clean = obj.get_clean() > + raw = obj.get_raw() > + > + self.assertEqual(expected.strip(), clean, 'unexpected clean rule') > + self.assertEqual(rawrule.strip(), raw, 'unexpected raw rule') > + > + def test_write_manually(self): > + obj = RlimitRule('as', '1024MB') > + > + expected = ' set rlimit as <= 1024MB,' > + > + self.assertEqual(expected, obj.get_clean(2), 'unexpected clean rule') > + self.assertEqual(expected, obj.get_raw(2), 'unexpected raw rule') > + > + > +class RlimitCoveredTest(AATest): > + def _run_test(self, param, expected): > + obj = RlimitRule.parse(self.rule) > + check_obj = RlimitRule.parse(param) > + > + self.assertTrue(RlimitRule.match(param)) > + > + self.assertEqual(obj.is_equal(check_obj), expected[0], 'Mismatch in > is_equal, expected %s' % expected[0]) > + self.assertEqual(obj.is_equal(check_obj, True), expected[1], > 'Mismatch in is_equal/strict, expected %s' % expected[1]) > + > + self.assertEqual(obj.is_covered(check_obj), expected[2], 'Mismatch > in is_covered, expected %s' % expected[2]) > + self.assertEqual(obj.is_covered(check_obj, True, True), expected[3], > 'Mismatch in is_covered/exact, expected %s' % expected[3]) > + > +class RlimitCoveredTest_01(RlimitCoveredTest): > + rule = 'set rlimit cpu <= 150,' > + > + tests = [ > + # rule equal strict equal > covered covered exact > + ('set rlimit as <= 100MB,' , [ False , False , False > , False ]), > + ('set rlimit rttime <= 150,' , [ False , False , False > , False ]), > + ('set rlimit cpu <= 100,' , [ False , False , True > , True ]), > + ('set rlimit cpu <= 150,' , [ True , True , True > , True ]), > + ('set rlimit cpu <= 300,' , [ False , False , False > , False ]), > + ('set rlimit cpu <= 10seconds,' , [ False , False , True > , True ]), > + ('set rlimit cpu <= 150seconds,', [ True , False , True > , True ]), > + ('set rlimit cpu <= 300seconds,', [ False , False , False > , False ]), > + ('set rlimit cpu <= 1minutes,' , [ False , False , True > , True ]), > + ('set rlimit cpu <= 1m,' , [ False , False , True > , True ]), > + ('set rlimit cpu <= 3minutes,' , [ False , False , False > , False ]), > + ('set rlimit cpu <= 1hour,' , [ False , False , False > , False ]), > + ] > + > +class RlimitCoveredTest_02(RlimitCoveredTest): > + rule = 'set rlimit data <= 4MB,' > + > + tests = [ > + # rule equal strict equal > covered covered exact > + ('set rlimit data <= 100,' , [ False , False , True > , True ]), > + ('set rlimit data <= 2KB,' , [ False , False , True > , True ]), > + ('set rlimit data <= 2MB,' , [ False , False , True > , True ]), > + ('set rlimit data <= 4194304,' , [ True , False , True > , True ]), > + ('set rlimit data <= 4096KB,' , [ True , False , True > , True ]), > + ('set rlimit data <= 4MB,' , [ True , True , True > , True ]), > + ('set rlimit data <= 6MB,' , [ False , False , False > , False ]), > + ('set rlimit data <= 1GB,' , [ False , False , False > , False ]), > + ] > + > +class RlimitCoveredTest_03(RlimitCoveredTest): > + rule = 'set rlimit nice <= -1,' > + > + tests = [ > + # rule equal strict equal > covered covered exact > + ('set rlimit nice <= 5,' , [ False , False , True > , True ]), > + ('set rlimit nice <= 0,' , [ False , False , True > , True ]), > + ('set rlimit nice <= -1,' , [ True , True , True > , True ]), > + ('set rlimit nice <= -3,' , [ False , False , False > , False ]), > + ] > + > +class RlimitCoveredTest_04(RlimitCoveredTest): > + rule = 'set rlimit locks <= 42,' > + > + tests = [ > + # rule equal strict equal > covered covered exact > + ('set rlimit locks <= 20,' , [ False , False , True > , True ]), > + ('set rlimit locks <= 40,' , [ False , False , True > , True ]), > + ('set rlimit locks <= 42,' , [ True , True , True > , True ]), > + ('set rlimit locks <= 60,' , [ False , False , False > , False ]), > + ('set rlimit locks <= infinity,', [ False , False , False > , False ]), > + ] > + > +class RlimitCoveredTest_05(RlimitCoveredTest): > + rule = 'set rlimit locks <= infinity,' > + > + tests = [ > + # rule equal strict equal > covered covered exact > + ('set rlimit locks <= 20,' , [ False , False , True > , True ]), > + ('set rlimit cpu <= 40,' , [ False , False , False > , False ]), > + ('set rlimit locks <= infinity,', [ True , True , True > , True ]), > + ] > + > +class RlimitCoveredTest_Invalid(AATest): > + def test_borked_obj_is_covered_1(self): > + obj = RlimitRule.parse('set rlimit cpu <= 1024,') > + > + testobj = RlimitRule('cpu', '1024') > + testobj.rlimit = '' > + > + with self.assertRaises(AppArmorBug): > + obj.is_covered(testobj) > + > + def test_borked_obj_is_covered_2(self): > + obj = RlimitRule.parse('set rlimit cpu <= 1024,') > + > + testobj = RlimitRule('cpu', '1024') > + testobj.value = '' > + > + with self.assertRaises(AppArmorBug): > + obj.is_covered(testobj) > + > + def test_invalid_is_covered(self): > + obj = RlimitRule.parse('set rlimit cpu <= 1024,') > + > + testobj = BaseRule() # different type > + > + with self.assertRaises(AppArmorBug): > + obj.is_covered(testobj) > + > + def test_invalid_is_equal(self): > + obj = RlimitRule.parse('set rlimit cpu <= 1024,') > + > + testobj = BaseRule() # different type > + > + with self.assertRaises(AppArmorBug): > + obj.is_equal(testobj) > + > +class CapabilityLogprofHeaderTest(AATest): I suspect you intended this to be s/Capability/Rlimit/ > + tests = [ > + ('set rlimit cpu <= infinity,', [_('Rlimit'), 'cpu', > _('Value'), 'infinity', ]), > + ('set rlimit as <= 200MB,', [_('Rlimit'), 'as', > _('Value'), '200MB', ]), > + ('set rlimit rttime <= 200ms,', [_('Rlimit'), 'rttime', > _('Value'), '200ms', ]), > + ('set rlimit nproc <= 1,', [_('Rlimit'), 'nproc', > _('Value'), '1', ]), > + ] > + > + def _run_test(self, params, expected): > + obj = RlimitRule._parse(params) > + self.assertEqual(obj.logprof_header(), expected) > + > +# --- tests for RlimitRuleset --- # > + > +class RlimitRulesTest(AATest): > + def test_empty_ruleset(self): > + ruleset = RlimitRuleset() > + ruleset_2 = RlimitRuleset() > + self.assertEqual([], ruleset.get_raw(2)) > + self.assertEqual([], ruleset.get_clean(2)) > + self.assertEqual([], ruleset_2.get_raw(2)) > + self.assertEqual([], ruleset_2.get_clean(2)) > + > + def test_ruleset_1(self): > + ruleset = RlimitRuleset() > + rules = [ > + ' set rlimit cpu <= 100,', > + ' set rlimit as <= 50MB,', > + ] > + > + expected_raw = [ > + 'set rlimit cpu <= 100,', > + 'set rlimit as <= 50MB,', > + '', > + ] > + > + expected_clean = [ > + 'set rlimit as <= 50MB,', > + 'set rlimit cpu <= 100,', > + '', > + ] > + > + for rule in rules: > + ruleset.add(RlimitRule.parse(rule)) > + > + self.assertEqual(expected_raw, ruleset.get_raw()) > + self.assertEqual(expected_clean, ruleset.get_clean()) > + > +class RlimitGlobTestAATest(AATest): > + def setUp(self): > + self.ruleset = RlimitRuleset() > + > + def test_glob_1(self): > + with self.assertRaises(AppArmorBug): > + self.ruleset.get_glob('set rlimit cpu <= 100,') > + > + # not supported or used yet, glob behaviour not decided yet > + # def test_glob_2(self): > + # self.assertEqual(self.ruleset.get_glob('rlimit /foo -> /bar,'), > 'rlimit -> /bar,') > + > + def test_glob_ext(self): > + with self.assertRaises(AppArmorBug): > + # get_glob_ext is not available for rlimit rules > + self.ruleset.get_glob_ext('set rlimit cpu <= 100,') > + > +class RlimitDeleteTestAATest(AATest): > + pass Sorry, what's this class intended for? > +# --- other tests --- # > +class RlimitSplit_unitTest(AATest): > + tests = [ > + ('40MB' , ( 40, 'MB',)), > + ('40' , ( 40, '', )), > + ] > + > + def _run_test(self, params, expected): > + self.assertEqual(split_unit(params), expected) > + > + def test_invalid_split_unit(self): > + with self.assertRaises(AppArmorBug): > + split_unit('MB') > + > +class RlimitSize_to_intTest(AATest): > + def AASetup(self): > + self.obj = RlimitRule('cpu', '1') > + > + tests = [ > + ('40GB' , 40 * 1024 * 1024 * 1024), > + ('40MB' , 41943040), > + ('40KB' , 40960), > + ('40' , 40), > + ] > + > + def _run_test(self, params, expected): > + self.assertEqual(self.obj.size_to_int(params), expected) > + > + def test_invalid_size_to_int_01(self): > + with self.assertRaises(AppArmorException): > + self.obj.size_to_int('20mice') > + > +class RlimitTime_to_intTest(AATest): > + def AASetup(self): > + self.obj = RlimitRule('cpu', '1') > + > + tests = [ > + ('40ms' , 0.04), > + ('40' , 40), > + ('40seconds', 40), > + ('2minutes' , 2*60), > + ('2hours' , 2*60*60), > + ] > + > + def _run_test(self, params, expected): > + self.assertEqual(self.obj.time_to_int(params, 'seconds'), expected) > + > + def test_with_ms_as_default(self): > + self.assertEqual(self.obj.time_to_int('40', 'ms'), 0.04) > + > + def test_invalid_time_to_int(self): > + with self.assertRaises(AppArmorException): > + self.obj.time_to_int('20mice', 'seconds') > + > + > + > +setup_all_loops(__name__) > +if __name__ == '__main__': > + unittest.main(verbosity=2) Acked-by: Steve Beattie <[email protected]> with the capability/rlimit fix; would like to see a followup for whatever the RlimitDeleteTestAATest class is supposed to do. -- Steve Beattie <[email protected]> http://NxNW.org/~steve/
signature.asc
Description: Digital signature
-- AppArmor mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
