check.bend

bend-osdev-apparmor@0.1.0.0 · 181 lines · 13 definitions

1import Base
2import bend-osdev-bytes@0.1.0.0/bytes.bend as B
3import bend-osdev-apparmor@0.1.0.0/text.bend as X
4import bend-osdev-apparmor@0.1.0.0/glob.bend as G
5import bend-osdev-apparmor@0.1.0.0/perm.bend as P
6import bend-osdev-apparmor@0.1.0.0/error.bend as E
7import bend-osdev-apparmor@0.1.0.0/options.bend as O
8import bend-osdev-apparmor@0.1.0.0/profile.bend as PR
9import bend-osdev-apparmor@0.1.0.0/eval.bend as V
10import bend-osdev-apparmor@0.1.0.0/transitions.bend as TR
11import bend-osdev-apparmor@0.1.0.0/rule_file.bend as F
12import bend-osdev-apparmor@0.1.0.0/rule_mount.bend as RM
13import bend-osdev-apparmor@0.1.0.0/rule_dbus.bend as RD
14import bend-osdev-apparmor@0.1.0.0/example.bend as EX
15import bend-osdev-apparmor@0.1.0.0/apparmor.bend as A
16
17def o(s: String) -> B.Octets:
18  B.Octets.of_string(s)
19
20def l(s: String) -> List<&2, U32>:
21  X.AaText.of_string(s)
22
23def show.d(m: Maybe<&2, V.AaDecision>) -> String:
24  match m:
25    case None{}:
26      "no profile"
27    case Some{d}:
28      V.AaDecision.show(d)
29
30def show.load(r: Result<&2, &2, E.AaError, PR.AaPolicy>) -> String:
31  match r:
32    case Fail{+e}:
33      "error " ++ E.AaError.name(e) ++ " at line " ++ U32.show(E.AaError.line(e))
34    case Done{p}:
35      "ok, " ++ Nat.show(List.length(&2, PR.AaProfile, PR.AaPolicy.profiles(p))) ++ " profiles"
36
37# a one-file policy
38def load1(t: String) -> String:
39  show.load(A.Aa.load_default([EX.AaExample.source("p", t)], o("p")))
40
41def g(+p: String, +s: String) -> String:
42  p ++ " ~ " ++ s ++ ": " ++ Bool.show(G.AaGlob.match_text(l(p), l(s)))
43
44def pol() -> PR.AaPolicy:
45  EX.AaExample.pol()
46
47# Larger inputs: a profile of n rules, and a long path
48
49def big.rules(n: Nat, +i: U32, acc: String) -> String:
50  match n:
51    case 0n:
52      acc
53    case 1n+k:
54      big.rules(k, U32.add(i, 1), acc ++ "  /data/d" ++ U32.show(i) ++ "/** r,\n  deny /data/d" ++ U32.show(i) ++ "/secret w,\n")
55
56def big.text(n: Nat) -> String:
57  "profile big {\n" ++ big.rules(n, 0, "") ++ "}\n"
58
59def big.path.go(n: Nat, acc: String) -> String:
60  match n:
61    case 0n:
62      acc
63    case 1n+k:
64      big.path.go(k, acc ++ "/abcdefghij")
65
66def big.path(n: Nat) -> String:
67  "/data/d299" ++ big.path.go(n, "") ++ "/file"
68
69def big.query(+r: Result<&2, &2, E.AaError, PR.AaPolicy>, path: String, perms: String) -> String:
70  match r:
71    case Fail{e}:
72      "no policy"
73    case Done{p}:
74      show.d(A.Aa.file(O.AaOptions.default(), p, o("big"), o(path), False{}, F.AaFile.perms(perms)))
75
76def main() -> IO(Unit):
77  +big = A.Aa.load_default([EX.AaExample.source("big", big.text(300n))], o("big"))
78  do IO<Unit>:
79    IO.print("example: " ++ show.load(EX.AaExample.loaded()))
80    IO.print(show.d(EX.AaExample.file("/usr/bin/foo", "/etc/ld.so.cache", "r")))
81    IO.print(show.d(EX.AaExample.file("/usr/bin/foo", "/etc/ld.so.cache", "w")))
82    IO.print(show.d(EX.AaExample.file("/usr/bin/foo", "/lib/x86_64/libc.so.6", "mr")))
83    IO.print(show.d(EX.AaExample.file("/usr/bin/foo", "/home/bob/.foo_file", "rw")))
84    IO.print(show.d(EX.AaExample.file("/usr/bin/foo", "/etc/shadow", "r")))
85    IO.print(show.d(EX.AaExample.file("/usr/bin/foo", "/var/log/foo", "w")))
86    IO.print(show.d(EX.AaExample.file("/usr/bin/foo", "/tmp/foo.1", "l")))
87    IO.print(show.d(A.Aa.file(O.AaOptions.default(), pol(), o("/usr/bin/foo"), o("/proc/42/stat"), True{}, F.AaFile.perms("r"))))
88    IO.print(show.d(EX.AaExample.file("/usr/bin/foo", "/proc/42/stat", "r")))
89    IO.print(show.d(EX.AaExample.file("/usr/bin/foo//hat", "/var/spool/q", "rw")))
90    IO.print(show.d(EX.AaExample.file("bar", "/etc/anything", "r")))
91    IO.print(show.d(EX.AaExample.file("bar", "/etc/secret", "r")))
92    IO.print(show.d(A.Aa.file(O.AaOptions.with_complain_deny(O.AaOptions.default(), False{}), pol(), o("bar"), o("/etc/secret"), False{}, F.AaFile.perms("r"))))
93    IO.print(show.d(A.Aa.capability(O.AaOptions.default(), pol(), o("/usr/bin/foo"), 7)))
94    IO.print(show.d(A.Aa.capability(O.AaOptions.default(), pol(), o("/usr/bin/foo"), 21)))
95    IO.print(show.d(A.Aa.network(O.AaOptions.default(), pol(), o("/usr/bin/foo"), o("inet"), o("stream"), o("tcp"))))
96    IO.print(show.d(A.Aa.network(O.AaOptions.default(), pol(), o("/usr/bin/foo"), o("inet6"), o("stream"), o("tcp"))))
97    IO.print(show.d(A.Aa.signal(O.AaOptions.default(), pol(), o("/usr/bin/foo"), P.AaPerms.bit(0n), o("term"), o("/usr/bin/bar"))))
98    IO.print(show.d(A.Aa.signal(O.AaOptions.default(), pol(), o("/usr/bin/foo"), P.AaPerms.bit(1n), o("term"), o("/usr/bin/bar"))))
99    IO.print(EX.AaExample.exec("/usr/bin/foo", "/bin/mount"))
100    IO.print(EX.AaExample.exec("/usr/bin/foo", "/usr/bin/baz"))
101    IO.print(EX.AaExample.exec("/usr/bin/foo", "/usr/bin/bar"))
102    IO.print(EX.AaExample.exec("/usr/bin/foo", "/usr/bin/zzz"))
103    IO.print(EX.AaExample.exec("/usr/bin/foo", "/bin/sh"))
104    IO.print(EX.AaExample.exec("/usr/bin/foo//baz", "/bin/bash"))
105    IO.print(TR.AaExecResult.show(A.Aa.exec_unconfined(pol(), o("/usr/bin/bar"))))
106    IO.print(TR.AaExecResult.show(A.Aa.exec_unconfined(pol(), o("/usr/bin/other"))))
107    IO.print(load1("profile e { /x wa, }"))
108    IO.print(load1("profile e {\n  /x r,\n  /y ix px,\n}"))
109    IO.print(load1("profile e { capability bogus, }"))
110    IO.print(load1("profile e { @{NOPE}/x r, }"))
111    IO.print(load1("@{A} = /x\n@{A} = /y\nprofile e { }"))
112    IO.print(load1("profile e { /x ix, /x px, }"))
113    IO.print(load1("profile e { unix, }"))
114    IO.print(load1("profile e { include <missing> }"))
115    IO.print(load1("profile e { include if exists <missing> }"))
116    IO.print(load1("profile e { /x/{a} r, }"))
117    IO.print(load1("profile e flags=(complain,kill) { }"))
118    IO.print(load1("profile e { } profile e { }"))
119    IO.print(load1("profile e { /x r }"))
120    IO.print(g("/tmp/*", "/tmp/"))
121    IO.print(g("/tmp/**", "/tmp/a/b"))
122    IO.print(g("/a/{b,c{d,e}}/*", "/a/cd/x"))
123    IO.print(g("/a/[^b]c", "/a//c"))
124    IO.print(g("/a/**/b/**/c/**/d/**/e*", "/a/1/2/b/3/c/4/5/d/6/7/8/f/9/x/y/z/w/v/u/t/s/r/q/p/o/n/m/l"))
125    IO.print("big: " ++ show.load(big))
126    IO.print(big.query(big, "/data/d150/x", "r"))
127    IO.print(big.query(big, "/data/d150/secret", "w"))
128    IO.print(big.query(big, "/data/d300/x", "r"))
129    IO.print(big.query(big, big.path(200n), "r"))
130
131#|example: ok, 2 profiles
132#|allow
133#|deny
134#|allow
135#|allow
136#|deny-quiet
137#|audit
138#|allow
139#|allow
140#|deny
141#|allow
142#|complain
143#|deny-quiet
144#|complain
145#|allow
146#|deny
147#|allow
148#|deny
149#|allow
150#|deny
151#|unconfined
152#|profile /usr/bin/foo//baz scrub
153#|profile bar
154#|stay
155#|denied (deny)
156#|stay
157#|profile bar
158#|unconfined
159#|error perms at line 1
160#|error syntax at line 3
161#|error name at line 1
162#|error var-undefined at line 1
163#|error var-redefined at line 2
164#|error exec-conflict at line 1
165#|error unsupported at line 1
166#|error include at line 1
167#|ok, 1 profiles
168#|error glob at line 1
169#|error flag at line 1
170#|error duplicate at line 1
171#|error syntax at line 1
172#|/tmp/* ~ /tmp/: False
173#|/tmp/** ~ /tmp/a/b: True
174#|/a/{b,c{d,e}}/* ~ /a/cd/x: True
175#|/a/[^b]c ~ /a//c: True
176#|/a/**/b/**/c/**/d/**/e* ~ /a/1/2/b/3/c/4/5/d/6/7/8/f/9/x/y/z/w/v/u/t/s/r/q/p/o/n/m/l: False
177#|big: ok, 1 profiles
178#|allow
179#|deny-quiet
180#|deny
181#|allow