2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-05 08:45:22 +00:00
Files
apparmor/kernel-patches/for-mainline/apparmor-audit-flags2.diff
2008-04-07 17:48:20 +00:00

746 lines
22 KiB
Diff

---
security/apparmor/apparmor.h | 14 -
security/apparmor/apparmorfs.c | 2
security/apparmor/inline.h | 14 -
security/apparmor/main.c | 490 +++++++++++++++++++----------------
security/apparmor/match.c | 9
security/apparmor/module_interface.c | 10
6 files changed, 309 insertions(+), 230 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -44,8 +44,7 @@
AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
AA_EXEC_MOD_4)
-#define AA_EXEC_TYPE (MAY_EXEC | AA_EXEC_UNSAFE | \
- AA_EXEC_MODIFIERS)
+#define AA_EXEC_TYPE (AA_EXEC_UNSAFE | AA_EXEC_MODIFIERS)
#define AA_EXEC_UNCONFINED AA_EXEC_MOD_0
#define AA_EXEC_INHERIT AA_EXEC_MOD_1
@@ -85,6 +84,10 @@
AA_AUDIT_FIELD)
#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_SHARED_PERMS)
+
+/* audit bits for the second accept field */
+#define AUDIT_FILE_MASK 0x1fc07f
+#define AUDIT_QUIET_MASK(mask) ((mask >> 7) & AUDIT_FILE_MASK)
#define AA_VALID_PERM2_MASK 0x0fffffff
#define AA_SECURE_EXEC_NEEDED 1
@@ -179,6 +182,9 @@ struct aa_profile {
int isstale;
kernel_cap_t capabilities;
+ kernel_cap_t audit_caps;
+ kernel_cap_t quiet_caps;
+
struct kref count;
struct list_head task_contexts;
spinlock_t lock;
@@ -226,7 +232,7 @@ struct aa_audit {
const char *name;
const char *name2;
const char *name3;
- int request_mask, denied_mask;
+ int request_mask, denied_mask, audit_mask;
struct iattr *iattr;
pid_t task, parent;
int error_code;
@@ -331,7 +337,7 @@ extern struct aa_dfa *aa_match_alloc(voi
extern void aa_match_free(struct aa_dfa *dfa);
extern int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size);
extern int verify_dfa(struct aa_dfa *dfa);
-extern unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str);
+extern unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str, int *);
extern unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start,
const char *str);
extern unsigned int aa_match_state(struct aa_dfa *dfa, unsigned int start,
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -89,7 +89,7 @@ static struct file_operations apparmorfs
static ssize_t aa_matching_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
- const char *matching = "pattern=aadfa perms=rwxamlk/ user::other";
+ const char *matching = "pattern=aadfa audit perms=rwxamlk/ user::other";
return simple_read_from_buffer(buf, size, ppos, matching,
strlen(matching));
--- a/security/apparmor/inline.h
+++ b/security/apparmor/inline.h
@@ -232,9 +232,19 @@ static inline void unlock_both_profiles(
}
}
-static inline unsigned int aa_match(struct aa_dfa *dfa, const char *pathname)
+static inline unsigned int aa_match(struct aa_dfa *dfa, const char *pathname,
+ int *audit_mask)
{
- return dfa ? aa_dfa_match(dfa, pathname) : 0;
+ if (dfa)
+ return aa_dfa_match(dfa, pathname, audit_mask);
+ if (audit_mask)
+ *audit_mask = 0;
+ return 0;
+}
+
+static inline int dfa_audit_mask(struct aa_dfa *dfa, unsigned int state)
+{
+ return ACCEPT_TABLE2(dfa)[state];
}
#endif /* __INLINE_H__ */
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -36,204 +36,6 @@ static int aa_inode_mode(struct inode *i
return AA_OTHER_SHIFT;
}
-/**
- * aa_file_denied - check for @mask access on a file
- * @profile: profile to check against
- * @name: pathname of file
- * @mask: permission mask requested for file
- *
- * Return %0 on success, or else the permissions in @mask that the
- * profile denies.
- */
-static int aa_file_denied(struct aa_profile *profile, const char *name,
- int mask)
-{
- return (mask & ~aa_match(profile->file_rules, name));
-}
-
-/**
- * aa_link_denied - check for permission to link a file
- * @profile: profile to check against
- * @link: pathname of link being created
- * @target: pathname of target to be linked to
- * @target_mode: UGO shift for target inode
- * @request_mask: the permissions subset valid only if link succeeds
- * Return %0 on success, or else the permissions that the profile denies.
- */
-static int aa_link_denied(struct aa_profile *profile, const char *link,
- const char *target, int target_mode,
- int *request_mask)
-{
- unsigned int state;
- int l_mode, t_mode, denied_mask = 0;
- int link_mask = AA_MAY_LINK << target_mode;
-
- *request_mask = link_mask;
-
- l_mode = aa_match_state(profile->file_rules, DFA_START, link, &state);
- if (l_mode & link_mask) {
- int mode;
- /* test to see if target can be paired with link */
- state = aa_dfa_null_transition(profile->file_rules, state);
- mode = aa_match_state(profile->file_rules, state, target,
- NULL);
-
- if (!(mode & link_mask))
- denied_mask |= link_mask;
- /* return if link subset test is not required */
- if (!(mode & (AA_LINK_SUBSET_TEST << target_mode)))
- return denied_mask;
- }
-
- /* Do link perm subset test
- * If a subset test is required a permission subset test of the
- * perms for the link are done against the user::other of the
- * target's 'r', 'w', 'x', 'a', 'k', and 'm' permissions.
- *
- * If the link has 'x', an exact match of all the execute flags
- * must match.
- */
- denied_mask |= ~l_mode & link_mask;
-
- t_mode = aa_match(profile->file_rules, target);
-
- /* For actual subset test ignore valid-profile-transition flags,
- * and link bits
- */
- l_mode &= AA_FILE_PERMS & ~AA_LINK_BITS;
- t_mode &= AA_FILE_PERMS & ~AA_LINK_BITS;
-
- *request_mask = l_mode | link_mask;
-
- if (l_mode) {
- denied_mask |= l_mode & ~t_mode;
- if ((l_mode & AA_EXEC_BITS) &&
- (l_mode & ALL_AA_EXEC_TYPE) !=
- (t_mode & ALL_AA_EXEC_TYPE))
- denied_mask = (denied_mask & ~ALL_AA_EXEC_TYPE) |
- (l_mode & ALL_AA_EXEC_TYPE);
- }
-
- return denied_mask;
-}
-
-/**
- * aa_get_name - compute the pathname of a file
- * @dentry: dentry of the file
- * @mnt: vfsmount of the file
- * @buffer: buffer that aa_get_name() allocated
- * @check: AA_CHECK_DIR is set if the file is a directory
- *
- * Returns a pointer to the beginning of the pathname (which usually differs
- * from the beginning of the buffer), or an error code.
- *
- * We need @check to indicate whether the file is a directory or not because
- * the file may not yet exist, and so we cannot check the inode's file type.
- */
-static char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt,
- char **buffer, int check)
-{
- char *name;
- int is_dir, size = 256;
-
- is_dir = (check & AA_CHECK_DIR) ? 1 : 0;
-
- for (;;) {
- char *buf = kmalloc(size, GFP_KERNEL);
- if (!buf)
- return ERR_PTR(-ENOMEM);
-
- name = d_namespace_path(dentry, mnt, buf, size - is_dir);
- if (!IS_ERR(name)) {
- if (name[0] != '/') {
- /*
- * This dentry is not connected to the
- * namespace root -- reject access.
- */
- kfree(buf);
- return ERR_PTR(-ENOENT);
- }
- if (is_dir && name[1] != '\0') {
- /*
- * Append "/" to the pathname. The root
- * directory is a special case; it already
- * ends in slash.
- */
- buf[size - 2] = '/';
- buf[size - 1] = '\0';
- }
-
- *buffer = buf;
- return name;
- }
- if (PTR_ERR(name) != -ENAMETOOLONG)
- return name;
-
- kfree(buf);
- size <<= 1;
- if (size > apparmor_path_max)
- return ERR_PTR(-ENAMETOOLONG);
- }
-}
-
-static inline void aa_put_name_buffer(char *buffer)
-{
- kfree(buffer);
-}
-
-/**
- * aa_perm_dentry - check if @profile allows @mask for a file
- * @profile: profile to check against
- * @dentry: dentry of the file
- * @mnt: vfsmount o the file
- * @sa: audit context
- * @mask: requested profile permissions
- * @check: kind of check to perform
- *
- * Returns 0 upon success, or else an error code.
- *
- * @check indicates the file type, and whether the file was accessed through
- * an open file descriptor (AA_CHECK_FD) or not.
- */
-static int aa_perm_dentry(struct aa_profile *profile, struct dentry *dentry,
- struct vfsmount *mnt, struct aa_audit *sa, int check)
-{
- int error;
- char *buffer = NULL;
-
- sa->name = aa_get_name(dentry, mnt, &buffer, check);
- sa->request_mask <<= aa_inode_mode(dentry->d_inode);
- if (IS_ERR(sa->name)) {
- /*
- * deleted files are given a pass on permission checks when
- * accessed through a file descriptor.
- */
- if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
- sa->denied_mask = 0;
- else {
- sa->denied_mask = sa->request_mask;
- sa->error_code = PTR_ERR(sa->name);
- if (sa->error_code == -ENOENT)
- sa->info = "Failed name resolution - object not a valid entry";
- else if (sa->error_code == -ENAMETOOLONG)
- sa->info = "Failed name resolution - name too long";
- else
- sa->info = "Failed name resolution";
- }
- sa->name = NULL;
- } else
- sa->denied_mask = aa_file_denied(profile, sa->name,
- sa->request_mask);
-
- if (!sa->denied_mask)
- sa->error_code = 0;
-
- error = aa_audit(profile, sa);
- aa_put_name_buffer(buffer);
-
- return error;
-}
-
int alloc_default_namespace(void)
{
struct aa_namespace *ns;
@@ -471,20 +273,259 @@ int aa_audit(struct aa_profile *profile,
int type = AUDIT_APPARMOR_DENIED;
struct audit_context *audit_cxt;
- if (likely(!sa->error_code)) {
- if (likely(!PROFILE_AUDIT(profile)))
- /* nothing to log */
- return 0;
- else
- type = AUDIT_APPARMOR_AUDIT;
- } else if (PROFILE_COMPLAIN(profile)) {
+ if (likely(!sa->error_code))
+ type = AUDIT_APPARMOR_AUDIT;
+ else if (PROFILE_COMPLAIN(profile))
type = AUDIT_APPARMOR_ALLOWED;
- }
audit_cxt = apparmor_logsyscall ? current->audit_context : NULL;
return aa_audit_base(profile, sa, audit_cxt, type);
}
+static int aa_audit_file(struct aa_profile *profile, struct aa_audit *sa)
+{
+ if (likely(!sa->error_code)) {
+ int mask = sa->audit_mask & AUDIT_FILE_MASK;
+
+ if (unlikely(PROFILE_AUDIT(profile)))
+ mask |= AUDIT_FILE_MASK;
+
+ if (likely(!(sa->request_mask & mask)))
+ return 0;
+
+ /* mask off perms that are not being force audited */
+ sa->request_mask &= mask | ALL_AA_EXEC_TYPE;
+ } else {
+ int mask = AUDIT_QUIET_MASK(sa->audit_mask);
+
+ if (!(sa->denied_mask & ~mask))
+ return sa->error_code;
+
+ /* mask off perms whose denial is being silenced */
+ sa->denied_mask &= (~mask) | ALL_AA_EXEC_TYPE;
+ }
+
+ return aa_audit(profile, sa);
+}
+
+static int aa_audit_caps(struct aa_profile *profile, struct aa_audit *sa,
+ int cap)
+{
+ if (likely(!sa->error_code)) {
+ if (likely(!PROFILE_AUDIT(profile) &&
+ !cap_raised(profile->audit_caps, cap)))
+ return 0;
+ }
+
+ /* quieting of capabilities is handled the caps_logged cache */
+ return aa_audit(profile, sa);
+}
+
+/**
+ * aa_file_denied - check for @mask access on a file
+ * @profile: profile to check against
+ * @name: pathname of file
+ * @mask: permission mask requested for file
+ * @audit_mask: return audit mask for the match
+ *
+ * Return %0 on success, or else the permissions in @mask that the
+ * profile denies.
+ */
+static int aa_file_denied(struct aa_profile *profile, const char *name,
+ int mask, int *audit_mask)
+{
+ return (mask & ~aa_match(profile->file_rules, name, audit_mask));
+}
+
+/**
+ * aa_link_denied - check for permission to link a file
+ * @profile: profile to check against
+ * @link: pathname of link being created
+ * @target: pathname of target to be linked to
+ * @target_mode: UGO shift for target inode
+ * @request_mask: the permissions subset valid only if link succeeds
+ * @audit_mask: return the audit_mask for the link permission
+ * Return %0 on success, or else the permissions that the profile denies.
+ */
+static int aa_link_denied(struct aa_profile *profile, const char *link,
+ const char *target, int target_mode,
+ int *request_mask, int *audit_mask)
+{
+ unsigned int state;
+ int l_mode, t_mode, denied_mask = 0;
+ int link_mask = AA_MAY_LINK << target_mode;
+
+ *request_mask = link_mask;
+
+ l_mode = aa_match_state(profile->file_rules, DFA_START, link, &state);
+
+ if (l_mode & link_mask) {
+ int mode;
+ /* test to see if target can be paired with link */
+ state = aa_dfa_null_transition(profile->file_rules, state);
+ mode = aa_match_state(profile->file_rules, state, target,
+ &state);
+
+ if (!(mode & link_mask))
+ denied_mask |= link_mask;
+
+ *audit_mask = dfa_audit_mask(profile->file_rules, state);
+
+ /* return if link subset test is not required */
+ if (!(mode & (AA_LINK_SUBSET_TEST << target_mode)))
+ return denied_mask;
+ }
+
+ /* Do link perm subset test
+ * If a subset test is required a permission subset test of the
+ * perms for the link are done against the user::other of the
+ * target's 'r', 'w', 'x', 'a', 'k', and 'm' permissions.
+ *
+ * If the link has 'x', an exact match of all the execute flags
+ * must match.
+ */
+ denied_mask |= ~l_mode & link_mask;
+
+ t_mode = aa_match(profile->file_rules, target, NULL);
+
+ /* For actual subset test ignore valid-profile-transition flags,
+ * and link bits
+ */
+ l_mode &= AA_FILE_PERMS & ~AA_LINK_BITS;
+ t_mode &= AA_FILE_PERMS & ~AA_LINK_BITS;
+
+ *request_mask = l_mode | link_mask;
+
+ if (l_mode) {
+ denied_mask |= l_mode & ~t_mode;
+ if ((l_mode & AA_EXEC_BITS) &&
+ (l_mode & ALL_AA_EXEC_TYPE) !=
+ (t_mode & ALL_AA_EXEC_TYPE))
+ denied_mask = (denied_mask & ~ALL_AA_EXEC_TYPE) |
+ (l_mode & (ALL_AA_EXEC_TYPE | AA_EXEC_BITS));
+ }
+
+ return denied_mask;
+}
+
+/**
+ * aa_get_name - compute the pathname of a file
+ * @dentry: dentry of the file
+ * @mnt: vfsmount of the file
+ * @buffer: buffer that aa_get_name() allocated
+ * @check: AA_CHECK_DIR is set if the file is a directory
+ *
+ * Returns a pointer to the beginning of the pathname (which usually differs
+ * from the beginning of the buffer), or an error code.
+ *
+ * We need @check to indicate whether the file is a directory or not because
+ * the file may not yet exist, and so we cannot check the inode's file type.
+ */
+static char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt,
+ char **buffer, int check)
+{
+ char *name;
+ int is_dir, size = 256;
+
+ is_dir = (check & AA_CHECK_DIR) ? 1 : 0;
+
+ for (;;) {
+ char *buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ name = d_namespace_path(dentry, mnt, buf, size - is_dir);
+ if (!IS_ERR(name)) {
+ if (name[0] != '/') {
+ /*
+ * This dentry is not connected to the
+ * namespace root -- reject access.
+ */
+ kfree(buf);
+ return ERR_PTR(-ENOENT);
+ }
+ if (is_dir && name[1] != '\0') {
+ /*
+ * Append "/" to the pathname. The root
+ * directory is a special case; it already
+ * ends in slash.
+ */
+ buf[size - 2] = '/';
+ buf[size - 1] = '\0';
+ }
+
+ *buffer = buf;
+ return name;
+ }
+ if (PTR_ERR(name) != -ENAMETOOLONG)
+ return name;
+
+ kfree(buf);
+ size <<= 1;
+ if (size > apparmor_path_max)
+ return ERR_PTR(-ENAMETOOLONG);
+ }
+}
+
+static inline void aa_put_name_buffer(char *buffer)
+{
+ kfree(buffer);
+}
+
+/**
+ * aa_perm_dentry - check if @profile allows @mask for a file
+ * @profile: profile to check against
+ * @dentry: dentry of the file
+ * @mnt: vfsmount o the file
+ * @sa: audit context
+ * @mask: requested profile permissions
+ * @check: kind of check to perform
+ *
+ * Returns 0 upon success, or else an error code.
+ *
+ * @check indicates the file type, and whether the file was accessed through
+ * an open file descriptor (AA_CHECK_FD) or not.
+ */
+static int aa_perm_dentry(struct aa_profile *profile, struct dentry *dentry,
+ struct vfsmount *mnt, struct aa_audit *sa, int check)
+{
+ int error;
+ char *buffer = NULL;
+
+ sa->name = aa_get_name(dentry, mnt, &buffer, check);
+ sa->request_mask <<= aa_inode_mode(dentry->d_inode);
+ if (IS_ERR(sa->name)) {
+ /*
+ * deleted files are given a pass on permission checks when
+ * accessed through a file descriptor.
+ */
+ if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
+ sa->denied_mask = 0;
+ else {
+ sa->denied_mask = sa->request_mask;
+ sa->error_code = PTR_ERR(sa->name);
+ if (sa->error_code == -ENOENT)
+ sa->info = "Failed name resolution - object not a valid entry";
+ else if (sa->error_code == -ENAMETOOLONG)
+ sa->info = "Failed name resolution - name too long";
+ else
+ sa->info = "Failed name resolution";
+ }
+ sa->name = NULL;
+ } else
+ sa->denied_mask = aa_file_denied(profile, sa->name,
+ sa->request_mask,
+ &sa->audit_mask);
+
+ if (!sa->denied_mask)
+ sa->error_code = 0;
+
+ error = aa_audit_file(profile, sa);
+ aa_put_name_buffer(buffer);
+
+ return error;
+}
+
/**
* aa_attr - check if attribute change is allowed
* @profile: profile to check against
@@ -621,10 +662,11 @@ int aa_perm_path(struct aa_profile *prof
else
sa.request_mask = mask << AA_OTHER_SHIFT;
- sa.denied_mask = aa_file_denied(profile, name, sa.request_mask) ;
+ sa.denied_mask = aa_file_denied(profile, name, sa.request_mask,
+ &sa.audit_mask) ;
sa.error_code = sa.denied_mask ? -EACCES : 0;
- return aa_audit(profile, &sa);
+ return aa_audit_file(profile, &sa);
}
/**
@@ -660,7 +702,7 @@ int aa_capability(struct aa_task_context
sa.name = capability_names[cap];
sa.error_code = error;
- error = aa_audit(cxt->profile, &sa);
+ error = aa_audit_caps(cxt->profile, &sa, cap);
return error;
}
@@ -709,11 +751,12 @@ int aa_link(struct aa_profile *profile,
if (sa.name && sa.name2) {
sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2,
aa_inode_mode(target->d_inode),
- &sa.request_mask);
+ &sa.request_mask,
+ &sa.audit_mask);
sa.error_code = sa.denied_mask ? -EACCES : 0;
}
- error = aa_audit(profile, &sa);
+ error = aa_audit_file(profile, &sa);
aa_put_name_buffer(buffer);
aa_put_name_buffer(buffer2);
@@ -802,8 +845,8 @@ aa_register_find(struct aa_profile *prof
new_profile =
aa_dup_profile(profile->ns->null_complain_profile);
} else {
- aa_audit_reject(profile, sa);
- return ERR_PTR(-EACCES); /* was -EPERM */
+ sa->error_code = -EACCES;
+ return ERR_PTR(aa_audit_file(profile, sa));
}
} else {
/* Only way we can get into this code is if task
@@ -863,7 +906,8 @@ repeat:
/* Confined task, determine what mode inherit, unconfined or
* mandatory to load new profile
*/
- exec_mode = aa_match(profile->file_rules, filename);
+ exec_mode = aa_match(profile->file_rules, filename,
+ &sa.audit_mask);
if (exec_mode & sa.request_mask) {
switch ((exec_mode >> shift) & AA_EXEC_MODIFIERS) {
@@ -906,6 +950,9 @@ repeat:
break;
}
+ } else if (sa.request_mask & AUDIT_QUIET_MASK(sa.audit_mask)) {
+ /* quiet failed exit */
+ new_profile = ERR_PTR(-EACCES);
} else if (complain) {
/* There was no entry in calling profile
* describing mode to execute image in.
@@ -916,8 +963,8 @@ repeat:
exec_mode |= AA_EXEC_UNSAFE << shift;
} else {
sa.denied_mask = sa.request_mask;
- aa_audit_reject(profile, &sa);
- new_profile = ERR_PTR(-EPERM);
+ sa.error_code = -EACCES;
+ new_profile = ERR_PTR(aa_audit_file(profile, &sa));
}
} else {
/* Unconfined task, load profile if it exists */
@@ -973,6 +1020,7 @@ repeat:
sa.info = "set profile";
aa_audit_hint(new_profile, &sa);
}
+
cleanup:
aa_put_name_buffer(buffer);
if (IS_ERR(new_profile))
@@ -1149,7 +1197,7 @@ repeat:
if (PROFILE_COMPLAIN(profile) ||
(ns == profile->ns &&
- (aa_match(profile->file_rules, name) & AA_CHANGE_PROFILE)))
+ (aa_match(profile->file_rules, name, NULL) & AA_CHANGE_PROFILE)))
error = do_change_profile(profile, ns, name, 0, 0, &sa);
else {
/* check for a rule with a namespace prepended */
@@ -1356,9 +1404,11 @@ void aa_change_task_context(struct task_
call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback);
}
if (new_cxt) {
- /* clear the caps_logged cache, so that new profile/hat has
- * chance to emit its own set of cap messages */
- new_cxt->caps_logged = CAP_EMPTY_SET;
+ /* set the caps_logged cache to the quiet_caps mask
+ * this has the effect of quieting caps that are not
+ * supposed to be logged
+ */
+ new_cxt->caps_logged = profile->quiet_caps;
new_cxt->cookie = cookie;
new_cxt->task = task;
new_cxt->profile = aa_dup_profile(profile);
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -14,6 +14,7 @@
#include <linux/errno.h>
#include "apparmor.h"
#include "match.h"
+#include "inline.h"
static struct table_header *unpack_table(void *blob, size_t bsize)
{
@@ -295,13 +296,17 @@ unsigned int aa_dfa_null_transition(stru
* aa_dfa_match - find accept perm for @str in @dfa
* @dfa: the dfa to match @str against
* @str: the string to match against the dfa
+ * @audit_mask: the audit_mask for the final state
*
* aa_dfa_match will match @str and return the accept perms for the
* final state.
*/
-unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str)
+unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str, int *audit_mask)
{
- return ACCEPT_TABLE(dfa)[aa_dfa_next_state(dfa, DFA_START, str)];
+ int state = aa_dfa_next_state(dfa, DFA_START, str);
+ if (audit_mask)
+ *audit_mask = dfa_audit_mask(dfa, state);
+ return ACCEPT_TABLE(dfa)[state];
}
/**
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -310,6 +310,10 @@ static struct aa_profile *aa_unpack_prof
if (!aa_is_u32(e, &(profile->capabilities), NULL))
goto fail;
+ if (!aa_is_u32(e, &(profile->audit_caps), NULL))
+ goto fail;
+ if (!aa_is_u32(e, &(profile->quiet_caps), NULL))
+ goto fail;
/* get file rules */
profile->file_rules = aa_unpack_dfa(e);
@@ -317,6 +321,10 @@ static struct aa_profile *aa_unpack_prof
error = PTR_ERR(profile->file_rules);
profile->file_rules = NULL;
goto fail;
+ if (!aa_is_u16(e, &profile->audit_network[i], NULL))
+ goto fail;
+ if (!aa_is_u16(e, &profile->quiet_network[i], NULL))
+ goto fail;
}
if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
@@ -360,7 +368,7 @@ static int aa_verify_header(struct aa_ex
}
/* check that the interface version is currently supported */
- if (e->version != 3) {
+ if (e->version != 4) {
struct aa_audit sa;
memset(&sa, 0, sizeof(sa));
sa.operation = operation;