blob: a509137448236f6132f2c7b44a2413c6224848a4 [file] [log] [blame]
John Johansencdff2642010-07-29 14:47:57 -07001/*
2 * AppArmor security module
3 *
4 * This file contains basic common functions used in AppArmor
5 *
6 * Copyright (C) 1998-2008 Novell/SUSE
7 * Copyright 2009-2010 Canonical Ltd.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
12 * License.
13 */
14
John Johansen3b0aaf52017-01-16 00:42:23 -080015#include <linux/ctype.h>
Alexey Dobriyanb7f080c2011-06-16 11:01:34 +000016#include <linux/mm.h>
John Johansencdff2642010-07-29 14:47:57 -070017#include <linux/slab.h>
18#include <linux/string.h>
19#include <linux/vmalloc.h>
20
21#include "include/audit.h"
James Morris32c3df62011-08-29 11:15:25 +100022#include "include/apparmor.h"
John Johansen12557dc2017-01-16 00:42:13 -080023#include "include/lib.h"
John Johansenfc7e0b22017-05-26 01:57:09 -070024#include "include/perms.h"
John Johansenfe6bb312017-01-16 00:42:14 -080025#include "include/policy.h"
John Johansencdff2642010-07-29 14:47:57 -070026
John Johansenaa9aeea2017-05-29 12:16:04 -070027struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
28 .quiet = ALL_PERMS_MASK,
29 .hide = ALL_PERMS_MASK };
30
John Johansencdff2642010-07-29 14:47:57 -070031/**
32 * aa_split_fqname - split a fqname into a profile and namespace name
33 * @fqname: a full qualified name in namespace profile format (NOT NULL)
34 * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
35 *
36 * Returns: profile name or NULL if one is not specified
37 *
38 * Split a namespace name from a profile name (see policy.c for naming
39 * description). If a portion of the name is missing it returns NULL for
40 * that portion.
41 *
42 * NOTE: may modify the @fqname string. The pointers returned point
43 * into the @fqname string.
44 */
45char *aa_split_fqname(char *fqname, char **ns_name)
46{
47 char *name = strim(fqname);
48
49 *ns_name = NULL;
50 if (name[0] == ':') {
51 char *split = strchr(&name[1], ':');
John Johansen04ccd532010-08-27 18:33:28 -070052 *ns_name = skip_spaces(&name[1]);
John Johansencdff2642010-07-29 14:47:57 -070053 if (split) {
54 /* overwrite ':' with \0 */
John Johansen2654bfb2013-02-27 03:45:05 -080055 *split++ = 0;
56 if (strncmp(split, "//", 2) == 0)
57 split += 2;
58 name = skip_spaces(split);
John Johansencdff2642010-07-29 14:47:57 -070059 } else
60 /* a ns name without a following profile is allowed */
61 name = NULL;
John Johansencdff2642010-07-29 14:47:57 -070062 }
63 if (name && *name == 0)
64 name = NULL;
65
66 return name;
67}
68
69/**
John Johansen3b0aaf52017-01-16 00:42:23 -080070 * skipn_spaces - Removes leading whitespace from @str.
71 * @str: The string to be stripped.
72 *
73 * Returns a pointer to the first non-whitespace character in @str.
74 * if all whitespace will return NULL
75 */
76
John Johansenb91deb92017-05-22 02:47:22 -070077const char *skipn_spaces(const char *str, size_t n)
John Johansen3b0aaf52017-01-16 00:42:23 -080078{
79 for (; n && isspace(*str); --n)
80 ++str;
81 if (n)
82 return (char *)str;
83 return NULL;
84}
85
86const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
87 size_t *ns_len)
88{
89 const char *end = fqname + n;
90 const char *name = skipn_spaces(fqname, n);
91
92 if (!name)
93 return NULL;
94 *ns_name = NULL;
95 *ns_len = 0;
96 if (name[0] == ':') {
97 char *split = strnchr(&name[1], end - &name[1], ':');
98 *ns_name = skipn_spaces(&name[1], end - &name[1]);
99 if (!*ns_name)
100 return NULL;
101 if (split) {
102 *ns_len = split - *ns_name;
103 if (*ns_len == 0)
104 *ns_name = NULL;
105 split++;
106 if (end - split > 1 && strncmp(split, "//", 2) == 0)
107 split += 2;
108 name = skipn_spaces(split, end - split);
109 } else {
110 /* a ns name without a following profile is allowed */
111 name = NULL;
112 *ns_len = end - *ns_name;
113 }
114 }
115 if (name && *name == 0)
116 name = NULL;
117
118 return name;
119}
120
121/**
John Johansencdff2642010-07-29 14:47:57 -0700122 * aa_info_message - log a none profile related status message
123 * @str: message to log
124 */
125void aa_info_message(const char *str)
126{
127 if (audit_enabled) {
John Johansenef88a7a2017-01-16 00:43:02 -0800128 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
129
130 aad(&sa)->info = str;
John Johansencdff2642010-07-29 14:47:57 -0700131 aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
132 }
133 printk(KERN_INFO "AppArmor: %s\n", str);
134}
135
John Johansene53cfe62017-05-26 15:07:22 -0700136const 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 * @mask: permission mask to convert
183 */
184void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask)
185{
186 unsigned int i, perm = 1;
187
188 for (i = 0; i < 32; perm <<= 1, i++) {
189 if (mask & perm)
190 *str++ = chrs[i];
191 }
192 *str = '\0';
193}
194
John Johansenaa9aeea2017-05-29 12:16:04 -0700195void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask)
196{
197 const char *fmt = "%s";
198 unsigned int i, perm = 1;
199 bool prev = false;
200
201 for (i = 0; i < 32; perm <<= 1, i++) {
202 if (mask & perm) {
203 audit_log_format(ab, fmt, names[i]);
204 if (!prev) {
205 prev = true;
206 fmt = " %s";
207 }
208 }
209 }
210}
211
212void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
213 u32 chrsmask, const char **names, u32 namesmask)
214{
215 char str[33];
216
217 audit_log_format(ab, "\"");
218 if ((mask & chrsmask) && chrs) {
219 aa_perm_mask_to_str(str, chrs, mask & chrsmask);
220 mask &= ~chrsmask;
221 audit_log_format(ab, "%s", str);
222 if (mask & namesmask)
223 audit_log_format(ab, " ");
224 }
225 if ((mask & namesmask) && names)
226 aa_audit_perm_names(ab, names, mask & namesmask);
227 audit_log_format(ab, "\"");
228}
229
230/**
231 * aa_apply_modes_to_perms - apply namespace and profile flags to perms
232 * @profile: that perms where computed from
233 * @perms: perms to apply mode modifiers to
234 *
235 * TODO: split into profile and ns based flags for when accumulating perms
236 */
237void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
238{
239 switch (AUDIT_MODE(profile)) {
240 case AUDIT_ALL:
241 perms->audit = ALL_PERMS_MASK;
242 /* fall through */
243 case AUDIT_NOQUIET:
244 perms->quiet = 0;
245 break;
246 case AUDIT_QUIET:
247 perms->audit = 0;
248 /* fall through */
249 case AUDIT_QUIET_DENIED:
250 perms->quiet = ALL_PERMS_MASK;
251 break;
252 }
253
254 if (KILL_MODE(profile))
255 perms->kill = ALL_PERMS_MASK;
256 else if (COMPLAIN_MODE(profile))
257 perms->complain = ALL_PERMS_MASK;
258/*
259 * TODO:
260 * else if (PROMPT_MODE(profile))
261 * perms->prompt = ALL_PERMS_MASK;
262 */
263}
264
265static u32 map_other(u32 x)
266{
267 return ((x & 0x3) << 8) | /* SETATTR/GETATTR */
268 ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */
269 ((x & 0x60) << 19); /* SETOPT/GETOPT */
270}
271
272void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
273 struct aa_perms *perms)
274{
275 perms->deny = 0;
276 perms->kill = perms->stop = 0;
277 perms->complain = perms->cond = 0;
278 perms->hide = 0;
279 perms->prompt = 0;
280 perms->allow = dfa_user_allow(dfa, state);
281 perms->audit = dfa_user_audit(dfa, state);
282 perms->quiet = dfa_user_quiet(dfa, state);
283
284 /* for v5 perm mapping in the policydb, the other set is used
285 * to extend the general perm set
286 */
287 perms->allow |= map_other(dfa_other_allow(dfa, state));
288 perms->audit |= map_other(dfa_other_audit(dfa, state));
289 perms->quiet |= map_other(dfa_other_quiet(dfa, state));
290// perms->xindex = dfa_user_xindex(dfa, state);
291}
292
John Johansencdff2642010-07-29 14:47:57 -0700293/**
John Johansenfe6bb312017-01-16 00:42:14 -0800294 * aa_policy_init - initialize a policy structure
295 * @policy: policy to initialize (NOT NULL)
296 * @prefix: prefix name if any is required. (MAYBE NULL)
297 * @name: name of the policy, init will make a copy of it (NOT NULL)
298 *
299 * Note: this fn creates a copy of strings passed in
300 *
301 * Returns: true if policy init successful
302 */
303bool aa_policy_init(struct aa_policy *policy, const char *prefix,
John Johansend102d892017-01-16 00:42:31 -0800304 const char *name, gfp_t gfp)
John Johansenfe6bb312017-01-16 00:42:14 -0800305{
306 /* freed by policy_free */
307 if (prefix) {
308 policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3,
John Johansend102d892017-01-16 00:42:31 -0800309 gfp);
John Johansenfe6bb312017-01-16 00:42:14 -0800310 if (policy->hname)
John Johansenbbe4a7c2017-01-16 00:42:30 -0800311 sprintf((char *)policy->hname, "%s//%s", prefix, name);
John Johansenfe6bb312017-01-16 00:42:14 -0800312 } else
John Johansend102d892017-01-16 00:42:31 -0800313 policy->hname = kstrdup(name, gfp);
John Johansenfe6bb312017-01-16 00:42:14 -0800314 if (!policy->hname)
kbuild test robotb9c42ac2017-04-06 06:55:19 -0700315 return false;
John Johansenfe6bb312017-01-16 00:42:14 -0800316 /* base.name is a substring of fqname */
John Johansend102d892017-01-16 00:42:31 -0800317 policy->name = basename(policy->hname);
John Johansenfe6bb312017-01-16 00:42:14 -0800318 INIT_LIST_HEAD(&policy->list);
319 INIT_LIST_HEAD(&policy->profiles);
320
kbuild test robotb9c42ac2017-04-06 06:55:19 -0700321 return true;
John Johansenfe6bb312017-01-16 00:42:14 -0800322}
323
324/**
325 * aa_policy_destroy - free the elements referenced by @policy
326 * @policy: policy that is to have its elements freed (NOT NULL)
327 */
328void aa_policy_destroy(struct aa_policy *policy)
329{
John Johansen5fd1b952017-01-16 00:42:32 -0800330 AA_BUG(on_list_rcu(&policy->profiles));
331 AA_BUG(on_list_rcu(&policy->list));
John Johansenfe6bb312017-01-16 00:42:14 -0800332
333 /* don't free name as its a subset of hname */
334 kzfree(policy->hname);
335}