Loading...
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * AppArmor security module
4 *
5 * This file contains basic common functions used in AppArmor
6 *
7 * Copyright (C) 1998-2008 Novell/SUSE
8 * Copyright 2009-2010 Canonical Ltd.
9 */
10
11#include <linux/ctype.h>
12#include <linux/mm.h>
13#include <linux/slab.h>
14#include <linux/string.h>
15#include <linux/vmalloc.h>
16
17#include "include/audit.h"
18#include "include/apparmor.h"
19#include "include/lib.h"
20#include "include/perms.h"
21#include "include/policy.h"
22
23struct aa_perms nullperms;
24struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
25 .quiet = ALL_PERMS_MASK,
26 .hide = ALL_PERMS_MASK };
27
28/**
29 * aa_free_str_table - free entries str table
30 * @t: the string table to free (MAYBE NULL)
31 */
32void aa_free_str_table(struct aa_str_table *t)
33{
34 int i;
35
36 if (t) {
37 if (!t->table)
38 return;
39
40 for (i = 0; i < t->size; i++)
41 kfree_sensitive(t->table[i]);
42 kfree_sensitive(t->table);
43 t->table = NULL;
44 t->size = 0;
45 }
46}
47
48/**
49 * skipn_spaces - Removes leading whitespace from @str.
50 * @str: The string to be stripped.
51 * @n: length of str to parse, will stop at \0 if encountered before n
52 *
53 * Returns a pointer to the first non-whitespace character in @str.
54 * if all whitespace will return NULL
55 */
56
57const char *skipn_spaces(const char *str, size_t n)
58{
59 for (; n && isspace(*str); --n)
60 ++str;
61 if (n)
62 return (char *)str;
63 return NULL;
64}
65
66const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
67 size_t *ns_len)
68{
69 const char *end = fqname + n;
70 const char *name = skipn_spaces(fqname, n);
71
72 *ns_name = NULL;
73 *ns_len = 0;
74
75 if (!name)
76 return NULL;
77
78 if (name[0] == ':') {
79 char *split = strnchr(&name[1], end - &name[1], ':');
80 *ns_name = skipn_spaces(&name[1], end - &name[1]);
81 if (!*ns_name)
82 return NULL;
83 if (split) {
84 *ns_len = split - *ns_name;
85 if (*ns_len == 0)
86 *ns_name = NULL;
87 split++;
88 if (end - split > 1 && strncmp(split, "//", 2) == 0)
89 split += 2;
90 name = skipn_spaces(split, end - split);
91 } else {
92 /* a ns name without a following profile is allowed */
93 name = NULL;
94 *ns_len = end - *ns_name;
95 }
96 }
97 if (name && *name == 0)
98 name = NULL;
99
100 return name;
101}
102
103/**
104 * aa_info_message - log a none profile related status message
105 * @str: message to log
106 */
107void aa_info_message(const char *str)
108{
109 if (audit_enabled) {
110 DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
111
112 ad.info = str;
113 aa_audit_msg(AUDIT_APPARMOR_STATUS, &ad, NULL);
114 }
115 printk(KERN_INFO "AppArmor: %s\n", str);
116}
117
118__counted char *aa_str_alloc(int size, gfp_t gfp)
119{
120 struct counted_str *str;
121
122 str = kmalloc(struct_size(str, name, size), gfp);
123 if (!str)
124 return NULL;
125
126 kref_init(&str->count);
127 return str->name;
128}
129
130void aa_str_kref(struct kref *kref)
131{
132 kfree(container_of(kref, struct counted_str, count));
133}
134
135
136const char aa_file_perm_chrs[] = "xwracd km l ";
137const char *aa_file_perm_names[] = {
138 "exec",
139 "write",
140 "read",
141 "append",
142
143 "create",
144 "delete",
145 "open",
146 "rename",
147
148 "setattr",
149 "getattr",
150 "setcred",
151 "getcred",
152
153 "chmod",
154 "chown",
155 "chgrp",
156 "lock",
157
158 "mmap",
159 "mprot",
160 "link",
161 "snapshot",
162
163 "unknown",
164 "unknown",
165 "unknown",
166 "unknown",
167
168 "unknown",
169 "unknown",
170 "unknown",
171 "unknown",
172
173 "stack",
174 "change_onexec",
175 "change_profile",
176 "change_hat",
177};
178
179/**
180 * aa_perm_mask_to_str - convert a perm mask to its short string
181 * @str: character buffer to store string in (at least 10 characters)
182 * @str_size: size of the @str buffer
183 * @chrs: NUL-terminated character buffer of permission characters
184 * @mask: permission mask to convert
185 */
186void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
187{
188 unsigned int i, perm = 1;
189 size_t num_chrs = strlen(chrs);
190
191 for (i = 0; i < num_chrs; perm <<= 1, i++) {
192 if (mask & perm) {
193 /* Ensure that one byte is left for NUL-termination */
194 if (WARN_ON_ONCE(str_size <= 1))
195 break;
196
197 *str++ = chrs[i];
198 str_size--;
199 }
200 }
201 *str = '\0';
202}
203
204void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
205 u32 mask)
206{
207 const char *fmt = "%s";
208 unsigned int i, perm = 1;
209 bool prev = false;
210
211 for (i = 0; i < 32; perm <<= 1, i++) {
212 if (mask & perm) {
213 audit_log_format(ab, fmt, names[i]);
214 if (!prev) {
215 prev = true;
216 fmt = " %s";
217 }
218 }
219 }
220}
221
222void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
223 u32 chrsmask, const char * const *names, u32 namesmask)
224{
225 char str[33];
226
227 audit_log_format(ab, "\"");
228 if ((mask & chrsmask) && chrs) {
229 aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
230 mask &= ~chrsmask;
231 audit_log_format(ab, "%s", str);
232 if (mask & namesmask)
233 audit_log_format(ab, " ");
234 }
235 if ((mask & namesmask) && names)
236 aa_audit_perm_names(ab, names, mask & namesmask);
237 audit_log_format(ab, "\"");
238}
239
240/**
241 * aa_apply_modes_to_perms - apply namespace and profile flags to perms
242 * @profile: that perms where computed from
243 * @perms: perms to apply mode modifiers to
244 *
245 * TODO: split into profile and ns based flags for when accumulating perms
246 */
247void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
248{
249 switch (AUDIT_MODE(profile)) {
250 case AUDIT_ALL:
251 perms->audit = ALL_PERMS_MASK;
252 fallthrough;
253 case AUDIT_NOQUIET:
254 perms->quiet = 0;
255 break;
256 case AUDIT_QUIET:
257 perms->audit = 0;
258 fallthrough;
259 case AUDIT_QUIET_DENIED:
260 perms->quiet = ALL_PERMS_MASK;
261 break;
262 }
263
264 if (KILL_MODE(profile))
265 perms->kill = ALL_PERMS_MASK;
266 else if (COMPLAIN_MODE(profile))
267 perms->complain = ALL_PERMS_MASK;
268 else if (USER_MODE(profile))
269 perms->prompt = ALL_PERMS_MASK;
270}
271
272void aa_profile_match_label(struct aa_profile *profile,
273 struct aa_ruleset *rules,
274 struct aa_label *label,
275 int type, u32 request, struct aa_perms *perms)
276{
277 /* TODO: doesn't yet handle extended types */
278 aa_state_t state;
279
280 state = aa_dfa_next(rules->policy->dfa,
281 rules->policy->start[AA_CLASS_LABEL],
282 type);
283 aa_label_match(profile, rules, label, state, false, request, perms);
284}
285
286
287/**
288 * aa_check_perms - do audit mode selection based on perms set
289 * @profile: profile being checked
290 * @perms: perms computed for the request
291 * @request: requested perms
292 * @ad: initialized audit structure (MAY BE NULL if not auditing)
293 * @cb: callback fn for type specific fields (MAY BE NULL)
294 *
295 * Returns: 0 if permission else error code
296 *
297 * Note: profile audit modes need to be set before calling by setting the
298 * perm masks appropriately.
299 *
300 * If not auditing then complain mode is not enabled and the
301 * error code will indicate whether there was an explicit deny
302 * with a positive value.
303 */
304int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
305 u32 request, struct apparmor_audit_data *ad,
306 void (*cb)(struct audit_buffer *, void *))
307{
308 int type, error;
309 u32 denied = request & (~perms->allow | perms->deny);
310
311 if (likely(!denied)) {
312 /* mask off perms that are not being force audited */
313 request &= perms->audit;
314 if (!request || !ad)
315 return 0;
316
317 type = AUDIT_APPARMOR_AUDIT;
318 error = 0;
319 } else {
320 error = -EACCES;
321
322 if (denied & perms->kill)
323 type = AUDIT_APPARMOR_KILL;
324 else if (denied == (denied & perms->complain))
325 type = AUDIT_APPARMOR_ALLOWED;
326 else
327 type = AUDIT_APPARMOR_DENIED;
328
329 if (denied == (denied & perms->hide))
330 error = -ENOENT;
331
332 denied &= ~perms->quiet;
333 if (!ad || !denied)
334 return error;
335 }
336
337 if (ad) {
338 ad->subj_label = &profile->label;
339 ad->request = request;
340 ad->denied = denied;
341 ad->error = error;
342 aa_audit_msg(type, ad, cb);
343 }
344
345 if (type == AUDIT_APPARMOR_ALLOWED)
346 error = 0;
347
348 return error;
349}
350
351
352/**
353 * aa_policy_init - initialize a policy structure
354 * @policy: policy to initialize (NOT NULL)
355 * @prefix: prefix name if any is required. (MAYBE NULL)
356 * @name: name of the policy, init will make a copy of it (NOT NULL)
357 * @gfp: allocation mode
358 *
359 * Note: this fn creates a copy of strings passed in
360 *
361 * Returns: true if policy init successful
362 */
363bool aa_policy_init(struct aa_policy *policy, const char *prefix,
364 const char *name, gfp_t gfp)
365{
366 char *hname;
367
368 /* freed by policy_free */
369 if (prefix) {
370 hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
371 if (hname)
372 sprintf(hname, "%s//%s", prefix, name);
373 } else {
374 hname = aa_str_alloc(strlen(name) + 1, gfp);
375 if (hname)
376 strcpy(hname, name);
377 }
378 if (!hname)
379 return false;
380 policy->hname = hname;
381 /* base.name is a substring of fqname */
382 policy->name = basename(policy->hname);
383 INIT_LIST_HEAD(&policy->list);
384 INIT_LIST_HEAD(&policy->profiles);
385
386 return true;
387}
388
389/**
390 * aa_policy_destroy - free the elements referenced by @policy
391 * @policy: policy that is to have its elements freed (NOT NULL)
392 */
393void aa_policy_destroy(struct aa_policy *policy)
394{
395 AA_BUG(on_list_rcu(&policy->profiles));
396 AA_BUG(on_list_rcu(&policy->list));
397
398 /* don't free name as its a subset of hname */
399 aa_put_str(policy->hname);
400}
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * AppArmor security module
4 *
5 * This file contains basic common functions used in AppArmor
6 *
7 * Copyright (C) 1998-2008 Novell/SUSE
8 * Copyright 2009-2010 Canonical Ltd.
9 */
10
11#include <linux/ctype.h>
12#include <linux/mm.h>
13#include <linux/slab.h>
14#include <linux/string.h>
15#include <linux/vmalloc.h>
16
17#include "include/audit.h"
18#include "include/apparmor.h"
19#include "include/lib.h"
20#include "include/perms.h"
21#include "include/policy.h"
22
23struct aa_perms nullperms;
24struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
25 .quiet = ALL_PERMS_MASK,
26 .hide = ALL_PERMS_MASK };
27
28/**
29 * aa_free_str_table - free entries str table
30 * @str: the string table to free (MAYBE NULL)
31 */
32void aa_free_str_table(struct aa_str_table *t)
33{
34 int i;
35
36 if (t) {
37 if (!t->table)
38 return;
39
40 for (i = 0; i < t->size; i++)
41 kfree_sensitive(t->table[i]);
42 kfree_sensitive(t->table);
43 t->table = NULL;
44 }
45}
46
47/**
48 * aa_split_fqname - split a fqname into a profile and namespace name
49 * @fqname: a full qualified name in namespace profile format (NOT NULL)
50 * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
51 *
52 * Returns: profile name or NULL if one is not specified
53 *
54 * Split a namespace name from a profile name (see policy.c for naming
55 * description). If a portion of the name is missing it returns NULL for
56 * that portion.
57 *
58 * NOTE: may modify the @fqname string. The pointers returned point
59 * into the @fqname string.
60 */
61char *aa_split_fqname(char *fqname, char **ns_name)
62{
63 char *name = strim(fqname);
64
65 *ns_name = NULL;
66 if (name[0] == ':') {
67 char *split = strchr(&name[1], ':');
68 *ns_name = skip_spaces(&name[1]);
69 if (split) {
70 /* overwrite ':' with \0 */
71 *split++ = 0;
72 if (strncmp(split, "//", 2) == 0)
73 split += 2;
74 name = skip_spaces(split);
75 } else
76 /* a ns name without a following profile is allowed */
77 name = NULL;
78 }
79 if (name && *name == 0)
80 name = NULL;
81
82 return name;
83}
84
85/**
86 * skipn_spaces - Removes leading whitespace from @str.
87 * @str: The string to be stripped.
88 *
89 * Returns a pointer to the first non-whitespace character in @str.
90 * if all whitespace will return NULL
91 */
92
93const char *skipn_spaces(const char *str, size_t n)
94{
95 for (; n && isspace(*str); --n)
96 ++str;
97 if (n)
98 return (char *)str;
99 return NULL;
100}
101
102const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
103 size_t *ns_len)
104{
105 const char *end = fqname + n;
106 const char *name = skipn_spaces(fqname, n);
107
108 *ns_name = NULL;
109 *ns_len = 0;
110
111 if (!name)
112 return NULL;
113
114 if (name[0] == ':') {
115 char *split = strnchr(&name[1], end - &name[1], ':');
116 *ns_name = skipn_spaces(&name[1], end - &name[1]);
117 if (!*ns_name)
118 return NULL;
119 if (split) {
120 *ns_len = split - *ns_name;
121 if (*ns_len == 0)
122 *ns_name = NULL;
123 split++;
124 if (end - split > 1 && strncmp(split, "//", 2) == 0)
125 split += 2;
126 name = skipn_spaces(split, end - split);
127 } else {
128 /* a ns name without a following profile is allowed */
129 name = NULL;
130 *ns_len = end - *ns_name;
131 }
132 }
133 if (name && *name == 0)
134 name = NULL;
135
136 return name;
137}
138
139/**
140 * aa_info_message - log a none profile related status message
141 * @str: message to log
142 */
143void aa_info_message(const char *str)
144{
145 if (audit_enabled) {
146 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
147
148 aad(&sa)->info = str;
149 aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
150 }
151 printk(KERN_INFO "AppArmor: %s\n", str);
152}
153
154__counted char *aa_str_alloc(int size, gfp_t gfp)
155{
156 struct counted_str *str;
157
158 str = kmalloc(struct_size(str, name, size), gfp);
159 if (!str)
160 return NULL;
161
162 kref_init(&str->count);
163 return str->name;
164}
165
166void aa_str_kref(struct kref *kref)
167{
168 kfree(container_of(kref, struct counted_str, count));
169}
170
171
172const char aa_file_perm_chrs[] = "xwracd km l ";
173const char *aa_file_perm_names[] = {
174 "exec",
175 "write",
176 "read",
177 "append",
178
179 "create",
180 "delete",
181 "open",
182 "rename",
183
184 "setattr",
185 "getattr",
186 "setcred",
187 "getcred",
188
189 "chmod",
190 "chown",
191 "chgrp",
192 "lock",
193
194 "mmap",
195 "mprot",
196 "link",
197 "snapshot",
198
199 "unknown",
200 "unknown",
201 "unknown",
202 "unknown",
203
204 "unknown",
205 "unknown",
206 "unknown",
207 "unknown",
208
209 "stack",
210 "change_onexec",
211 "change_profile",
212 "change_hat",
213};
214
215/**
216 * aa_perm_mask_to_str - convert a perm mask to its short string
217 * @str: character buffer to store string in (at least 10 characters)
218 * @str_size: size of the @str buffer
219 * @chrs: NUL-terminated character buffer of permission characters
220 * @mask: permission mask to convert
221 */
222void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
223{
224 unsigned int i, perm = 1;
225 size_t num_chrs = strlen(chrs);
226
227 for (i = 0; i < num_chrs; perm <<= 1, i++) {
228 if (mask & perm) {
229 /* Ensure that one byte is left for NUL-termination */
230 if (WARN_ON_ONCE(str_size <= 1))
231 break;
232
233 *str++ = chrs[i];
234 str_size--;
235 }
236 }
237 *str = '\0';
238}
239
240void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
241 u32 mask)
242{
243 const char *fmt = "%s";
244 unsigned int i, perm = 1;
245 bool prev = false;
246
247 for (i = 0; i < 32; perm <<= 1, i++) {
248 if (mask & perm) {
249 audit_log_format(ab, fmt, names[i]);
250 if (!prev) {
251 prev = true;
252 fmt = " %s";
253 }
254 }
255 }
256}
257
258void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
259 u32 chrsmask, const char * const *names, u32 namesmask)
260{
261 char str[33];
262
263 audit_log_format(ab, "\"");
264 if ((mask & chrsmask) && chrs) {
265 aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
266 mask &= ~chrsmask;
267 audit_log_format(ab, "%s", str);
268 if (mask & namesmask)
269 audit_log_format(ab, " ");
270 }
271 if ((mask & namesmask) && names)
272 aa_audit_perm_names(ab, names, mask & namesmask);
273 audit_log_format(ab, "\"");
274}
275
276/**
277 * aa_audit_perms_cb - generic callback fn for auditing perms
278 * @ab: audit buffer (NOT NULL)
279 * @va: audit struct to audit values of (NOT NULL)
280 */
281static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
282{
283 struct common_audit_data *sa = va;
284
285 if (aad(sa)->request) {
286 audit_log_format(ab, " requested_mask=");
287 aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
288 PERMS_CHRS_MASK, aa_file_perm_names,
289 PERMS_NAMES_MASK);
290 }
291 if (aad(sa)->denied) {
292 audit_log_format(ab, "denied_mask=");
293 aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
294 PERMS_CHRS_MASK, aa_file_perm_names,
295 PERMS_NAMES_MASK);
296 }
297 audit_log_format(ab, " peer=");
298 aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
299 FLAGS_NONE, GFP_ATOMIC);
300}
301
302/**
303 * aa_apply_modes_to_perms - apply namespace and profile flags to perms
304 * @profile: that perms where computed from
305 * @perms: perms to apply mode modifiers to
306 *
307 * TODO: split into profile and ns based flags for when accumulating perms
308 */
309void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
310{
311 switch (AUDIT_MODE(profile)) {
312 case AUDIT_ALL:
313 perms->audit = ALL_PERMS_MASK;
314 fallthrough;
315 case AUDIT_NOQUIET:
316 perms->quiet = 0;
317 break;
318 case AUDIT_QUIET:
319 perms->audit = 0;
320 fallthrough;
321 case AUDIT_QUIET_DENIED:
322 perms->quiet = ALL_PERMS_MASK;
323 break;
324 }
325
326 if (KILL_MODE(profile))
327 perms->kill = ALL_PERMS_MASK;
328 else if (COMPLAIN_MODE(profile))
329 perms->complain = ALL_PERMS_MASK;
330 else if (USER_MODE(profile))
331 perms->prompt = ALL_PERMS_MASK;
332}
333
334void aa_profile_match_label(struct aa_profile *profile,
335 struct aa_ruleset *rules,
336 struct aa_label *label,
337 int type, u32 request, struct aa_perms *perms)
338{
339 /* TODO: doesn't yet handle extended types */
340 aa_state_t state;
341
342 state = aa_dfa_next(rules->policy.dfa,
343 rules->policy.start[AA_CLASS_LABEL],
344 type);
345 aa_label_match(profile, rules, label, state, false, request, perms);
346}
347
348
349/* currently unused */
350int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
351 u32 request, int type, u32 *deny,
352 struct common_audit_data *sa)
353{
354 struct aa_ruleset *rules = list_first_entry(&profile->rules,
355 typeof(*rules), list);
356 struct aa_perms perms;
357
358 aad(sa)->label = &profile->label;
359 aad(sa)->peer = &target->label;
360 aad(sa)->request = request;
361
362 aa_profile_match_label(profile, rules, &target->label, type, request,
363 &perms);
364 aa_apply_modes_to_perms(profile, &perms);
365 *deny |= request & perms.deny;
366 return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
367}
368
369/**
370 * aa_check_perms - do audit mode selection based on perms set
371 * @profile: profile being checked
372 * @perms: perms computed for the request
373 * @request: requested perms
374 * @deny: Returns: explicit deny set
375 * @sa: initialized audit structure (MAY BE NULL if not auditing)
376 * @cb: callback fn for type specific fields (MAY BE NULL)
377 *
378 * Returns: 0 if permission else error code
379 *
380 * Note: profile audit modes need to be set before calling by setting the
381 * perm masks appropriately.
382 *
383 * If not auditing then complain mode is not enabled and the
384 * error code will indicate whether there was an explicit deny
385 * with a positive value.
386 */
387int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
388 u32 request, struct common_audit_data *sa,
389 void (*cb)(struct audit_buffer *, void *))
390{
391 int type, error;
392 u32 denied = request & (~perms->allow | perms->deny);
393
394 if (likely(!denied)) {
395 /* mask off perms that are not being force audited */
396 request &= perms->audit;
397 if (!request || !sa)
398 return 0;
399
400 type = AUDIT_APPARMOR_AUDIT;
401 error = 0;
402 } else {
403 error = -EACCES;
404
405 if (denied & perms->kill)
406 type = AUDIT_APPARMOR_KILL;
407 else if (denied == (denied & perms->complain))
408 type = AUDIT_APPARMOR_ALLOWED;
409 else
410 type = AUDIT_APPARMOR_DENIED;
411
412 if (denied == (denied & perms->hide))
413 error = -ENOENT;
414
415 denied &= ~perms->quiet;
416 if (!sa || !denied)
417 return error;
418 }
419
420 if (sa) {
421 aad(sa)->label = &profile->label;
422 aad(sa)->request = request;
423 aad(sa)->denied = denied;
424 aad(sa)->error = error;
425 aa_audit_msg(type, sa, cb);
426 }
427
428 if (type == AUDIT_APPARMOR_ALLOWED)
429 error = 0;
430
431 return error;
432}
433
434
435/**
436 * aa_policy_init - initialize a policy structure
437 * @policy: policy to initialize (NOT NULL)
438 * @prefix: prefix name if any is required. (MAYBE NULL)
439 * @name: name of the policy, init will make a copy of it (NOT NULL)
440 * @gfp: allocation mode
441 *
442 * Note: this fn creates a copy of strings passed in
443 *
444 * Returns: true if policy init successful
445 */
446bool aa_policy_init(struct aa_policy *policy, const char *prefix,
447 const char *name, gfp_t gfp)
448{
449 char *hname;
450
451 /* freed by policy_free */
452 if (prefix) {
453 hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
454 if (hname)
455 sprintf(hname, "%s//%s", prefix, name);
456 } else {
457 hname = aa_str_alloc(strlen(name) + 1, gfp);
458 if (hname)
459 strcpy(hname, name);
460 }
461 if (!hname)
462 return false;
463 policy->hname = hname;
464 /* base.name is a substring of fqname */
465 policy->name = basename(policy->hname);
466 INIT_LIST_HEAD(&policy->list);
467 INIT_LIST_HEAD(&policy->profiles);
468
469 return true;
470}
471
472/**
473 * aa_policy_destroy - free the elements referenced by @policy
474 * @policy: policy that is to have its elements freed (NOT NULL)
475 */
476void aa_policy_destroy(struct aa_policy *policy)
477{
478 AA_BUG(on_list_rcu(&policy->profiles));
479 AA_BUG(on_list_rcu(&policy->list));
480
481 /* don't free name as its a subset of hname */
482 aa_put_str(policy->hname);
483}