rule_capability.bend

bend-osdev-apparmor@0.1.0.0 · 149 lines · 20 definitions

1# bend-osdev-apparmor: capability rules (apparmor.d(5), "CAPABILITY RULE"):
2# `capability` alone (every capability) or a list of lower-case capability
3# names without the CAP_ prefix (capabilities(7)). Names and numbers come
4# from bend-osdev-caps. One permission bit: use.
5import Base
6import bend-osdev-caps@0.1.0.0/caps.bend as C
7import bend-osdev-apparmor@0.1.0.0/text.bend as X
8import bend-osdev-apparmor@0.1.0.0/perm.bend as P
9import bend-osdev-apparmor@0.1.0.0/token.bend as T
10import bend-osdev-apparmor@0.1.0.0/error.bend as E
11import bend-osdev-apparmor@0.1.0.0/rule.bend as R
12
13# caps: None for every capability
14type AaCapRule is Data:
15  AaCapRule{qual: P.AaQual, caps: Maybe<&2, List<&2, U32>>}
16
17# a request to use capability number cap (CAP_CHOWN is 0)
18type AaCapQuery is Data:
19  AaCapQuery{cap: U32}
20
21def AaCap.upper(xs: List<&2, U32>) -> List<&2, U32>:
22  match xs:
23    case Nil{}:
24      Nil{}
25    case Con{+h, t}:
26      Con{Bool.pick(U32, Bool.and(U32.is_ge(h, 97), U32.is_le(h, 122)), U32.sub(h, 32), h), AaCap.upper(t)}
27
28# no upper-case letter
29def AaCap.lower(xs: List<&2, U32>) -> Bool:
30  match xs:
31    case Nil{}:
32      True{}
33    case Con{+h, t}:
34      Bool.and(Bool.not(Bool.and(U32.is_ge(h, 65), U32.is_le(h, 90))), AaCap.lower(t))
35
36# the number of the capability named w (lower case, no CAP_ prefix)
37def AaCap.of_name(+w: List<&2, U32>) -> Maybe<&2, U32>:
38  Bool.pick(Maybe<&2, U32>, AaCap.lower(w), C.Cap.of_name(X.AaText.to_string(X.AaText.append(X.AaText.of_string("CAP_"), AaCap.upper(w)))), None{})
39
40def AaCap.name.go(m: Maybe<&2, String>) -> String:
41  match m:
42    case None{}:
43      "?"
44    case Some{s}:
45      s
46
47def AaCap.name(k: U32) -> String:
48  AaCap.name.go(C.Cap.name(k))
49
50def AaCap.parse.one(m: Maybe<&2, U32>, r: Result<&2, &2, E.AaError, List<&2, U32>>, src: E.AaSrc) -> Result<&2, &2, E.AaError, List<&2, U32>>:
51  match m:
52    case None{}:
53      Fail{E.AaSrc.name(src)}
54    case Some{k}:
55      match r:
56        case Fail{e}:
57          Fail{e}
58        case Done{ks}:
59          Done{Con{k, ks}}
60
61def AaCap.parse.names(ts: List<&2, T.AaTerm>, +src: E.AaSrc) -> Result<&2, &2, E.AaError, List<&2, U32>>:
62  match ts:
63    case Nil{}:
64      Done{Nil{}}
65    case Con{t, rest}:
66      match t:
67        case T.AaTmWord{w}:
68          AaCap.parse.one(AaCap.of_name(w), AaCap.parse.names(rest, src), src)
69        case _:
70          Fail{E.AaSrc.syntax(src)}
71
72def AaCap.parse.go(r: Result<&2, &2, E.AaError, List<&2, U32>>, q: P.AaQual) -> Result<&2, &2, E.AaError, AaCapRule>:
73  match r:
74    case Fail{e}:
75      Fail{e}
76    case Done{ks}:
77      Done{AaCapRule{q, Some{ks}}}
78
79def AaCap.parse.q(r: Result<&2, &2, E.AaError, P.AaQual>, ts: List<&2, T.AaTerm>, +src: E.AaSrc) -> Result<&2, &2, E.AaError, AaCapRule>:
80  match r:
81    case Fail{e}:
82      Fail{e}
83    case Done{q}:
84      match ts:
85        case Nil{}:
86          Done{AaCapRule{q, None{}}}
87        case Con{t, rest}:
88          AaCap.parse.go(AaCap.parse.names(Con{t, rest}, src), q)
89
90# the terms after `capability`; the owner qualifier is not allowed
91def AaCap.parse(ts: List<&2, T.AaTerm>, q: P.AaQual, +src: E.AaSrc) -> Result<&2, &2, E.AaError, AaCapRule>:
92  AaCap.parse.q(R.AaRule.no_owner(q, src), ts, src)
93
94# Matching
95
96def AaCap.member(ks: List<&2, U32>, +k: U32) -> Bool:
97  match ks:
98    case Nil{}:
99      False{}
100    case Con{h, t}:
101      Bool.or(U32.is_eq(h, k), AaCap.member(t, k))
102
103def AaCapRule.matches(r: AaCapRule, q: AaCapQuery) -> Bool:
104  match r:
105    case AaCapRule{qu, ks}:
106      match ks:
107        case None{}:
108          True{}
109        case Some{xs}:
110          match q:
111            case AaCapQuery{k}:
112              AaCap.member(xs, k)
113
114def AaCapRule.matching.go(hit: Bool, r: AaCapRule, rest: List<&2, AaCapRule>) -> List<&2, AaCapRule>:
115  match hit:
116    case True{}:
117      Con{r, rest}
118    case False{}:
119      rest
120
121def AaCapRule.matching(rs: List<&2, AaCapRule>, +q: AaCapQuery) -> List<&2, AaCapRule>:
122  match rs:
123    case Nil{}:
124      Nil{}
125    case Con{+r, t}:
126      AaCapRule.matching.go(AaCapRule.matches(r, q), r, AaCapRule.matching(t, q))
127
128def AaCapRule.grants.of(rs: List<&2, AaCapRule>) -> List<&2, P.AaGrant>:
129  match rs:
130    case Nil{}:
131      Nil{}
132    case Con{r, t}:
133      match r:
134        case AaCapRule{qu, ks}:
135          Con{P.AaGrant.of(qu, P.AaPerms.bit(0n)), AaCapRule.grants.of(t)}
136
137def AaCapRule.grants(rs: List<&2, AaCapRule>, +q: AaCapQuery) -> List<&2, P.AaGrant>:
138  AaCapRule.grants.of(AaCapRule.matching(rs, q))
139
140def AaCapRule.append(xs: List<&2, AaCapRule>, ys: List<&2, AaCapRule>) -> List<&2, AaCapRule>:
141  match xs:
142    case Nil{}:
143      ys
144    case Con{h, t}:
145      Con{h, AaCapRule.append(t, ys)}
146
147# the request's permission: use
148def AaCapQuery.req() -> P.AaPerms:
149  P.AaPerms.bit(0n)