[apparmor] [patch] Several fixes for variable handling
John Johansen
john.johansen at canonical.com
Sat Dec 12 06:19:31 UTC 2015
On 11/15/2015 11:37 AM, Christian Boltz wrote:
> Hello,
>
> parsing variables was broken in several ways:
> - empty quotes (representing an intentionally empty value) were lost,
> causing parser failures
> - items consisting of only one letter were lost due to a bug in RE_VARS
> - RE_VARS didn't start with ^, which means leading garbage (= syntax
> errors) was ignored
> - trailing garbage was also ignored
>
> This patch fixes those issues in separate_vars() and changes
> var_transform() to write out empty quotes (instead of nothing) for empty
> values.
>
> Also add some tests for separate_vars() with empty quotes and adjust
> several tests with invalid syntax to expect an AppArmorException.
>
> var_transform() gets some tests added.
>
> Finally, remove 3 testcases from the "fails to raise an exception" list
> in test-parser-simple-tests.py.
>
>
> I propose this patch for trunk and 2.9 (except the test-parser-simple-tests.py
> changes because this file isn't in 2.9)
>
>
Acked-by: John Johansen <john.johansen at canonical.com>
>
> [ 20-variable-fixes.diff ]
>
> === modified file ./utils/apparmor/aa.py
> --- utils/apparmor/aa.py 2015-11-15 20:30:42.251877998 +0100
> +++ utils/apparmor/aa.py 2015-11-15 20:01:17.937507807 +0100
> @@ -2800,7 +2800,7 @@
>
> list_var = strip_quotes(matches[0])
> var_operation = matches[1]
> - value = strip_quotes(matches[2])
> + value = matches[2]
>
> if profile:
> if not profile_data[profile][hat].get('lvar', False):
> @@ -3165,12 +3165,16 @@
> def separate_vars(vs):
> """Returns a list of all the values for a variable"""
> data = set()
> + vs = vs.strip()
>
> - RE_VARS = re.compile('\s*((\".+?\")|([^\"]\S+))\s*(.*)$')
> + RE_VARS = re.compile('^(("[^"]*")|([^"\s]+))\s*(.*)$')
> while RE_VARS.search(vs):
> matches = RE_VARS.search(vs).groups()
> data.add(strip_quotes(matches[0]))
> - vs = matches[3]
> + vs = matches[3].strip()
> +
> + if vs:
> + raise AppArmorException('Variable assignments contains invalid parts (unbalanced quotes?): %s' % vs)
>
> return data
>
> @@ -3298,6 +3302,8 @@
> def var_transform(ref):
> data = []
> for value in ref:
> + if not value:
> + value = '""'
> data.append(quote_if_needed(value))
> return ' '.join(data)
>
> === modified file ./utils/test/test-aa.py
> --- utils/test/test-aa.py 2015-11-15 20:30:42.251877998 +0100
> +++ utils/test/test-aa.py 2015-11-15 20:32:26.799188737 +0100
> @@ -17,7 +17,8 @@
>
> from apparmor.aa import (check_for_apparmor, get_interpreter_and_abstraction, create_new_profile,
> get_profile_flags, set_profile_flags, is_skippable_file, is_skippable_dir,
> - parse_profile_start, parse_profile_data, separate_vars, store_list_var, write_header, serialize_parse_profile_start)
> + parse_profile_start, parse_profile_data, separate_vars, store_list_var, write_header,
> + var_transform, serialize_parse_profile_start)
> from apparmor.common import AppArmorException, AppArmorBug
>
> class AaTestWithTempdir(AATest):
> @@ -484,20 +485,29 @@
> ('' , set() ),
> (' ' , set() ),
> (' foo bar' , {'foo', 'bar' }),
> - ('foo " ' , {'foo' }), # XXX " is ignored
> - (' " foo ' , {' "', 'foo' }), # XXX really?
> + ('foo " ' , AppArmorException ),
> + (' " foo ' , AppArmorException ), # half-quoted
> (' foo bar ' , {'foo', 'bar' }),
> - (' foo bar # comment' , {'foo', 'bar', 'comment' }), # XXX should comments be stripped?
> + (' foo bar # comment' , {'foo', 'bar', '#', 'comment'}), # XXX should comments be stripped?
> ('foo' , {'foo' }),
> ('"foo" "bar baz"' , {'foo', 'bar baz' }),
> ('foo "bar baz" xy' , {'foo', 'bar baz', 'xy' }),
> - ('foo "bar baz ' , {'foo', 'bar', 'baz' }), # half-quoted
> + ('foo "bar baz ' , AppArmorException ), # half-quoted
> (' " foo" bar' , {' foo', 'bar' }),
> + (' " foo" bar x' , {' foo', 'bar', 'x' }),
> + ('""' , {'' }), # empty value
> + ('"" foo' , {'', 'foo' }), # empty value + 'foo'
> + ('"" foo "bar"' , {'', 'foo', 'bar' }), # empty value + 'foo' + 'bar' (bar has superfluous quotes)
> + ('"bar"' , {'bar' }), # 'bar' with superfluous quotes
> ]
>
> def _run_test(self, params, expected):
> - result = separate_vars(params)
> - self.assertEqual(result, expected)
> + if expected == AppArmorException:
> + with self.assertRaises(expected):
> + separate_vars(params)
> + else:
> + result = separate_vars(params)
> + self.assertEqual(result, expected)
>
>
> class AaTest_store_list_var(AATest):
> @@ -579,6 +589,17 @@
> result = write_header(prof_data, depth, name, embedded_hat, write_flags)
> self.assertEqual(result, [expected])
>
> +class AaTest_var_transform(AATest):
> + tests = [
> + (['foo', ''], 'foo ""' ),
> + (['foo', 'bar'], 'foo bar' ),
> + ([''], '""' ),
> + (['bar baz', 'foo'], '"bar baz" foo' ),
> + ]
> +
> + def _run_test(self, params, expected):
> + self.assertEqual(var_transform(params), expected)
> +
> class AaTest_serialize_parse_profile_start(AATest):
> def _parse(self, line, profile, hat, prof_data_profile, prof_data_external):
> # 'correct' is always True in the code that uses serialize_parse_profile_start() (set some lines above the function call)
> === modified file ./utils/test/test-parser-simple-tests.py
> --- utils/test/test-parser-simple-tests.py 2015-11-15 20:30:42.251877998 +0100
> +++ utils/test/test-parser-simple-tests.py 2015-11-11 00:58:06.378155721 +0100
> @@ -167,8 +167,6 @@
> 'vars/boolean/boolean_bad_6.sd',
> 'vars/boolean/boolean_bad_7.sd',
> 'vars/boolean/boolean_bad_8.sd',
> - 'vars/vars_bad_1.sd',
> - 'vars/vars_bad_2.sd',
> 'vars/vars_bad_3.sd',
> 'vars/vars_bad_4.sd',
> 'vars/vars_bad_5.sd',
> @@ -178,7 +176,6 @@
> 'vars/vars_bad_trailing_comma_2.sd',
> 'vars/vars_bad_trailing_comma_3.sd',
> 'vars/vars_bad_trailing_comma_4.sd',
> - 'vars/vars_bad_trailing_garbage_1.sd',
> 'vars/vars_dbus_bad_01.sd',
> 'vars/vars_dbus_bad_02.sd',
> 'vars/vars_dbus_bad_03.sd',
>
>
> Regards,
>
> Christian Boltz
>
More information about the AppArmor
mailing list