xref: /linux-6.15/security/apparmor/include/lib.h (revision 75535669)
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