1b886d83cSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
212557dcbSJohn Johansen /*
312557dcbSJohn Johansen * AppArmor security module
412557dcbSJohn Johansen *
512557dcbSJohn Johansen * This file contains AppArmor lib definitions
612557dcbSJohn Johansen *
712557dcbSJohn Johansen * 2017 Canonical Ltd.
812557dcbSJohn Johansen */
912557dcbSJohn Johansen
1012557dcbSJohn Johansen #ifndef __AA_LIB_H
1112557dcbSJohn Johansen #define __AA_LIB_H
1212557dcbSJohn Johansen
1312557dcbSJohn Johansen #include <linux/slab.h>
1412557dcbSJohn Johansen #include <linux/fs.h>
15bbd3662aSCasey Schaufler #include <linux/lsm_hooks.h>
1612557dcbSJohn Johansen
1712557dcbSJohn Johansen #include "match.h"
1812557dcbSJohn Johansen
19*98b824ffSJohn Johansen extern struct aa_dfa *stacksplitdfa;
20*98b824ffSJohn Johansen
2112557dcbSJohn Johansen /*
2212557dcbSJohn Johansen * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
2312557dcbSJohn Johansen * which is not related to profile accesses.
2412557dcbSJohn Johansen */
2512557dcbSJohn Johansen
26680cd62eSJohn Johansen #define DEBUG_ON (aa_g_debug)
27511f7b5bSJohn Johansen /*
28511f7b5bSJohn Johansen * split individual debug cases out in preparation for finer grained
29511f7b5bSJohn Johansen * debug controls in the future.
30511f7b5bSJohn Johansen */
31511f7b5bSJohn Johansen #define AA_DEBUG_LABEL DEBUG_ON
32680cd62eSJohn Johansen #define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args)
3312557dcbSJohn Johansen #define AA_DEBUG(fmt, args...) \
3412557dcbSJohn Johansen do { \
35680cd62eSJohn Johansen if (DEBUG_ON) \
3612557dcbSJohn Johansen pr_debug_ratelimited("AppArmor: " fmt, ##args); \
3712557dcbSJohn Johansen } while (0)
3812557dcbSJohn Johansen
39680cd62eSJohn Johansen #define AA_WARN(X) WARN((X), "APPARMOR WARN %s: %s\n", __func__, #X)
40680cd62eSJohn Johansen
414d47fbbeSJohn Johansen #define AA_BUG(X, args...) \
424d47fbbeSJohn Johansen do { \
434d47fbbeSJohn Johansen _Pragma("GCC diagnostic ignored \"-Wformat-zero-length\""); \
444d47fbbeSJohn Johansen AA_BUG_FMT((X), "" args); \
454d47fbbeSJohn Johansen _Pragma("GCC diagnostic warning \"-Wformat-zero-length\""); \
464d47fbbeSJohn Johansen } while (0)
47680cd62eSJohn Johansen #ifdef CONFIG_SECURITY_APPARMOR_DEBUG_ASSERTS
48680cd62eSJohn Johansen #define AA_BUG_FMT(X, fmt, args...) \
49680cd62eSJohn Johansen WARN((X), "AppArmor WARN %s: (" #X "): " fmt, __func__, ##args)
50680cd62eSJohn Johansen #else
51c75ea024SArnd Bergmann #define AA_BUG_FMT(X, fmt, args...) no_printk(fmt, ##args)
52680cd62eSJohn Johansen #endif
53680cd62eSJohn Johansen
5412557dcbSJohn Johansen #define AA_ERROR(fmt, args...) \
5512557dcbSJohn Johansen pr_err_ratelimited("AppArmor: " fmt, ##args)
5612557dcbSJohn Johansen
5712557dcbSJohn Johansen /* Flag indicating whether initialization completed */
58545de8feSJohn Johansen extern int apparmor_initialized;
5912557dcbSJohn Johansen
6012557dcbSJohn Johansen /* fn's in lib */
61b91deb9dSJohn Johansen const char *skipn_spaces(const char *str, size_t n);
623b0aaf58SJohn Johansen const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
633b0aaf58SJohn Johansen size_t *ns_len);
6412557dcbSJohn Johansen void aa_info_message(const char *str);
6512557dcbSJohn Johansen
66bbd3662aSCasey Schaufler /* Security blob offsets */
67bbd3662aSCasey Schaufler extern struct lsm_blob_sizes apparmor_blob_sizes;
68bbd3662aSCasey Schaufler
6912557dcbSJohn Johansen /**
7012557dcbSJohn Johansen * aa_strneq - compare null terminated @str to a non null terminated substring
7112557dcbSJohn Johansen * @str: a null terminated string
7212557dcbSJohn Johansen * @sub: a substring, not necessarily null terminated
7312557dcbSJohn Johansen * @len: length of @sub to compare
7412557dcbSJohn Johansen *
7512557dcbSJohn Johansen * The @str string must be full consumed for this to be considered a match
7612557dcbSJohn Johansen */
aa_strneq(const char * str,const char * sub,int len)7712557dcbSJohn Johansen static inline bool aa_strneq(const char *str, const char *sub, int len)
7812557dcbSJohn Johansen {
7912557dcbSJohn Johansen return !strncmp(str, sub, len) && !str[len];
8012557dcbSJohn Johansen }
8112557dcbSJohn Johansen
8212557dcbSJohn Johansen /**
8312557dcbSJohn Johansen * aa_dfa_null_transition - step to next state after null character
8412557dcbSJohn Johansen * @dfa: the dfa to match against
8512557dcbSJohn Johansen * @start: the state of the dfa to start matching in
8612557dcbSJohn Johansen *
8712557dcbSJohn Johansen * aa_dfa_null_transition transitions to the next state after a null
8812557dcbSJohn Johansen * character which is not used in standard matching and is only
8912557dcbSJohn Johansen * used to separate pairs.
9012557dcbSJohn Johansen */
aa_dfa_null_transition(struct aa_dfa * dfa,aa_state_t start)9133fc95d8SJohn Johansen static inline aa_state_t aa_dfa_null_transition(struct aa_dfa *dfa,
9233fc95d8SJohn Johansen aa_state_t start)
9312557dcbSJohn Johansen {
9412557dcbSJohn Johansen /* the null transition only needs the string's null terminator byte */
9512557dcbSJohn Johansen return aa_dfa_next(dfa, start, 0);
9612557dcbSJohn Johansen }
9712557dcbSJohn Johansen
path_mediated_fs(struct dentry * dentry)98efeee83aSJohn Johansen static inline bool path_mediated_fs(struct dentry *dentry)
9912557dcbSJohn Johansen {
1001751e8a6SLinus Torvalds return !(dentry->d_sb->s_flags & SB_NOUSER);
10112557dcbSJohn Johansen }
10212557dcbSJohn Johansen
10390917d5bSJohn Johansen struct aa_str_table {
10490917d5bSJohn Johansen int size;
10590917d5bSJohn Johansen char **table;
10690917d5bSJohn Johansen };
10790917d5bSJohn Johansen
10890917d5bSJohn Johansen void aa_free_str_table(struct aa_str_table *table);
109a1bd627bSJohn Johansen
110a1bd627bSJohn Johansen struct counted_str {
111a1bd627bSJohn Johansen struct kref count;
112a1bd627bSJohn Johansen char name[];
113a1bd627bSJohn Johansen };
114a1bd627bSJohn Johansen
115a1bd627bSJohn Johansen #define str_to_counted(str) \
116a1bd627bSJohn Johansen ((struct counted_str *)(str - offsetof(struct counted_str, name)))
117a1bd627bSJohn Johansen
118a1bd627bSJohn Johansen #define __counted /* atm just a notation */
119a1bd627bSJohn Johansen
120a1bd627bSJohn Johansen void aa_str_kref(struct kref *kref);
121a1bd627bSJohn Johansen char *aa_str_alloc(int size, gfp_t gfp);
122a1bd627bSJohn Johansen
123a1bd627bSJohn Johansen
aa_get_str(__counted char * str)124a1bd627bSJohn Johansen static inline __counted char *aa_get_str(__counted char *str)
125a1bd627bSJohn Johansen {
126a1bd627bSJohn Johansen if (str)
127a1bd627bSJohn Johansen kref_get(&(str_to_counted(str)->count));
128a1bd627bSJohn Johansen
129a1bd627bSJohn Johansen return str;
130a1bd627bSJohn Johansen }
131a1bd627bSJohn Johansen
aa_put_str(__counted char * str)132a1bd627bSJohn Johansen static inline void aa_put_str(__counted char *str)
133a1bd627bSJohn Johansen {
134a1bd627bSJohn Johansen if (str)
135a1bd627bSJohn Johansen kref_put(&str_to_counted(str)->count, aa_str_kref);
136a1bd627bSJohn Johansen }
137a1bd627bSJohn Johansen
138a1bd627bSJohn Johansen
139fe6bb31fSJohn Johansen /* struct aa_policy - common part of both namespaces and profiles
140fe6bb31fSJohn Johansen * @name: name of the object
141fe6bb31fSJohn Johansen * @hname - The hierarchical name
142fe6bb31fSJohn Johansen * @list: list policy object is on
143fe6bb31fSJohn Johansen * @profiles: head of the profiles list contained in the object
144fe6bb31fSJohn Johansen */
145fe6bb31fSJohn Johansen struct aa_policy {
146bbe4a7c8SJohn Johansen const char *name;
147a1bd627bSJohn Johansen __counted char *hname;
148fe6bb31fSJohn Johansen struct list_head list;
149fe6bb31fSJohn Johansen struct list_head profiles;
150fe6bb31fSJohn Johansen };
151fe6bb31fSJohn Johansen
152fe6bb31fSJohn Johansen /**
1536e474e30SJohn Johansen * basename - find the last component of an hname
154fe6bb31fSJohn Johansen * @name: hname to find the base profile name component of (NOT NULL)
155fe6bb31fSJohn Johansen *
156fe6bb31fSJohn Johansen * Returns: the tail (base profile name) name component of an hname
157fe6bb31fSJohn Johansen */
basename(const char * hname)1586e474e30SJohn Johansen static inline const char *basename(const char *hname)
159fe6bb31fSJohn Johansen {
160fe6bb31fSJohn Johansen char *split;
161fe6bb31fSJohn Johansen
162fe6bb31fSJohn Johansen hname = strim((char *)hname);
163fe6bb31fSJohn Johansen for (split = strstr(hname, "//"); split; split = strstr(hname, "//"))
164fe6bb31fSJohn Johansen hname = split + 2;
165fe6bb31fSJohn Johansen
166fe6bb31fSJohn Johansen return hname;
167fe6bb31fSJohn Johansen }
168fe6bb31fSJohn Johansen
169fe6bb31fSJohn Johansen /**
170fe6bb31fSJohn Johansen * __policy_find - find a policy by @name on a policy list
171fe6bb31fSJohn Johansen * @head: list to search (NOT NULL)
172fe6bb31fSJohn Johansen * @name: name to search for (NOT NULL)
173fe6bb31fSJohn Johansen *
174fe6bb31fSJohn Johansen * Requires: rcu_read_lock be held
175fe6bb31fSJohn Johansen *
176fe6bb31fSJohn Johansen * Returns: unrefcounted policy that match @name or NULL if not found
177fe6bb31fSJohn Johansen */
__policy_find(struct list_head * head,const char * name)178fe6bb31fSJohn Johansen static inline struct aa_policy *__policy_find(struct list_head *head,
179fe6bb31fSJohn Johansen const char *name)
180fe6bb31fSJohn Johansen {
181fe6bb31fSJohn Johansen struct aa_policy *policy;
182fe6bb31fSJohn Johansen
183fe6bb31fSJohn Johansen list_for_each_entry_rcu(policy, head, list) {
184fe6bb31fSJohn Johansen if (!strcmp(policy->name, name))
185fe6bb31fSJohn Johansen return policy;
186fe6bb31fSJohn Johansen }
187fe6bb31fSJohn Johansen return NULL;
188fe6bb31fSJohn Johansen }
189fe6bb31fSJohn Johansen
190fe6bb31fSJohn Johansen /**
191fe6bb31fSJohn Johansen * __policy_strn_find - find a policy that's name matches @len chars of @str
192fe6bb31fSJohn Johansen * @head: list to search (NOT NULL)
193fe6bb31fSJohn Johansen * @str: string to search for (NOT NULL)
194fe6bb31fSJohn Johansen * @len: length of match required
195fe6bb31fSJohn Johansen *
196fe6bb31fSJohn Johansen * Requires: rcu_read_lock be held
197fe6bb31fSJohn Johansen *
198fe6bb31fSJohn Johansen * Returns: unrefcounted policy that match @str or NULL if not found
199fe6bb31fSJohn Johansen *
200fe6bb31fSJohn Johansen * if @len == strlen(@strlen) then this is equiv to __policy_find
201fe6bb31fSJohn Johansen * other wise it allows searching for policy by a partial match of name
202fe6bb31fSJohn Johansen */
__policy_strn_find(struct list_head * head,const char * str,int len)203fe6bb31fSJohn Johansen static inline struct aa_policy *__policy_strn_find(struct list_head *head,
204fe6bb31fSJohn Johansen const char *str, int len)
205fe6bb31fSJohn Johansen {
206fe6bb31fSJohn Johansen struct aa_policy *policy;
207fe6bb31fSJohn Johansen
208fe6bb31fSJohn Johansen list_for_each_entry_rcu(policy, head, list) {
209fe6bb31fSJohn Johansen if (aa_strneq(policy->name, str, len))
210fe6bb31fSJohn Johansen return policy;
211fe6bb31fSJohn Johansen }
212fe6bb31fSJohn Johansen
213fe6bb31fSJohn Johansen return NULL;
214fe6bb31fSJohn Johansen }
215fe6bb31fSJohn Johansen
216fe6bb31fSJohn Johansen bool aa_policy_init(struct aa_policy *policy, const char *prefix,
217d102d895SJohn Johansen const char *name, gfp_t gfp);
218fe6bb31fSJohn Johansen void aa_policy_destroy(struct aa_policy *policy);
219fe6bb31fSJohn Johansen
22093c98a48SJohn Johansen
22193c98a48SJohn Johansen /*
22293c98a48SJohn Johansen * fn_label_build - abstract out the build of a label transition
22393c98a48SJohn Johansen * @L: label the transition is being computed for
22493c98a48SJohn Johansen * @P: profile parameter derived from L by this macro, can be passed to FN
22593c98a48SJohn Johansen * @GFP: memory allocation type to use
22693c98a48SJohn Johansen * @FN: fn to call for each profile transition. @P is set to the profile
22793c98a48SJohn Johansen *
22893c98a48SJohn Johansen * Returns: new label on success
22993c98a48SJohn Johansen * ERR_PTR if build @FN fails
23093c98a48SJohn Johansen * NULL if label_build fails due to low memory conditions
23193c98a48SJohn Johansen *
23293c98a48SJohn Johansen * @FN must return a label or ERR_PTR on failure. NULL is not allowed
23393c98a48SJohn Johansen */
23493c98a48SJohn Johansen #define fn_label_build(L, P, GFP, FN) \
23593c98a48SJohn Johansen ({ \
2369a1f37ebSPeter Zijlstra __label__ __do_cleanup, __done; \
23793c98a48SJohn Johansen struct aa_label *__new_; \
23893c98a48SJohn Johansen \
23993c98a48SJohn Johansen if ((L)->size > 1) { \
24093c98a48SJohn Johansen /* TODO: add cache of transitions already done */ \
24193c98a48SJohn Johansen struct label_it __i; \
24293c98a48SJohn Johansen int __j, __k, __count; \
24393c98a48SJohn Johansen DEFINE_VEC(label, __lvec); \
24493c98a48SJohn Johansen DEFINE_VEC(profile, __pvec); \
24593c98a48SJohn Johansen if (vec_setup(label, __lvec, (L)->size, (GFP))) { \
24693c98a48SJohn Johansen __new_ = NULL; \
24793c98a48SJohn Johansen goto __done; \
24893c98a48SJohn Johansen } \
24993c98a48SJohn Johansen __j = 0; \
25093c98a48SJohn Johansen label_for_each(__i, (L), (P)) { \
25193c98a48SJohn Johansen __new_ = (FN); \
25293c98a48SJohn Johansen AA_BUG(!__new_); \
25393c98a48SJohn Johansen if (IS_ERR(__new_)) \
2549a1f37ebSPeter Zijlstra goto __do_cleanup; \
25593c98a48SJohn Johansen __lvec[__j++] = __new_; \
25693c98a48SJohn Johansen } \
25793c98a48SJohn Johansen for (__j = __count = 0; __j < (L)->size; __j++) \
25893c98a48SJohn Johansen __count += __lvec[__j]->size; \
25993c98a48SJohn Johansen if (!vec_setup(profile, __pvec, __count, (GFP))) { \
26093c98a48SJohn Johansen for (__j = __k = 0; __j < (L)->size; __j++) { \
26193c98a48SJohn Johansen label_for_each(__i, __lvec[__j], (P)) \
26293c98a48SJohn Johansen __pvec[__k++] = aa_get_profile(P); \
26393c98a48SJohn Johansen } \
26493c98a48SJohn Johansen __count -= aa_vec_unique(__pvec, __count, 0); \
26593c98a48SJohn Johansen if (__count > 1) { \
26693c98a48SJohn Johansen __new_ = aa_vec_find_or_create_label(__pvec,\
26793c98a48SJohn Johansen __count, (GFP)); \
26893c98a48SJohn Johansen /* only fails if out of Mem */ \
26993c98a48SJohn Johansen if (!__new_) \
27093c98a48SJohn Johansen __new_ = NULL; \
27193c98a48SJohn Johansen } else \
27293c98a48SJohn Johansen __new_ = aa_get_label(&__pvec[0]->label); \
27393c98a48SJohn Johansen vec_cleanup(profile, __pvec, __count); \
27493c98a48SJohn Johansen } else \
27593c98a48SJohn Johansen __new_ = NULL; \
2769a1f37ebSPeter Zijlstra __do_cleanup: \
27793c98a48SJohn Johansen vec_cleanup(label, __lvec, (L)->size); \
27893c98a48SJohn Johansen } else { \
27993c98a48SJohn Johansen (P) = labels_profile(L); \
28093c98a48SJohn Johansen __new_ = (FN); \
28193c98a48SJohn Johansen } \
28293c98a48SJohn Johansen __done: \
28393c98a48SJohn Johansen if (!__new_) \
28493c98a48SJohn Johansen AA_DEBUG("label build failed\n"); \
28593c98a48SJohn Johansen (__new_); \
28693c98a48SJohn Johansen })
28793c98a48SJohn Johansen
28893c98a48SJohn Johansen
28993c98a48SJohn Johansen #define __fn_build_in_ns(NS, P, NS_FN, OTHER_FN) \
29093c98a48SJohn Johansen ({ \
29193c98a48SJohn Johansen struct aa_label *__new; \
29293c98a48SJohn Johansen if ((P)->ns != (NS)) \
29393c98a48SJohn Johansen __new = (OTHER_FN); \
29493c98a48SJohn Johansen else \
29593c98a48SJohn Johansen __new = (NS_FN); \
29693c98a48SJohn Johansen (__new); \
29793c98a48SJohn Johansen })
29893c98a48SJohn Johansen
29993c98a48SJohn Johansen #define fn_label_build_in_ns(L, P, GFP, NS_FN, OTHER_FN) \
30093c98a48SJohn Johansen ({ \
30193c98a48SJohn Johansen fn_label_build((L), (P), (GFP), \
30293c98a48SJohn Johansen __fn_build_in_ns(labels_ns(L), (P), (NS_FN), (OTHER_FN))); \
30393c98a48SJohn Johansen })
30493c98a48SJohn Johansen
30593c98a48SJohn Johansen #endif /* __AA_LIB_H */
306