diff --git a/parser/tst/simple_tests/mount/ok_opt_85.sd b/parser/tst/simple_tests/mount/ok_opt_85.sd new file mode 100644 index 000000000..d9752248a --- /dev/null +++ b/parser/tst/simple_tests/mount/ok_opt_85.sd @@ -0,0 +1,9 @@ +# +#=Description test globbed destination MR 1195 +#=EXRESULT PASS +/usr/bin/foo { + mount options=(rw, make-slave) -> **, + mount options=(rw) foo -> **, + mount fstype=tmpfs options=(rw) foo -> **, + mount -> **, +} diff --git a/utils/apparmor/rule/mount.py b/utils/apparmor/rule/mount.py index e18a812d3..1dbdd01f1 100644 --- a/utils/apparmor/rule/mount.py +++ b/utils/apparmor/rule/mount.py @@ -15,7 +15,7 @@ import re from apparmor.common import AppArmorBug, AppArmorException -from apparmor.regex import RE_PROFILE_MOUNT, RE_PROFILE_PATH_OR_VAR, strip_parenthesis +from apparmor.regex import RE_PROFILE_MOUNT, strip_parenthesis from apparmor.rule import AARE from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers, logprof_value_or_all, check_and_split_list @@ -72,9 +72,13 @@ mount_condition_pattern = rf'({fs_type_pattern})?\s*({option_pattern})?' # - A filesystem : sysfs (sudo mount -t tmpfs tmpfs /tmp/bar) # - Any label : mntlabel (sudo mount -t tmpfs mntlabel /tmp/bar) # Thus we cannot use directly RE_PROFILE_PATH_OR_VAR +# Destination can also be +# - A path : /foo +# - A globbed Path : ** -source_fileglob_pattern = r'(\s*(?P([/{]\S*|"[/{][^"]*"|@{\S+}\S*|"@{\S+}[^"]*")|\w+))' -dest_fileglob_pattern = r'(\s*' + RE_PROFILE_PATH_OR_VAR % 'dest_file' + r')' +glob_pattern = r'(\s*(?P<%s>(([/{]|\*\*)\S*|"([/{]|\*\*)[^"]*"|@{\S+}\S*|"@{\S+}[^"]*")|\w+))' +source_fileglob_pattern = glob_pattern % 'source_file' +dest_fileglob_pattern = glob_pattern % 'dest_file' RE_MOUNT_DETAILS = re.compile(r'^\s*' + mount_condition_pattern + rf'(\s+{source_fileglob_pattern})?' + rf'(\s+->\s+{dest_fileglob_pattern})?\s*' + r'$') RE_UMOUNT_DETAILS = re.compile(r'^\s*' + mount_condition_pattern + rf'(\s+{dest_fileglob_pattern})?\s*' + r'$') @@ -142,7 +146,7 @@ class MountRule(BaseRule): if self.operation == 'mount' and not self.all_source and not self.all_options and flags_forbidden_with_source & self.options != set(): raise AppArmorException(f'Operation {flags_forbidden_with_source & self.options} cannot have a source. Source = {self.source}') - self.dest, self.all_dest = self._aare_or_all(dest, 'dest', is_path=True, log_event=log_event) + self.dest, self.all_dest = self._aare_or_all(dest, 'dest', is_path=False, log_event=log_event) self.can_glob = not self.all_source and not self.all_dest and not self.all_options diff --git a/utils/test/test-mount.py b/utils/test/test-mount.py index cdeb3521c..e37c287c7 100644 --- a/utils/test/test-mount.py +++ b/utils/test/test-mount.py @@ -29,6 +29,8 @@ class MountTestParse(AATest): tests = ( # Rule Operation Filesystem Options Source Destination Audit Deny Allow Comment + ('mount -> **,', MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '**', False, False, False, '' )), + ('mount options=(rw, shared) -> **,', MountRule('mount', MountRule.ALL, ('=', ('rw', 'shared')), MountRule.ALL, '**', False, False, False, '' )), ('mount fstype=bpf options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('bpf')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )), ('mount fstype=fuse.obex* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('fuse.obex*')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )), ('mount fstype=fuse.* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('fuse.*')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),