~apparmor-dev/apparmor/master

« back to all changes in this revision

Viewing changes to utils/vim/create-apparmor.vim.py

  • Committer: Steve Beattie
  • Date: 2019-02-19 09:38:13 UTC
  • Revision ID: sbeattie@ubuntu.com-20190219093813-ud526ee6hwn8nljz
The AppArmor project has been converted to git and is now hosted on
gitlab.

To get the converted repository, please do
  git clone https://gitlab.com/apparmor/apparmor

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
2
 
#
3
 
#    Copyright (C) 2012 Canonical Ltd.
4
 
#
5
 
#    This program is free software; you can redistribute it and/or
6
 
#    modify it under the terms of version 2 of the GNU General Public
7
 
#    License published by the Free Software Foundation.
8
 
#
9
 
#    Written by Steve Beattie <steve@nxnw.org>, based on work by
10
 
#    Christian Boltz <apparmor@cboltz.de>
11
 
 
12
 
from __future__ import with_statement
13
 
import re
14
 
import subprocess
15
 
import sys
16
 
 
17
 
# dangerous capabilities
18
 
danger_caps = ["audit_control",
19
 
               "audit_write",
20
 
               "mac_override",
21
 
               "mac_admin",
22
 
               "set_fcap",
23
 
               "sys_admin",
24
 
               "sys_module",
25
 
               "sys_rawio"]
26
 
 
27
 
 
28
 
def cmd(command, input=None, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, stdin=None, timeout=None):
29
 
    '''Try to execute given command (array) and return its stdout, or
30
 
    return a textual error if it failed.'''
31
 
 
32
 
    try:
33
 
        sp = subprocess.Popen(command, stdin=stdin, stdout=stdout, stderr=stderr, close_fds=True, universal_newlines=True)
34
 
    except OSError as ex:
35
 
        return [127, str(ex)]
36
 
 
37
 
    out, outerr = sp.communicate(input)
38
 
 
39
 
    # Handle redirection of stdout
40
 
    if out is None:
41
 
        out = ''
42
 
    # Handle redirection of stderr
43
 
    if outerr is None:
44
 
        outerr = ''
45
 
    return [sp.returncode, out + outerr]
46
 
 
47
 
# get capabilities list
48
 
(rc, output) = cmd(['make', '-s', '--no-print-directory', 'list_capabilities'])
49
 
if rc != 0:
50
 
    sys.stderr.write("make list_capabilities failed: " + output)
51
 
    exit(rc)
52
 
 
53
 
capabilities = re.sub('CAP_', '', output.strip()).lower().split(" ")
54
 
benign_caps = []
55
 
for cap in capabilities:
56
 
    if cap not in danger_caps:
57
 
        benign_caps.append(cap)
58
 
 
59
 
# get network protos list
60
 
(rc, output) = cmd(['make', '-s', '--no-print-directory', 'list_af_names'])
61
 
if rc != 0:
62
 
    sys.stderr.write("make list_af_names failed: " + output)
63
 
    exit(rc)
64
 
 
65
 
af_names = []
66
 
af_pairs = re.sub('AF_', '', output.strip()).lower().split(",")
67
 
for af_pair in af_pairs:
68
 
    af_name = af_pair.lstrip().split(" ")[0]
69
 
    # skip max af name definition
70
 
    if len(af_name) > 0 and af_name != "max":
71
 
        af_names.append(af_name)
72
 
 
73
 
# TODO: does a "debug" flag exist? Listed in apparmor.vim.in sdFlagKey,
74
 
# but not in aa_flags...
75
 
# -> currently (2011-01-11) not, but might come back
76
 
 
77
 
aa_network_types = r'\s+tcp|\s+udp|\s+icmp'
78
 
 
79
 
aa_flags = ['complain',
80
 
            'audit',
81
 
            'attach_disconnected',
82
 
            'no_attach_disconnected',
83
 
            'chroot_attach',
84
 
            'chroot_no_attach',
85
 
            'chroot_relative',
86
 
            'namespace_relative',
87
 
            'mediate_deleted',
88
 
            'delegate_deleted']
89
 
 
90
 
filename = r'(\/|\@\{\S*\})\S*'
91
 
 
92
 
aa_regex_map = {
93
 
    'FILENAME':         filename,
94
 
    'FILE':             r'\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?' + filename + r'\s+',  # Start of a file rule
95
 
                        # (whitespace_+_, owner etc. flag_?_, filename pattern, whitespace_+_)
96
 
    'DENYFILE':         r'\v^\s*(audit\s+)?deny\s+(owner\s+|other\s+)?' + filename + r'\s+',  # deny, otherwise like FILE
97
 
    'auditdenyowner':   r'(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?',
98
 
    'audit_DENY_owner': r'(audit\s+)?deny\s+(owner\s+|other\s+)?',  # must include "deny", otherwise like auditdenyowner
99
 
    'auditdeny':        r'(audit\s+)?(deny\s+|allow\s+)?',
100
 
    'EOL':              r'\s*,(\s*$|(\s*#.*$)\@=)',  # End of a line (whitespace_?_, comma, whitespace_?_ comment.*)
101
 
    'TRANSITION':       r'(\s+-\>\s+\S+)?',
102
 
    'sdKapKey':         " ".join(benign_caps),
103
 
    'sdKapKeyDanger':   " ".join(danger_caps),
104
 
    'sdKapKeyRegex':    "|".join(capabilities),
105
 
    'sdNetworkType':    aa_network_types,
106
 
    'sdNetworkProto':   "|".join(af_names),
107
 
    'flags':            r'((flags\s*\=\s*)?\(\s*(' + '|'.join(aa_flags) + r')(\s*,\s*(' + '|'.join(aa_flags) + r'))*\s*\)\s+)',
108
 
}
109
 
 
110
 
 
111
 
