1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * AppArmor security module
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This file contains AppArmor lib definitions
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * 2017 Canonical Ltd.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #ifndef __AA_LIB_H
11*4882a593Smuzhiyun #define __AA_LIB_H
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/fs.h>
15*4882a593Smuzhiyun #include <linux/lsm_hooks.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include "match.h"
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun /*
20*4882a593Smuzhiyun * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
21*4882a593Smuzhiyun * which is not related to profile accesses.
22*4882a593Smuzhiyun */
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #define DEBUG_ON (aa_g_debug)
25*4882a593Smuzhiyun /*
26*4882a593Smuzhiyun * split individual debug cases out in preparation for finer grained
27*4882a593Smuzhiyun * debug controls in the future.
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun #define AA_DEBUG_LABEL DEBUG_ON
30*4882a593Smuzhiyun #define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args)
31*4882a593Smuzhiyun #define AA_DEBUG(fmt, args...) \
32*4882a593Smuzhiyun do { \
33*4882a593Smuzhiyun if (DEBUG_ON) \
34*4882a593Smuzhiyun pr_debug_ratelimited("AppArmor: " fmt, ##args); \
35*4882a593Smuzhiyun } while (0)
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define AA_WARN(X) WARN((X), "APPARMOR WARN %s: %s\n", __func__, #X)
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define AA_BUG(X, args...) AA_BUG_FMT((X), "" args)
40*4882a593Smuzhiyun #ifdef CONFIG_SECURITY_APPARMOR_DEBUG_ASSERTS
41*4882a593Smuzhiyun #define AA_BUG_FMT(X, fmt, args...) \
42*4882a593Smuzhiyun WARN((X), "AppArmor WARN %s: (" #X "): " fmt, __func__, ##args)
43*4882a593Smuzhiyun #else
44*4882a593Smuzhiyun #define AA_BUG_FMT(X, fmt, args...)
45*4882a593Smuzhiyun #endif
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #define AA_ERROR(fmt, args...) \
48*4882a593Smuzhiyun pr_err_ratelimited("AppArmor: " fmt, ##args)
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* Flag indicating whether initialization completed */
51*4882a593Smuzhiyun extern int apparmor_initialized;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* fn's in lib */
54*4882a593Smuzhiyun const char *skipn_spaces(const char *str, size_t n);
55*4882a593Smuzhiyun char *aa_split_fqname(char *args, char **ns_name);
56*4882a593Smuzhiyun const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
57*4882a593Smuzhiyun size_t *ns_len);
58*4882a593Smuzhiyun void aa_info_message(const char *str);
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* Security blob offsets */
61*4882a593Smuzhiyun extern struct lsm_blob_sizes apparmor_blob_sizes;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /**
64*4882a593Smuzhiyun * aa_strneq - compare null terminated @str to a non null terminated substring
65*4882a593Smuzhiyun * @str: a null terminated string
66*4882a593Smuzhiyun * @sub: a substring, not necessarily null terminated
67*4882a593Smuzhiyun * @len: length of @sub to compare
68*4882a593Smuzhiyun *
69*4882a593Smuzhiyun * The @str string must be full consumed for this to be considered a match
70*4882a593Smuzhiyun */
aa_strneq(const char * str,const char * sub,int len)71*4882a593Smuzhiyun static inline bool aa_strneq(const char *str, const char *sub, int len)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun return !strncmp(str, sub, len) && !str[len];
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /**
77*4882a593Smuzhiyun * aa_dfa_null_transition - step to next state after null character
78*4882a593Smuzhiyun * @dfa: the dfa to match against
79*4882a593Smuzhiyun * @start: the state of the dfa to start matching in
80*4882a593Smuzhiyun *
81*4882a593Smuzhiyun * aa_dfa_null_transition transitions to the next state after a null
82*4882a593Smuzhiyun * character which is not used in standard matching and is only
83*4882a593Smuzhiyun * used to separate pairs.
84*4882a593Smuzhiyun */
aa_dfa_null_transition(struct aa_dfa * dfa,unsigned int start)85*4882a593Smuzhiyun static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
86*4882a593Smuzhiyun unsigned int start)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun /* the null transition only needs the string's null terminator byte */
89*4882a593Smuzhiyun return aa_dfa_next(dfa, start, 0);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
path_mediated_fs(struct dentry * dentry)92*4882a593Smuzhiyun static inline bool path_mediated_fs(struct dentry *dentry)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun return !(dentry->d_sb->s_flags & SB_NOUSER);
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun struct counted_str {
99*4882a593Smuzhiyun struct kref count;
100*4882a593Smuzhiyun char name[];
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun #define str_to_counted(str) \
104*4882a593Smuzhiyun ((struct counted_str *)(str - offsetof(struct counted_str, name)))
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun #define __counted /* atm just a notation */
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun void aa_str_kref(struct kref *kref);
109*4882a593Smuzhiyun char *aa_str_alloc(int size, gfp_t gfp);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun
aa_get_str(__counted char * str)112*4882a593Smuzhiyun static inline __counted char *aa_get_str(__counted char *str)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun if (str)
115*4882a593Smuzhiyun kref_get(&(str_to_counted(str)->count));
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun return str;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
aa_put_str(__counted char * str)120*4882a593Smuzhiyun static inline void aa_put_str(__counted char *str)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun if (str)
123*4882a593Smuzhiyun kref_put(&str_to_counted(str)->count, aa_str_kref);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* struct aa_policy - common part of both namespaces and profiles
128*4882a593Smuzhiyun * @name: name of the object
129*4882a593Smuzhiyun * @hname - The hierarchical name
130*4882a593Smuzhiyun * @list: list policy object is on
131*4882a593Smuzhiyun * @profiles: head of the profiles list contained in the object
132*4882a593Smuzhiyun */
133*4882a593Smuzhiyun struct aa_policy {
134*4882a593Smuzhiyun const char *name;
135*4882a593Smuzhiyun __counted char *hname;
136*4882a593Smuzhiyun struct list_head list;
137*4882a593Smuzhiyun struct list_head profiles;
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun /**
141*4882a593Smuzhiyun * basename - find the last component of an hname
142*4882a593Smuzhiyun * @name: hname to find the base profile name component of (NOT NULL)
143*4882a593Smuzhiyun *
144*4882a593Smuzhiyun * Returns: the tail (base profile name) name component of an hname
145*4882a593Smuzhiyun */
basename(const char * hname)146*4882a593Smuzhiyun static inline const char *basename(const char *hname)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun char *split;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun hname = strim((char *)hname);
151*4882a593Smuzhiyun for (split = strstr(hname, "//"); split; split = strstr(hname, "//"))
152*4882a593Smuzhiyun hname = split + 2;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun return hname;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /**
158*4882a593Smuzhiyun * __policy_find - find a policy by @name on a policy list
159*4882a593Smuzhiyun * @head: list to search (NOT NULL)
160*4882a593Smuzhiyun * @name: name to search for (NOT NULL)
161*4882a593Smuzhiyun *
162*4882a593Smuzhiyun * Requires: rcu_read_lock be held
163*4882a593Smuzhiyun *
164*4882a593Smuzhiyun * Returns: unrefcounted policy that match @name or NULL if not found
165*4882a593Smuzhiyun */
__policy_find(struct list_head * head,const char * name)166*4882a593Smuzhiyun static inline struct aa_policy *__policy_find(struct list_head *head,
167*4882a593Smuzhiyun const char *name)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun struct aa_policy *policy;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun list_for_each_entry_rcu(policy, head, list) {
172*4882a593Smuzhiyun if (!strcmp(policy->name, name))
173*4882a593Smuzhiyun return policy;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun return NULL;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /**
179*4882a593Smuzhiyun * __policy_strn_find - find a policy that's name matches @len chars of @str
180*4882a593Smuzhiyun * @head: list to search (NOT NULL)
181*4882a593Smuzhiyun * @str: string to search for (NOT NULL)
182*4882a593Smuzhiyun * @len: length of match required
183*4882a593Smuzhiyun *
184*4882a593Smuzhiyun * Requires: rcu_read_lock be held
185*4882a593Smuzhiyun *
186*4882a593Smuzhiyun * Returns: unrefcounted policy that match @str or NULL if not found
187*4882a593Smuzhiyun *
188*4882a593Smuzhiyun * if @len == strlen(@strlen) then this is equiv to __policy_find
189*4882a593Smuzhiyun * other wise it allows searching for policy by a partial match of name
190*4882a593Smuzhiyun */
__policy_strn_find(struct list_head * head,const char * str,int len)191*4882a593Smuzhiyun static inline struct aa_policy *__policy_strn_find(struct list_head *head,
192*4882a593Smuzhiyun const char *str, int len)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun struct aa_policy *policy;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun list_for_each_entry_rcu(policy, head, list) {
197*4882a593Smuzhiyun if (aa_strneq(policy->name, str, len))
198*4882a593Smuzhiyun return policy;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun return NULL;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun bool aa_policy_init(struct aa_policy *policy, const char *prefix,
205*4882a593Smuzhiyun const char *name, gfp_t gfp);
206*4882a593Smuzhiyun void aa_policy_destroy(struct aa_policy *policy);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun /*
210*4882a593Smuzhiyun * fn_label_build - abstract out the build of a label transition
211*4882a593Smuzhiyun * @L: label the transition is being computed for
212*4882a593Smuzhiyun * @P: profile parameter derived from L by this macro, can be passed to FN
213*4882a593Smuzhiyun * @GFP: memory allocation type to use
214*4882a593Smuzhiyun * @FN: fn to call for each profile transition. @P is set to the profile
215*4882a593Smuzhiyun *
216*4882a593Smuzhiyun * Returns: new label on success
217*4882a593Smuzhiyun * ERR_PTR if build @FN fails
218*4882a593Smuzhiyun * NULL if label_build fails due to low memory conditions
219*4882a593Smuzhiyun *
220*4882a593Smuzhiyun * @FN must return a label or ERR_PTR on failure. NULL is not allowed
221*4882a593Smuzhiyun */
222*4882a593Smuzhiyun #define fn_label_build(L, P, GFP, FN) \
223*4882a593Smuzhiyun ({ \
224*4882a593Smuzhiyun __label__ __cleanup, __done; \
225*4882a593Smuzhiyun struct aa_label *__new_; \
226*4882a593Smuzhiyun \
227*4882a593Smuzhiyun if ((L)->size > 1) { \
228*4882a593Smuzhiyun /* TODO: add cache of transitions already done */ \
229*4882a593Smuzhiyun struct label_it __i; \
230*4882a593Smuzhiyun int __j, __k, __count; \
231*4882a593Smuzhiyun DEFINE_VEC(label, __lvec); \
232*4882a593Smuzhiyun DEFINE_VEC(profile, __pvec); \
233*4882a593Smuzhiyun if (vec_setup(label, __lvec, (L)->size, (GFP))) { \
234*4882a593Smuzhiyun __new_ = NULL; \
235*4882a593Smuzhiyun goto __done; \
236*4882a593Smuzhiyun } \
237*4882a593Smuzhiyun __j = 0; \
238*4882a593Smuzhiyun label_for_each(__i, (L), (P)) { \
239*4882a593Smuzhiyun __new_ = (FN); \
240*4882a593Smuzhiyun AA_BUG(!__new_); \
241*4882a593Smuzhiyun if (IS_ERR(__new_)) \
242*4882a593Smuzhiyun goto __cleanup; \
243*4882a593Smuzhiyun __lvec[__j++] = __new_; \
244*4882a593Smuzhiyun } \
245*4882a593Smuzhiyun for (__j = __count = 0; __j < (L)->size; __j++) \
246*4882a593Smuzhiyun __count += __lvec[__j]->size; \
247*4882a593Smuzhiyun if (!vec_setup(profile, __pvec, __count, (GFP))) { \
248*4882a593Smuzhiyun for (__j = __k = 0; __j < (L)->size; __j++) { \
249*4882a593Smuzhiyun label_for_each(__i, __lvec[__j], (P)) \
250*4882a593Smuzhiyun __pvec[__k++] = aa_get_profile(P); \
251*4882a593Smuzhiyun } \
252*4882a593Smuzhiyun __count -= aa_vec_unique(__pvec, __count, 0); \
253*4882a593Smuzhiyun if (__count > 1) { \
254*4882a593Smuzhiyun __new_ = aa_vec_find_or_create_label(__pvec,\
255*4882a593Smuzhiyun __count, (GFP)); \
256*4882a593Smuzhiyun /* only fails if out of Mem */ \
257*4882a593Smuzhiyun if (!__new_) \
258*4882a593Smuzhiyun __new_ = NULL; \
259*4882a593Smuzhiyun } else \
260*4882a593Smuzhiyun __new_ = aa_get_label(&__pvec[0]->label); \
261*4882a593Smuzhiyun vec_cleanup(profile, __pvec, __count); \
262*4882a593Smuzhiyun } else \
263*4882a593Smuzhiyun __new_ = NULL; \
264*4882a593Smuzhiyun __cleanup: \
265*4882a593Smuzhiyun vec_cleanup(label, __lvec, (L)->size); \
266*4882a593Smuzhiyun } else { \
267*4882a593Smuzhiyun (P) = labels_profile(L); \
268*4882a593Smuzhiyun __new_ = (FN); \
269*4882a593Smuzhiyun } \
270*4882a593Smuzhiyun __done: \
271*4882a593Smuzhiyun if (!__new_) \
272*4882a593Smuzhiyun AA_DEBUG("label build failed\n"); \
273*4882a593Smuzhiyun (__new_); \
274*4882a593Smuzhiyun })
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun #define __fn_build_in_ns(NS, P, NS_FN, OTHER_FN) \
278*4882a593Smuzhiyun ({ \
279*4882a593Smuzhiyun struct aa_label *__new; \
280*4882a593Smuzhiyun if ((P)->ns != (NS)) \
281*4882a593Smuzhiyun __new = (OTHER_FN); \
282*4882a593Smuzhiyun else \
283*4882a593Smuzhiyun __new = (NS_FN); \
284*4882a593Smuzhiyun (__new); \
285*4882a593Smuzhiyun })
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun #define fn_label_build_in_ns(L, P, GFP, NS_FN, OTHER_FN) \
288*4882a593Smuzhiyun ({ \
289*4882a593Smuzhiyun fn_label_build((L), (P), (GFP), \
290*4882a593Smuzhiyun __fn_build_in_ns(labels_ns(L), (P), (NS_FN), (OTHER_FN))); \
291*4882a593Smuzhiyun })
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun #endif /* __AA_LIB_H */
294