#!/usr/bin/env python3 import sys blocks = [] denies = [] # # 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': []}) # @prev is an array of dicts which containing 'path' and # 'children'. @path is a string. We are looking for an entry # in @prev which contains @path, and will return its # children array. def child_get(prev, path): for p in prev: if p['path'] == path: return p['children'] 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 # TODO - should we find the longest match? 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'] 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']) def main(): config = "config" if len(sys.argv) > 1: config = sys.argv[1] lines = None try: with open(config) as f: lines = f.readlines() except FileNotFoundError as err: print("Config file not found") print(err) sys.exit(1) for line in lines: line.strip() if line.startswith('#'): continue try: (cmd, path) = line.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) for block in blocks: gen_denies(block['path'], block['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) if __name__ == "__main__": main()