mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 14:55:10 +00:00
[2/3] Make ProfileStorage a class
Move ProfileStorage() from aa.py to the new profile_storage.py and make it a class. The variable name in __init__() changes (profile -> self.data), but the content stays the same. The ProfileStorage class acts like a dict(), but has some additional checks for unknown keys in place. Also add some tests to make sure unknown keys really raise an exception. Acked-by: Seth Arnold <seth.arnold@canonical.com>
This commit is contained in:
@@ -49,16 +49,18 @@ from apparmor.regex import (RE_PROFILE_START, RE_PROFILE_END, RE_PROFILE_LINK,
|
|||||||
RE_PROFILE_UNIX, RE_RULE_HAS_COMMA, RE_HAS_COMMENT_SPLIT,
|
RE_PROFILE_UNIX, RE_RULE_HAS_COMMA, RE_HAS_COMMENT_SPLIT,
|
||||||
strip_quotes, parse_profile_start_line, re_match_include )
|
strip_quotes, parse_profile_start_line, re_match_include )
|
||||||
|
|
||||||
|
from apparmor.profile_storage import ProfileStorage
|
||||||
|
|
||||||
import apparmor.rules as aarules
|
import apparmor.rules as aarules
|
||||||
|
|
||||||
from apparmor.rule.capability import CapabilityRuleset, CapabilityRule
|
from apparmor.rule.capability import CapabilityRule
|
||||||
from apparmor.rule.change_profile import ChangeProfileRuleset, ChangeProfileRule
|
from apparmor.rule.change_profile import ChangeProfileRule
|
||||||
from apparmor.rule.dbus import DbusRuleset, DbusRule
|
from apparmor.rule.dbus import DbusRule
|
||||||
from apparmor.rule.file import FileRuleset, FileRule
|
from apparmor.rule.file import FileRule
|
||||||
from apparmor.rule.network import NetworkRuleset, NetworkRule
|
from apparmor.rule.network import NetworkRule
|
||||||
from apparmor.rule.ptrace import PtraceRuleset, PtraceRule
|
from apparmor.rule.ptrace import PtraceRule
|
||||||
from apparmor.rule.rlimit import RlimitRuleset, RlimitRule
|
from apparmor.rule.rlimit import RlimitRule
|
||||||
from apparmor.rule.signal import SignalRuleset, SignalRule
|
from apparmor.rule.signal import SignalRule
|
||||||
from apparmor.rule import quote_if_needed
|
from apparmor.rule import quote_if_needed
|
||||||
|
|
||||||
ruletypes = ['capability', 'change_profile', 'dbus', 'file', 'network', 'ptrace', 'rlimit', 'signal']
|
ruletypes = ['capability', 'change_profile', 'dbus', 'file', 'network', 'ptrace', 'rlimit', 'signal']
|
||||||
@@ -426,60 +428,6 @@ def get_inactive_profile(local_profile):
|
|||||||
return {local_profile: extras[local_profile]}
|
return {local_profile: extras[local_profile]}
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
def ProfileStorage(profilename, hat, calledby):
|
|
||||||
# keys used in aa[profile][hat]:
|
|
||||||
# a) rules (as dict): alias, include, lvar
|
|
||||||
# b) rules (as hasher): allow, deny
|
|
||||||
# c) one for each rule class
|
|
||||||
# d) other: external, flags, name, profile, attachment, initial_comment, filename, info,
|
|
||||||
# profile_keyword, header_comment (these two are currently only set by set_profile_flags())
|
|
||||||
|
|
||||||
profile = dict()
|
|
||||||
|
|
||||||
# profile['info'] isn't used anywhere, but can be helpful in debugging.
|
|
||||||
profile['info'] = {'profile': profilename, 'hat': hat, 'calledby': calledby}
|
|
||||||
|
|
||||||
profile['capability'] = CapabilityRuleset()
|
|
||||||
profile['dbus'] = DbusRuleset()
|
|
||||||
profile['file'] = FileRuleset()
|
|
||||||
profile['change_profile'] = ChangeProfileRuleset()
|
|
||||||
profile['network'] = NetworkRuleset()
|
|
||||||
profile['ptrace'] = PtraceRuleset()
|
|
||||||
profile['rlimit'] = RlimitRuleset()
|
|
||||||
profile['signal'] = SignalRuleset()
|
|
||||||
|
|
||||||
profile['alias'] = dict()
|
|
||||||
profile['include'] = dict()
|
|
||||||
profile['localinclude'] = dict()
|
|
||||||
profile['repo'] = dict()
|
|
||||||
profile['lvar'] = dict()
|
|
||||||
|
|
||||||
profile['filename'] = ''
|
|
||||||
profile['name'] = ''
|
|
||||||
profile['attachment'] = ''
|
|
||||||
profile['flags'] = ''
|
|
||||||
profile['external'] = False
|
|
||||||
profile['header_comment'] = ''
|
|
||||||
profile['initial_comment'] = ''
|
|
||||||
profile['profile_keyword'] = False
|
|
||||||
profile['profile'] = False # profile or hat?
|
|
||||||
|
|
||||||
profile['allow'] = dict()
|
|
||||||
profile['deny'] = dict()
|
|
||||||
|
|
||||||
profile['allow']['link'] = hasher()
|
|
||||||
profile['deny']['link'] = hasher()
|
|
||||||
|
|
||||||
# mount, pivot_root, unix have a .get() fallback to list() - initialize them nevertheless
|
|
||||||
profile['allow']['mount'] = list()
|
|
||||||
profile['deny']['mount'] = list()
|
|
||||||
profile['allow']['pivot_root'] = list()
|
|
||||||
profile['deny']['pivot_root'] = list()
|
|
||||||
profile['allow']['unix'] = list()
|
|
||||||
profile['deny']['unix'] = list()
|
|
||||||
|
|
||||||
return profile
|
|
||||||
|
|
||||||
def create_new_profile(localfile, is_stub=False):
|
def create_new_profile(localfile, is_stub=False):
|
||||||
local_profile = hasher()
|
local_profile = hasher()
|
||||||
local_profile[localfile] = ProfileStorage('NEW', localfile, 'create_new_profile()')
|
local_profile[localfile] = ProfileStorage('NEW', localfile, 'create_new_profile()')
|
||||||
|
101
utils/apparmor/profile_storage.py
Normal file
101
utils/apparmor/profile_storage.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||||
|
# Copyright (C) 2014-2017 Christian Boltz <apparmor@cboltz.de>
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
from apparmor.common import AppArmorBug, hasher
|
||||||
|
|
||||||
|
from apparmor.rule.capability import CapabilityRuleset
|
||||||
|
from apparmor.rule.change_profile import ChangeProfileRuleset
|
||||||
|
from apparmor.rule.dbus import DbusRuleset
|
||||||
|
from apparmor.rule.file import FileRuleset
|
||||||
|
from apparmor.rule.network import NetworkRuleset
|
||||||
|
from apparmor.rule.ptrace import PtraceRuleset
|
||||||
|
from apparmor.rule.rlimit import RlimitRuleset
|
||||||
|
from apparmor.rule.signal import SignalRuleset
|
||||||
|
|
||||||
|
class ProfileStorage:
|
||||||
|
'''class to store the content (header, rules, comments) of a profilename
|
||||||
|
|
||||||
|
Acts like a dict(), but has some additional checks.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, profilename, hat, calledby):
|
||||||
|
data = dict()
|
||||||
|
|
||||||
|
# self.data['info'] isn't used anywhere, but can be helpful in debugging.
|
||||||
|
data['info'] = {'profile': profilename, 'hat': hat, 'calledby': calledby}
|
||||||
|
|
||||||
|
data['capability'] = CapabilityRuleset()
|
||||||
|
data['dbus'] = DbusRuleset()
|
||||||
|
data['file'] = FileRuleset()
|
||||||
|
data['change_profile'] = ChangeProfileRuleset()
|
||||||
|
data['network'] = NetworkRuleset()
|
||||||
|
data['ptrace'] = PtraceRuleset()
|
||||||
|
data['rlimit'] = RlimitRuleset()
|
||||||
|
data['signal'] = SignalRuleset()
|
||||||
|
|
||||||
|
data['alias'] = dict()
|
||||||
|
data['include'] = dict()
|
||||||
|
data['localinclude'] = dict()
|
||||||
|
data['lvar'] = dict()
|
||||||
|
data['repo'] = dict()
|
||||||
|
|
||||||
|
data['filename'] = ''
|
||||||
|
data['name'] = ''
|
||||||
|
data['attachment'] = ''
|
||||||
|
data['flags'] = ''
|
||||||
|
data['external'] = False
|
||||||
|
data['header_comment'] = '' # currently only set by set_profile_flags()
|
||||||
|
data['initial_comment'] = ''
|
||||||
|
data['profile_keyword'] = False # currently only set by set_profile_flags()
|
||||||
|
data['profile'] = False # profile or hat?
|
||||||
|
|
||||||
|
data['allow'] = dict()
|
||||||
|
data['deny'] = dict()
|
||||||
|
|
||||||
|
data['allow']['link'] = hasher()
|
||||||
|
data['deny']['link'] = hasher()
|
||||||
|
|
||||||
|
# mount, pivot_root, unix have a .get() fallback to list() - initialize them nevertheless
|
||||||
|
data['allow']['mount'] = list()
|
||||||
|
data['deny']['mount'] = list()
|
||||||
|
data['allow']['pivot_root'] = list()
|
||||||
|
data['deny']['pivot_root'] = list()
|
||||||
|
data['allow']['unix'] = list()
|
||||||
|
data['deny']['unix'] = list()
|
||||||
|
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if key in self.data:
|
||||||
|
return self.data[key]
|
||||||
|
else:
|
||||||
|
raise AppArmorBug('attempt to read unknown key %s' % key)
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
# TODO: Most of the keys (containing *Ruleset, dict(), list() or hasher()) should be read-only.
|
||||||
|
# Their content needs to be changed, but the container shouldn't
|
||||||
|
# Note: serialize_profile_from_old_profile.write_prior_segments() and write_prior_segments() expect the container to be writeable!
|
||||||
|
# TODO: check if value has the expected type
|
||||||
|
if key in self.data:
|
||||||
|
self.data[key] = value
|
||||||
|
else:
|
||||||
|
raise AppArmorBug('attempt to set unknown key %s' % key)
|
||||||
|
|
||||||
|
def get(self, key, fallback=None):
|
||||||
|
if key in self.data:
|
||||||
|
return self.data.get(key, fallback)
|
||||||
|
else:
|
||||||
|
raise AppArmorBug('attempt to read unknown key %s' % key)
|
41
utils/test/test-profile-storage.py
Normal file
41
utils/test/test-profile-storage.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017 Christian Boltz <apparmor@cboltz.de>
|
||||||
|
#
|
||||||
|
# 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 unittest
|
||||||
|
from common_test import AATest, setup_all_loops
|
||||||
|
|
||||||
|
from apparmor.common import AppArmorBug
|
||||||
|
from apparmor.profile_storage import ProfileStorage
|
||||||
|
|
||||||
|
class TestUnknownKey(AATest):
|
||||||
|
def AASetup(self):
|
||||||
|
self.storage = ProfileStorage('/test/foo', 'hat', 'TEST')
|
||||||
|
|
||||||
|
def test_read(self):
|
||||||
|
with self.assertRaises(AppArmorBug):
|
||||||
|
self.storage['foo']
|
||||||
|
|
||||||
|
def test_get(self):
|
||||||
|
with self.assertRaises(AppArmorBug):
|
||||||
|
self.storage.get('foo')
|
||||||
|
|
||||||
|
def test_get_with_fallback(self):
|
||||||
|
with self.assertRaises(AppArmorBug):
|
||||||
|
self.storage.get('foo', 'bar')
|
||||||
|
|
||||||
|
def test_set(self):
|
||||||
|
with self.assertRaises(AppArmorBug):
|
||||||
|
self.storage['foo'] = 'bar'
|
||||||
|
|
||||||
|
|
||||||
|
setup_all_loops(__name__)
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(verbosity=2)
|
Reference in New Issue
Block a user