2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-01 14:55:10 +00:00

ProfileList: add profile_from_attachment()

... to get the profile name for a given attachment.

Since this is not very different from filename_from_attachment(), move
most of the code into a thing_from_attachment() function, and make
{profile,filename}_from_attachment wrappers for it.

Also adjust the tests to the changed internal data structure, and add
tests for profile_from_attachment().
This commit is contained in:
Christian Boltz
2023-10-08 15:25:55 +02:00
parent 884adcc58f
commit 26903320fd
2 changed files with 39 additions and 8 deletions

View File

@@ -44,8 +44,8 @@ class ProfileList:
def __init__(self):
self.profile_names = {} # profile name -> filename
self.attachments = {} # attachment -> filename
self.attachments_AARE = {} # AARE(attachment) -> filename
self.attachments = {} # attachment -> {'f': filename, 'p': profile}
self.attachments_AARE = {} # attachment -> AARE(attachment)
self.files = {} # filename -> content - see init_file()
self.profiles = {} # profile_name -> ProfileStorage
@@ -90,7 +90,7 @@ class ProfileList:
self.profile_names[profile_name] = filename
if attachment:
self.attachments[attachment] = filename
self.attachments[attachment] = {'f': filename, 'p': profile_name or attachment} # if a profile doesn't have a name, the attachment is stored as profile name
self.attachments_AARE[attachment] = AARE(attachment, True)
self.init_file(filename)
@@ -204,18 +204,28 @@ class ProfileList:
def filename_from_attachment(self, attachment):
"""Return profile filename for the given attachment/executable path, or None"""
return self.thing_from_attachment(attachment, 'f')
def profile_from_attachment(self, attachment):
"""Return profile filename for the given attachment/executable path, or None"""
return self.thing_from_attachment(attachment, 'p')
def thing_from_attachment(self, attachment, thing):
"""Return thing for the given attachment/executable path, or None.
thing can be 'f' for filename or 'p' for profile name"""
if not attachment.startswith(('/', '@', '{')):
raise AppArmorBug('Called filename_from_attachment with non-path attachment: %s' % attachment)
# plain path
if self.attachments.get(attachment):
return self.attachments[attachment]
return self.attachments[attachment][thing]
# try AARE matches to cover profile names with alternations and wildcards
for path in self.attachments.keys():
if self.attachments_AARE[path].match(attachment):
return self.attachments[path] # XXX this returns the first match, not necessarily the best one
return self.attachments[path][thing] # XXX this returns the first match, not necessarily the best one
return None # nothing found

View File

@@ -38,14 +38,14 @@ class TestAdd_profile(AATest):
def testAdd_profile_1(self):
self.pl.add_profile('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo', self.dummy_profile)
self.assertEqual(self.pl.profile_names, {'foo': '/etc/apparmor.d/bin.foo'})
self.assertEqual(self.pl.attachments, {'/bin/foo': '/etc/apparmor.d/bin.foo'})
self.assertEqual(self.pl.attachments, {'/bin/foo': {'f': '/etc/apparmor.d/bin.foo', 'p': 'foo'}})
self.assertEqual(self.pl.profiles_in_file('/etc/apparmor.d/bin.foo'), ['foo'])
self.assertEqual(str(self.pl), '\n<ProfileList>\n/etc/apparmor.d/bin.foo\n</ProfileList>\n')
def testAdd_profile_2(self):
self.pl.add_profile('/etc/apparmor.d/bin.foo', None, '/bin/foo', self.dummy_profile)
self.assertEqual(self.pl.profile_names, {})
self.assertEqual(self.pl.attachments, {'/bin/foo': '/etc/apparmor.d/bin.foo'})
self.assertEqual(self.pl.attachments, {'/bin/foo': {'f': '/etc/apparmor.d/bin.foo', 'p': '/bin/foo'}})
self.assertEqual(self.pl.profiles_in_file('/etc/apparmor.d/bin.foo'), ['/bin/foo'])
self.assertEqual(str(self.pl), '\n<ProfileList>\n/etc/apparmor.d/bin.foo\n</ProfileList>\n')
@@ -139,9 +139,10 @@ class TestFilename_from_attachment(AATest):
self.pl.add_profile('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo', self.dummy_profile)
self.pl.add_profile('/etc/apparmor.d/bin.baz', 'baz', '/bin/ba*', self.dummy_profile)
self.pl.add_profile('/etc/apparmor.d/bin.foobar', 'foobar', '/bin/foo{bar,baz}', self.dummy_profile)
self.pl.add_profile('/etc/apparmor.d/bin.asdf', None, '/bin/asdf', self.dummy_profile)
self.pl.add_profile(
'/etc/apparmor.d/usr.bin.wine',
'/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}',
'wine',
'/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}',
self.dummy_profile)
@@ -152,6 +153,26 @@ class TestFilename_from_attachment(AATest):
with self.assertRaises(AppArmorBug):
self.pl.filename_from_attachment('foo')
class TestProfile_from_attachment(TestFilename_from_attachment):
# uses AASetup from TestFilename_from_attachment
tests = (
('/bin/foo', 'foo'),
('/bin/baz', 'baz'),
('/bin/foobar', 'foobar'),
('/bin/asdf', '/bin/asdf'),
('@{foo}', None), # XXX variables not supported yet (and @{foo} isn't defined in this test)
('/bin/404', None),
('/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}', 'wine'), # XXX should this really match, or should attachment matching only use AARE?
('/usr/lib/wine/bin/wine-preloader-staging-foo', 'wine'), # AARE match
)
def _run_test(self, params, expected):
self.assertEqual(self.pl.profile_from_attachment(params), expected)
def test_non_path_attachment(self):
with self.assertRaises(AppArmorBug):
self.pl.profile_from_attachment('foo')
class TestAdd_inc_ie(AATest):
def AASetup(self):