mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-05-28 19:17:15 +00:00

This uses the generate-apparmor-rules.py script I sent out some time ago to auto-generate apparmor rules based on a higher level set of block/allow rules. Add apparmor policy testcase to make sure that some of the paths we expect to be denied (and allowed) write access to are in fact in effect in the final policy. With this policy, libvirt in a container is able to start its default network, which previously it could not. v2: address feedback from stgraber put lxc-generate-aa-rules.py into EXTRA_DIST add lxc-test-apparmor, container-base and container-rules to .gitignore take lxc-test-apparmor out of EXTRA_DIST make lxc-generate-aa-rules.py pep8-compliant don't automatically generate apparmor rules This is only bc we can't be guaranteed that python3 will be available. Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com> Acked-by: Stéphane Graber <stgraber@ubuntu.com>
136 lines
3.4 KiB
Python
Executable File
136 lines
3.4 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
import sys
|
|
|
|
blocks = []
|
|
|
|
#
|
|
# blocks is an array of paths under which we want to block by
|
|
# default.
|
|
#
|
|
# blocks[0] = ['path' = '/sys', 'children' = [A,B] ]
|
|
# blocks[1] = ['path' = '/proc/sys', 'children' = [ E ] ]
|
|
# A = [ 'path' = 'fs', children = [C] ]
|
|
# C = [ 'path' = 'cgroup', children = [F] ]
|
|
# B = [ 'path' = 'class', children = [D] ]
|
|
# D = [ 'path' = 'net', children = [F] ]
|
|
# E = [ 'path' = 'shm*' ]
|
|
# F = [ 'path' = '**' ]
|
|
|
|
|
|
def add_block(path):
|
|
for b in blocks:
|
|
if b['path'] == path:
|
|
# duplicate
|
|
return
|
|
blocks.append({'path': path.strip(), 'children': []})
|
|
|
|
|
|
def child_get(prev, path):
|
|
for p in prev:
|
|
if p['path'] == path:
|
|
return p
|
|
return None
|
|
|
|
|
|
def add_allow(path):
|
|
# find which block we belong to
|
|
found = None
|
|
for b in blocks:
|
|
l = len(b['path'])
|
|
if len(path) <= l:
|
|
continue
|
|
if path[0:l] == b['path']:
|
|
found = b
|
|
break
|
|
if found is None:
|
|
print("allow with no previous block at %s" % path)
|
|
sys.exit(1)
|
|
p = path[l:].strip()
|
|
while p[:1] == "/":
|
|
p = p[1:]
|
|
prev = b['children']
|
|
for s in p.split('/'):
|
|
n = {'path': s.strip(), 'children': []}
|
|
tmp = child_get(prev, n['path'])
|
|
if tmp is not None:
|
|
prev = tmp
|
|
else:
|
|
prev.append(n)
|
|
prev = n['children']
|
|
|
|
config = "config"
|
|
if len(sys.argv) > 1:
|
|
config = sys.argv[1]
|
|
with open(config) as f:
|
|
for x in f.readlines():
|
|
x.strip()
|
|
if x[:1] == '#':
|
|
continue
|
|
try:
|
|
(cmd, path) = x.split(' ')
|
|
except: # blank line
|
|
continue
|
|
if cmd == "block":
|
|
add_block(path)
|
|
elif cmd == "allow":
|
|
add_allow(path)
|
|
else:
|
|
print("Unknown command: %s" % cmd)
|
|
sys.exit(1)
|
|
|
|
denies = []
|
|
|
|
|
|
def collect_chars(children, ref, index):
|
|
r = ""
|
|
for c in children:
|
|
if index >= len(c['path']):
|
|
continue
|
|
if ref[0:index] != c['path'][0:index]:
|
|
continue
|
|
if c['path'][index] not in r:
|
|
r = r + c['path'][index]
|
|
return r
|
|
|
|
|
|
def append_deny(s):
|
|
s = "%s wklx," % s
|
|
if s not in denies:
|
|
denies.append(s)
|
|
|
|
|
|
def gen_denies(pathsofar, children):
|
|
for c in children:
|
|
for char in range(len(c['path'])):
|
|
if char == len(c['path'])-1 and c['path'][char] == '*':
|
|
continue
|
|
if char == len(c['path'])-2:
|
|
if c['path'][char:char+2] == '**':
|
|
continue
|
|
x = collect_chars(children, c['path'], char)
|
|
newdeny = "deny %s/%s[^%s]*{,/**}" % (pathsofar,
|
|
c['path'][0:char], x)
|
|
append_deny(newdeny)
|
|
if c['path'] != '**' and c['path'][len(c['path'])-1] != '*':
|
|
newdeny = "deny %s/%s?*{,/**}" % (pathsofar, c['path'])
|
|
append_deny(newdeny)
|
|
elif c['path'] != '**':
|
|
newdeny = "deny %s/%s/**" % (pathsofar, c['path'])
|
|
append_deny(newdeny)
|
|
if len(c['children']) != 0:
|
|
newpath = "%s/%s" % (pathsofar, c['path'])
|
|
gen_denies(newpath, c['children'])
|
|
|
|
for b in blocks:
|
|
gen_denies(b['path'], b['children'])
|
|
|
|
denies.sort()
|
|
|
|
genby = " # generated by: lxc-generate-aa-rules.py"
|
|
for a in sys.argv[1:]:
|
|
genby += " %s" % a
|
|
print(genby)
|
|
for d in denies:
|
|
print(" %s" % d)
|