def my_repl(matchobj):
112
 
    matchobj.group(1)
113
 
    if matchobj.group(1) in aa_regex_map:
114
 
        return aa_regex_map[matchobj.group(1)]
115
 
 
116
 
    return matchobj.group(0)
117
 
 
118
 
 
119
 
def create_file_rule(highlighting, permissions, comment, denyrule=0):
120
 
 
121
 
    if denyrule == 0:
122
 
        keywords = '@@auditdenyowner@@'
123
 
    else:
124
 
        keywords = '@@audit_DENY_owner@@'  # TODO: not defined yet, will be '(audit\s+)?deny\s+(owner\s+)?'
125
 
 
126
 
    sniplet = ''
127
 
    sniplet = sniplet + "\n" + '" ' + comment + "\n"
128
 
 
129
 
    prefix = r'syn match  ' + highlighting + r' /\v^\s*' + keywords
130
 
    suffix = r'@@EOL@@/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude' + "\n"
131
 
    # filename without quotes
132
 
    sniplet = sniplet + prefix + r'@@FILENAME@@\s+' + permissions + suffix
133
 
    # filename with quotes
134
 
    sniplet = sniplet + prefix + r'"@@FILENAME@@"\s+' + permissions + suffix
135
 
    # filename without quotes, reverse syntax
136
 
    sniplet = sniplet + prefix + permissions + r'\s+@@FILENAME@@' + suffix
137
 
    # filename with quotes, reverse syntax
138
 
    sniplet = sniplet + prefix + permissions + r'\s+"@@FILENAME@@"+' + suffix
139
 
 
140
 
    return sniplet
141
 
 
142
 
 
143
 
filerule = ''
144
 
filerule = filerule + create_file_rule('sdEntryWriteExec ', r'(l|r|w|a|m|k|[iuUpPcC]x)+@@TRANSITION@@', 'write + exec/mmap - danger! (known bug: accepts aw to keep things simple)')
145
 
filerule = filerule + create_file_rule('sdEntryUX',  r'(r|m|k|ux|pux)+@@TRANSITION@@',  'ux(mr) - unconstrained entry, flag the line red. also includes pux which is unconstrained if no profile exists')
146
 
filerule = filerule + create_file_rule('sdEntryUXe', r'(r|m|k|Ux|PUx)+@@TRANSITION@@',  'Ux(mr) and PUx(mr) - like ux + clean environment')
147
 
filerule = filerule + create_file_rule('sdEntryPX',  r'(r|m|k|px|cx|pix|cix)+@@TRANSITION@@',  'px/cx/pix/cix(mrk) - standard exec entry, flag the line blue')
148
 
filerule = filerule + create_file_rule('sdEntryPXe', r'(r|m|k|Px|Cx|Pix|Cix)+@@TRANSITION@@', 'Px/Cx/Pix/Cix(mrk) - like px/cx + clean environment')
149
 
filerule = filerule + create_file_rule('sdEntryIX',  r'(r|m|k|ix)+',  'ix(mr) - standard exec entry, flag the line green')
150
 
filerule = filerule + create_file_rule('sdEntryM',   r'(r|m|k)+',  'mr - mmap with PROT_EXEC')
151
 
 
152
 
filerule = filerule + create_file_rule('sdEntryM',   r'(r|m|k|x)+',  'special case: deny x is allowed (does not need to be ix, px, ux or cx)', 1)
153
 
#syn match  sdEntryM /@@DENYFILE@@(r|m|k|x)+@@EOL@@/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
154
 
 
155
 
 
156
 
filerule = filerule + create_file_rule('sdError',    r'\S*(w\S*a|a\S*w)\S*',  'write + append is an error')
157
 
filerule = filerule + create_file_rule('sdEntryW',   r'(l|r|w|k)+',  'write entry, flag the line yellow')
158
 
filerule = filerule + create_file_rule('sdEntryW',   r'(l|r|a|k)+',  'append entry, flag the line yellow')
159
 
filerule = filerule + create_file_rule('sdEntryK',   r'[rlk]+',  'read entry + locking, currently no highlighting')
160
 
filerule = filerule + create_file_rule('sdEntryR',   r'[rl]+',  'read entry, no highlighting')
161
 
 
162
 
# " special case: deny x is allowed (doesn't need to be ix, px, ux or cx)
163
 
# syn match  sdEntryM /@@DENYFILE@@(r|m|k|x)+@@EOL@@/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
164
 
 
165
 
# " TODO: Support filenames enclosed in quotes ("/home/foo/My Documents/") - ideally by only allowing quotes pair-wise
166
 
 
167
 
 
168
 
regex = "@@(" + "|".join(aa_regex_map) + ")@@"
169
 
 
170
 
sys.stdout.write('" generated from apparmor.vim.in by create-apparmor.vim.py\n')
171
 
sys.stdout.write('" do not edit this file - edit apparmor.vim.in or create-apparmor.vim.py instead' + "\n\n")
172
 
 
173
 
with open("apparmor.vim.in") as template:
174
 
    for line in template:
175
 
        line = re.sub(regex, my_repl, line.rstrip())
176
 
        sys.stdout.write('%s\n' % line)
177
 
 
178
 
sys.stdout.write("\n\n\n\n")
179
 
 
180
 
sys.stdout.write('" file rules added with create_file_rule()\n')
181
 
sys.stdout.write(re.sub(regex, my_repl, filerule) + '\n')