Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

AppArmor: file enforcement routines

AppArmor does files enforcement via pathname matching. Matching is done
at file open using a dfa match engine. Permission is against the final
file object not parent directories, ie. the traversal of directories
as part of the file match is implicitly allowed. In the case of nonexistant
files (creation) permissions are checked against the target file not the
directory. eg. In case of creating the file /dir/new, permissions are
checked against the match /dir/new not against /dir/.

The permissions for matches are currently stored in the dfa accept table,
but this will change to allow for dfa reuse and also to allow for sharing
of wider accept states.

Signed-off-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: James Morris <jmorris@namei.org>

authored by

John Johansen and committed by
James Morris
6380bd8d 63e2b423

+674
+457
security/apparmor/file.c
··· 1 + /* 2 + * AppArmor security module 3 + * 4 + * This file contains AppArmor mediation of files 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 + 15 + #include "include/apparmor.h" 16 + #include "include/audit.h" 17 + #include "include/file.h" 18 + #include "include/match.h" 19 + #include "include/path.h" 20 + #include "include/policy.h" 21 + 22 + struct file_perms nullperms; 23 + 24 + 25 + /** 26 + * audit_file_mask - convert mask to permission string 27 + * @buffer: buffer to write string to (NOT NULL) 28 + * @mask: permission mask to convert 29 + */ 30 + static void audit_file_mask(struct audit_buffer *ab, u32 mask) 31 + { 32 + char str[10]; 33 + 34 + char *m = str; 35 + 36 + if (mask & AA_EXEC_MMAP) 37 + *m++ = 'm'; 38 + if (mask & (MAY_READ | AA_MAY_META_READ)) 39 + *m++ = 'r'; 40 + if (mask & (MAY_WRITE | AA_MAY_META_WRITE | AA_MAY_CHMOD | 41 + AA_MAY_CHOWN)) 42 + *m++ = 'w'; 43 + else if (mask & MAY_APPEND) 44 + *m++ = 'a'; 45 + if (mask & AA_MAY_CREATE) 46 + *m++ = 'c'; 47 + if (mask & AA_MAY_DELETE) 48 + *m++ = 'd'; 49 + if (mask & AA_MAY_LINK) 50 + *m++ = 'l'; 51 + if (mask & AA_MAY_LOCK) 52 + *m++ = 'k'; 53 + if (mask & MAY_EXEC) 54 + *m++ = 'x'; 55 + *m = '\0'; 56 + 57 + audit_log_string(ab, str); 58 + } 59 + 60 + /** 61 + * file_audit_cb - call back for file specific audit fields 62 + * @ab: audit_buffer (NOT NULL) 63 + * @va: audit struct to audit values of (NOT NULL) 64 + */ 65 + static void file_audit_cb(struct audit_buffer *ab, void *va) 66 + { 67 + struct common_audit_data *sa = va; 68 + uid_t fsuid = current_fsuid(); 69 + 70 + if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) { 71 + audit_log_format(ab, " requested_mask="); 72 + audit_file_mask(ab, sa->aad.fs.request); 73 + } 74 + if (sa->aad.fs.denied & AA_AUDIT_FILE_MASK) { 75 + audit_log_format(ab, " denied_mask="); 76 + audit_file_mask(ab, sa->aad.fs.denied); 77 + } 78 + if (sa->aad.fs.request & AA_AUDIT_FILE_MASK) { 79 + audit_log_format(ab, " fsuid=%d", fsuid); 80 + audit_log_format(ab, " ouid=%d", sa->aad.fs.ouid); 81 + } 82 + 83 + if (sa->aad.fs.target) { 84 + audit_log_format(ab, " target="); 85 + audit_log_untrustedstring(ab, sa->aad.fs.target); 86 + } 87 + } 88 + 89 + /** 90 + * aa_audit_file - handle the auditing of file operations 91 + * @profile: the profile being enforced (NOT NULL) 92 + * @perms: the permissions computed for the request (NOT NULL) 93 + * @gfp: allocation flags 94 + * @op: operation being mediated 95 + * @request: permissions requested 96 + * @name: name of object being mediated (MAYBE NULL) 97 + * @target: name of target (MAYBE NULL) 98 + * @ouid: object uid 99 + * @info: extra information message (MAYBE NULL) 100 + * @error: 0 if operation allowed else failure error code 101 + * 102 + * Returns: %0 or error on failure 103 + */ 104 + int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, 105 + gfp_t gfp, int op, u32 request, const char *name, 106 + const char *target, uid_t ouid, const char *info, int error) 107 + { 108 + int type = AUDIT_APPARMOR_AUTO; 109 + struct common_audit_data sa; 110 + COMMON_AUDIT_DATA_INIT(&sa, NONE); 111 + sa.aad.op = op, 112 + sa.aad.fs.request = request; 113 + sa.aad.name = name; 114 + sa.aad.fs.target = target; 115 + sa.aad.fs.ouid = ouid; 116 + sa.aad.info = info; 117 + sa.aad.error = error; 118 + 119 + if (likely(!sa.aad.error)) { 120 + u32 mask = perms->audit; 121 + 122 + if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL)) 123 + mask = 0xffff; 124 + 125 + /* mask off perms that are not being force audited */ 126 + sa.aad.fs.request &= mask; 127 + 128 + if (likely(!sa.aad.fs.request)) 129 + return 0; 130 + type = AUDIT_APPARMOR_AUDIT; 131 + } else { 132 + /* only report permissions that were denied */ 133 + sa.aad.fs.request = sa.aad.fs.request & ~perms->allow; 134 + 135 + if (sa.aad.fs.request & perms->kill) 136 + type = AUDIT_APPARMOR_KILL; 137 + 138 + /* quiet known rejects, assumes quiet and kill do not overlap */ 139 + if ((sa.aad.fs.request & perms->quiet) && 140 + AUDIT_MODE(profile) != AUDIT_NOQUIET && 141 + AUDIT_MODE(profile) != AUDIT_ALL) 142 + sa.aad.fs.request &= ~perms->quiet; 143 + 144 + if (!sa.aad.fs.request) 145 + return COMPLAIN_MODE(profile) ? 0 : sa.aad.error; 146 + } 147 + 148 + sa.aad.fs.denied = sa.aad.fs.request & ~perms->allow; 149 + return aa_audit(type, profile, gfp, &sa, file_audit_cb); 150 + } 151 + 152 + /** 153 + * map_old_perms - map old file perms layout to the new layout 154 + * @old: permission set in old mapping 155 + * 156 + * Returns: new permission mapping 157 + */ 158 + static u32 map_old_perms(u32 old) 159 + { 160 + u32 new = old & 0xf; 161 + if (old & MAY_READ) 162 + new |= AA_MAY_META_READ; 163 + if (old & MAY_WRITE) 164 + new |= AA_MAY_META_WRITE | AA_MAY_CREATE | AA_MAY_DELETE | 165 + AA_MAY_CHMOD | AA_MAY_CHOWN; 166 + if (old & 0x10) 167 + new |= AA_MAY_LINK; 168 + /* the old mapping lock and link_subset flags where overlaid 169 + * and use was determined by part of a pair that they were in 170 + */ 171 + if (old & 0x20) 172 + new |= AA_MAY_LOCK | AA_LINK_SUBSET; 173 + if (old & 0x40) /* AA_EXEC_MMAP */ 174 + new |= AA_EXEC_MMAP; 175 + 176 + new |= AA_MAY_META_READ; 177 + 178 + return new; 179 + } 180 + 181 + /** 182 + * compute_perms - convert dfa compressed perms to internal perms 183 + * @dfa: dfa to compute perms for (NOT NULL) 184 + * @state: state in dfa 185 + * @cond: conditions to consider (NOT NULL) 186 + * 187 + * TODO: convert from dfa + state to permission entry, do computation conversion 188 + * at load time. 189 + * 190 + * Returns: computed permission set 191 + */ 192 + static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state, 193 + struct path_cond *cond) 194 + { 195 + struct file_perms perms; 196 + 197 + /* FIXME: change over to new dfa format 198 + * currently file perms are encoded in the dfa, new format 199 + * splits the permissions from the dfa. This mapping can be 200 + * done at profile load 201 + */ 202 + perms.kill = 0; 203 + 204 + if (current_fsuid() == cond->uid) { 205 + perms.allow = map_old_perms(dfa_user_allow(dfa, state)); 206 + perms.audit = map_old_perms(dfa_user_audit(dfa, state)); 207 + perms.quiet = map_old_perms(dfa_user_quiet(dfa, state)); 208 + perms.xindex = dfa_user_xindex(dfa, state); 209 + } else { 210 + perms.allow = map_old_perms(dfa_other_allow(dfa, state)); 211 + perms.audit = map_old_perms(dfa_other_audit(dfa, state)); 212 + perms.quiet = map_old_perms(dfa_other_quiet(dfa, state)); 213 + perms.xindex = dfa_other_xindex(dfa, state); 214 + } 215 + 216 + /* change_profile wasn't determined by ownership in old mapping */ 217 + if (ACCEPT_TABLE(dfa)[state] & 0x80000000) 218 + perms.allow |= AA_MAY_CHANGE_PROFILE; 219 + 220 + return perms; 221 + } 222 + 223 + /** 224 + * aa_str_perms - find permission that match @name 225 + * @dfa: to match against (MAYBE NULL) 226 + * @state: state to start matching in 227 + * @name: string to match against dfa (NOT NULL) 228 + * @cond: conditions to consider for permission set computation (NOT NULL) 229 + * @perms: Returns - the permissions found when matching @name 230 + * 231 + * Returns: the final state in @dfa when beginning @start and walking @name 232 + */ 233 + unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start, 234 + const char *name, struct path_cond *cond, 235 + struct file_perms *perms) 236 + { 237 + unsigned int state; 238 + if (!dfa) { 239 + *perms = nullperms; 240 + return DFA_NOMATCH; 241 + } 242 + 243 + state = aa_dfa_match(dfa, start, name); 244 + *perms = compute_perms(dfa, state, cond); 245 + 246 + return state; 247 + } 248 + 249 + /** 250 + * is_deleted - test if a file has been completely unlinked 251 + * @dentry: dentry of file to test for deletion (NOT NULL) 252 + * 253 + * Returns: %1 if deleted else %0 254 + */ 255 + static inline bool is_deleted(struct dentry *dentry) 256 + { 257 + if (d_unlinked(dentry) && dentry->d_inode->i_nlink == 0) 258 + return 1; 259 + return 0; 260 + } 261 + 262 + /** 263 + * aa_path_perm - do permissions check & audit for @path 264 + * @op: operation being checked 265 + * @profile: profile being enforced (NOT NULL) 266 + * @path: path to check permissions of (NOT NULL) 267 + * @flags: any additional path flags beyond what the profile specifies 268 + * @request: requested permissions 269 + * @cond: conditional info for this request (NOT NULL) 270 + * 271 + * Returns: %0 else error if access denied or other error 272 + */ 273 + int aa_path_perm(int op, struct aa_profile *profile, struct path *path, 274 + int flags, u32 request, struct path_cond *cond) 275 + { 276 + char *buffer = NULL; 277 + struct file_perms perms = {}; 278 + const char *name, *info = NULL; 279 + int error; 280 + 281 + flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0); 282 + error = aa_get_name(path, flags, &buffer, &name); 283 + if (error) { 284 + if (error == -ENOENT && is_deleted(path->dentry)) { 285 + /* Access to open files that are deleted are 286 + * give a pass (implicit delegation) 287 + */ 288 + error = 0; 289 + perms.allow = request; 290 + } else if (error == -ENOENT) 291 + info = "Failed name lookup - deleted entry"; 292 + else if (error == -ESTALE) 293 + info = "Failed name lookup - disconnected path"; 294 + else if (error == -ENAMETOOLONG) 295 + info = "Failed name lookup - name too long"; 296 + else 297 + info = "Failed name lookup"; 298 + } else { 299 + aa_str_perms(profile->file.dfa, profile->file.start, name, cond, 300 + &perms); 301 + if (request & ~perms.allow) 302 + error = -EACCES; 303 + } 304 + error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name, 305 + NULL, cond->uid, info, error); 306 + kfree(buffer); 307 + 308 + return error; 309 + } 310 + 311 + /** 312 + * xindex_is_subset - helper for aa_path_link 313 + * @link: link permission set 314 + * @target: target permission set 315 + * 316 + * test target x permissions are equal OR a subset of link x permissions 317 + * this is done as part of the subset test, where a hardlink must have 318 + * a subset of permissions that the target has. 319 + * 320 + * Returns: %1 if subset else %0 321 + */ 322 + static inline bool xindex_is_subset(u32 link, u32 target) 323 + { 324 + if (((link & ~AA_X_UNSAFE) != (target & ~AA_X_UNSAFE)) || 325 + ((link & AA_X_UNSAFE) && !(target & AA_X_UNSAFE))) 326 + return 0; 327 + 328 + return 1; 329 + } 330 + 331 + /** 332 + * aa_path_link - Handle hard link permission check 333 + * @profile: the profile being enforced (NOT NULL) 334 + * @old_dentry: the target dentry (NOT NULL) 335 + * @new_dir: directory the new link will be created in (NOT NULL) 336 + * @new_dentry: the link being created (NOT NULL) 337 + * 338 + * Handle the permission test for a link & target pair. Permission 339 + * is encoded as a pair where the link permission is determined 340 + * first, and if allowed, the target is tested. The target test 341 + * is done from the point of the link match (not start of DFA) 342 + * making the target permission dependent on the link permission match. 343 + * 344 + * The subset test if required forces that permissions granted 345 + * on link are a subset of the permission granted to target. 346 + * 347 + * Returns: %0 if allowed else error 348 + */ 349 + int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, 350 + struct path *new_dir, struct dentry *new_dentry) 351 + { 352 + struct path link = { new_dir->mnt, new_dentry }; 353 + struct path target = { new_dir->mnt, old_dentry }; 354 + struct path_cond cond = { 355 + old_dentry->d_inode->i_uid, 356 + old_dentry->d_inode->i_mode 357 + }; 358 + char *buffer = NULL, *buffer2 = NULL; 359 + const char *lname, *tname = NULL, *info = NULL; 360 + struct file_perms lperms, perms; 361 + u32 request = AA_MAY_LINK; 362 + unsigned int state; 363 + int error; 364 + 365 + lperms = nullperms; 366 + 367 + /* buffer freed below, lname is pointer in buffer */ 368 + error = aa_get_name(&link, profile->path_flags, &buffer, &lname); 369 + if (error) 370 + goto audit; 371 + 372 + /* buffer2 freed below, tname is pointer in buffer2 */ 373 + error = aa_get_name(&target, profile->path_flags, &buffer2, &tname); 374 + if (error) 375 + goto audit; 376 + 377 + error = -EACCES; 378 + /* aa_str_perms - handles the case of the dfa being NULL */ 379 + state = aa_str_perms(profile->file.dfa, profile->file.start, lname, 380 + &cond, &lperms); 381 + 382 + if (!(lperms.allow & AA_MAY_LINK)) 383 + goto audit; 384 + 385 + /* test to see if target can be paired with link */ 386 + state = aa_dfa_null_transition(profile->file.dfa, state); 387 + aa_str_perms(profile->file.dfa, state, tname, &cond, &perms); 388 + 389 + /* force audit/quiet masks for link are stored in the second entry 390 + * in the link pair. 391 + */ 392 + lperms.audit = perms.audit; 393 + lperms.quiet = perms.quiet; 394 + lperms.kill = perms.kill; 395 + 396 + if (!(perms.allow & AA_MAY_LINK)) { 397 + info = "target restricted"; 398 + goto audit; 399 + } 400 + 401 + /* done if link subset test is not required */ 402 + if (!(perms.allow & AA_LINK_SUBSET)) 403 + goto done_tests; 404 + 405 + /* Do link perm subset test requiring allowed permission on link are a 406 + * subset of the allowed permissions on target. 407 + */ 408 + aa_str_perms(profile->file.dfa, profile->file.start, tname, &cond, 409 + &perms); 410 + 411 + /* AA_MAY_LINK is not considered in the subset test */ 412 + request = lperms.allow & ~AA_MAY_LINK; 413 + lperms.allow &= perms.allow | AA_MAY_LINK; 414 + 415 + request |= AA_AUDIT_FILE_MASK & (lperms.allow & ~perms.allow); 416 + if (request & ~lperms.allow) { 417 + goto audit; 418 + } else if ((lperms.allow & MAY_EXEC) && 419 + !xindex_is_subset(lperms.xindex, perms.xindex)) { 420 + lperms.allow &= ~MAY_EXEC; 421 + request |= MAY_EXEC; 422 + info = "link not subset of target"; 423 + goto audit; 424 + } 425 + 426 + done_tests: 427 + error = 0; 428 + 429 + audit: 430 + error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK, request, 431 + lname, tname, cond.uid, info, error); 432 + kfree(buffer); 433 + kfree(buffer2); 434 + 435 + return error; 436 + } 437 + 438 + /** 439 + * aa_file_perm - do permission revalidation check & audit for @file 440 + * @op: operation being checked 441 + * @profile: profile being enforced (NOT NULL) 442 + * @file: file to revalidate access permissions on (NOT NULL) 443 + * @request: requested permissions 444 + * 445 + * Returns: %0 if access allowed else error 446 + */ 447 + int aa_file_perm(int op, struct aa_profile *profile, struct file *file, 448 + u32 request) 449 + { 450 + struct path_cond cond = { 451 + .uid = file->f_path.dentry->d_inode->i_uid, 452 + .mode = file->f_path.dentry->d_inode->i_mode 453 + }; 454 + 455 + return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED, 456 + request, &cond); 457 + }
+217
security/apparmor/include/file.h
··· 1 + /* 2 + * AppArmor security module 3 + * 4 + * This file contains AppArmor file mediation function definitions. 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 + 15 + #ifndef __AA_FILE_H 16 + #define __AA_FILE_H 17 + 18 + #include <linux/path.h> 19 + 20 + #include "domain.h" 21 + #include "match.h" 22 + 23 + struct aa_profile; 24 + 25 + /* 26 + * We use MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND and the following flags 27 + * for profile permissions 28 + */ 29 + #define AA_MAY_CREATE 0x0010 30 + #define AA_MAY_DELETE 0x0020 31 + #define AA_MAY_META_WRITE 0x0040 32 + #define AA_MAY_META_READ 0x0080 33 + 34 + #define AA_MAY_CHMOD 0x0100 35 + #define AA_MAY_CHOWN 0x0200 36 + #define AA_MAY_LOCK 0x0400 37 + #define AA_EXEC_MMAP 0x0800 38 + 39 + #define AA_MAY_LINK 0x1000 40 + #define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */ 41 + #define AA_MAY_ONEXEC 0x40000000 /* exec allows onexec */ 42 + #define AA_MAY_CHANGE_PROFILE 0x80000000 43 + #define AA_MAY_CHANGEHAT 0x80000000 /* ctrl auditing only */ 44 + 45 + #define AA_AUDIT_FILE_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND |\ 46 + AA_MAY_CREATE | AA_MAY_DELETE | \ 47 + AA_MAY_META_READ | AA_MAY_META_WRITE | \ 48 + AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \ 49 + AA_EXEC_MMAP | AA_MAY_LINK) 50 + 51 + /* 52 + * The xindex is broken into 3 parts 53 + * - index - an index into either the exec name table or the variable table 54 + * - exec type - which determines how the executable name and index are used 55 + * - flags - which modify how the destination name is applied 56 + */ 57 + #define AA_X_INDEX_MASK 0x03ff 58 + 59 + #define AA_X_TYPE_MASK 0x0c00 60 + #define AA_X_TYPE_SHIFT 10 61 + #define AA_X_NONE 0x0000 62 + #define AA_X_NAME 0x0400 /* use executable name px */ 63 + #define AA_X_TABLE 0x0800 /* use a specified name ->n# */ 64 + 65 + #define AA_X_UNSAFE 0x1000 66 + #define AA_X_CHILD 0x2000 /* make >AA_X_NONE apply to children */ 67 + #define AA_X_INHERIT 0x4000 68 + #define AA_X_UNCONFINED 0x8000 69 + 70 + /* AA_SECURE_X_NEEDED - is passed in the bprm->unsafe field */ 71 + #define AA_SECURE_X_NEEDED 0x8000 72 + 73 + /* need to make conditional which ones are being set */ 74 + struct path_cond { 75 + uid_t uid; 76 + umode_t mode; 77 + }; 78 + 79 + /* struct file_perms - file permission 80 + * @allow: mask of permissions that are allowed 81 + * @audit: mask of permissions to force an audit message for 82 + * @quiet: mask of permissions to quiet audit messages for 83 + * @kill: mask of permissions that when matched will kill the task 84 + * @xindex: exec transition index if @allow contains MAY_EXEC 85 + * 86 + * The @audit and @queit mask should be mutually exclusive. 87 + */ 88 + struct file_perms { 89 + u32 allow; 90 + u32 audit; 91 + u32 quiet; 92 + u32 kill; 93 + u16 xindex; 94 + }; 95 + 96 + extern struct file_perms nullperms; 97 + 98 + #define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill) 99 + 100 + /* FIXME: split perms from dfa and match this to description 101 + * also add delegation info. 102 + */ 103 + static inline u16 dfa_map_xindex(u16 mask) 104 + { 105 + u16 old_index = (mask >> 10) & 0xf; 106 + u16 index = 0; 107 + 108 + if (mask & 0x100) 109 + index |= AA_X_UNSAFE; 110 + if (mask & 0x200) 111 + index |= AA_X_INHERIT; 112 + if (mask & 0x80) 113 + index |= AA_X_UNCONFINED; 114 + 115 + if (old_index == 1) { 116 + index |= AA_X_UNCONFINED; 117 + } else if (old_index == 2) { 118 + index |= AA_X_NAME; 119 + } else if (old_index == 3) { 120 + index |= AA_X_NAME | AA_X_CHILD; 121 + } else { 122 + index |= AA_X_TABLE; 123 + index |= old_index - 4; 124 + } 125 + 126 + return index; 127 + } 128 + 129 + /* 130 + * map old dfa inline permissions to new format 131 + */ 132 + #define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \ 133 + ((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) 134 + #define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f) 135 + #define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f) 136 + #define dfa_user_xindex(dfa, state) \ 137 + (dfa_map_xindex(ACCEPT_TABLE(dfa)[state] & 0x3fff)) 138 + 139 + #define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \ 140 + 0x7f) | \ 141 + ((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) 142 + #define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f) 143 + #define dfa_other_quiet(dfa, state) \ 144 + ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f) 145 + #define dfa_other_xindex(dfa, state) \ 146 + dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff) 147 + 148 + int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, 149 + gfp_t gfp, int op, u32 request, const char *name, 150 + const char *target, uid_t ouid, const char *info, int error); 151 + 152 + /** 153 + * struct aa_file_rules - components used for file rule permissions 154 + * @dfa: dfa to match path names and conditionals against 155 + * @perms: permission table indexed by the matched state accept entry of @dfa 156 + * @trans: transition table for indexed by named x transitions 157 + * 158 + * File permission are determined by matching a path against @dfa and then 159 + * then using the value of the accept entry for the matching state as 160 + * an index into @perms. If a named exec transition is required it is 161 + * looked up in the transition table. 162 + */ 163 + struct aa_file_rules { 164 + unsigned int start; 165 + struct aa_dfa *dfa; 166 + /* struct perms perms; */ 167 + struct aa_domain trans; 168 + /* TODO: add delegate table */ 169 + }; 170 + 171 + unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start, 172 + const char *name, struct path_cond *cond, 173 + struct file_perms *perms); 174 + 175 + int aa_path_perm(int op, struct aa_profile *profile, struct path *path, 176 + int flags, u32 request, struct path_cond *cond); 177 + 178 + int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, 179 + struct path *new_dir, struct dentry *new_dentry); 180 + 181 + int aa_file_perm(int op, struct aa_profile *profile, struct file *file, 182 + u32 request); 183 + 184 + static inline void aa_free_file_rules(struct aa_file_rules *rules) 185 + { 186 + aa_put_dfa(rules->dfa); 187 + aa_free_domain_entries(&rules->trans); 188 + } 189 + 190 + #define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40)) 191 + 192 + /* from namei.c */ 193 + #define MAP_OPEN_FLAGS(x) ((((x) + 1) & O_ACCMODE) ? (x) + 1 : (x)) 194 + 195 + /** 196 + * aa_map_file_perms - map file flags to AppArmor permissions 197 + * @file: open file to map flags to AppArmor permissions 198 + * 199 + * Returns: apparmor permission set for the file 200 + */ 201 + static inline u32 aa_map_file_to_perms(struct file *file) 202 + { 203 + int flags = MAP_OPEN_FLAGS(file->f_flags); 204 + u32 perms = ACC_FMODE(file->f_mode); 205 + 206 + if ((flags & O_APPEND) && (perms & MAY_WRITE)) 207 + perms = (perms & ~MAY_WRITE) | MAY_APPEND; 208 + /* trunc implies write permission */ 209 + if (flags & O_TRUNC) 210 + perms |= MAY_WRITE; 211 + if (flags & O_CREAT) 212 + perms |= AA_MAY_CREATE; 213 + 214 + return perms; 215 + } 216 + 217 + #endif /* __AA_FILE_H */