diff --git a/kernel-patches/for-mainline/apparmor-audit.diff b/kernel-patches/for-mainline/apparmor-audit.diff index 4db2e65b7..7dc1bb225 100644 --- a/kernel-patches/for-mainline/apparmor-audit.diff +++ b/kernel-patches/for-mainline/apparmor-audit.diff @@ -12,9 +12,9 @@ Signed-off-by: Andreas Gruenbacher Signed-off-by: John Johansen --- - include/linux/audit.h | 7 ++++++- + include/linux/audit.h | 12 +++++++++++- kernel/audit.c | 6 ++++-- - 2 files changed, 10 insertions(+), 3 deletions(-) + 2 files changed, 15 insertions(+), 3 deletions(-) --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -27,16 +27,21 @@ Signed-off-by: John Johansen * 1600 - 1699 kernel crypto events * 1700 - 1799 kernel anomaly records * 1800 - 1999 future kernel use (maybe integrity labels and related events) -@@ -114,6 +114,8 @@ - #define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */ - #define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */ +@@ -109,6 +109,13 @@ + #define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Add a XFRM policy */ + #define AUDIT_MAC_IPSEC_DELSPD 1414 /* Delete a XFRM policy */ -+#define AUDIT_APPARMOR 1500 /* AppArmor audit */ ++#define AUDIT_APPARMOR_AUDIT 1501 /* AppArmor audited grants */ ++#define AUDIT_APPARMOR_ALLOWED 1502 /* Allowed Access for learning */ ++#define AUDIT_APPARMOR_DENIED 1503 ++#define AUDIT_APPARMOR_HINT 1504 /* Process Tracking information */ ++#define AUDIT_APPARMOR_STATUS 1505 /* Changes in config */ ++#define AUDIT_APPARMOR_ERROR 1506 /* Internal AppArmor Errors */ + - #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ - - /* Rule flags */ -@@ -499,6 +501,9 @@ extern void audit_log(struct audit_ + #define AUDIT_FIRST_KERN_ANOM_MSG 1700 + #define AUDIT_LAST_KERN_ANOM_MSG 1799 + #define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */ +@@ -499,6 +506,9 @@ extern void audit_log(struct audit_ __attribute__((format(printf,4,5))); extern struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type); diff --git a/kernel-patches/for-mainline/apparmor-lockdep.diff b/kernel-patches/for-mainline/apparmor-lockdep.diff deleted file mode 100644 index d66395957..000000000 --- a/kernel-patches/for-mainline/apparmor-lockdep.diff +++ /dev/null @@ -1,145 +0,0 @@ -From: John Johansen -Subject: AppArmor: add lock subtyping so lockdep does not report false dependencies - -AppArmor uses lock subtyping to avoid false positives from lockdep. The -profile lock is often taken nested, but it is guaranteed to be in a lock -safe order and not the same lock when done, so it is safe. - -A third lock type (aa_lock_task_release) is given to the profile lock -when it is taken in soft irq context during task release (aa_release). -This is to avoid a false positive between the task lock and the profile -lock. In task context the profile lock wraps the task lock with irqs -off, but the kernel takes the task lock with irqs enabled. This won't -ever result in a deadlock because aa_release doesn't need to take the -task lock of the dead task that is released. - -Signed-off-by: John Johansen -Signed-off-by: Andreas Gruenbacher -Cc: Ingo Molnar - ---- - security/apparmor/apparmor.h | 7 +++++++ - security/apparmor/inline.h | 25 ++++++++++++++++++------- - security/apparmor/locking.txt | 21 +++++++++++++++------ - security/apparmor/main.c | 6 +++--- - 4 files changed, 43 insertions(+), 16 deletions(-) - ---- a/security/apparmor/apparmor.h -+++ b/security/apparmor/apparmor.h -@@ -185,6 +185,13 @@ struct aa_audit { - #define AA_CHECK_DIR 2 /* file type is directory */ - #define AA_CHECK_MANGLE 4 /* leave extra room for name mangling */ - -+/* lock subtypes so lockdep does not raise false dependencies */ -+enum aa_lock_class { -+ aa_lock_normal, -+ aa_lock_nested, -+ aa_lock_task_release -+}; -+ - /* main.c */ - extern int alloc_null_complain_profile(void); - extern void free_null_complain_profile(void); ---- a/security/apparmor/inline.h -+++ b/security/apparmor/inline.h -@@ -99,7 +99,8 @@ static inline void aa_free_task_context( - * While the profile is locked, local interrupts are disabled. This also - * gives us RCU reader safety. - */ --static inline void lock_profile(struct aa_profile *profile) -+static inline void lock_profile_nested(struct aa_profile *profile, -+ enum aa_lock_class lock_class) - { - /* We always lock top-level profiles instead of children. */ - if (profile) -@@ -112,7 +113,13 @@ static inline void lock_profile(struct a - * the task_free_security hook, which may run in RCU context. - */ - if (profile) -- spin_lock_irqsave(&profile->lock, profile->int_flags); -+ spin_lock_irqsave_nested(&profile->lock, profile->int_flags, -+ lock_class); -+} -+ -+static inline void lock_profile(struct aa_profile *profile) -+{ -+ lock_profile_nested(profile, aa_lock_normal); - } - - /** -@@ -161,17 +168,21 @@ static inline void lock_both_profiles(st - */ - if (!profile1 || profile1 == profile2) { - if (profile2) -- spin_lock_irqsave(&profile2->lock, profile2->int_flags); -+ spin_lock_irqsave_nested(&profile2->lock, -+ profile2->int_flags, -+ aa_lock_normal); - } else if (profile1 > profile2) { - /* profile1 cannot be NULL here. */ -- spin_lock_irqsave(&profile1->lock, profile1->int_flags); -+ spin_lock_irqsave_nested(&profile1->lock, profile1->int_flags, -+ aa_lock_normal); - if (profile2) -- spin_lock(&profile2->lock); -+ spin_lock_nested(&profile2->lock, aa_lock_nested); - - } else { - /* profile2 cannot be NULL here. */ -- spin_lock_irqsave(&profile2->lock, profile2->int_flags); -- spin_lock(&profile1->lock); -+ spin_lock_irqsave_nested(&profile2->lock, profile2->int_flags, -+ aa_lock_normal); -+ spin_lock_nested(&profile1->lock, aa_lock_nested); - } - } - ---- a/security/apparmor/locking.txt -+++ b/security/apparmor/locking.txt -@@ -51,9 +51,18 @@ list, and can sleep. This ensures that p - won't race with itself. We release the profile_list_lock as soon as - possible to avoid stalling exec during profile loading/replacement/removal. - --lock_dep reports a false 'possible irq lock inversion dependency detected' --when the profile lock is taken in aa_release. This is due to that the --task_lock is often taken inside the profile lock but other kernel code --takes the task_lock with interrupts enabled. A deadlock will not actually --occur because apparmor does not take the task_lock in hard_irq or soft_irq --context. -+AppArmor uses lock subtyping to avoid false positives from lockdep. The -+profile lock is often taken nested, but it is guaranteed to be in a lock -+safe order and not the same lock when done, so it is safe. -+ -+A third lock type (aa_lock_task_release) is given to the profile lock -+when it is taken in soft irq context during task release (aa_release). -+This is to avoid a false positive between the task lock and the profile -+lock. In task context the profile lock wraps the task lock with irqs -+off, but the kernel takes the task lock with irqs enabled. This won't -+result in a deadlock because for a deadlock to occur the kernel must -+take dead task A's lock (irqs on), the rcu callback hook freeing -+dead task A must be run and AppArmor must be changing the profile on -+dead task A. The kernel should not be taking a dead task's task_lock -+at the same time the task is being freed by task rcu cleanup other wise -+the task would not be out of its quiescent period. ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -1081,8 +1081,8 @@ void aa_release(struct task_struct *task - * sufficient to prevent the replacement race so we do not lock - * the task. - * -- * lock_dep reports a false 'possible irq lock inversion dependency' -- * between the profile lock and the task_lock. -+ * Use lock subtyping to avoid lockdep reporting a false irq -+ * possible inversion between the task_lock and profile_lock - * - * We also avoid taking the task_lock here because lock_dep - * would report another false {softirq-on-W} potential irq_lock -@@ -1095,7 +1095,7 @@ void aa_release(struct task_struct *task - repeat: - profile = aa_get_profile(task); - if (profile) { -- lock_profile(profile); -+ lock_profile_nested(profile, aa_lock_task_release); - cxt = aa_task_context(task); - if (unlikely(!cxt || cxt->profile != profile)) { - unlock_profile(profile); diff --git a/kernel-patches/for-mainline/apparmor-main.diff b/kernel-patches/for-mainline/apparmor-main.diff index fb5b393cd..5a7dd767a 100644 --- a/kernel-patches/for-mainline/apparmor-main.diff +++ b/kernel-patches/for-mainline/apparmor-main.diff @@ -6,11 +6,13 @@ The underlying functions by which the AppArmor LSM hooks are implemented. Signed-off-by: John Johansen Signed-off-by: Andreas Gruenbacher -Index: b/security/apparmor/main.c -=================================================================== +--- + security/apparmor/main.c | 1248 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 1248 insertions(+) + --- /dev/null +++ b/security/apparmor/main.c -@@ -0,0 +1,1399 @@ +@@ -0,0 +1,1248 @@ +/* + * Copyright (C) 2002-2007 Novell/SUSE + * @@ -51,17 +53,6 @@ Index: b/security/apparmor/main.c + */ +struct aa_profile *null_complain_profile; + -+static inline void aa_permerror2result(int perm_result, struct aa_audit *sa) -+{ -+ if (perm_result == 0) { /* success */ -+ sa->result = 1; -+ sa->error_code = 0; -+ } else { /* -ve internal error code or +ve mask of denied perms */ -+ sa->result = 0; -+ sa->error_code = perm_result; -+ } -+} -+ +/** + * aa_file_denied - check for @mask access on a file + * @profile: profile to check against @@ -82,16 +73,17 @@ Index: b/security/apparmor/main.c + * @profile: profile to check against + * @link: pathname of link being created + * @target: pathname of target to be linked to -+ * ++ * @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) ++ const char *target, int *request_mask) +{ -+ int l_mode, t_mode; ++ int l_mode, t_mode, denied_mask; + + l_mode = aa_match(profile->file_rules, link); + t_mode = aa_match(profile->file_rules, target); ++ *request_mask = l_mode | AA_MAY_LINK; + + /* Link always requires 'l' on the link, a subset of the + * target's 'r', 'w', 'x', and 'm' permissions on the link, and @@ -99,72 +91,17 @@ Index: b/security/apparmor/main.c + * ('i', 'u', 'U', 'p', 'P'). + */ +#define RWXM (MAY_READ | MAY_WRITE | MAY_EXEC | AA_EXEC_MMAP) -+ if ((l_mode & AA_MAY_LINK) && -+ (l_mode & RWXM) && !(l_mode & ~t_mode & RWXM) && -+ (!(l_mode & MAY_EXEC) || -+ ((l_mode & AA_EXEC_MODIFIERS) == (t_mode & AA_EXEC_MODIFIERS) && -+ (l_mode & AA_EXEC_UNSAFE) == (t_mode & AA_EXEC_UNSAFE)))) -+ return 0; ++ denied_mask = ~l_mode & AA_MAY_LINK; ++ if (l_mode & RWXM) ++ denied_mask |= (l_mode & ~ AA_MAY_LINK) & ~t_mode; ++ else ++ denied_mask |= t_mode | AA_MAY_LINK; ++ if (denied_mask & AA_EXEC_MODIFIERS) ++ denied_mask |= MAY_EXEC; ++ +#undef RWXM -+ /* FIXME: There currenly is no way to report which permissions -+ * we expect in t_mode, so linking could fail even after learning -+ * the required l_mode. -+ */ -+ return AA_MAY_LINK; -+} + -+/** -+ * mangle -- escape special characters in str -+ * @str: string to escape -+ * @buffer: buffer containing str -+ * -+ * Escape special characters in @str, which is contained in @buffer. @str must -+ * be aligned to the end of the buffer, and the space between @buffer and @str -+ * may be used for escaping. -+ * -+ * Returns @str if no escaping was necessary, a pointer to the beginning of the -+ * escaped string, or NULL if there was not enough space in @buffer. When -+ * called with a NULL buffer, the return value tells whether any escaping is -+ * necessary. -+ */ -+static const char *mangle(const char *str, char *buffer) -+{ -+ static const char c_escape[] = { -+ ['\a'] = 'a', ['\b'] = 'b', -+ ['\f'] = 'f', ['\n'] = 'n', -+ ['\r'] = 'r', ['\t'] = 't', -+ ['\v'] = 'v', -+ [' '] = ' ', ['\\'] = '\\', -+ }; -+ const char *s; -+ char *t, c; -+ -+#define mangle_escape(c) \ -+ unlikely((unsigned char)(c) < ARRAY_SIZE(c_escape) && \ -+ c_escape[(unsigned char)c]) -+ -+ for (s = (char *)str; (c = *s) != '\0'; s++) -+ if (mangle_escape(c)) -+ goto escape; -+ return str; -+ -+escape: -+ if (!buffer) -+ return NULL; -+ for (s = str, t = buffer; (c = *s) != '\0'; s++) { -+ if (mangle_escape(c)) { -+ if (t == s) -+ return NULL; -+ *t++ = '\\'; -+ *t++ = c_escape[(unsigned char)c]; -+ } else -+ *t++ = c; -+ } -+ *t++ = '\0'; -+ -+#undef mangle_escape -+ -+ return buffer; ++ return denied_mask; +} + +/** @@ -194,12 +131,6 @@ Index: b/security/apparmor/main.c + return ERR_PTR(-ENOMEM); + + name = d_namespace_path(dentry, mnt, buf, size - is_dir); -+ -+ /* Make sure we have enough space for name mangling. */ -+ if (!IS_ERR(name) && -+ (check & AA_CHECK_MANGLE) && name - buf <= size / 2) -+ name = ERR_PTR(-ENAMETOOLONG); -+ + if (!IS_ERR(name)) { + if (name[0] != '/') { + /* @@ -252,14 +183,12 @@ Index: b/security/apparmor/main.c + * 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 mask, -+ int check) ++ struct vfsmount *mnt, struct aa_audit *sa, int check) +{ -+ int denied_mask, error; ++ int error; ++ char *buffer = NULL; + -+again: -+ sa->buffer = NULL; -+ sa->name = aa_get_name(dentry, mnt, &sa->buffer, check); ++ sa->name = aa_get_name(dentry, mnt, &buffer, check); + + if (IS_ERR(sa->name)) { + /* @@ -267,23 +196,19 @@ Index: b/security/apparmor/main.c + * accessed through a file descriptor. + */ + if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD)) -+ denied_mask = 0; ++ sa->denied_mask = 0; + else -+ denied_mask = PTR_ERR(sa->name); ++ sa->denied_mask = PTR_ERR(sa->name); + sa->name = NULL; + } else -+ denied_mask = aa_file_denied(profile, sa->name, mask); ++ sa->denied_mask = aa_file_denied(profile, sa->name, ++ sa->requested_mask); + -+ aa_permerror2result(denied_mask, sa); ++ if (!sa->denied_mask) ++ sa->error_code = 0; + + error = aa_audit(profile, sa); -+ -+ aa_put_name_buffer(sa->buffer); -+ if (error == -ENAMETOOLONG) { -+ BUG_ON(check & AA_CHECK_MANGLE); -+ check |= AA_CHECK_MANGLE; -+ goto again; -+ } ++ aa_put_name_buffer(buffer); + + return error; +} @@ -364,53 +289,165 @@ Index: b/security/apparmor/main.c + null_complain_profile = NULL; +} + -+/** -+ * aa_audit_message - Log a message to the audit subsystem -+ * @profile: profile to check against -+ * @gfp: allocation flags -+ * @flags: audit flags -+ * @fmt: varargs fmt -+ */ -+int aa_audit_message(struct aa_profile *profile, gfp_t gfp, const char *fmt, -+ ...) ++static void aa_audit_file_mask(struct audit_buffer *ab, const char *name, ++ int mask) +{ -+ int ret; -+ struct aa_audit sa; ++ char mask_str[10], *m = mask_str; + -+ sa.type = AA_AUDITTYPE_MSG; -+ sa.name = fmt; -+ va_start(sa.vaval, fmt); -+ sa.flags = 0; -+ sa.gfp_mask = gfp; -+ sa.error_code = 0; -+ sa.result = 0; /* fake failure: force message to be logged */ ++ if (mask & AA_EXEC_MMAP) ++ *m++ = 'm'; ++ if (mask & MAY_READ) ++ *m++ = 'r'; ++ if (mask & MAY_WRITE) ++ *m++ = 'w'; ++ if (mask & (MAY_EXEC | AA_EXEC_MODIFIERS)) { ++ if (mask & AA_EXEC_UNSAFE) { ++ if (mask & AA_EXEC_INHERIT) ++ *m++ = 'i'; ++ if (mask & AA_EXEC_UNCONFINED) ++ *m++ = 'u'; ++ if (mask & AA_EXEC_PROFILE) ++ *m++ = 'p'; ++ } else { ++ if (mask & AA_EXEC_INHERIT) ++ *m++ = 'I'; ++ if (mask & AA_EXEC_UNCONFINED) ++ *m++ = 'U'; ++ if (mask & AA_EXEC_PROFILE) ++ *m++ = 'P'; ++ } ++ if (mask & MAY_EXEC) ++ *m++ = 'x'; ++ } ++ if (mask & AA_MAY_LINK) ++ *m++ = 'l'; ++ *m++ = '\0'; + -+ ret = aa_audit(profile, &sa); ++ audit_log_format(ab, " %s=\"%s\"", name, mask_str); ++} + -+ va_end(sa.vaval); ++/** ++ * aa_audit - Log an audit event to the audit subsystem ++ * @profile: profile to check against ++ * @sa: audit event ++ * @audit_cxt: audit context to log message to ++ * @type: audit event number ++ */ ++static int aa_audit_base(struct aa_profile *profile, struct aa_audit *sa, ++ struct audit_context *audit_cxt, int type) ++{ ++ struct audit_buffer *ab = NULL; + -+ return ret; ++ ab = audit_log_start(audit_cxt, sa->gfp_mask, type); ++ ++ if (!ab) { ++ AA_ERROR("Unable to log event (%d) to audit subsys\n", ++ type); ++ /* don't fail operations in complain mode even if logging ++ * fails */ ++ return type == AUDIT_APPARMOR_ALLOWED ? 0 : -ENOMEM; ++ } ++ ++ if (sa->operation) ++ audit_log_format(ab, "operation=\"%s\"", sa->operation); ++ ++ if (sa->info) ++ audit_log_format(ab, " info=\"%s\"", sa->info); ++ ++ if (sa->requested_mask) ++ aa_audit_file_mask(ab, "requested_mask", sa->requested_mask); ++ ++ if (sa->denied_mask) ++ aa_audit_file_mask(ab, "denied_mask", sa->denied_mask); ++ ++ if (sa->iattr) { ++ struct iattr *iattr = sa->iattr; ++ ++ audit_log_format(ab, " attribute=\"%s%s%s%s%s%s%s\"", ++ iattr->ia_valid & ATTR_MODE ? "mode," : "", ++ iattr->ia_valid & ATTR_UID ? "uid," : "", ++ iattr->ia_valid & ATTR_GID ? "gid," : "", ++ iattr->ia_valid & ATTR_SIZE ? "size," : "", ++ iattr->ia_valid & (ATTR_ATIME | ATTR_ATIME_SET) ? ++ "atime," : "", ++ iattr->ia_valid & (ATTR_MTIME | ATTR_MTIME_SET) ? ++ "mtime," : "", ++ iattr->ia_valid & ATTR_CTIME ? "ctime," : ""); ++ } ++ ++ if (sa->task) ++ audit_log_format(ab, " task=%d", sa->task); ++ ++ if (sa->parent) ++ audit_log_format(ab, " parent=%d", sa->parent); ++ ++ if (sa->name) { ++ audit_log_format(ab, " name="); ++ audit_log_untrustedstring(ab, sa->name); ++ } ++ ++ if (sa->name2) { ++ audit_log_format(ab, " name2="); ++ audit_log_untrustedstring(ab, sa->name2); ++ } ++ ++ if (sa->magic_token) ++ audit_log_format(ab, " magic_token=%llu", sa->magic_token); ++ ++ audit_log_format(ab, " pid=%d", current->pid); ++ ++ if (profile) { ++ audit_log_format(ab, " profile="); ++ audit_log_untrustedstring(ab, profile->parent->name); ++ } ++ ++ audit_log_end(ab); ++ ++ return type == AUDIT_APPARMOR_ALLOWED ? 0 : sa->error_code; +} + +/** + * aa_audit_syscallreject - Log a syscall rejection to the audit subsystem + * @profile: profile to check against -+ * @msg: string describing syscall being rejected + * @gfp: memory allocation flags ++ * @msg: string describing syscall being rejected + */ +int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp, + const char *msg) +{ + struct aa_audit sa; -+ -+ sa.type = AA_AUDITTYPE_SYSCALL; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "syscall"; + sa.name = msg; -+ sa.flags = 0; + sa.gfp_mask = gfp; -+ sa.error_code = 0; -+ sa.result = 0; /* failure */ ++ sa.error_code = -EPERM; + -+ return aa_audit(profile, &sa); ++ return aa_audit_base(profile, &sa, current->audit_context, ++ AUDIT_APPARMOR_DENIED); ++} ++ ++int aa_audit_message(struct aa_profile *profile, struct aa_audit *sa, ++ int type) ++{ ++ struct audit_context *audit_cxt; ++ ++ audit_cxt = apparmor_logsyscall ? current->audit_context : NULL; ++ return aa_audit_base(profile, sa, audit_cxt, type); ++} ++ ++void aa_audit_hint(struct aa_profile *profile, struct aa_audit *sa) ++{ ++ aa_audit_message(profile, sa, AUDIT_APPARMOR_HINT); ++} ++ ++void aa_audit_status(struct aa_profile *profile, struct aa_audit *sa) ++{ ++ aa_audit_message(profile, sa, AUDIT_APPARMOR_STATUS); ++} ++ ++int aa_audit_reject(struct aa_profile *profile, struct aa_audit *sa) ++{ ++ return aa_audit_message(profile, sa, AUDIT_APPARMOR_DENIED); +} + +/** @@ -420,174 +457,21 @@ Index: b/security/apparmor/main.c + */ +int aa_audit(struct aa_profile *profile, struct aa_audit *sa) +{ -+ struct audit_buffer *ab = NULL; ++ int type = AUDIT_APPARMOR_DENIED; + struct audit_context *audit_cxt; + -+ const char *logcls; -+ unsigned int flags; -+ int audit = 0, -+ complain = 0, -+ error = -EINVAL, -+ opspec_error = -EACCES; -+ -+ const gfp_t gfp_mask = sa->gfp_mask; -+ -+ /* -+ * sa->result: 1 success, 0 failure -+ * sa->error_code: success: 0 -+ * failure: +ve mask of failed permissions or -ve -+ * system error -+ */ -+ -+ if (likely(sa->result)) { -+ if (likely(!PROFILE_AUDIT(profile))) { ++ if (likely(!sa->error_code)) { ++ if (likely(!PROFILE_AUDIT(profile))) + /* nothing to log */ -+ error = 0; -+ goto out; -+ } else { -+ audit = 1; -+ logcls = "AUDITING"; -+ } -+ } else if (sa->error_code < 0) { -+ audit_log(current->audit_context, gfp_mask, AUDIT_APPARMOR, -+ "Internal error auditing event type %d (error %d)", -+ sa->type, sa->error_code); -+ AA_ERROR("Internal error auditing event type %d (error %d)\n", -+ sa->type, sa->error_code); -+ error = sa->error_code; -+ goto out; -+ } else if (sa->type == AA_AUDITTYPE_SYSCALL) { -+ /* Currently AA_AUDITTYPE_SYSCALL is for rejects only. -+ * Values set by aa_audit_syscallreject will get us here. -+ */ -+ logcls = "REJECTING"; -+ } else { -+ complain = PROFILE_COMPLAIN(profile); -+ logcls = complain ? "PERMITTING" : "REJECTING"; ++ return 0; ++ else ++ type = AUDIT_APPARMOR_AUDIT; ++ } else if (PROFILE_COMPLAIN(profile)) { ++ type = AUDIT_APPARMOR_ALLOWED; + } + -+ /* In future extend w/ per-profile flags -+ * (flags |= sa->profile->flags) -+ */ -+ flags = sa->flags; -+ if (apparmor_logsyscall) -+ flags |= AA_AUDITFLAG_AUDITSS_SYSCALL; -+ -+ -+ /* Force full audit syscall logging regardless of global setting if -+ * we are rejecting a syscall -+ */ -+ if (sa->type == AA_AUDITTYPE_SYSCALL) { -+ audit_cxt = current->audit_context; -+ } else { -+ audit_cxt = (flags & AA_AUDITFLAG_AUDITSS_SYSCALL) ? -+ current->audit_context : NULL; -+ } -+ -+ ab = audit_log_start(audit_cxt, gfp_mask, AUDIT_APPARMOR); -+ -+ if (!ab) { -+ AA_ERROR("Unable to log event (%d) to audit subsys\n", -+ sa->type); -+ if (complain) -+ error = 0; -+ goto out; -+ } -+ -+ /* messages get special handling */ -+ if (sa->type == AA_AUDITTYPE_MSG) { -+ audit_log_vformat(ab, sa->name, sa->vaval); -+ audit_log_end(ab); -+ error = 0; -+ goto out; -+ } -+ -+ if (sa->type & AA_MANGLE_NAME) { -+ sa->name = mangle(sa->name, sa->buffer); -+ if (!sa->name) -+ return -ENAMETOOLONG; -+ } -+ if (sa->type & AA_MANGLE_NAME2) { -+ sa->name2 = mangle(sa->name2, sa->buffer2); -+ if (!sa->name2) -+ return -ENAMETOOLONG; -+ -+ } -+ -+ /* log operation */ -+ -+ audit_log_format(ab, "%s ", logcls); /* REJECTING/ALLOWING/etc */ -+ -+#define NOFLAGS(x) ((x) & ~(AA_MANGLE_NAME | AA_MANGLE_NAME2)) -+ -+ switch(NOFLAGS(sa->type)) { -+ case NOFLAGS(AA_AUDITTYPE_FILE): { -+ int perm = audit ? sa->mask : sa->error_code; -+ -+ audit_log_format(ab, "%s%s%s%s%s access to %s ", -+ perm & AA_EXEC_MMAP ? "m" : "", -+ perm & MAY_READ ? "r" : "", -+ perm & MAY_WRITE ? "w" : "", -+ perm & MAY_EXEC ? "x" : "", -+ perm & AA_MAY_LINK ? "l" : "", -+ sa->name); -+ opspec_error = -EPERM; -+ break; -+ } -+ case NOFLAGS(AA_AUDITTYPE_DIR): -+ audit_log_format(ab, "%s on %s ", sa->name2, sa->name); -+ break; -+ case NOFLAGS(AA_AUDITTYPE_ATTR): { -+ struct iattr *iattr = sa->iattr; -+ -+ audit_log_format(ab, -+ "attribute (%s%s%s%s%s%s%s) change to %s ", -+ iattr->ia_valid & ATTR_MODE ? "mode," : "", -+ iattr->ia_valid & ATTR_UID ? "uid," : "", -+ iattr->ia_valid & ATTR_GID ? "gid," : "", -+ iattr->ia_valid & ATTR_SIZE ? "size," : "", -+ ((iattr->ia_valid & ATTR_ATIME_SET) || -+ (iattr->ia_valid & ATTR_ATIME)) ? "atime," : "", -+ ((iattr->ia_valid & ATTR_MTIME_SET) || -+ (iattr->ia_valid & ATTR_MTIME)) ? "mtime," : "", -+ iattr->ia_valid & ATTR_CTIME ? "ctime," : "", -+ sa->name); -+ break; -+ } -+ case NOFLAGS(AA_AUDITTYPE_XATTR): -+ audit_log_format(ab, "%s on %s ", sa->name2, sa->name); -+ break; -+ case NOFLAGS(AA_AUDITTYPE_LINK): -+ audit_log_format(ab, "link access from %s to %s ", sa->name, -+ sa->name2); -+ break; -+ case NOFLAGS(AA_AUDITTYPE_CAP): -+ audit_log_format(ab, "access to capability '%s' ", -+ capability_names[sa->capability]); -+ opspec_error = -EPERM; -+ break; -+ case NOFLAGS(AA_AUDITTYPE_SYSCALL): -+ audit_log_format(ab, "access to syscall '%s' ", sa->name); -+ opspec_error = -EPERM; -+ break; -+ default: -+ WARN_ON(1); -+ return error; -+ } -+ -+#undef NOFLAGS -+ -+ audit_log_format(ab, "(%d profile %s active %s)", -+ current->pid, profile->parent->name, profile->name); -+ -+ audit_log_end(ab); -+ -+ if (complain) -+ error = 0; -+ else -+ error = sa->result ? 0 : opspec_error; -+out: -+ return error; ++ audit_cxt = apparmor_logsyscall ? current->audit_context : NULL; ++ return aa_audit_base(profile, sa, audit_cxt, type); +} + +/** @@ -604,10 +488,12 @@ Index: b/security/apparmor/main.c + int error, check; + struct aa_audit sa; + -+ sa.type = AA_AUDITTYPE_ATTR; -+ sa.iattr = iattr; -+ sa.flags = 0; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "setattr"; + sa.gfp_mask = GFP_KERNEL; ++ sa.iattr = iattr; ++ sa.requested_mask = MAY_WRITE; ++ sa.error_code = -EACCES; + + check = 0; + if (inode && S_ISDIR(inode->i_mode)) @@ -615,7 +501,7 @@ Index: b/security/apparmor/main.c + if (iattr->ia_valid & ATTR_FILE) + check |= AA_CHECK_FD; + -+ error = aa_perm_dentry(profile, dentry, mnt, &sa, MAY_WRITE, check); ++ error = aa_perm_dentry(profile, dentry, mnt, &sa, check); + + return error; +} @@ -629,23 +515,24 @@ Index: b/security/apparmor/main.c + * @mask: access mode requested + * @check: kind of check to perform + */ -+int aa_perm_xattr(struct aa_profile *profile, struct dentry *dentry, -+ struct vfsmount *mnt, const char *operation, -+ int mask, int check) ++int aa_perm_xattr(struct aa_profile *profile, const char *operation, ++ struct dentry *dentry, struct vfsmount *mnt, int mask, ++ int check) +{ + struct inode *inode = dentry->d_inode; + int error; + struct aa_audit sa; + -+ sa.type = AA_AUDITTYPE_XATTR; -+ sa.name2 = operation; -+ sa.flags = 0; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = operation; + sa.gfp_mask = GFP_KERNEL; ++ sa.requested_mask = mask; ++ sa.error_code = -EACCES; + + if (inode && S_ISDIR(inode->i_mode)) + check |= AA_CHECK_DIR; + -+ error = aa_perm_dentry(profile, dentry, mnt, &sa, mask, check); ++ error = aa_perm_dentry(profile, dentry, mnt, &sa, check); + + return error; +} @@ -661,8 +548,8 @@ Index: b/security/apparmor/main.c + * Determine if access @mask for the file is authorized by @profile. + * Returns 0 on success, or else an error code. + */ -+int aa_perm(struct aa_profile *profile, struct dentry *dentry, -+ struct vfsmount *mnt, int mask, int check) ++int aa_perm(struct aa_profile *profile, const char *operation, ++ struct dentry *dentry, struct vfsmount *mnt, int mask, int check) +{ + struct aa_audit sa; + int error = 0; @@ -670,11 +557,13 @@ Index: b/security/apparmor/main.c + if (mask == 0) + goto out; + -+ sa.type = AA_AUDITTYPE_FILE; -+ sa.mask = mask; -+ sa.flags = 0; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = operation; + sa.gfp_mask = GFP_KERNEL; -+ error = aa_perm_dentry(profile, dentry, mnt, &sa, mask, check); ++ sa.requested_mask = mask; ++ sa.error_code = -EACCES; ++ ++ error = aa_perm_dentry(profile, dentry, mnt, &sa, check); + +out: + return error; @@ -692,32 +581,33 @@ Index: b/security/apparmor/main.c + * by @profile. + * Returns 0 on success, or else an error code. + */ -+int aa_perm_dir(struct aa_profile *profile, struct dentry *dentry, -+ struct vfsmount *mnt, const char *operation, int mask) ++int aa_perm_dir(struct aa_profile *profile, const char *operation, ++ struct dentry *dentry, struct vfsmount *mnt, int mask) +{ + struct aa_audit sa; + -+ sa.type = AA_AUDITTYPE_DIR; -+ sa.name2 = operation; -+ sa.flags = 0; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = operation; + sa.gfp_mask = GFP_KERNEL; ++ sa.requested_mask = mask; ++ sa.error_code = -EACCES; + -+ return aa_perm_dentry(profile, dentry, mnt, &sa, mask, AA_CHECK_DIR); ++ return aa_perm_dentry(profile, dentry, mnt, &sa, AA_CHECK_DIR); +} + -+int aa_perm_path(struct aa_profile *profile, const char *name, int mask) ++int aa_perm_path(struct aa_profile *profile, const char *operation, ++ const char *name, int mask) +{ + struct aa_audit sa; -+ int denied_mask; + -+ sa.type = AA_AUDITTYPE_FILE; -+ sa.mask = mask; -+ sa.flags = 0; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = operation; + sa.gfp_mask = GFP_KERNEL; ++ sa.requested_mask = mask; + sa.name = name; + -+ denied_mask = aa_file_denied(profile, name, mask); -+ aa_permerror2result(denied_mask, &sa); ++ sa.denied_mask = aa_file_denied(profile, name, mask); ++ sa.error_code = sa.denied_mask ? -EACCES : 0; + + return aa_audit(profile, &sa); +} @@ -749,13 +639,11 @@ Index: b/security/apparmor/main.c + */ + cap_raise(cxt->caps_logged, cap); + -+ sa.type = AA_AUDITTYPE_CAP; -+ sa.name = NULL; -+ sa.capability = cap; -+ sa.flags = 0; -+ sa.error_code = 0; -+ sa.result = !error; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "capable"; + sa.gfp_mask = GFP_ATOMIC; ++ sa.name = capability_names[cap]; ++ sa.error_code = error; + + error = aa_audit(cxt->profile, &sa); + @@ -784,42 +672,36 @@ Index: b/security/apparmor/main.c + struct dentry *link, struct vfsmount *link_mnt, + struct dentry *target, struct vfsmount *target_mnt) +{ -+ int denied_mask = -EPERM, error, check = 0; ++ int error, check = 0; + struct aa_audit sa; ++ char *buffer = NULL, *buffer2 = NULL; + -+again: -+ sa.buffer = NULL; -+ sa.name = aa_get_name(link, link_mnt, &sa.buffer, check); -+ sa.buffer2 = NULL; -+ sa.name2 = aa_get_name(target, target_mnt, &sa.buffer2, check); ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "inode_link"; ++ sa.gfp_mask = GFP_KERNEL; ++ sa.name = aa_get_name(link, link_mnt, &buffer, check); ++ sa.name2 = aa_get_name(target, target_mnt, &buffer2, check); + + if (IS_ERR(sa.name)) { -+ denied_mask = PTR_ERR(sa.name); ++ sa.error_code = PTR_ERR(sa.name); + sa.name = NULL; + } + if (IS_ERR(sa.name2)) { -+ denied_mask = PTR_ERR(sa.name2); ++ sa.error_code = PTR_ERR(sa.name2); + sa.name2 = NULL; + } + -+ if (sa.name && sa.name2) -+ denied_mask = aa_link_denied(profile, sa.name, sa.name2); -+ -+ aa_permerror2result(denied_mask, &sa); -+ -+ sa.type = AA_AUDITTYPE_LINK; -+ sa.flags = 0; -+ sa.gfp_mask = GFP_KERNEL; ++ if (sa.name && sa.name2) { ++ sa.requested_mask = AA_MAY_LINK; ++ sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2, ++ &sa.requested_mask); ++ sa.error_code = sa.denied_mask ? -EACCES : 0; ++ } + + error = aa_audit(profile, &sa); + -+ aa_put_name_buffer(sa.buffer); -+ aa_put_name_buffer(sa.buffer2); -+ if (error == -ENAMETOOLONG) { -+ BUG_ON(check & AA_CHECK_MANGLE); -+ check |= AA_CHECK_MANGLE; -+ goto again; -+ } ++ aa_put_name_buffer(buffer); ++ aa_put_name_buffer(buffer2); + + return error; +} @@ -867,12 +749,14 @@ Index: b/security/apparmor/main.c + unlock_profile(profile); + + if (APPARMOR_COMPLAIN(child_cxt) && -+ profile == null_complain_profile) -+ aa_audit_message(profile, GFP_KERNEL, -+ "LOGPROF-HINT fork child=%d " -+ "(%d profile %s active %s)", -+ child->pid, current->pid, -+ profile->parent->name, profile->name); ++ profile == null_complain_profile) { ++ struct aa_audit sa; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "clone"; ++ sa.gfp_mask = GFP_KERNEL; ++ sa.task = child->pid; ++ aa_audit_hint(profile, &sa); ++ } + aa_put_profile(profile); + } else + aa_free_task_context(child_cxt); @@ -881,8 +765,8 @@ Index: b/security/apparmor/main.c +} + +static struct aa_profile * -+aa_register_find(struct aa_profile *profile, const char *name, char *buffer, -+ int mandatory, int complain) ++aa_register_find(struct aa_profile *profile, const char *name, int mandatory, ++ int complain, struct aa_audit *sa) +{ + struct aa_profile *new_profile; + @@ -892,22 +776,14 @@ Index: b/security/apparmor/main.c + AA_DEBUG("%s: setting profile %s\n", + __FUNCTION__, new_profile->name); + } else if (mandatory && profile) { -+ name = mangle(name, buffer); ++ sa->info = "mandatory profile missing"; ++ sa->denied_mask = MAY_EXEC; + if (complain) { -+ aa_audit_message(profile, GFP_KERNEL, "LOGPROF-HINT " -+ "missing_mandatory_profile image '%s' " -+ "(%d profile %s active %s)", -+ name, current->pid, -+ profile->parent->name, profile->name); ++ aa_audit_hint(profile, sa); + profile = aa_dup_profile(null_complain_profile); + } else { -+ aa_audit_message(profile, GFP_KERNEL, "REJECTING " -+ "exec(2) of image '%s'. Profile " -+ "mandatory and not found. " -+ "(%d profile %s active %s)", -+ name, current->pid, -+ profile->parent->name, profile->name); -+ return ERR_PTR(-EPERM); ++ aa_audit_reject(profile, sa); ++ return ERR_PTR(-EACCES); /* was -EPERM */ + } + } else { + /* Only way we can get into this code is if task @@ -934,16 +810,22 @@ Index: b/security/apparmor/main.c + struct file *filp = bprm->file; + struct aa_profile *profile, *old_profile, *new_profile = NULL; + int exec_mode = AA_EXEC_UNSAFE, complain = 0; ++ struct aa_audit sa; + + AA_DEBUG("%s\n", __FUNCTION__); + -+ filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt, &buffer, -+ AA_CHECK_MANGLE); ++ filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt, &buffer, 0); + if (IS_ERR(filename)) { + AA_ERROR("%s: Failed to get filename", __FUNCTION__); + return -ENOENT; + } + ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "exec"; ++ sa.gfp_mask = GFP_KERNEL; ++ sa.name = filename; ++ sa.requested_mask = MAY_EXEC; ++ +repeat: + profile = aa_get_profile(current); + if (profile) { @@ -978,20 +860,8 @@ Index: b/security/apparmor/main.c + filename); + new_profile = aa_register_find(profile, + filename, -+ buffer, 1, -+ complain); -+ break; -+ -+ default: -+ AA_ERROR("Rejecting exec(2) of image '%s'. " -+ "Unknown exec qualifier %x " -+ "(%d profile %s active %s)\n", -+ filename, -+ exec_mode & AA_EXEC_MODIFIERS, -+ current->pid, -+ profile->parent->name, -+ profile->name); -+ new_profile = ERR_PTR(-EPERM); ++ 1, complain, ++ &sa); + break; + } + @@ -1003,18 +873,13 @@ Index: b/security/apparmor/main.c + new_profile = aa_dup_profile(null_complain_profile); + exec_mode |= AA_EXEC_UNSAFE; + } else { -+ filename = mangle(filename, buffer); -+ aa_audit_message(profile, GFP_KERNEL, "REJECTING " -+ "exec(2) of image '%s'. Unable to " -+ "determine exec qualifier. " -+ "(%d profile %s active %s)", -+ filename, current->pid, -+ profile->parent->name, profile->name); ++ sa.denied_mask = MAY_EXEC; ++ aa_audit_reject(profile, &sa); + new_profile = ERR_PTR(-EPERM); + } + } else { + /* Unconfined task, load profile if it exists */ -+ new_profile = aa_register_find(NULL, filename, buffer, 0, 0); ++ new_profile = aa_register_find(NULL, filename, 0, 0, &sa); + if (new_profile == NULL) + goto cleanup; + } @@ -1029,14 +894,10 @@ Index: b/security/apparmor/main.c + if (PTR_ERR(old_profile) == -ESTALE) + goto repeat; + if (PTR_ERR(old_profile) == -EPERM) { -+ filename = mangle(filename, buffer); -+ aa_audit_message(profile, GFP_KERNEL, -+ "REJECTING exec(2) of image '%s'. " -+ "Unable to change profile, ptraced by " -+ "%d. (%d profile %s active %s)", -+ filename, current->parent->pid, -+ current->pid, -+ profile->parent->name, profile->name); ++ sa.denied_mask = MAY_EXEC; ++ sa.info = "unable to set profile due to ptrace"; ++ sa.task = current->parent->pid; ++ aa_audit_reject(profile, &sa); + } + new_profile = old_profile; + goto cleanup; @@ -1061,12 +922,12 @@ Index: b/security/apparmor/main.c + ((unsigned long)bprm->security | bprm_flags); + } + -+ if (complain && new_profile == null_complain_profile) -+ aa_audit_message(new_profile, GFP_ATOMIC, -+ "LOGPROF-HINT changing_profile " -+ "(%d profile %s active %s)", -+ current->pid, -+ new_profile->parent->name, new_profile->name); ++ if (complain && new_profile == null_complain_profile) { ++ sa.requested_mask = 0; ++ sa.name = NULL; ++ sa.info = "set profile"; ++ aa_audit_hint(new_profile, &sa); ++ } +cleanup: + aa_put_name_buffer(buffer); + if (IS_ERR(new_profile)) @@ -1094,8 +955,8 @@ Index: b/security/apparmor/main.c + * sufficient to prevent the replacement race so we do not lock + * the task. + * -+ * lock_dep reports a false 'possible irq lock inversion dependency' -+ * between the profile lock and the task_lock. ++ * Use lock subtyping to avoid lockdep reporting a false irq ++ * possible inversion between the task_lock and profile_lock + * + * We also avoid taking the task_lock here because lock_dep + * would report another false {softirq-on-W} potential irq_lock @@ -1108,7 +969,7 @@ Index: b/security/apparmor/main.c +repeat: + profile = aa_get_profile(task); + if (profile) { -+ lock_profile(profile); ++ lock_profile_nested(profile, aa_lock_task_release); + cxt = aa_task_context(task); + if (unlikely(!cxt || cxt->profile != profile)) { + unlock_profile(profile); @@ -1129,8 +990,8 @@ Index: b/security/apparmor/main.c + * + * Switch to a new hat. Returns %0 on success, error otherwise. + */ -+static int do_change_hat(const char *hat_name, -+ struct aa_task_context *new_cxt, u64 hat_magic) ++static int do_change_hat(const char *hat_name, struct aa_task_context *new_cxt, ++ u64 hat_magic, struct aa_audit *sa) +{ + struct aa_task_context *cxt = aa_task_context(current); + struct aa_profile *sub; @@ -1143,7 +1004,7 @@ Index: b/security/apparmor/main.c + sub = __aa_find_profile(hat_name, &cxt->profile->parent->sub); + + if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, sub)) -+ return -EPERM; ++ return -EACCES; + + if (sub) { + /* change hat */ @@ -1152,11 +1013,8 @@ Index: b/security/apparmor/main.c + struct aa_profile *profile = cxt->profile; + + if (APPARMOR_COMPLAIN(cxt)) { -+ aa_audit_message(profile, GFP_ATOMIC, -+ "LOGPROF-HINT unknown_hat %s " -+ "(%d profile %s active %s)", -+ hat_name, current->pid, -+ profile->parent->name, profile->name); ++ sa->info = "unknown hat"; ++ aa_audit_hint(profile, sa); + } else { + AA_DEBUG("%s: Unknown hatname '%s'. " + "Changing to NULL profile " @@ -1197,15 +1055,13 @@ Index: b/security/apparmor/main.c +{ + struct aa_task_context *cxt, *new_cxt; + struct aa_profile *profile = NULL; ++ struct aa_audit sa; + int error = 0; + -+ /* Dump out above debugging in WARN mode if we are in AUDIT mode */ -+ if (APPARMOR_AUDIT(aa_task_context(current))) { -+ aa_audit_message(NULL, GFP_KERNEL, "change_hat %s, 0x%llx " -+ "(pid %d)", -+ hat_name ? hat_name : "NULL", hat_magic, -+ current->pid); -+ } ++ memset(&sa, 0, sizeof(sa)); ++ sa.gfp_mask = GFP_ATOMIC; ++ sa.magic_token = hat_magic; ++ sa.name = hat_name; + + new_cxt = aa_alloc_task_context(GFP_KERNEL); + if (!new_cxt) @@ -1214,6 +1070,8 @@ Index: b/security/apparmor/main.c + cxt = lock_task_and_profiles(current, NULL); + if (!cxt) { + /* An unconfined process cannot change_hat(). */ ++ if (APPARMOR_AUDIT(cxt)) ++ aa_audit_message(NULL, &sa, AUDIT_APPARMOR_AUDIT); + error = -EPERM; + goto out; + } @@ -1221,6 +1079,9 @@ Index: b/security/apparmor/main.c + /* No need to get reference count: we do not sleep. */ + profile = cxt->profile; + ++ if (APPARMOR_AUDIT(cxt)) ++ aa_audit_message(profile, &sa, AUDIT_APPARMOR_AUDIT); ++ + /* check to see if the confined process has any hats. */ + if (list_empty(&profile->parent->sub) && !PROFILE_COMPLAIN(profile)) { + error = -ECHILD; @@ -1234,7 +1095,8 @@ Index: b/security/apparmor/main.c + __FUNCTION__, + hat_name, + hat_magic); -+ error = do_change_hat(hat_name, new_cxt, hat_magic); ++ error = do_change_hat(hat_name, new_cxt, hat_magic, ++ &sa); + } + } else { + /* @@ -1256,27 +1118,16 @@ Index: b/security/apparmor/main.c + * stick with the same hat_magic. + */ + error = do_change_hat(hat_name, new_cxt, -+ cxt->hat_magic); ++ cxt->hat_magic, &sa); + } + } else if (cxt->hat_magic) { -+ AA_ERROR("KILLING process %d " -+ "Invalid change_hat() magic# 0x%llx " -+ "(hatname %s profile %s active %s)\n", -+ current->pid, hat_magic, -+ hat_name ? hat_name : "NULL", -+ profile->parent->name, -+ profile->name); -+ ++ sa.info = "killing process"; ++ aa_audit_status(profile, &sa); + /* terminate current process */ + (void)send_sig_info(SIGKILL, NULL, current); + } else { /* cxt->hat_magic == 0 */ -+ AA_ERROR("KILLING process %d " -+ "Task was confined to current subprofile " -+ "(profile %s active %s)\n", -+ current->pid, -+ profile->parent->name, -+ profile->name); -+ ++ sa.info = "killing process confined to current hat"; ++ aa_audit_status(profile, &sa); + /* terminate current process */ + (void)send_sig_info(SIGKILL, NULL, current); + } diff --git a/kernel-patches/for-mainline/apparmor-misc.diff b/kernel-patches/for-mainline/apparmor-misc.diff index 320683dd7..89686dd34 100644 --- a/kernel-patches/for-mainline/apparmor-misc.diff +++ b/kernel-patches/for-mainline/apparmor-misc.diff @@ -13,13 +13,13 @@ Signed-off-by: Andreas Gruenbacher --- security/apparmor/Kconfig | 9 + security/apparmor/Makefile | 13 ++ - security/apparmor/apparmor.h | 259 +++++++++++++++++++++++++++++++++++++++++ - security/apparmor/apparmorfs.c | 250 +++++++++++++++++++++++++++++++++++++++ - security/apparmor/inline.h | 219 ++++++++++++++++++++++++++++++++++ + security/apparmor/apparmor.h | 262 +++++++++++++++++++++++++++++++++++++++++ + security/apparmor/apparmorfs.c | 252 +++++++++++++++++++++++++++++++++++++++ + security/apparmor/inline.h | 230 +++++++++++++++++++++++++++++++++++ security/apparmor/list.c | 94 ++++++++++++++ - security/apparmor/locking.txt | 59 +++++++++ - security/apparmor/procattr.c | 138 +++++++++++++++++++++ - 8 files changed, 1041 insertions(+) + security/apparmor/locking.txt | 68 ++++++++++ + security/apparmor/procattr.c | 137 +++++++++++++++++++++ + 8 files changed, 1065 insertions(+) --- /dev/null +++ b/security/apparmor/Kconfig @@ -51,7 +51,7 @@ Signed-off-by: Andreas Gruenbacher + $(call cmd,make-caps) --- /dev/null +++ b/security/apparmor/apparmor.h -@@ -0,0 +1,259 @@ +@@ -0,0 +1,262 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * @@ -86,8 +86,13 @@ Signed-off-by: Andreas Gruenbacher + AA_EXEC_UNCONFINED | \ + AA_EXEC_PROFILE) + ++#define AA_VALID_PERM_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | \ ++ AA_MAY_LINK | AA_EXEC_MODIFIERS | \ ++ AA_EXEC_MMAP | AA_EXEC_UNSAFE) ++ +#define AA_SECURE_EXEC_NEEDED 1 + ++ +/* Control parameters (0 or 1), settable thru module/boot flags or + * via /sys/kernel/security/apparmor/control */ +extern int apparmor_complain; @@ -199,68 +204,66 @@ Signed-off-by: Andreas Gruenbacher + */ + +struct aa_audit { -+ unsigned short type, flags; -+ unsigned int result; ++ const char *operation; + gfp_t gfp_mask; -+ int error_code; ++ const char *info; + const char *name; -+ char *buffer; -+ union { -+ int mask; -+ int capability; -+ struct { -+ const char *name2; -+ char *buffer2; -+ }; -+ struct iattr *iattr; -+ va_list vaval; -+ }; ++ const char *name2; ++ int requested_mask, denied_mask; ++ struct iattr *iattr; ++ pid_t task, parent; ++ u64 magic_token; ++ int error_code; +}; + +/* audit types */ -+#define AA_MANGLE_NAME 32 -+#define AA_MANGLE_NAME2 64 -+#define AA_AUDITTYPE_FILE (1 | AA_MANGLE_NAME) -+#define AA_AUDITTYPE_DIR (2 | AA_MANGLE_NAME) -+#define AA_AUDITTYPE_ATTR (3 | AA_MANGLE_NAME) -+#define AA_AUDITTYPE_XATTR (4 | AA_MANGLE_NAME) -+#define AA_AUDITTYPE_LINK (5 | AA_MANGLE_NAME | AA_MANGLE_NAME2) ++#define AA_AUDITTYPE_FILE 1 ++#define AA_AUDITTYPE_DIR 2 ++#define AA_AUDITTYPE_ATTR 3 ++#define AA_AUDITTYPE_XATTR 4 ++#define AA_AUDITTYPE_LINK 5 +#define AA_AUDITTYPE_CAP 6 +#define AA_AUDITTYPE_MSG 7 +#define AA_AUDITTYPE_SYSCALL 8 + -+/* audit flags */ -+#define AA_AUDITFLAG_AUDITSS_SYSCALL 1 /* log syscall context */ -+#define AA_AUDITFLAG_LOGERR 2 /* log operations that failed due to -+ non permission errors */ -+ +/* Flags for the permission check functions */ +#define AA_CHECK_FD 1 /* coming from a file descriptor */ +#define AA_CHECK_DIR 2 /* file type is directory */ -+#define AA_CHECK_MANGLE 4 /* leave extra room for name mangling */ ++ ++/* lock subtypes so lockdep does not raise false dependencies */ ++enum aa_lock_class { ++ aa_lock_normal, ++ aa_lock_nested, ++ aa_lock_task_release ++}; + +/* main.c */ +extern int alloc_null_complain_profile(void); +extern void free_null_complain_profile(void); +extern int attach_nullprofile(struct aa_profile *profile); -+extern int aa_audit_message(struct aa_profile *profile, gfp_t gfp, -+ const char *, ...) -+ __attribute__ ((format (printf, 3, 4))); ++extern int aa_audit_message(struct aa_profile *profile, struct aa_audit *sa, ++ int type); ++void aa_audit_hint(struct aa_profile *profile, struct aa_audit *sa); ++void aa_audit_status(struct aa_profile *profile, struct aa_audit *sa); ++int aa_audit_reject(struct aa_profile *profile, struct aa_audit *sa); +extern int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp, + const char *); +extern int aa_audit(struct aa_profile *profile, struct aa_audit *); + +extern int aa_attr(struct aa_profile *profile, struct dentry *dentry, + struct vfsmount *mnt, struct iattr *iattr); -+extern int aa_perm_xattr(struct aa_profile *profile, struct dentry *dentry, -+ struct vfsmount *mnt, const char *operation, int mask, -+ int check); ++extern int aa_perm_xattr(struct aa_profile *profile, const char *operation, ++ struct dentry *dentry, struct vfsmount *mnt, ++ int mask, int check); +extern int aa_capability(struct aa_task_context *cxt, int cap); -+extern int aa_perm(struct aa_profile *profile, struct dentry *dentry, -+ struct vfsmount *mnt, int mask, int check); -+extern int aa_perm_dir(struct aa_profile *profile, struct dentry *dentry, -+ struct vfsmount *mnt, const char *operation, int mask); -+extern int aa_perm_path(struct aa_profile *, const char *, int); ++extern int aa_perm(struct aa_profile *profile, const char *operation, ++ struct dentry *dentry, struct vfsmount *mnt, int mask, ++ int check); ++extern int aa_perm_dir(struct aa_profile *profile, const char *operation, ++ struct dentry *dentry, struct vfsmount *mnt, ++ int mask); ++extern int aa_perm_path(struct aa_profile *, const char *operation, ++ const char *name, int); +extern int aa_link(struct aa_profile *profile, + struct dentry *link, struct vfsmount *link_mnt, + struct dentry *target, struct vfsmount *target_mnt); @@ -313,7 +316,7 @@ Signed-off-by: Andreas Gruenbacher +#endif /* __APPARMOR_H */ --- /dev/null +++ b/security/apparmor/apparmorfs.c -@@ -0,0 +1,250 @@ +@@ -0,0 +1,252 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * @@ -336,7 +339,7 @@ Signed-off-by: Andreas Gruenbacher + +static char *aa_simple_write_to_buffer(const char __user *userbuf, + size_t alloc_size, size_t copy_size, -+ loff_t *pos, const char *msg) ++ loff_t *pos, const char *operation) +{ + struct aa_profile *profile; + char *data; @@ -354,13 +357,13 @@ Signed-off-by: Andreas Gruenbacher + */ + profile = aa_get_profile(current); + if (profile) { -+ aa_audit_message(NULL, GFP_KERNEL, "REJECTING access to " -+ "profile %s (%d profile %s active %s)", -+ msg, current->pid, profile->parent->name, -+ profile->name); ++ struct aa_audit sa; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = operation; ++ sa.gfp_mask = GFP_KERNEL; ++ sa.error_code = -EACCES; ++ data = ERR_PTR(aa_audit_reject(profile, &sa)); + aa_put_profile(profile); -+ -+ data = ERR_PTR(-EPERM); + goto out; + } + @@ -422,7 +425,7 @@ Signed-off-by: Andreas Gruenbacher + char *data; + ssize_t error; + -+ data = aa_simple_write_to_buffer(buf, size, size, pos, "load"); ++ data = aa_simple_write_to_buffer(buf, size, size, pos, "profile_load"); + + error = PTR_ERR(data); + if (!IS_ERR(data)) { @@ -445,7 +448,8 @@ Signed-off-by: Andreas Gruenbacher + char *data; + ssize_t error; + -+ data = aa_simple_write_to_buffer(buf, size, size, pos, "replacement"); ++ data = aa_simple_write_to_buffer(buf, size, size, pos, ++ "profile_replace"); + + error = PTR_ERR(data); + if (!IS_ERR(data)) { @@ -472,7 +476,8 @@ Signed-off-by: Andreas Gruenbacher + * aa_remove_profile needs a null terminated string so 1 extra + * byte is allocated and the copied data is null terminated. + */ -+ data = aa_simple_write_to_buffer(buf, size + 1, size, pos, "removal"); ++ data = aa_simple_write_to_buffer(buf, size + 1, size, pos, ++ "profile_remove"); + + error = PTR_ERR(data); + if (!IS_ERR(data)) { @@ -566,7 +571,7 @@ Signed-off-by: Andreas Gruenbacher + --- /dev/null +++ b/security/apparmor/inline.h -@@ -0,0 +1,219 @@ +@@ -0,0 +1,230 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * @@ -668,7 +673,8 @@ Signed-off-by: Andreas Gruenbacher + * While the profile is locked, local interrupts are disabled. This also + * gives us RCU reader safety. + */ -+static inline void lock_profile(struct aa_profile *profile) ++static inline void lock_profile_nested(struct aa_profile *profile, ++ enum aa_lock_class lock_class) +{ + /* We always lock top-level profiles instead of children. */ + if (profile) @@ -681,7 +687,13 @@ Signed-off-by: Andreas Gruenbacher + * the task_free_security hook, which may run in RCU context. + */ + if (profile) -+ spin_lock_irqsave(&profile->lock, profile->int_flags); ++ spin_lock_irqsave_nested(&profile->lock, profile->int_flags, ++ lock_class); ++} ++ ++static inline void lock_profile(struct aa_profile *profile) ++{ ++ lock_profile_nested(profile, aa_lock_normal); +} + +/** @@ -730,17 +742,21 @@ Signed-off-by: Andreas Gruenbacher + */ + if (!profile1 || profile1 == profile2) { + if (profile2) -+ spin_lock_irqsave(&profile2->lock, profile2->int_flags); ++ spin_lock_irqsave_nested(&profile2->lock, ++ profile2->int_flags, ++ aa_lock_normal); + } else if (profile1 > profile2) { + /* profile1 cannot be NULL here. */ -+ spin_lock_irqsave(&profile1->lock, profile1->int_flags); ++ spin_lock_irqsave_nested(&profile1->lock, profile1->int_flags, ++ aa_lock_normal); + if (profile2) -+ spin_lock(&profile2->lock); ++ spin_lock_nested(&profile2->lock, aa_lock_nested); + + } else { + /* profile2 cannot be NULL here. */ -+ spin_lock_irqsave(&profile2->lock, profile2->int_flags); -+ spin_lock(&profile1->lock); ++ spin_lock_irqsave_nested(&profile2->lock, profile2->int_flags, ++ aa_lock_normal); ++ spin_lock_nested(&profile1->lock, aa_lock_nested); + } +} + @@ -885,7 +901,7 @@ Signed-off-by: Andreas Gruenbacher +}; --- /dev/null +++ b/security/apparmor/locking.txt -@@ -0,0 +1,59 @@ +@@ -0,0 +1,68 @@ +Locking in AppArmor +=================== + @@ -939,15 +955,24 @@ Signed-off-by: Andreas Gruenbacher +won't race with itself. We release the profile_list_lock as soon as +possible to avoid stalling exec during profile loading/replacement/removal. + -+lock_dep reports a false 'possible irq lock inversion dependency detected' -+when the profile lock is taken in aa_release. This is due to that the -+task_lock is often taken inside the profile lock but other kernel code -+takes the task_lock with interrupts enabled. A deadlock will not actually -+occur because apparmor does not take the task_lock in hard_irq or soft_irq -+context. ++AppArmor uses lock subtyping to avoid false positives from lockdep. The ++profile lock is often taken nested, but it is guaranteed to be in a lock ++safe order and not the same lock when done, so it is safe. ++ ++A third lock type (aa_lock_task_release) is given to the profile lock ++when it is taken in soft irq context during task release (aa_release). ++This is to avoid a false positive between the task lock and the profile ++lock. In task context the profile lock wraps the task lock with irqs ++off, but the kernel takes the task lock with irqs enabled. This won't ++result in a deadlock because for a deadlock to occur the kernel must ++take dead task A's lock (irqs on), the rcu callback hook freeing ++dead task A must be run and AppArmor must be changing the profile on ++dead task A. The kernel should not be taking a dead task's task_lock ++at the same time the task is being freed by task rcu cleanup other wise ++the task would not be out of its quiescent period. --- /dev/null +++ b/security/apparmor/procattr.c -@@ -0,0 +1,138 @@ +@@ -0,0 +1,137 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * @@ -1031,6 +1056,12 @@ Signed-off-by: Andreas Gruenbacher +int aa_setprocattr_setprofile(struct task_struct *task, char *args) +{ + struct aa_profile *old_profile, *new_profile; ++ struct aa_audit sa; ++ ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "profile_set"; ++ sa.gfp_mask = GFP_KERNEL; ++ sa.task = task->pid; + + AA_DEBUG("%s: current %d\n", + __FUNCTION__, current->pid); @@ -1041,11 +1072,9 @@ Signed-off-by: Andreas Gruenbacher + else { + new_profile = aa_find_profile(args); + if (!new_profile) { -+ aa_audit_message(NULL, GFP_KERNEL, "Unable to switch " -+ "task %d to profile '%s'. No such " -+ "profile.", -+ task->pid, args); -+ ++ sa.name = args; ++ sa.info = "unknown profile"; ++ aa_audit_reject(NULL, &sa); + return -EINVAL; + } + } @@ -1062,25 +1091,20 @@ Signed-off-by: Andreas Gruenbacher + } + + if (new_profile) { -+ aa_audit_message(NULL, GFP_KERNEL, "Switching task %d profile " -+ "%s active %s to new profile %s", -+ task->pid, old_profile ? -+ old_profile->parent->name : "unconfined", -+ old_profile ? old_profile->name : "unconfined", -+ args); ++ sa.name = args; ++ sa.name2 = old_profile ? old_profile->parent->name : ++ "unconfined"; ++ aa_audit_status(NULL, &sa); + } else { + if (old_profile) { -+ aa_audit_message(NULL, GFP_KERNEL, "Unconfining task " -+ "%d profile %s active %s", -+ task->pid, old_profile->parent->name, -+ old_profile->name); ++ sa.name = "unconfined"; ++ sa.name2 = old_profile->parent->name; ++ aa_audit_status(NULL, &sa); + } else { -+ aa_audit_message(NULL, GFP_KERNEL, "task %d is already " -+ "unconfined", -+ task->pid); ++ sa.info = "task is unconfined"; ++ aa_audit_status(NULL, &sa); + } + } -+ + aa_put_profile(old_profile); + aa_put_profile(new_profile); + diff --git a/kernel-patches/for-mainline/apparmor-module_interface.diff b/kernel-patches/for-mainline/apparmor-module_interface.diff index 90dd2ab7d..de1d1a41a 100644 --- a/kernel-patches/for-mainline/apparmor-module_interface.diff +++ b/kernel-patches/for-mainline/apparmor-module_interface.diff @@ -8,14 +8,14 @@ Signed-off-by: John Johansen Signed-off-by: Andreas Gruenbacher --- - security/apparmor/match.c | 232 ++++++++++++ + security/apparmor/match.c | 248 +++++++++++++ security/apparmor/match.h | 83 ++++ - security/apparmor/module_interface.c | 643 +++++++++++++++++++++++++++++++++++ - 3 files changed, 958 insertions(+) + security/apparmor/module_interface.c | 661 +++++++++++++++++++++++++++++++++++ + 3 files changed, 992 insertions(+) --- /dev/null +++ b/security/apparmor/match.c -@@ -0,0 +1,232 @@ +@@ -0,0 +1,248 @@ +/* + * Copyright (C) 2007 Novell/SUSE + * @@ -30,6 +30,7 @@ Signed-off-by: Andreas Gruenbacher +#include +#include +#include ++#include "apparmor.h" +#include "match.h" + +static struct table_header *unpack_table(void *blob, size_t bsize) @@ -188,6 +189,21 @@ Signed-off-by: Andreas Gruenbacher + goto out; + } + ++ /* verify accept permissions */ ++ for (i = 0; i < state_count; i++) { ++ int mode = ACCEPT_TABLE(dfa)[i]; ++ ++ if (mode & ~AA_VALID_PERM_MASK) ++ goto out; ++ ++ /* if MAY_EXEC, exactly one exec modifier must be set */ ++ if (mode & MAY_EXEC) { ++ mode &= AA_EXEC_MODIFIERS; ++ if (mode & (mode - 1)) ++ goto out; ++ } ++ } ++ + error = 0; +out: + return error; @@ -336,7 +352,7 @@ Signed-off-by: Andreas Gruenbacher +#endif /* __MATCH_H */ --- /dev/null +++ b/security/apparmor/module_interface.c -@@ -0,0 +1,643 @@ +@@ -0,0 +1,661 @@ +/* + * Copyright (C) 1998-2007 Novell/SUSE + * @@ -580,11 +596,14 @@ Signed-off-by: Andreas Gruenbacher +/** + * aa_unpack_profile - unpack a serialized profile + * @e: serialized data extent information -+ * @error: error code returned if unpacking fails ++ * @depth: recursion depth of unpack ++ * @operation: operation profile is being unpacked for + */ -+static struct aa_profile *aa_unpack_profile(struct aa_ext *e, int depth) ++static struct aa_profile *aa_unpack_profile(struct aa_ext *e, int depth, ++ const char *operation) +{ + struct aa_profile *profile = NULL; ++ struct aa_audit sa; + + int error = -EPROTO; + @@ -627,7 +646,7 @@ Signed-off-by: Andreas Gruenbacher + goto fail; + while (!aa_is_nameX(e, AA_LISTEND, NULL)) { + struct aa_profile *subprofile; -+ subprofile = aa_unpack_profile(e, depth + 1); ++ subprofile = aa_unpack_profile(e, depth + 1, operation); + if (IS_ERR(subprofile)) { + error = PTR_ERR(subprofile); + goto fail; @@ -643,8 +662,12 @@ Signed-off-by: Andreas Gruenbacher + return profile; + +fail: -+ aa_audit_message(NULL, GFP_KERNEL, "Invalid profile %s", -+ profile && profile->name ? profile->name : "unknown"); ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = operation; ++ sa.gfp_mask = GFP_KERNEL; ++ sa.name = profile && profile->name ? profile->name : "unknown"; ++ sa.info = "failed to unpack profile"; ++ aa_audit_status(NULL, &sa); + + if (profile) + free_aa_profile(profile); @@ -659,9 +682,10 @@ Signed-off-by: Andreas Gruenbacher + * check interface version unpack a profile and all its hats and patch + * in any extra information that the profile needs. + */ -+static struct aa_profile *aa_unpack_profile_wrapper(struct aa_ext *e) ++static struct aa_profile *aa_unpack_profile_wrapper(struct aa_ext *e, ++ const char *operation) +{ -+ struct aa_profile *profile = aa_unpack_profile(e, 0); ++ struct aa_profile *profile = aa_unpack_profile(e, 0, operation); + if (!IS_ERR(profile) && + (!list_empty(&profile->sub) || profile->flags.complain)) { + int error; @@ -677,21 +701,31 @@ Signed-off-by: Andreas Gruenbacher +/** + * aa_verify_head - unpack serialized stream header + * @e: serialized data read head ++ * @operation: operation header is being verified for + * + * returns error or 0 if header is good + */ -+static int aa_verify_header(struct aa_ext *e) ++static int aa_verify_header(struct aa_ext *e, const char *operation) +{ + /* get the interface version */ + if (!aa_is_u32(e, &e->version, "version")) { -+ aa_audit_message(NULL, GFP_KERNEL, "Interface version missing"); ++ struct aa_audit sa; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = operation; ++ sa.gfp_mask = GFP_KERNEL; ++ sa.info = "invalid profile format"; ++ aa_audit_status(NULL, &sa); + return -EPROTONOSUPPORT; + } + + /* check that the interface version is currently supported */ + if (e->version != 3) { -+ aa_audit_message(NULL, GFP_KERNEL, "Unsupported interface " -+ "version (%d)", e->version); ++ struct aa_audit sa; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = operation; ++ sa.gfp_mask = GFP_KERNEL; ++ sa.info = "unsupported interface version"; ++ aa_audit_status(NULL, &sa); + return -EPROTONOSUPPORT; + } + return 0; @@ -710,11 +744,11 @@ Signed-off-by: Andreas Gruenbacher + .end = data + size, + .pos = data + }; -+ ssize_t error = aa_verify_header(&e); ++ ssize_t error = aa_verify_header(&e, "profile_load"); + if (error) + return error; + -+ profile = aa_unpack_profile_wrapper(&e); ++ profile = aa_unpack_profile_wrapper(&e, "profile_load"); + if (IS_ERR(profile)) + return PTR_ERR(profile); + @@ -790,11 +824,11 @@ Signed-off-by: Andreas Gruenbacher + .end = udata + size, + .pos = udata + }; -+ ssize_t error = aa_verify_header(&e); ++ ssize_t error = aa_verify_header(&e, "profile_replace"); + if (error) + return error; + -+ new_profile = aa_unpack_profile_wrapper(&e); ++ new_profile = aa_unpack_profile_wrapper(&e, "profile_replace"); + if (IS_ERR(new_profile)) + return PTR_ERR(new_profile); + diff --git a/kernel-patches/for-mainline/apparmor_ptrace-cleanup.diff b/kernel-patches/for-mainline/apparmor_ptrace-cleanup.diff index ca15575da..34067b551 100644 --- a/kernel-patches/for-mainline/apparmor_ptrace-cleanup.diff +++ b/kernel-patches/for-mainline/apparmor_ptrace-cleanup.diff @@ -1,10 +1,18 @@ --- - security/apparmor/lsm.c | 37 ++++++++++++++++++++----------------- - 1 file changed, 20 insertions(+), 17 deletions(-) + security/apparmor/lsm.c | 135 ++++++++++++++++++++++++++++-------------------- + 1 file changed, 79 insertions(+), 56 deletions(-) --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c -@@ -108,8 +108,6 @@ static int apparmor_ptrace(struct task_s +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include "apparmor.h" + #include "inline.h" +@@ -108,8 +109,6 @@ static int apparmor_ptrace(struct task_s struct task_struct *child) { struct aa_task_context *cxt; @@ -13,7 +21,7 @@ int error = 0; /* -@@ -123,22 +121,27 @@ static int apparmor_ptrace(struct task_s +@@ -123,22 +122,32 @@ static int apparmor_ptrace(struct task_s rcu_read_lock(); cxt = aa_task_context(parent); @@ -27,17 +35,22 @@ - } else { - error = aa_may_ptrace(cxt, child_profile); - if (cxt && PROFILE_COMPLAIN(cxt->profile)) { -+ if (cxt) { -+ if (parent->nsproxy != child->nsproxy) { - aa_audit_message(cxt->profile, GFP_ATOMIC, +- aa_audit_message(cxt->profile, GFP_ATOMIC, - "LOGPROF-HINT ptrace pid=%d child=%d " - "(%d profile %s active %s)", - current->pid, child->pid, current->pid, - cxt->profile->parent->name, - cxt->profile->name); -+ "REJECTING ptrace across " -+ "namespace of %d by %d", -+ parent->pid, child->pid); ++ if (cxt) { ++ if (parent->nsproxy != child->nsproxy) { ++ struct aa_audit sa; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "ptrace"; ++ sa.gfp_mask = GFP_ATOMIC; ++ sa.parent = parent->pid; ++ sa.task = child->pid; ++ sa.info = "different namespaces"; ++ aa_audit_reject(cxt->profile, &sa); + error = -EPERM; + } else { + struct aa_task_context *child_cxt = @@ -46,13 +59,244 @@ + error = aa_may_ptrace(cxt, child_cxt ? + child_cxt->profile : NULL); + if (PROFILE_COMPLAIN(cxt->profile)) { -+ aa_audit_message(cxt->profile, GFP_ATOMIC, -+ "LOGPROF-HINT ptrace pid=%d child=%d " -+ "(%d profile %s active %s)", -+ current->pid, child->pid, current->pid, -+ cxt->profile->parent->name, -+ cxt->profile->name); ++ struct aa_audit sa; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "ptrace"; ++ sa.gfp_mask = GFP_ATOMIC; ++ sa.parent = parent->pid; ++ sa.task = child->pid; ++ aa_audit_hint(cxt->profile, &sa); + } } } rcu_read_unlock(); +@@ -189,7 +198,7 @@ static int apparmor_sysctl(struct ctl_ta + if (name && name - buffer >= 5) { + name -= 5; + memcpy(name, "/proc", 5); +- error = aa_perm_path(profile, name, mask); ++ error = aa_perm_path(profile, "sysctl", name, mask); + } + free_page((unsigned long)buffer); + } +@@ -244,7 +253,8 @@ static int apparmor_inode_mkdir(struct i + profile = aa_get_profile(current); + + if (profile) +- error = aa_perm_dir(profile, dentry, mnt, "mkdir", MAY_WRITE); ++ error = aa_perm_dir(profile, "inode_mkdir", dentry, mnt, ++ MAY_WRITE); + + aa_put_profile(profile); + +@@ -264,7 +274,8 @@ static int apparmor_inode_rmdir(struct i + profile = aa_get_profile(current); + + if (profile) +- error = aa_perm_dir(profile, dentry, mnt, "rmdir", MAY_WRITE); ++ error = aa_perm_dir(profile, "inode_rmdir", dentry, mnt, ++ MAY_WRITE); + + aa_put_profile(profile); + +@@ -272,8 +283,9 @@ out: + return error; + } + +-static int aa_permission(struct inode *inode, struct dentry *dentry, +- struct vfsmount *mnt, int mask, int check) ++static int aa_permission(struct inode *inode, const char *operation, ++ struct dentry *dentry, struct vfsmount *mnt, ++ int mask, int check) + { + int error = 0; + +@@ -282,7 +294,8 @@ static int aa_permission(struct inode *i + + profile = aa_get_profile(current); + if (profile) +- error = aa_perm(profile, dentry, mnt, mask, check); ++ error = aa_perm(profile, operation, dentry, mnt, mask, ++ check); + aa_put_profile(profile); + } + return error; +@@ -291,7 +304,7 @@ static int aa_permission(struct inode *i + static int apparmor_inode_create(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mask) + { +- return aa_permission(dir, dentry, mnt, MAY_WRITE, 0); ++ return aa_permission(dir, "inode_create", dentry, mnt, MAY_WRITE, 0); + } + + static int apparmor_inode_link(struct dentry *old_dentry, +@@ -324,19 +337,20 @@ static int apparmor_inode_unlink(struct + + if (S_ISDIR(dentry->d_inode->i_mode)) + check |= AA_CHECK_DIR; +- return aa_permission(dir, dentry, mnt, MAY_WRITE, check); ++ return aa_permission(dir, "inode_unlink", dentry, mnt, MAY_WRITE, ++ check); + } + + static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, const char *old_name) + { +- return aa_permission(dir, dentry, mnt, MAY_WRITE, 0); ++ return aa_permission(dir, "inode_symlink", dentry, mnt, MAY_WRITE, 0); + } + + static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry, + struct vfsmount *mnt, int mode, dev_t dev) + { +- return aa_permission(dir, dentry, mnt, MAY_WRITE, 0); ++ return aa_permission(dir, "inode_mknod", dentry, mnt, MAY_WRITE, 0); + } + + static int apparmor_inode_rename(struct inode *old_dir, +@@ -361,12 +375,12 @@ static int apparmor_inode_rename(struct + if (inode && S_ISDIR(inode->i_mode)) + check |= AA_CHECK_DIR; + if (old_mnt) +- error = aa_perm(profile, old_dentry, old_mnt, +- MAY_READ | MAY_WRITE, check); ++ error = aa_perm(profile, "inode_rename", old_dentry, ++ old_mnt, MAY_READ | MAY_WRITE, check); + + if (!error && new_mnt) { +- error = aa_perm(profile, new_dentry, new_mnt, +- MAY_WRITE, check); ++ error = aa_perm(profile, "inode_rename", new_dentry, ++ new_mnt, MAY_WRITE, check); + } + } + +@@ -389,7 +403,8 @@ static int apparmor_inode_permission(str + /* allow traverse accesses to directories */ + mask &= ~MAY_EXEC; + } +- return aa_permission(inode, nd->dentry, nd->mnt, mask, check); ++ return aa_permission(inode, "inode_permission", nd->dentry, nd->mnt, ++ mask, check); + } + + static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, +@@ -429,7 +444,7 @@ static int aa_xattr_permission(struct de + int check = file ? AA_CHECK_FD : 0; + + if (profile) +- error = aa_perm_xattr(profile, dentry, mnt, operation, ++ error = aa_perm_xattr(profile, operation, dentry, mnt, + mask, check); + aa_put_profile(profile); + } +@@ -491,7 +506,8 @@ static int apparmor_file_permission(stru + if (S_ISDIR(inode->i_mode)) + check |= AA_CHECK_DIR; + mask &= (MAY_READ | MAY_WRITE | MAY_EXEC); +- error = aa_permission(inode, dentry, mnt, mask, check); ++ error = aa_permission(inode, "file_permission", dentry, mnt, ++ mask, check); + } + aa_put_profile(profile); + +@@ -517,8 +533,8 @@ static void apparmor_file_free_security( + aa_put_profile(file_profile); + } + +-static inline int aa_mmap(struct file *file, unsigned long prot, +- unsigned long flags) ++static inline int aa_mmap(struct file *file, const char *operation, ++ unsigned long prot, unsigned long flags) + { + struct dentry *dentry; + int mask = 0; +@@ -536,20 +552,20 @@ static inline int aa_mmap(struct file *f + mask |= AA_EXEC_MMAP; + + dentry = file->f_dentry; +- return aa_permission(dentry->d_inode, dentry, file->f_vfsmnt, mask, +- AA_CHECK_FD); ++ return aa_permission(dentry->d_inode, operation, dentry, ++ file->f_vfsmnt, mask, AA_CHECK_FD); + } + + static int apparmor_file_mmap(struct file *file, unsigned long reqprot, + unsigned long prot, unsigned long flags) + { +- return aa_mmap(file, prot, flags); ++ return aa_mmap(file, "file_mmap", prot, flags); + } + + static int apparmor_file_mprotect(struct vm_area_struct *vma, + unsigned long reqprot, unsigned long prot) + { +- return aa_mmap(vma->vm_file, prot, ++ return aa_mmap(vma->vm_file, "file_mprotect", prot, + !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0); + } + +@@ -625,24 +641,27 @@ static int apparmor_setprocattr(struct t + + profile = aa_get_profile(current); + if (profile) { ++ struct aa_audit sa; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "profile_set"; ++ sa.gfp_mask = GFP_KERNEL; ++ sa.task = task->pid; ++ sa.info = "from confined process"; ++ aa_audit_reject(profile, &sa); + aa_put_profile(profile); +- aa_audit_message(NULL, GFP_KERNEL, "Attempt by " +- "confined task %d [user %d] to " +- "assign profile to task %d", +- current->pid, current->uid, +- task->pid); + return -EACCES; + } + error = aa_setprocattr_setprofile(task, args); + } else { +- AA_ERROR("Unknown setprocattr command '%.*s' " +- "by task %d [user %d] for task %d", +- size < 16 ? (int)size : 16, +- command, +- current->pid, +- current->uid, +- task->pid); +- error = -EINVAL; ++ struct aa_audit sa; ++ memset(&sa, 0, sizeof(sa)); ++ sa.operation = "setprocattr"; ++ sa.gfp_mask = GFP_KERNEL; ++ sa.info = "invalid command"; ++ sa.name = command; ++ sa.task = task->pid; ++ aa_audit_reject(NULL, &sa); ++ return -EINVAL; + } + + if (!error) +@@ -700,8 +719,12 @@ struct security_operations apparmor_ops + + static void info_message(const char *str) + { ++ struct aa_audit sa; ++ memset(&sa, 0, sizeof(sa)); ++ sa.gfp_mask = GFP_KERNEL; ++ sa.info = str; + printk(KERN_INFO "AppArmor: %s", str); +- aa_audit_message(NULL, GFP_KERNEL, "%s", str); ++ aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS); + } + + static int __init apparmor_init(void) +@@ -719,7 +742,7 @@ static int __init apparmor_init(void) + } + + if ((error = register_security(&apparmor_ops))) { +- AA_ERROR("Unable to load AppArmor\n"); ++ AA_ERROR("Unable to register AppArmor\n"); + goto register_security_out; + } + diff --git a/kernel-patches/for-mainline/audit-defines.diff b/kernel-patches/for-mainline/audit-defines.diff deleted file mode 100644 index 7d7674cb0..000000000 --- a/kernel-patches/for-mainline/audit-defines.diff +++ /dev/null @@ -1,27 +0,0 @@ ---- - include/linux/audit.h | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - ---- a/include/linux/audit.h -+++ b/include/linux/audit.h -@@ -109,13 +109,18 @@ - #define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Add a XFRM policy */ - #define AUDIT_MAC_IPSEC_DELSPD 1414 /* Delete a XFRM policy */ - -+#define AUDIT_APPARMOR_AUDIT 1501 /* AppArmor audited grants */ -+#define AUDIT_APPARMOR_ALLOWED 1502 /* Allowed Access for learning */ -+#define AUDIT_APPARMOR_DENIED 1503 -+#define AUDIT_APPARMOR_HINT 1504 /* Process Tracking information */ -+#define AUDIT_APPARMOR_STATUS 1505 /* Changes in config */ -+#define AUDIT_APPARMOR_ERROR 1506 /* Internal AppArmor Errors */ -+ - #define AUDIT_FIRST_KERN_ANOM_MSG 1700 - #define AUDIT_LAST_KERN_ANOM_MSG 1799 - #define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */ - #define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */ - --#define AUDIT_APPARMOR 1500 /* AppArmor audit */ -- - #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ - - /* Rule flags */ diff --git a/kernel-patches/for-mainline/audit-link-perms.diff b/kernel-patches/for-mainline/audit-link-perms.diff deleted file mode 100644 index 267267330..000000000 --- a/kernel-patches/for-mainline/audit-link-perms.diff +++ /dev/null @@ -1,87 +0,0 @@ ---- - security/apparmor/main.c | 43 +++++++++++++++++++++++-------------------- - 1 file changed, 23 insertions(+), 20 deletions(-) - ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -58,35 +58,41 @@ static int aa_file_denied(struct aa_prof - * @profile: profile to check against - * @link: pathname of link being created - * @target: pathname of target to be linked to -- * -+ * @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) -+ const char *target, int *request_mask) - { -- int l_mode, t_mode; -+ int l_mode, t_mode, denied_mask; - - l_mode = aa_match(profile->file_rules, link); - t_mode = aa_match(profile->file_rules, target); -+ *request_mask = l_mode; - - /* Link always requires 'l' on the link, a subset of the - * target's 'r', 'w', 'x', and 'm' permissions on the link, and - * if the link has 'x', an exact match of all the execute flags - * ('i', 'u', 'U', 'p', 'P'). - */ --#define RWXM (MAY_READ | MAY_WRITE | MAY_EXEC | AA_EXEC_MMAP) -- if ((l_mode & AA_MAY_LINK) && -- (l_mode & RWXM) && !(l_mode & ~t_mode & RWXM) && -- (!(l_mode & MAY_EXEC) || -- ((l_mode & AA_EXEC_MODIFIERS) == (t_mode & AA_EXEC_MODIFIERS) && -- (l_mode & AA_EXEC_UNSAFE) == (t_mode & AA_EXEC_UNSAFE)))) -- return 0; --#undef RWXM -- /* FIXME: There currenly is no way to report which permissions -- * we expect in t_mode, so linking could fail even after learning -- * the required l_mode. -+ denied_mask = ~l_mode & AA_MAY_LINK; -+ denied_mask |= l_mode & ~t_mode; -+ if (denied_mask & AA_EXEC_MODIFIERS) -+ denied_mask |= MAY_EXEC; -+ -+ /* FIXME: denied mask has no way of reporting that the secure -+ * execmode required is safe exec. This means that if link -+ * has safe exec and target unsafe exec, the difference is not -+ * reported, back, this isn't a significant problem since -+ * safe exec is a subset of unsafe exec, but it violates the -+ * exec should be exactly equal rule. -+ * -+ * The reverse situation does not cause a problem, if link -+ * requires an unsafe exec and target a safe exec we report -+ * the missing unsafe exec bit. - */ -- return AA_MAY_LINK; -+ -+ return denied_mask; - } - - /** -@@ -648,21 +654,18 @@ int aa_link(struct aa_profile *profile, - sa.name2 = aa_get_name(target, target_mnt, &sa.buffer2, check); - - if (IS_ERR(sa.name)) { -- sa.requested_mask = 0; -- sa.denied_mask = 0; - sa.error_code = PTR_ERR(sa.name); - sa.name = NULL; - } - if (IS_ERR(sa.name2)) { -- sa.requested_mask = 0; -- sa.denied_mask = 0; - sa.error_code = PTR_ERR(sa.name2); - sa.name2 = NULL; - } - - if (sa.name && sa.name2) { - sa.requested_mask = AA_MAY_LINK; -- sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2); -+ sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2, -+ &sa.requested_mask); - sa.error_code = sa.denied_mask ? -EACCES : 0; - } - diff --git a/kernel-patches/for-mainline/audit-pairs-2.diff b/kernel-patches/for-mainline/audit-pairs-2.diff deleted file mode 100644 index c9f05c4fd..000000000 --- a/kernel-patches/for-mainline/audit-pairs-2.diff +++ /dev/null @@ -1,40 +0,0 @@ ---- - security/apparmor/main.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -331,10 +331,10 @@ static int aa_audit_base(struct aa_profi - } - - if (sa->task) -- audit_log_format(ab, " task=\"%d\"", sa->task); -+ audit_log_format(ab, " task=%d", sa->task); - - if (sa->parent) -- audit_log_format(ab, "parent=\"%d\"", sa->parent); -+ audit_log_format(ab, " parent=%d", sa->parent); - - if (sa->name) { - audit_log_format(ab, " name="); -@@ -347,9 +347,9 @@ static int aa_audit_base(struct aa_profi - } - - if (sa->magic_token) -- audit_log_format(ab, " magic_token=\"%llu\"", sa->magic_token); -+ audit_log_format(ab, " magic_token=%llu", sa->magic_token); - -- audit_log_format(ab, "pid=\"%d\"", current->pid); -+ audit_log_format(ab, " pid=%d", current->pid); - - if (profile) { - audit_log_format(ab, " profile="); -@@ -854,7 +854,7 @@ repeat: - goto repeat; - if (PTR_ERR(old_profile) == -EPERM) { - sa.denied_mask = MAY_EXEC; -- sa.info = "Unable to set profile due to ptrace"; -+ sa.info = "unable to set profile due to ptrace"; - sa.task = current->parent->pid; - aa_audit_reject(profile, &sa); - } diff --git a/kernel-patches/for-mainline/audit-pairs-3.diff b/kernel-patches/for-mainline/audit-pairs-3.diff deleted file mode 100644 index fd987d9bc..000000000 --- a/kernel-patches/for-mainline/audit-pairs-3.diff +++ /dev/null @@ -1,64 +0,0 @@ ---- - security/apparmor/main.c | 37 +++++++++++++++++++++++-------------- - 1 file changed, 23 insertions(+), 14 deletions(-) - ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -274,6 +274,22 @@ void free_null_complain_profile(void) - null_complain_profile = NULL; - } - -+static void aa_audit_file_mask(struct audit_buffer *ab, const char *name, -+ int mask) -+{ -+ audit_log_format(ab, " %s=\"%s%s%s%s%s%s%s%s%s\"", -+ name, -+ mask & AA_EXEC_UNSAFE ? "unsafe " : "", -+ mask & AA_EXEC_MMAP ? "m" : "", -+ mask & MAY_READ ? "r" : "", -+ mask & MAY_WRITE ? "w" : "", -+ mask & AA_EXEC_INHERIT ? "i" : "", -+ mask & AA_EXEC_UNCONFINED ? "u" : "", -+ mask & AA_EXEC_PROFILE ? "p" : "", -+ mask & MAY_EXEC ? "x" : "", -+ mask & AA_MAY_LINK ? "l" : ""); -+} -+ - /** - * aa_audit - Log an audit event to the audit subsystem - * @profile: profile to check against -@@ -291,9 +307,8 @@ static int aa_audit_base(struct aa_profi - if (!ab) { - AA_ERROR("Unable to log event (%d) to audit subsys\n", - type); -- /* FIXME: do we want to keep old behavior - as below -- * don't fail operations in complain mode even if logging -- * fails */ -+ /* don't fail operations in complain mode even if logging -+ * fails */ - return type == AUDIT_APPARMOR_ALLOWED ? 0 : -ENOMEM; - } - -@@ -303,17 +318,11 @@ static int aa_audit_base(struct aa_profi - if (sa->info) - audit_log_format(ab, " info=\"%s\"", sa->info); - -- if (sa->requested_mask | sa->denied_mask) { -- int mask = sa->denied_mask ? sa->denied_mask : -- sa->requested_mask; -- -- audit_log_format(ab, " mask=\"%s%s%s%s%s\"", -- mask & AA_EXEC_MMAP ? "m" : "", -- mask & MAY_READ ? "r" : "", -- mask & MAY_WRITE ? "w" : "", -- mask & MAY_EXEC ? "x" : "", -- mask & AA_MAY_LINK ? "l" : ""); -- } -+ if (sa->requested_mask) -+ aa_audit_file_mask(ab, "requested_mask", sa->requested_mask); -+ -+ if (sa->denied_mask) -+ aa_audit_file_mask(ab, "denied_mask", sa->denied_mask); - - if (sa->iattr) { - struct iattr *iattr = sa->iattr; diff --git a/kernel-patches/for-mainline/audit-pairs-4.diff b/kernel-patches/for-mainline/audit-pairs-4.diff deleted file mode 100644 index 05ed89828..000000000 --- a/kernel-patches/for-mainline/audit-pairs-4.diff +++ /dev/null @@ -1,71 +0,0 @@ ---- - security/apparmor/main.c | 51 +++++++++++++++++++++++++++++++++-------------- - 1 file changed, 36 insertions(+), 15 deletions(-) - ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -277,17 +277,38 @@ void free_null_complain_profile(void) - static void aa_audit_file_mask(struct audit_buffer *ab, const char *name, - int mask) - { -- audit_log_format(ab, " %s=\"%s%s%s%s%s%s%s%s%s\"", -- name, -- mask & AA_EXEC_UNSAFE ? "unsafe " : "", -- mask & AA_EXEC_MMAP ? "m" : "", -- mask & MAY_READ ? "r" : "", -- mask & MAY_WRITE ? "w" : "", -- mask & AA_EXEC_INHERIT ? "i" : "", -- mask & AA_EXEC_UNCONFINED ? "u" : "", -- mask & AA_EXEC_PROFILE ? "p" : "", -- mask & MAY_EXEC ? "x" : "", -- mask & AA_MAY_LINK ? "l" : ""); -+ char mask_str[10], *m = mask_str; -+ -+ if (mask & AA_EXEC_MMAP) -+ *m++ = 'm'; -+ if (mask & MAY_READ) -+ *m++ = 'r'; -+ if (mask & MAY_WRITE) -+ *m++ = 'w'; -+ if (mask & (MAY_EXEC | AA_EXEC_MODIFIERS)) { -+ if (mask & AA_EXEC_UNSAFE) { -+ if (mask & AA_EXEC_INHERIT) -+ *m++ = 'i'; -+ if (mask & AA_EXEC_UNCONFINED) -+ *m++ = 'u'; -+ if (mask & AA_EXEC_PROFILE) -+ *m++ = 'p'; -+ } else { -+ if (mask & AA_EXEC_INHERIT) -+ *m++ = 'I'; -+ if (mask & AA_EXEC_UNCONFINED) -+ *m++ = 'U'; -+ if (mask & AA_EXEC_PROFILE) -+ *m++ = 'P'; -+ } -+ if (mask & MAY_EXEC) -+ *m++ = 'x'; -+ } -+ if (mask & AA_MAY_LINK) -+ *m++ = 'l'; -+ *m++ = '\0'; -+ -+ audit_log_format(ab, " %s=\"%s\"", name, mask_str); - } - - /** -@@ -332,10 +353,10 @@ static int aa_audit_base(struct aa_profi - iattr->ia_valid & ATTR_UID ? "uid," : "", - iattr->ia_valid & ATTR_GID ? "gid," : "", - iattr->ia_valid & ATTR_SIZE ? "size," : "", -- ((iattr->ia_valid & ATTR_ATIME_SET) || -- (iattr->ia_valid & ATTR_ATIME)) ? "atime," : "", -- ((iattr->ia_valid & ATTR_MTIME_SET) || -- (iattr->ia_valid & ATTR_MTIME)) ? "mtime," : "", -+ iattr->ia_valid & (ATTR_ATIME | ATTR_ATIME_SET) ? -+ "atime," : "", -+ iattr->ia_valid & (ATTR_MTIME | ATTR_MTIME_SET) ? -+ "mtime," : "", - iattr->ia_valid & ATTR_CTIME ? "ctime," : ""); - } - diff --git a/kernel-patches/for-mainline/audit-pairs.diff b/kernel-patches/for-mainline/audit-pairs.diff deleted file mode 100644 index df951e754..000000000 --- a/kernel-patches/for-mainline/audit-pairs.diff +++ /dev/null @@ -1,1298 +0,0 @@ ---- - security/apparmor/apparmor.h | 44 +-- - security/apparmor/apparmorfs.c | 22 - - security/apparmor/lsm.c | 116 +++++---- - security/apparmor/main.c | 435 ++++++++++++++++------------------- - security/apparmor/module_interface.c | 48 ++- - security/apparmor/procattr.c | 37 +- - 6 files changed, 359 insertions(+), 343 deletions(-) - ---- a/security/apparmor/apparmor.h -+++ b/security/apparmor/apparmor.h -@@ -150,21 +150,18 @@ extern struct aa_profile *null_complain_ - */ - - struct aa_audit { -- unsigned short type; -+ const char *operation; - gfp_t gfp_mask; -+ const char *info; - const char *name; - char *buffer; -+ const char *name2; -+ char *buffer2; - int requested_mask, denied_mask; -+ struct iattr *iattr; -+ pid_t task, parent; -+ u64 magic_token; - int error_code; -- union { -- int capability; -- struct { -- const char *name2; -- char *buffer2; -- }; -- struct iattr *iattr; -- va_list vaval; -- }; - }; - - /* audit types */ -@@ -192,24 +189,29 @@ enum aa_lock_class { - extern int alloc_null_complain_profile(void); - extern void free_null_complain_profile(void); - extern int attach_nullprofile(struct aa_profile *profile); --extern void aa_audit_message(struct aa_profile *profile, gfp_t gfp, -- const char *, ...) -- __attribute__ ((format (printf, 3, 4))); -+extern int aa_audit_message(struct aa_profile *profile, struct aa_audit *sa, -+ int type); -+void aa_audit_hint(struct aa_profile *profile, struct aa_audit *sa); -+void aa_audit_status(struct aa_profile *profile, struct aa_audit *sa); -+int aa_audit_reject(struct aa_profile *profile, struct aa_audit *sa); - extern int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp, - const char *); - extern int aa_audit(struct aa_profile *profile, struct aa_audit *); - - extern int aa_attr(struct aa_profile *profile, struct dentry *dentry, - struct vfsmount *mnt, struct iattr *iattr); --extern int aa_perm_xattr(struct aa_profile *profile, struct dentry *dentry, -- struct vfsmount *mnt, const char *operation, int mask, -- int check); -+extern int aa_perm_xattr(struct aa_profile *profile, const char *operation, -+ struct dentry *dentry, struct vfsmount *mnt, -+ int mask, int check); - extern int aa_capability(struct aa_task_context *cxt, int cap); --extern int aa_perm(struct aa_profile *profile, struct dentry *dentry, -- struct vfsmount *mnt, int mask, int check); --extern int aa_perm_dir(struct aa_profile *profile, struct dentry *dentry, -- struct vfsmount *mnt, const char *operation, int mask); --extern int aa_perm_path(struct aa_profile *, const char *, int); -+extern int aa_perm(struct aa_profile *profile, const char *operation, -+ struct dentry *dentry, struct vfsmount *mnt, int mask, -+ int check); -+extern int aa_perm_dir(struct aa_profile *profile, const char *operation, -+ struct dentry *dentry, struct vfsmount *mnt, -+ int mask); -+extern int aa_perm_path(struct aa_profile *, const char *operation, -+ const char *name, int); - extern int aa_link(struct aa_profile *profile, - struct dentry *link, struct vfsmount *link_mnt, - struct dentry *target, struct vfsmount *target_mnt); ---- a/security/apparmor/apparmorfs.c -+++ b/security/apparmor/apparmorfs.c -@@ -20,7 +20,7 @@ - - static char *aa_simple_write_to_buffer(const char __user *userbuf, - size_t alloc_size, size_t copy_size, -- loff_t *pos, const char *msg) -+ loff_t *pos, const char *operation) - { - struct aa_profile *profile; - char *data; -@@ -38,13 +38,13 @@ static char *aa_simple_write_to_buffer(c - */ - profile = aa_get_profile(current); - if (profile) { -- aa_audit_message(NULL, GFP_KERNEL, "REJECTING access to " -- "profile %s (%d profile %s active %s)", -- msg, current->pid, profile->parent->name, -- profile->name); -+ struct aa_audit sa; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = operation; -+ sa.gfp_mask = GFP_KERNEL; -+ sa.error_code = -EACCES; -+ data = ERR_PTR(aa_audit_reject(profile, &sa)); - aa_put_profile(profile); -- -- data = ERR_PTR(-EPERM); - goto out; - } - -@@ -106,7 +106,7 @@ static ssize_t aa_profile_load(struct fi - char *data; - ssize_t error; - -- data = aa_simple_write_to_buffer(buf, size, size, pos, "load"); -+ data = aa_simple_write_to_buffer(buf, size, size, pos, "profile_load"); - - error = PTR_ERR(data); - if (!IS_ERR(data)) { -@@ -129,7 +129,8 @@ static ssize_t aa_profile_replace(struct - char *data; - ssize_t error; - -- data = aa_simple_write_to_buffer(buf, size, size, pos, "replacement"); -+ data = aa_simple_write_to_buffer(buf, size, size, pos, -+ "profile_replace"); - - error = PTR_ERR(data); - if (!IS_ERR(data)) { -@@ -156,7 +157,8 @@ static ssize_t aa_profile_remove(struct - * aa_remove_profile needs a null terminated string so 1 extra - * byte is allocated and the copied data is null terminated. - */ -- data = aa_simple_write_to_buffer(buf, size + 1, size, pos, "removal"); -+ data = aa_simple_write_to_buffer(buf, size + 1, size, pos, -+ "profile_remove"); - - error = PTR_ERR(data); - if (!IS_ERR(data)) { ---- a/security/apparmor/lsm.c -+++ b/security/apparmor/lsm.c -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - - #include "apparmor.h" - #include "inline.h" -@@ -123,10 +124,14 @@ static int apparmor_ptrace(struct task_s - cxt = aa_task_context(parent); - if (cxt) { - if (parent->nsproxy != child->nsproxy) { -- aa_audit_message(cxt->profile, GFP_ATOMIC, -- "REJECTING ptrace across " -- "namespace of %d by %d", -- parent->pid, child->pid); -+ struct aa_audit sa; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "ptrace"; -+ sa.gfp_mask = GFP_ATOMIC; -+ sa.parent = parent->pid; -+ sa.task = child->pid; -+ sa.info = "different namespaces"; -+ aa_audit_reject(cxt->profile, &sa); - error = -EPERM; - } else { - struct aa_task_context *child_cxt = -@@ -135,12 +140,13 @@ static int apparmor_ptrace(struct task_s - error = aa_may_ptrace(cxt, child_cxt ? - child_cxt->profile : NULL); - if (PROFILE_COMPLAIN(cxt->profile)) { -- aa_audit_message(cxt->profile, GFP_ATOMIC, -- "LOGPROF-HINT ptrace pid=%d child=%d " -- "(%d profile %s active %s)", -- current->pid, child->pid, current->pid, -- cxt->profile->parent->name, -- cxt->profile->name); -+ struct aa_audit sa; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "ptrace"; -+ sa.gfp_mask = GFP_ATOMIC; -+ sa.parent = parent->pid; -+ sa.task = child->pid; -+ aa_audit_hint(cxt->profile, &sa); - } - } - } -@@ -192,7 +198,7 @@ static int apparmor_sysctl(struct ctl_ta - if (name && name - buffer >= 5) { - name -= 5; - memcpy(name, "/proc", 5); -- error = aa_perm_path(profile, name, mask); -+ error = aa_perm_path(profile, "sysctl", name, mask); - } - free_page((unsigned long)buffer); - } -@@ -247,7 +253,8 @@ static int apparmor_inode_mkdir(struct i - profile = aa_get_profile(current); - - if (profile) -- error = aa_perm_dir(profile, dentry, mnt, "mkdir", MAY_WRITE); -+ error = aa_perm_dir(profile, "inode_mkdir", dentry, mnt, -+ MAY_WRITE); - - aa_put_profile(profile); - -@@ -267,7 +274,8 @@ static int apparmor_inode_rmdir(struct i - profile = aa_get_profile(current); - - if (profile) -- error = aa_perm_dir(profile, dentry, mnt, "rmdir", MAY_WRITE); -+ error = aa_perm_dir(profile, "inode_rmdir", dentry, mnt, -+ MAY_WRITE); - - aa_put_profile(profile); - -@@ -275,8 +283,9 @@ out: - return error; - } - --static int aa_permission(struct inode *inode, struct dentry *dentry, -- struct vfsmount *mnt, int mask, int check) -+static int aa_permission(struct inode *inode, const char *operation, -+ struct dentry *dentry, struct vfsmount *mnt, -+ int mask, int check) - { - int error = 0; - -@@ -285,7 +294,8 @@ static int aa_permission(struct inode *i - - profile = aa_get_profile(current); - if (profile) -- error = aa_perm(profile, dentry, mnt, mask, check); -+ error = aa_perm(profile, operation, dentry, mnt, mask, -+ check); - aa_put_profile(profile); - } - return error; -@@ -294,7 +304,7 @@ static int aa_permission(struct inode *i - static int apparmor_inode_create(struct inode *dir, struct dentry *dentry, - struct vfsmount *mnt, int mask) - { -- return aa_permission(dir, dentry, mnt, MAY_WRITE, 0); -+ return aa_permission(dir, "inode_create", dentry, mnt, MAY_WRITE, 0); - } - - static int apparmor_inode_link(struct dentry *old_dentry, -@@ -327,19 +337,20 @@ static int apparmor_inode_unlink(struct - - if (S_ISDIR(dentry->d_inode->i_mode)) - check |= AA_CHECK_DIR; -- return aa_permission(dir, dentry, mnt, MAY_WRITE, check); -+ return aa_permission(dir, "inode_unlink", dentry, mnt, MAY_WRITE, -+ check); - } - - static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry, - struct vfsmount *mnt, const char *old_name) - { -- return aa_permission(dir, dentry, mnt, MAY_WRITE, 0); -+ return aa_permission(dir, "inode_symlink", dentry, mnt, MAY_WRITE, 0); - } - - static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry, - struct vfsmount *mnt, int mode, dev_t dev) - { -- return aa_permission(dir, dentry, mnt, MAY_WRITE, 0); -+ return aa_permission(dir, "inode_mknod", dentry, mnt, MAY_WRITE, 0); - } - - static int apparmor_inode_rename(struct inode *old_dir, -@@ -364,12 +375,12 @@ static int apparmor_inode_rename(struct - if (inode && S_ISDIR(inode->i_mode)) - check |= AA_CHECK_DIR; - if (old_mnt) -- error = aa_perm(profile, old_dentry, old_mnt, -- MAY_READ | MAY_WRITE, check); -+ error = aa_perm(profile, "inode_rename", old_dentry, -+ old_mnt, MAY_READ | MAY_WRITE, check); - - if (!error && new_mnt) { -- error = aa_perm(profile, new_dentry, new_mnt, -- MAY_WRITE, check); -+ error = aa_perm(profile, "inode_rename", new_dentry, -+ new_mnt, MAY_WRITE, check); - } - } - -@@ -392,7 +403,8 @@ static int apparmor_inode_permission(str - /* allow traverse accesses to directories */ - mask &= ~MAY_EXEC; - } -- return aa_permission(inode, nd->dentry, nd->mnt, mask, check); -+ return aa_permission(inode, "inode_permission", nd->dentry, nd->mnt, -+ mask, check); - } - - static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, -@@ -432,7 +444,7 @@ static int aa_xattr_permission(struct de - int check = file ? AA_CHECK_FD : 0; - - if (profile) -- error = aa_perm_xattr(profile, dentry, mnt, operation, -+ error = aa_perm_xattr(profile, operation, dentry, mnt, - mask, check); - aa_put_profile(profile); - } -@@ -494,7 +506,8 @@ static int apparmor_file_permission(stru - if (S_ISDIR(inode->i_mode)) - check |= AA_CHECK_DIR; - mask &= (MAY_READ | MAY_WRITE | MAY_EXEC); -- error = aa_permission(inode, dentry, mnt, mask, check); -+ error = aa_permission(inode, "file_permission", dentry, mnt, -+ mask, check); - } - aa_put_profile(profile); - -@@ -520,8 +533,8 @@ static void apparmor_file_free_security( - aa_put_profile(file_profile); - } - --static inline int aa_mmap(struct file *file, unsigned long prot, -- unsigned long flags) -+static inline int aa_mmap(struct file *file, const char *operation, -+ unsigned long prot, unsigned long flags) - { - struct dentry *dentry; - int mask = 0; -@@ -539,20 +552,20 @@ static inline int aa_mmap(struct file *f - mask |= AA_EXEC_MMAP; - - dentry = file->f_dentry; -- return aa_permission(dentry->d_inode, dentry, file->f_vfsmnt, mask, -- AA_CHECK_FD); -+ return aa_permission(dentry->d_inode, operation, dentry, -+ file->f_vfsmnt, mask, AA_CHECK_FD); - } - - static int apparmor_file_mmap(struct file *file, unsigned long reqprot, - unsigned long prot, unsigned long flags) - { -- return aa_mmap(file, prot, flags); -+ return aa_mmap(file, "file_mmap", prot, flags); - } - - static int apparmor_file_mprotect(struct vm_area_struct *vma, - unsigned long reqprot, unsigned long prot) - { -- return aa_mmap(vma->vm_file, prot, -+ return aa_mmap(vma->vm_file, "file_mprotect", prot, - !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0); - } - -@@ -628,24 +641,27 @@ static int apparmor_setprocattr(struct t - - profile = aa_get_profile(current); - if (profile) { -+ struct aa_audit sa; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "profile_set"; -+ sa.gfp_mask = GFP_KERNEL; -+ sa.task = task->pid; -+ sa.info = "from confined process"; -+ aa_audit_reject(profile, &sa); - aa_put_profile(profile); -- aa_audit_message(NULL, GFP_KERNEL, "Attempt by " -- "confined task %d [user %d] to " -- "assign profile to task %d", -- current->pid, current->uid, -- task->pid); - return -EACCES; - } - error = aa_setprocattr_setprofile(task, args); - } else { -- AA_ERROR("Unknown setprocattr command '%.*s' " -- "by task %d [user %d] for task %d", -- size < 16 ? (int)size : 16, -- command, -- current->pid, -- current->uid, -- task->pid); -- error = -EINVAL; -+ struct aa_audit sa; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "setprocattr"; -+ sa.gfp_mask = GFP_KERNEL; -+ sa.info = "invalid command"; -+ sa.name = command; -+ sa.task = task->pid; -+ aa_audit_reject(NULL, &sa); -+ return -EINVAL; - } - - if (!error) -@@ -703,8 +719,12 @@ struct security_operations apparmor_ops - - static void info_message(const char *str) - { -+ struct aa_audit sa; -+ memset(&sa, 0, sizeof(sa)); -+ sa.gfp_mask = GFP_KERNEL; -+ sa.info = str; - printk(KERN_INFO "AppArmor: %s", str); -- aa_audit_message(NULL, GFP_KERNEL, "%s", str); -+ aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS); - } - - static int __init apparmor_init(void) -@@ -722,7 +742,7 @@ static int __init apparmor_init(void) - } - - if ((error = register_security(&apparmor_ops))) { -- AA_ERROR("Unable to load AppArmor\n"); -+ AA_ERROR("Unable to register AppArmor\n"); - goto register_security_out; - } - ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -275,49 +275,134 @@ void free_null_complain_profile(void) - } - - /** -- * aa_audit_message - Log a message to the audit subsystem -+ * aa_audit - Log an audit event to the audit subsystem - * @profile: profile to check against -- * @gfp: allocation flags -- * @flags: audit flags -- * @fmt: varargs fmt -+ * @sa: audit event -+ * @audit_cxt: audit context to log message to -+ * @type: audit event number - */ --void aa_audit_message(struct aa_profile *profile, gfp_t gfp, const char *fmt, -- ...) -+static int aa_audit_base(struct aa_profile *profile, struct aa_audit *sa, -+ struct audit_context *audit_cxt, int type) - { -- struct aa_audit sa; -+ struct audit_buffer *ab = NULL; - -- sa.type = AA_AUDITTYPE_MSG; -- sa.name = fmt; -- va_start(sa.vaval, fmt); -- sa.gfp_mask = gfp; -- sa.requested_mask = 0; -- sa.denied_mask = 0; -- sa.error_code = -EAGAIN; /* never reaches user space */ -+ ab = audit_log_start(audit_cxt, sa->gfp_mask, type); -+ -+ if (!ab) { -+ AA_ERROR("Unable to log event (%d) to audit subsys\n", -+ type); -+ /* FIXME: do we want to keep old behavior - as below -+ * don't fail operations in complain mode even if logging -+ * fails */ -+ return type == AUDIT_APPARMOR_ALLOWED ? 0 : -ENOMEM; -+ } -+ -+ if (sa->operation) -+ audit_log_format(ab, "operation=\"%s\"", sa->operation); -+ -+ if (sa->info) -+ audit_log_format(ab, " info=\"%s\"", sa->info); -+ -+ if (sa->requested_mask | sa->denied_mask) { -+ int mask = sa->denied_mask ? sa->denied_mask : -+ sa->requested_mask; -+ -+ audit_log_format(ab, " mask=\"%s%s%s%s%s\"", -+ mask & AA_EXEC_MMAP ? "m" : "", -+ mask & MAY_READ ? "r" : "", -+ mask & MAY_WRITE ? "w" : "", -+ mask & MAY_EXEC ? "x" : "", -+ mask & AA_MAY_LINK ? "l" : ""); -+ } -+ -+ if (sa->iattr) { -+ struct iattr *iattr = sa->iattr; -+ -+ audit_log_format(ab, " attribute=\"%s%s%s%s%s%s%s\"", -+ iattr->ia_valid & ATTR_MODE ? "mode," : "", -+ iattr->ia_valid & ATTR_UID ? "uid," : "", -+ iattr->ia_valid & ATTR_GID ? "gid," : "", -+ iattr->ia_valid & ATTR_SIZE ? "size," : "", -+ ((iattr->ia_valid & ATTR_ATIME_SET) || -+ (iattr->ia_valid & ATTR_ATIME)) ? "atime," : "", -+ ((iattr->ia_valid & ATTR_MTIME_SET) || -+ (iattr->ia_valid & ATTR_MTIME)) ? "mtime," : "", -+ iattr->ia_valid & ATTR_CTIME ? "ctime," : ""); -+ } -+ -+ if (sa->task) -+ audit_log_format(ab, " task=\"%d\"", sa->task); -+ -+ if (sa->parent) -+ audit_log_format(ab, "parent=\"%d\"", sa->parent); -+ -+ if (sa->name) { -+ audit_log_format(ab, " name="); -+ audit_log_untrustedstring(ab, sa->name); -+ } -+ -+ if (sa->name2) { -+ audit_log_format(ab, " name2="); -+ audit_log_untrustedstring(ab, sa->name2); -+ } -+ -+ if (sa->magic_token) -+ audit_log_format(ab, " magic_token=\"%llu\"", sa->magic_token); -+ -+ audit_log_format(ab, "pid=\"%d\"", current->pid); - -- (void)aa_audit(profile, &sa); -+ if (profile) { -+ audit_log_format(ab, " profile="); -+ audit_log_untrustedstring(ab, profile->parent->name); -+ } -+ -+ audit_log_end(ab); - -- va_end(sa.vaval); -+ return type == AUDIT_APPARMOR_ALLOWED ? 0 : sa->error_code; - } - - /** - * aa_audit_syscallreject - Log a syscall rejection to the audit subsystem - * @profile: profile to check against -- * @msg: string describing syscall being rejected - * @gfp: memory allocation flags -+ * @msg: string describing syscall being rejected - */ - int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp, - const char *msg) - { - struct aa_audit sa; -- -- sa.type = AA_AUDITTYPE_SYSCALL; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "syscall"; - sa.name = msg; - sa.gfp_mask = gfp; -- sa.requested_mask = 0; -- sa.denied_mask = 0; - sa.error_code = -EPERM; - -- return aa_audit(profile, &sa); -+ return aa_audit_base(profile, &sa, current->audit_context, -+ AUDIT_APPARMOR_DENIED); -+} -+ -+int aa_audit_message(struct aa_profile *profile, struct aa_audit *sa, -+ int type) -+{ -+ struct audit_context *audit_cxt; -+ -+ audit_cxt = apparmor_logsyscall ? current->audit_context : NULL; -+ return aa_audit_base(profile, sa, audit_cxt, type); -+} -+ -+void aa_audit_hint(struct aa_profile *profile, struct aa_audit *sa) -+{ -+ aa_audit_message(profile, sa, AUDIT_APPARMOR_HINT); -+} -+ -+void aa_audit_status(struct aa_profile *profile, struct aa_audit *sa) -+{ -+ aa_audit_message(profile, sa, AUDIT_APPARMOR_STATUS); -+} -+ -+int aa_audit_reject(struct aa_profile *profile, struct aa_audit *sa) -+{ -+ return aa_audit_message(profile, sa, AUDIT_APPARMOR_DENIED); - } - - /** -@@ -327,121 +412,21 @@ int aa_audit_syscallreject(struct aa_pro - */ - int aa_audit(struct aa_profile *profile, struct aa_audit *sa) - { -- struct audit_buffer *ab = NULL; -+ int type = AUDIT_APPARMOR_DENIED; - struct audit_context *audit_cxt; - -- const char *logcls; -- int complain = 0; -- -- const gfp_t gfp_mask = sa->gfp_mask; -- - if (likely(!sa->error_code)) { -- if (likely(!PROFILE_AUDIT(profile))) { -+ if (likely(!PROFILE_AUDIT(profile))) - /* nothing to log */ - return 0; -- } else -- logcls = "AUDITING"; -- } else if (sa->type == AA_AUDITTYPE_SYSCALL) { -- /* Currently AA_AUDITTYPE_SYSCALL is for rejects only. -- * Values set by aa_audit_syscallreject will get us here. -- */ -- logcls = "REJECTING"; -- } else { -- complain = PROFILE_COMPLAIN(profile); -- logcls = complain ? "PERMITTING" : "REJECTING"; -+ else -+ type = AUDIT_APPARMOR_AUDIT; -+ } else if (PROFILE_COMPLAIN(profile)) { -+ type = AUDIT_APPARMOR_ALLOWED; - } - -- /* Force full audit syscall logging regardless of global setting if -- * we are rejecting a syscall -- */ -- if (sa->type == AA_AUDITTYPE_SYSCALL) { -- audit_cxt = current->audit_context; -- } else { -- audit_cxt = apparmor_logsyscall ? -- current->audit_context : NULL; -- } -- -- ab = audit_log_start(audit_cxt, gfp_mask, AUDIT_APPARMOR); -- -- if (!ab) { -- AA_ERROR("Unable to log event (%d) to audit subsys\n", -- sa->type); -- return -ENOMEM; /* FIXME: was -EINVAL if !complain: ??? */ -- } -- -- /* messages get special handling */ -- if (sa->type == AA_AUDITTYPE_MSG) { -- audit_log_vformat(ab, sa->name, sa->vaval); -- audit_log_end(ab); -- goto out; -- } -- -- /* log operation */ -- -- audit_log_format(ab, "%s ", logcls); /* REJECTING/ALLOWING/etc */ -- -- switch(sa->type) { -- case AA_AUDITTYPE_FILE: { -- int mask = PROFILE_AUDIT(profile) ? -- sa->requested_mask : sa->denied_mask; -- -- audit_log_format(ab, "%s%s%s%s%s access to %s ", -- mask & AA_EXEC_MMAP ? "m" : "", -- mask & MAY_READ ? "r" : "", -- mask & MAY_WRITE ? "w" : "", -- mask & MAY_EXEC ? "x" : "", -- mask & AA_MAY_LINK ? "l" : "", -- sa->name); -- break; -- } -- case AA_AUDITTYPE_DIR: -- audit_log_format(ab, "%s on %s ", sa->name2, sa->name); -- break; -- case AA_AUDITTYPE_ATTR: { -- struct iattr *iattr = sa->iattr; -- -- audit_log_format(ab, -- "attribute (%s%s%s%s%s%s%s) change to %s ", -- iattr->ia_valid & ATTR_MODE ? "mode," : "", -- iattr->ia_valid & ATTR_UID ? "uid," : "", -- iattr->ia_valid & ATTR_GID ? "gid," : "", -- iattr->ia_valid & ATTR_SIZE ? "size," : "", -- ((iattr->ia_valid & ATTR_ATIME_SET) || -- (iattr->ia_valid & ATTR_ATIME)) ? "atime," : "", -- ((iattr->ia_valid & ATTR_MTIME_SET) || -- (iattr->ia_valid & ATTR_MTIME)) ? "mtime," : "", -- iattr->ia_valid & ATTR_CTIME ? "ctime," : "", -- sa->name); -- break; -- } -- case AA_AUDITTYPE_XATTR: -- audit_log_format(ab, "%s on %s ", sa->name2, sa->name); -- break; -- case AA_AUDITTYPE_LINK: -- audit_log_format(ab, "link access from %s to %s ", sa->name, -- sa->name2); -- break; -- case AA_AUDITTYPE_CAP: -- audit_log_format(ab, "access to capability '%s' ", -- capability_names[sa->capability]); -- break; -- case AA_AUDITTYPE_SYSCALL: -- audit_log_format(ab, "access to syscall '%s' ", sa->name); -- break; -- default: -- WARN_ON(1); -- return -EINVAL; -- } -- --#undef NOFLAGS -- -- audit_log_format(ab, "(%d profile %s active %s)", -- current->pid, profile->parent->name, profile->name); -- -- audit_log_end(ab); -- --out: -- return complain ? 0 : sa->error_code; -+ audit_cxt = apparmor_logsyscall ? current->audit_context : NULL; -+ return aa_audit_base(profile, sa, audit_cxt, type); - } - - /** -@@ -458,9 +443,10 @@ int aa_attr(struct aa_profile *profile, - int error, check; - struct aa_audit sa; - -- sa.type = AA_AUDITTYPE_ATTR; -- sa.iattr = iattr; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "setattr"; - sa.gfp_mask = GFP_KERNEL; -+ sa.iattr = iattr; - sa.requested_mask = MAY_WRITE; - sa.error_code = -EACCES; - -@@ -484,16 +470,16 @@ int aa_attr(struct aa_profile *profile, - * @mask: access mode requested - * @check: kind of check to perform - */ --int aa_perm_xattr(struct aa_profile *profile, struct dentry *dentry, -- struct vfsmount *mnt, const char *operation, -- int mask, int check) -+int aa_perm_xattr(struct aa_profile *profile, const char *operation, -+ struct dentry *dentry, struct vfsmount *mnt, int mask, -+ int check) - { - struct inode *inode = dentry->d_inode; - int error; - struct aa_audit sa; - -- sa.type = AA_AUDITTYPE_XATTR; -- sa.name2 = operation; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = operation; - sa.gfp_mask = GFP_KERNEL; - sa.requested_mask = mask; - sa.error_code = -EACCES; -@@ -517,8 +503,8 @@ int aa_perm_xattr(struct aa_profile *pro - * Determine if access @mask for the file is authorized by @profile. - * Returns 0 on success, or else an error code. - */ --int aa_perm(struct aa_profile *profile, struct dentry *dentry, -- struct vfsmount *mnt, int mask, int check) -+int aa_perm(struct aa_profile *profile, const char *operation, -+ struct dentry *dentry, struct vfsmount *mnt, int mask, int check) - { - struct aa_audit sa; - int error = 0; -@@ -526,10 +512,12 @@ int aa_perm(struct aa_profile *profile, - if (mask == 0) - goto out; - -- sa.type = AA_AUDITTYPE_FILE; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = operation; - sa.gfp_mask = GFP_KERNEL; - sa.requested_mask = mask; -- sa.error_code = -EACCES; /* FIXME: was -EPERM before: ??? */ -+ sa.error_code = -EACCES; -+ - error = aa_perm_dentry(profile, dentry, mnt, &sa, check); - - out: -@@ -548,13 +536,13 @@ out: - * by @profile. - * Returns 0 on success, or else an error code. - */ --int aa_perm_dir(struct aa_profile *profile, struct dentry *dentry, -- struct vfsmount *mnt, const char *operation, int mask) -+int aa_perm_dir(struct aa_profile *profile, const char *operation, -+ struct dentry *dentry, struct vfsmount *mnt, int mask) - { - struct aa_audit sa; - -- sa.type = AA_AUDITTYPE_DIR; -- sa.name2 = operation; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = operation; - sa.gfp_mask = GFP_KERNEL; - sa.requested_mask = mask; - sa.error_code = -EACCES; -@@ -562,13 +550,15 @@ int aa_perm_dir(struct aa_profile *profi - return aa_perm_dentry(profile, dentry, mnt, &sa, AA_CHECK_DIR); - } - --int aa_perm_path(struct aa_profile *profile, const char *name, int mask) -+int aa_perm_path(struct aa_profile *profile, const char *operation, -+ const char *name, int mask) - { - struct aa_audit sa; - -- sa.type = AA_AUDITTYPE_FILE; -- sa.requested_mask = mask; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = operation; - sa.gfp_mask = GFP_KERNEL; -+ sa.requested_mask = mask; - sa.name = name; - - sa.denied_mask = aa_file_denied(profile, name, mask); -@@ -604,11 +594,11 @@ int aa_capability(struct aa_task_context - */ - cap_raise(cxt->caps_logged, cap); - -- sa.type = AA_AUDITTYPE_CAP; -- sa.name = NULL; -- sa.capability = cap; -- sa.error_code = error; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "capable"; - sa.gfp_mask = GFP_ATOMIC; -+ sa.name = capability_names[cap]; -+ sa.error_code = error; - - error = aa_audit(cxt->profile, &sa); - -@@ -640,6 +630,9 @@ int aa_link(struct aa_profile *profile, - int error, check = 0; - struct aa_audit sa; - -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "inode_link"; -+ sa.gfp_mask = GFP_KERNEL; - sa.buffer = NULL; - sa.name = aa_get_name(link, link_mnt, &sa.buffer, check); - sa.buffer2 = NULL; -@@ -661,12 +654,9 @@ int aa_link(struct aa_profile *profile, - if (sa.name && sa.name2) { - sa.requested_mask = AA_MAY_LINK; - sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2); -- sa.error_code = sa.denied_mask ? -EPERM : 0; -+ sa.error_code = sa.denied_mask ? -EACCES : 0; - } - -- sa.type = AA_AUDITTYPE_LINK; -- sa.gfp_mask = GFP_KERNEL; -- - error = aa_audit(profile, &sa); - - aa_put_name_buffer(sa.buffer); -@@ -718,12 +708,14 @@ repeat: - unlock_profile(profile); - - if (APPARMOR_COMPLAIN(child_cxt) && -- profile == null_complain_profile) -- aa_audit_message(profile, GFP_KERNEL, -- "LOGPROF-HINT fork child=%d " -- "(%d profile %s active %s)", -- child->pid, current->pid, -- profile->parent->name, profile->name); -+ profile == null_complain_profile) { -+ struct aa_audit sa; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "clone"; -+ sa.gfp_mask = GFP_KERNEL; -+ sa.task = child->pid; -+ aa_audit_hint(profile, &sa); -+ } - aa_put_profile(profile); - } else - aa_free_task_context(child_cxt); -@@ -732,8 +724,8 @@ repeat: - } - - static struct aa_profile * --aa_register_find(struct aa_profile *profile, const char *name, char *buffer, -- int mandatory, int complain) -+aa_register_find(struct aa_profile *profile, const char *name, int mandatory, -+ int complain, struct aa_audit *sa) - { - struct aa_profile *new_profile; - -@@ -743,21 +735,14 @@ aa_register_find(struct aa_profile *prof - AA_DEBUG("%s: setting profile %s\n", - __FUNCTION__, new_profile->name); - } else if (mandatory && profile) { -+ sa->info = "mandatory profile missing"; -+ sa->denied_mask = MAY_EXEC; - if (complain) { -- aa_audit_message(profile, GFP_KERNEL, "LOGPROF-HINT " -- "missing_mandatory_profile image '%s' " -- "(%d profile %s active %s)", -- name, current->pid, -- profile->parent->name, profile->name); -+ aa_audit_hint(profile, sa); - profile = aa_dup_profile(null_complain_profile); - } else { -- aa_audit_message(profile, GFP_KERNEL, "REJECTING " -- "exec(2) of image '%s'. Profile " -- "mandatory and not found. " -- "(%d profile %s active %s)", -- name, current->pid, -- profile->parent->name, profile->name); -- return ERR_PTR(-EPERM); -+ aa_audit_reject(profile, sa); -+ return ERR_PTR(-EACCES); /* was -EPERM */ - } - } else { - /* Only way we can get into this code is if task -@@ -784,6 +769,7 @@ int aa_register(struct linux_binprm *bpr - struct file *filp = bprm->file; - struct aa_profile *profile, *old_profile, *new_profile = NULL; - int exec_mode = AA_EXEC_UNSAFE, complain = 0; -+ struct aa_audit sa; - - AA_DEBUG("%s\n", __FUNCTION__); - -@@ -793,6 +779,12 @@ int aa_register(struct linux_binprm *bpr - return -ENOENT; - } - -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "exec"; -+ sa.gfp_mask = GFP_KERNEL; -+ sa.name = filename; -+ sa.requested_mask = MAY_EXEC; -+ - repeat: - profile = aa_get_profile(current); - if (profile) { -@@ -827,8 +819,8 @@ repeat: - filename); - new_profile = aa_register_find(profile, - filename, -- buffer, 1, -- complain); -+ 1, complain, -+ &sa); - break; - } - -@@ -840,17 +832,13 @@ repeat: - new_profile = aa_dup_profile(null_complain_profile); - exec_mode |= AA_EXEC_UNSAFE; - } else { -- aa_audit_message(profile, GFP_KERNEL, "REJECTING " -- "exec(2) of image '%s'. Unable to " -- "determine exec qualifier. " -- "(%d profile %s active %s)", -- filename, current->pid, -- profile->parent->name, profile->name); -+ sa.denied_mask = MAY_EXEC; -+ aa_audit_reject(profile, &sa); - new_profile = ERR_PTR(-EPERM); - } - } else { - /* Unconfined task, load profile if it exists */ -- new_profile = aa_register_find(NULL, filename, buffer, 0, 0); -+ new_profile = aa_register_find(NULL, filename, 0, 0, &sa); - if (new_profile == NULL) - goto cleanup; - } -@@ -865,13 +853,10 @@ repeat: - if (PTR_ERR(old_profile) == -ESTALE) - goto repeat; - if (PTR_ERR(old_profile) == -EPERM) { -- aa_audit_message(profile, GFP_KERNEL, -- "REJECTING exec(2) of image '%s'. " -- "Unable to change profile, ptraced by " -- "%d. (%d profile %s active %s)", -- filename, current->parent->pid, -- current->pid, -- profile->parent->name, profile->name); -+ sa.denied_mask = MAY_EXEC; -+ sa.info = "Unable to set profile due to ptrace"; -+ sa.task = current->parent->pid; -+ aa_audit_reject(profile, &sa); - } - new_profile = old_profile; - goto cleanup; -@@ -896,12 +881,12 @@ repeat: - ((unsigned long)bprm->security | bprm_flags); - } - -- if (complain && new_profile == null_complain_profile) -- aa_audit_message(new_profile, GFP_ATOMIC, -- "LOGPROF-HINT changing_profile " -- "(%d profile %s active %s)", -- current->pid, -- new_profile->parent->name, new_profile->name); -+ if (complain && new_profile == null_complain_profile) { -+ sa.requested_mask = 0; -+ sa.name = NULL; -+ sa.info = "set profile"; -+ aa_audit_hint(new_profile, &sa); -+ } - cleanup: - aa_put_name_buffer(buffer); - if (IS_ERR(new_profile)) -@@ -964,8 +949,8 @@ repeat: - * - * Switch to a new hat. Returns %0 on success, error otherwise. - */ --static int do_change_hat(const char *hat_name, -- struct aa_task_context *new_cxt, u64 hat_magic) -+static int do_change_hat(const char *hat_name, struct aa_task_context *new_cxt, -+ u64 hat_magic, struct aa_audit *sa) - { - struct aa_task_context *cxt = aa_task_context(current); - struct aa_profile *sub; -@@ -978,7 +963,7 @@ static int do_change_hat(const char *hat - sub = __aa_find_profile(hat_name, &cxt->profile->parent->sub); - - if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, sub)) -- return -EPERM; -+ return -EACCES; - - if (sub) { - /* change hat */ -@@ -987,11 +972,8 @@ static int do_change_hat(const char *hat - struct aa_profile *profile = cxt->profile; - - if (APPARMOR_COMPLAIN(cxt)) { -- aa_audit_message(profile, GFP_ATOMIC, -- "LOGPROF-HINT unknown_hat %s " -- "(%d profile %s active %s)", -- hat_name, current->pid, -- profile->parent->name, profile->name); -+ sa->info = "unknown hat"; -+ aa_audit_hint(profile, sa); - } else { - AA_DEBUG("%s: Unknown hatname '%s'. " - "Changing to NULL profile " -@@ -1032,15 +1014,13 @@ int aa_change_hat(const char *hat_name, - { - struct aa_task_context *cxt, *new_cxt; - struct aa_profile *profile = NULL; -+ struct aa_audit sa; - int error = 0; - -- /* Dump out above debugging in WARN mode if we are in AUDIT mode */ -- if (APPARMOR_AUDIT(aa_task_context(current))) { -- aa_audit_message(NULL, GFP_KERNEL, "change_hat %s, 0x%llx " -- "(pid %d)", -- hat_name ? hat_name : "NULL", hat_magic, -- current->pid); -- } -+ memset(&sa, 0, sizeof(sa)); -+ sa.gfp_mask = GFP_ATOMIC; -+ sa.magic_token = hat_magic; -+ sa.name = hat_name; - - new_cxt = aa_alloc_task_context(GFP_KERNEL); - if (!new_cxt) -@@ -1049,6 +1029,8 @@ int aa_change_hat(const char *hat_name, - cxt = lock_task_and_profiles(current, NULL); - if (!cxt) { - /* An unconfined process cannot change_hat(). */ -+ if (APPARMOR_AUDIT(cxt)) -+ aa_audit_message(NULL, &sa, AUDIT_APPARMOR_AUDIT); - error = -EPERM; - goto out; - } -@@ -1056,6 +1038,9 @@ int aa_change_hat(const char *hat_name, - /* No need to get reference count: we do not sleep. */ - profile = cxt->profile; - -+ if (APPARMOR_AUDIT(cxt)) -+ aa_audit_message(profile, &sa, AUDIT_APPARMOR_AUDIT); -+ - /* check to see if the confined process has any hats. */ - if (list_empty(&profile->parent->sub) && !PROFILE_COMPLAIN(profile)) { - error = -ECHILD; -@@ -1069,7 +1054,8 @@ int aa_change_hat(const char *hat_name, - __FUNCTION__, - hat_name, - hat_magic); -- error = do_change_hat(hat_name, new_cxt, hat_magic); -+ error = do_change_hat(hat_name, new_cxt, hat_magic, -+ &sa); - } - } else { - /* -@@ -1091,27 +1077,16 @@ int aa_change_hat(const char *hat_name, - * stick with the same hat_magic. - */ - error = do_change_hat(hat_name, new_cxt, -- cxt->hat_magic); -+ cxt->hat_magic, &sa); - } - } else if (cxt->hat_magic) { -- AA_ERROR("KILLING process %d " -- "Invalid change_hat() magic# 0x%llx " -- "(hatname %s profile %s active %s)\n", -- current->pid, hat_magic, -- hat_name ? hat_name : "NULL", -- profile->parent->name, -- profile->name); -- -+ sa.info = "killing process"; -+ aa_audit_status(profile, &sa); - /* terminate current process */ - (void)send_sig_info(SIGKILL, NULL, current); - } else { /* cxt->hat_magic == 0 */ -- AA_ERROR("KILLING process %d " -- "Task was confined to current subprofile " -- "(profile %s active %s)\n", -- current->pid, -- profile->parent->name, -- profile->name); -- -+ sa.info = "killing process confined to current hat"; -+ aa_audit_status(profile, &sa); - /* terminate current process */ - (void)send_sig_info(SIGKILL, NULL, current); - } ---- a/security/apparmor/module_interface.c -+++ b/security/apparmor/module_interface.c -@@ -241,11 +241,14 @@ struct aa_dfa *aa_unpack_dfa(struct aa_e - /** - * aa_unpack_profile - unpack a serialized profile - * @e: serialized data extent information -- * @error: error code returned if unpacking fails -+ * @depth: recursion depth of unpack -+ * @operation: operation profile is being unpacked for - */ --static struct aa_profile *aa_unpack_profile(struct aa_ext *e, int depth) -+static struct aa_profile *aa_unpack_profile(struct aa_ext *e, int depth, -+ const char *operation) - { - struct aa_profile *profile = NULL; -+ struct aa_audit sa; - - int error = -EPROTO; - -@@ -288,7 +291,7 @@ static struct aa_profile *aa_unpack_prof - goto fail; - while (!aa_is_nameX(e, AA_LISTEND, NULL)) { - struct aa_profile *subprofile; -- subprofile = aa_unpack_profile(e, depth + 1); -+ subprofile = aa_unpack_profile(e, depth + 1, operation); - if (IS_ERR(subprofile)) { - error = PTR_ERR(subprofile); - goto fail; -@@ -304,8 +307,12 @@ static struct aa_profile *aa_unpack_prof - return profile; - - fail: -- aa_audit_message(NULL, GFP_KERNEL, "Invalid profile %s", -- profile && profile->name ? profile->name : "unknown"); -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = operation; -+ sa.gfp_mask = GFP_KERNEL; -+ sa.name = profile && profile->name ? profile->name : "unknown"; -+ sa.info = "failed to unpack profile"; -+ aa_audit_status(NULL, &sa); - - if (profile) - free_aa_profile(profile); -@@ -320,9 +327,10 @@ fail: - * check interface version unpack a profile and all its hats and patch - * in any extra information that the profile needs. - */ --static struct aa_profile *aa_unpack_profile_wrapper(struct aa_ext *e) -+static struct aa_profile *aa_unpack_profile_wrapper(struct aa_ext *e, -+ const char *operation) - { -- struct aa_profile *profile = aa_unpack_profile(e, 0); -+ struct aa_profile *profile = aa_unpack_profile(e, 0, operation); - if (!IS_ERR(profile) && - (!list_empty(&profile->sub) || profile->flags.complain)) { - int error; -@@ -338,21 +346,31 @@ static struct aa_profile *aa_unpack_prof - /** - * aa_verify_head - unpack serialized stream header - * @e: serialized data read head -+ * @operation: operation header is being verified for - * - * returns error or 0 if header is good - */ --static int aa_verify_header(struct aa_ext *e) -+static int aa_verify_header(struct aa_ext *e, const char *operation) - { - /* get the interface version */ - if (!aa_is_u32(e, &e->version, "version")) { -- aa_audit_message(NULL, GFP_KERNEL, "Interface version missing"); -+ struct aa_audit sa; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = operation; -+ sa.gfp_mask = GFP_KERNEL; -+ sa.info = "invalid profile format"; -+ aa_audit_status(NULL, &sa); - return -EPROTONOSUPPORT; - } - - /* check that the interface version is currently supported */ - if (e->version != 3) { -- aa_audit_message(NULL, GFP_KERNEL, "Unsupported interface " -- "version (%d)", e->version); -+ struct aa_audit sa; -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = operation; -+ sa.gfp_mask = GFP_KERNEL; -+ sa.info = "unsupported interface version"; -+ aa_audit_status(NULL, &sa); - return -EPROTONOSUPPORT; - } - return 0; -@@ -371,11 +389,11 @@ ssize_t aa_add_profile(void *data, size_ - .end = data + size, - .pos = data - }; -- ssize_t error = aa_verify_header(&e); -+ ssize_t error = aa_verify_header(&e, "profile_load"); - if (error) - return error; - -- profile = aa_unpack_profile_wrapper(&e); -+ profile = aa_unpack_profile_wrapper(&e, "profile_load"); - if (IS_ERR(profile)) - return PTR_ERR(profile); - -@@ -451,11 +469,11 @@ ssize_t aa_replace_profile(void *udata, - .end = udata + size, - .pos = udata - }; -- ssize_t error = aa_verify_header(&e); -+ ssize_t error = aa_verify_header(&e, "profile_replace"); - if (error) - return error; - -- new_profile = aa_unpack_profile_wrapper(&e); -+ new_profile = aa_unpack_profile_wrapper(&e, "profile_replace"); - if (IS_ERR(new_profile)) - return PTR_ERR(new_profile); - ---- a/security/apparmor/procattr.c -+++ b/security/apparmor/procattr.c -@@ -81,6 +81,12 @@ int aa_setprocattr_changehat(char *args) - int aa_setprocattr_setprofile(struct task_struct *task, char *args) - { - struct aa_profile *old_profile, *new_profile; -+ struct aa_audit sa; -+ -+ memset(&sa, 0, sizeof(sa)); -+ sa.operation = "profile_set"; -+ sa.gfp_mask = GFP_KERNEL; -+ sa.task = task->pid; - - AA_DEBUG("%s: current %d\n", - __FUNCTION__, current->pid); -@@ -91,11 +97,9 @@ repeat: - else { - new_profile = aa_find_profile(args); - if (!new_profile) { -- aa_audit_message(NULL, GFP_KERNEL, "Unable to switch " -- "task %d to profile '%s'. No such " -- "profile.", -- task->pid, args); -- -+ sa.name = args; -+ sa.info = "unknown profile"; -+ aa_audit_reject(NULL, &sa); - return -EINVAL; - } - } -@@ -112,25 +116,20 @@ repeat: - } - - if (new_profile) { -- aa_audit_message(NULL, GFP_KERNEL, "Switching task %d profile " -- "%s active %s to new profile %s", -- task->pid, old_profile ? -- old_profile->parent->name : "unconfined", -- old_profile ? old_profile->name : "unconfined", -- args); -+ sa.name = args; -+ sa.name2 = old_profile ? old_profile->parent->name : -+ "unconfined"; -+ aa_audit_status(NULL, &sa); - } else { - if (old_profile) { -- aa_audit_message(NULL, GFP_KERNEL, "Unconfining task " -- "%d profile %s active %s", -- task->pid, old_profile->parent->name, -- old_profile->name); -+ sa.name = "unconfined"; -+ sa.name2 = old_profile->parent->name; -+ aa_audit_status(NULL, &sa); - } else { -- aa_audit_message(NULL, GFP_KERNEL, "task %d is already " -- "unconfined", -- task->pid); -+ sa.info = "task is unconfined"; -+ aa_audit_status(NULL, &sa); - } - } -- - aa_put_profile(old_profile); - aa_put_profile(new_profile); - diff --git a/kernel-patches/for-mainline/audit-remove-buffer.diff b/kernel-patches/for-mainline/audit-remove-buffer.diff deleted file mode 100644 index a019c9f16..000000000 --- a/kernel-patches/for-mainline/audit-remove-buffer.diff +++ /dev/null @@ -1,69 +0,0 @@ ---- - security/apparmor/apparmor.h | 2 -- - security/apparmor/main.c | 17 ++++++++--------- - 2 files changed, 8 insertions(+), 11 deletions(-) - ---- a/security/apparmor/apparmor.h -+++ b/security/apparmor/apparmor.h -@@ -154,9 +154,7 @@ struct aa_audit { - gfp_t gfp_mask; - const char *info; - const char *name; -- char *buffer; - const char *name2; -- char *buffer2; - int requested_mask, denied_mask; - struct iattr *iattr; - pid_t task, parent; ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -177,9 +177,9 @@ static int aa_perm_dentry(struct aa_prof - struct vfsmount *mnt, struct aa_audit *sa, int check) - { - int error; -+ char *buffer = NULL; - -- sa->buffer = NULL; -- sa->name = aa_get_name(dentry, mnt, &sa->buffer, check); -+ sa->name = aa_get_name(dentry, mnt, &buffer, check); - - if (IS_ERR(sa->name)) { - /* -@@ -199,7 +199,7 @@ static int aa_perm_dentry(struct aa_prof - sa->error_code = 0; - - error = aa_audit(profile, sa); -- aa_put_name_buffer(sa->buffer); -+ aa_put_name_buffer(buffer); - - return error; - } -@@ -644,14 +644,13 @@ int aa_link(struct aa_profile *profile, - { - int error, check = 0; - struct aa_audit sa; -+ char *buffer = NULL, *buffer2 = NULL; - - memset(&sa, 0, sizeof(sa)); - sa.operation = "inode_link"; - sa.gfp_mask = GFP_KERNEL; -- sa.buffer = NULL; -- sa.name = aa_get_name(link, link_mnt, &sa.buffer, check); -- sa.buffer2 = NULL; -- sa.name2 = aa_get_name(target, target_mnt, &sa.buffer2, check); -+ sa.name = aa_get_name(link, link_mnt, &buffer, check); -+ sa.name2 = aa_get_name(target, target_mnt, &buffer2, check); - - if (IS_ERR(sa.name)) { - sa.error_code = PTR_ERR(sa.name); -@@ -671,8 +670,8 @@ int aa_link(struct aa_profile *profile, - - error = aa_audit(profile, &sa); - -- aa_put_name_buffer(sa.buffer); -- aa_put_name_buffer(sa.buffer2); -+ aa_put_name_buffer(buffer); -+ aa_put_name_buffer(buffer2); - - return error; - } diff --git a/kernel-patches/for-mainline/audit-remove-mangle.diff b/kernel-patches/for-mainline/audit-remove-mangle.diff deleted file mode 100644 index 1ceeea1aa..000000000 --- a/kernel-patches/for-mainline/audit-remove-mangle.diff +++ /dev/null @@ -1,250 +0,0 @@ ---- - security/apparmor/apparmor.h | 13 +---- - security/apparmor/main.c | 108 +++---------------------------------------- - 2 files changed, 14 insertions(+), 107 deletions(-) - ---- a/security/apparmor/apparmor.h -+++ b/security/apparmor/apparmor.h -@@ -168,13 +168,11 @@ struct aa_audit { - }; - - /* audit types */ --#define AA_MANGLE_NAME 32 --#define AA_MANGLE_NAME2 64 --#define AA_AUDITTYPE_FILE (1 | AA_MANGLE_NAME) --#define AA_AUDITTYPE_DIR (2 | AA_MANGLE_NAME) --#define AA_AUDITTYPE_ATTR (3 | AA_MANGLE_NAME) --#define AA_AUDITTYPE_XATTR (4 | AA_MANGLE_NAME) --#define AA_AUDITTYPE_LINK (5 | AA_MANGLE_NAME | AA_MANGLE_NAME2) -+#define AA_AUDITTYPE_FILE 1 -+#define AA_AUDITTYPE_DIR 2 -+#define AA_AUDITTYPE_ATTR 3 -+#define AA_AUDITTYPE_XATTR 4 -+#define AA_AUDITTYPE_LINK 5 - #define AA_AUDITTYPE_CAP 6 - #define AA_AUDITTYPE_MSG 7 - #define AA_AUDITTYPE_SYSCALL 8 -@@ -182,7 +180,6 @@ struct aa_audit { - /* Flags for the permission check functions */ - #define AA_CHECK_FD 1 /* coming from a file descriptor */ - #define AA_CHECK_DIR 2 /* file type is directory */ --#define AA_CHECK_MANGLE 4 /* leave extra room for name mangling */ - - /* lock subtypes so lockdep does not raise false dependencies */ - enum aa_lock_class { ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -90,60 +90,6 @@ static int aa_link_denied(struct aa_prof - } - - /** -- * mangle -- escape special characters in str -- * @str: string to escape -- * @buffer: buffer containing str -- * -- * Escape special characters in @str, which is contained in @buffer. @str must -- * be aligned to the end of the buffer, and the space between @buffer and @str -- * may be used for escaping. -- * -- * Returns @str if no escaping was necessary, a pointer to the beginning of the -- * escaped string, or NULL if there was not enough space in @buffer. When -- * called with a NULL buffer, the return value tells whether any escaping is -- * necessary. -- */ --static const char *mangle(const char *str, char *buffer) --{ -- static const char c_escape[] = { -- ['\a'] = 'a', ['\b'] = 'b', -- ['\f'] = 'f', ['\n'] = 'n', -- ['\r'] = 'r', ['\t'] = 't', -- ['\v'] = 'v', -- [' '] = ' ', ['\\'] = '\\', -- }; -- const char *s; -- char *t, c; -- --#define mangle_escape(c) \ -- unlikely((unsigned char)(c) < ARRAY_SIZE(c_escape) && \ -- c_escape[(unsigned char)c]) -- -- for (s = (char *)str; (c = *s) != '\0'; s++) -- if (mangle_escape(c)) -- goto escape; -- return str; -- --escape: -- if (!buffer) -- return NULL; -- for (s = str, t = buffer; (c = *s) != '\0'; s++) { -- if (mangle_escape(c)) { -- if (t == s) -- return NULL; -- *t++ = '\\'; -- *t++ = c_escape[(unsigned char)c]; -- } else -- *t++ = c; -- } -- *t++ = '\0'; -- --#undef mangle_escape -- -- return buffer; --} -- --/** - * aa_get_name - compute the pathname of a file - * @dentry: dentry of the file - * @mnt: vfsmount of the file -@@ -170,12 +116,6 @@ static char *aa_get_name(struct dentry * - return ERR_PTR(-ENOMEM); - - name = d_namespace_path(dentry, mnt, buf, size - is_dir); -- -- /* Make sure we have enough space for name mangling. */ -- if (!IS_ERR(name) && -- (check & AA_CHECK_MANGLE) && name - buf <= size / 2) -- name = ERR_PTR(-ENAMETOOLONG); -- - if (!IS_ERR(name)) { - if (name[0] != '/') { - /* -@@ -232,7 +172,6 @@ static int aa_perm_dentry(struct aa_prof - { - int error; - --again: - sa->buffer = NULL; - sa->name = aa_get_name(dentry, mnt, &sa->buffer, check); - -@@ -254,13 +193,7 @@ again: - sa->error_code = 0; - - error = aa_audit(profile, sa); -- - aa_put_name_buffer(sa->buffer); -- if (error == -ENAMETOOLONG) { -- BUG_ON(check & AA_CHECK_MANGLE); -- check |= AA_CHECK_MANGLE; -- goto again; -- } - - return error; - } -@@ -443,25 +376,12 @@ int aa_audit(struct aa_profile *profile, - goto out; - } - -- if (sa->type & AA_MANGLE_NAME) { -- sa->name = mangle(sa->name, sa->buffer); -- if (!sa->name) -- return -ENAMETOOLONG; -- } -- if (sa->type & AA_MANGLE_NAME2) { -- sa->name2 = mangle(sa->name2, sa->buffer2); -- if (!sa->name2) -- return -ENAMETOOLONG; -- } -- - /* log operation */ - - audit_log_format(ab, "%s ", logcls); /* REJECTING/ALLOWING/etc */ - --#define NOFLAGS(x) ((x) & ~(AA_MANGLE_NAME | AA_MANGLE_NAME2)) -- -- switch(NOFLAGS(sa->type)) { -- case NOFLAGS(AA_AUDITTYPE_FILE): { -+ switch(sa->type) { -+ case AA_AUDITTYPE_FILE: { - int mask = PROFILE_AUDIT(profile) ? - sa->requested_mask : sa->denied_mask; - -@@ -474,10 +394,10 @@ int aa_audit(struct aa_profile *profile, - sa->name); - break; - } -- case NOFLAGS(AA_AUDITTYPE_DIR): -+ case AA_AUDITTYPE_DIR: - audit_log_format(ab, "%s on %s ", sa->name2, sa->name); - break; -- case NOFLAGS(AA_AUDITTYPE_ATTR): { -+ case AA_AUDITTYPE_ATTR: { - struct iattr *iattr = sa->iattr; - - audit_log_format(ab, -@@ -494,18 +414,18 @@ int aa_audit(struct aa_profile *profile, - sa->name); - break; - } -- case NOFLAGS(AA_AUDITTYPE_XATTR): -+ case AA_AUDITTYPE_XATTR: - audit_log_format(ab, "%s on %s ", sa->name2, sa->name); - break; -- case NOFLAGS(AA_AUDITTYPE_LINK): -+ case AA_AUDITTYPE_LINK: - audit_log_format(ab, "link access from %s to %s ", sa->name, - sa->name2); - break; -- case NOFLAGS(AA_AUDITTYPE_CAP): -+ case AA_AUDITTYPE_CAP: - audit_log_format(ab, "access to capability '%s' ", - capability_names[sa->capability]); - break; -- case NOFLAGS(AA_AUDITTYPE_SYSCALL): -+ case AA_AUDITTYPE_SYSCALL: - audit_log_format(ab, "access to syscall '%s' ", sa->name); - break; - default: -@@ -720,7 +640,6 @@ int aa_link(struct aa_profile *profile, - int error, check = 0; - struct aa_audit sa; - --again: - sa.buffer = NULL; - sa.name = aa_get_name(link, link_mnt, &sa.buffer, check); - sa.buffer2 = NULL; -@@ -752,11 +671,6 @@ again: - - aa_put_name_buffer(sa.buffer); - aa_put_name_buffer(sa.buffer2); -- if (error == -ENAMETOOLONG) { -- BUG_ON(check & AA_CHECK_MANGLE); -- check |= AA_CHECK_MANGLE; -- goto again; -- } - - return error; - } -@@ -829,7 +743,6 @@ aa_register_find(struct aa_profile *prof - AA_DEBUG("%s: setting profile %s\n", - __FUNCTION__, new_profile->name); - } else if (mandatory && profile) { -- name = mangle(name, buffer); - if (complain) { - aa_audit_message(profile, GFP_KERNEL, "LOGPROF-HINT " - "missing_mandatory_profile image '%s' " -@@ -874,8 +787,7 @@ int aa_register(struct linux_binprm *bpr - - AA_DEBUG("%s\n", __FUNCTION__); - -- filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt, &buffer, -- AA_CHECK_MANGLE); -+ filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt, &buffer, 0); - if (IS_ERR(filename)) { - AA_ERROR("%s: Failed to get filename", __FUNCTION__); - return -ENOENT; -@@ -928,7 +840,6 @@ repeat: - new_profile = aa_dup_profile(null_complain_profile); - exec_mode |= AA_EXEC_UNSAFE; - } else { -- filename = mangle(filename, buffer); - aa_audit_message(profile, GFP_KERNEL, "REJECTING " - "exec(2) of image '%s'. Unable to " - "determine exec qualifier. " -@@ -954,7 +865,6 @@ repeat: - if (PTR_ERR(old_profile) == -ESTALE) - goto repeat; - if (PTR_ERR(old_profile) == -EPERM) { -- filename = mangle(filename, buffer); - aa_audit_message(profile, GFP_KERNEL, - "REJECTING exec(2) of image '%s'. " - "Unable to change profile, ptraced by " diff --git a/kernel-patches/for-mainline/fix-link-name2.diff b/kernel-patches/for-mainline/fix-link-name2.diff deleted file mode 100644 index a22cdb21e..000000000 --- a/kernel-patches/for-mainline/fix-link-name2.diff +++ /dev/null @@ -1,15 +0,0 @@ ---- - security/apparmor/main.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -735,7 +735,7 @@ again: - if (IS_ERR(sa.name2)) { - sa.requested_mask = 0; - sa.denied_mask = 0; -- sa.error_code = PTR_ERR(sa.name); -+ sa.error_code = PTR_ERR(sa.name2); - sa.name2 = NULL; - } - diff --git a/kernel-patches/for-mainline/fix_link_perm.diff b/kernel-patches/for-mainline/fix_link_perm.diff deleted file mode 100644 index 9c314d002..000000000 --- a/kernel-patches/for-mainline/fix_link_perm.diff +++ /dev/null @@ -1,45 +0,0 @@ -link perms were failing when 1 of the permissions was empty - ---- - security/apparmor/main.c | 20 +++++++------------- - 1 file changed, 7 insertions(+), 13 deletions(-) - ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -68,29 +68,23 @@ static int aa_link_denied(struct aa_prof - - l_mode = aa_match(profile->file_rules, link); - t_mode = aa_match(profile->file_rules, target); -- *request_mask = l_mode; -+ *request_mask = l_mode | AA_MAY_LINK; - - /* Link always requires 'l' on the link, a subset of the - * target's 'r', 'w', 'x', and 'm' permissions on the link, and - * if the link has 'x', an exact match of all the execute flags - * ('i', 'u', 'U', 'p', 'P'). - */ -+#define RWXM (MAY_READ | MAY_WRITE | MAY_EXEC | AA_EXEC_MMAP) - denied_mask = ~l_mode & AA_MAY_LINK; -- denied_mask |= l_mode & ~t_mode; -+ if (l_mode & RWXM) -+ denied_mask |= (l_mode & ~ AA_MAY_LINK) & ~t_mode; -+ else -+ denied_mask |= t_mode | AA_MAY_LINK; - if (denied_mask & AA_EXEC_MODIFIERS) - denied_mask |= MAY_EXEC; - -- /* FIXME: denied mask has no way of reporting that the secure -- * execmode required is safe exec. This means that if link -- * has safe exec and target unsafe exec, the difference is not -- * reported, back, this isn't a significant problem since -- * safe exec is a subset of unsafe exec, but it violates the -- * exec should be exactly equal rule. -- * -- * The reverse situation does not cause a problem, if link -- * requires an unsafe exec and target a safe exec we report -- * the missing unsafe exec bit. -- */ -+#undef RWXM - - return denied_mask; - } diff --git a/kernel-patches/for-mainline/get-rid-of-sa-flags.diff b/kernel-patches/for-mainline/get-rid-of-sa-flags.diff deleted file mode 100644 index 21b4d0303..000000000 --- a/kernel-patches/for-mainline/get-rid-of-sa-flags.diff +++ /dev/null @@ -1,133 +0,0 @@ ---- - security/apparmor/apparmor.h | 7 +------ - security/apparmor/main.c | 20 +------------------- - 2 files changed, 2 insertions(+), 25 deletions(-) - ---- a/security/apparmor/apparmor.h -+++ b/security/apparmor/apparmor.h -@@ -145,7 +145,7 @@ extern struct aa_profile *null_complain_ - */ - - struct aa_audit { -- unsigned short type, flags; -+ unsigned short type; - unsigned int result; - gfp_t gfp_mask; - int error_code; -@@ -175,11 +175,6 @@ struct aa_audit { - #define AA_AUDITTYPE_MSG 7 - #define AA_AUDITTYPE_SYSCALL 8 - --/* audit flags */ --#define AA_AUDITFLAG_AUDITSS_SYSCALL 1 /* log syscall context */ --#define AA_AUDITFLAG_LOGERR 2 /* log operations that failed due to -- non permission errors */ -- - /* Flags for the permission check functions */ - #define AA_CHECK_FD 1 /* coming from a file descriptor */ - #define AA_CHECK_DIR 2 /* file type is directory */ ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -367,7 +367,6 @@ int aa_audit_message(struct aa_profile * - sa.type = AA_AUDITTYPE_MSG; - sa.name = fmt; - va_start(sa.vaval, fmt); -- sa.flags = 0; - sa.gfp_mask = gfp; - sa.error_code = 0; - sa.result = 0; /* fake failure: force message to be logged */ -@@ -392,7 +391,6 @@ int aa_audit_syscallreject(struct aa_pro - - sa.type = AA_AUDITTYPE_SYSCALL; - sa.name = msg; -- sa.flags = 0; - sa.gfp_mask = gfp; - sa.error_code = 0; - sa.result = 0; /* failure */ -@@ -411,7 +409,6 @@ int aa_audit(struct aa_profile *profile, - struct audit_context *audit_cxt; - - const char *logcls; -- unsigned int flags; - int audit = 0, - complain = 0, - error = -EINVAL, -@@ -453,21 +450,13 @@ int aa_audit(struct aa_profile *profile, - logcls = complain ? "PERMITTING" : "REJECTING"; - } - -- /* In future extend w/ per-profile flags -- * (flags |= sa->profile->flags) -- */ -- flags = sa->flags; -- if (apparmor_logsyscall) -- flags |= AA_AUDITFLAG_AUDITSS_SYSCALL; -- -- - /* Force full audit syscall logging regardless of global setting if - * we are rejecting a syscall - */ - if (sa->type == AA_AUDITTYPE_SYSCALL) { - audit_cxt = current->audit_context; - } else { -- audit_cxt = (flags & AA_AUDITFLAG_AUDITSS_SYSCALL) ? -+ audit_cxt = apparmor_logsyscall ? - current->audit_context : NULL; - } - -@@ -593,7 +582,6 @@ int aa_attr(struct aa_profile *profile, - - sa.type = AA_AUDITTYPE_ATTR; - sa.iattr = iattr; -- sa.flags = 0; - sa.gfp_mask = GFP_KERNEL; - - check = 0; -@@ -626,7 +614,6 @@ int aa_perm_xattr(struct aa_profile *pro - - sa.type = AA_AUDITTYPE_XATTR; - sa.name2 = operation; -- sa.flags = 0; - sa.gfp_mask = GFP_KERNEL; - - if (inode && S_ISDIR(inode->i_mode)) -@@ -659,7 +646,6 @@ int aa_perm(struct aa_profile *profile, - - sa.type = AA_AUDITTYPE_FILE; - sa.mask = mask; -- sa.flags = 0; - sa.gfp_mask = GFP_KERNEL; - error = aa_perm_dentry(profile, dentry, mnt, &sa, mask, check); - -@@ -686,7 +672,6 @@ int aa_perm_dir(struct aa_profile *profi - - sa.type = AA_AUDITTYPE_DIR; - sa.name2 = operation; -- sa.flags = 0; - sa.gfp_mask = GFP_KERNEL; - - return aa_perm_dentry(profile, dentry, mnt, &sa, mask, AA_CHECK_DIR); -@@ -699,7 +684,6 @@ int aa_perm_path(struct aa_profile *prof - - sa.type = AA_AUDITTYPE_FILE; - sa.mask = mask; -- sa.flags = 0; - sa.gfp_mask = GFP_KERNEL; - sa.name = name; - -@@ -739,7 +723,6 @@ int aa_capability(struct aa_task_context - sa.type = AA_AUDITTYPE_CAP; - sa.name = NULL; - sa.capability = cap; -- sa.flags = 0; - sa.error_code = 0; - sa.result = !error; - sa.gfp_mask = GFP_ATOMIC; -@@ -795,7 +778,6 @@ again: - aa_permerror2result(denied_mask, &sa); - - sa.type = AA_AUDITTYPE_LINK; -- sa.flags = 0; - sa.gfp_mask = GFP_KERNEL; - - error = aa_audit(profile, &sa); diff --git a/kernel-patches/for-mainline/multi-profile-load.diff b/kernel-patches/for-mainline/multi-profile-load.diff deleted file mode 100644 index 5052993ec..000000000 --- a/kernel-patches/for-mainline/multi-profile-load.diff +++ /dev/null @@ -1,268 +0,0 @@ ---- - security/apparmor/apparmor.h | 2 - security/apparmor/module_interface.c | 177 +++++++++++++++++++++++------------ - 2 files changed, 122 insertions(+), 57 deletions(-) - ---- a/security/apparmor/apparmor.h -+++ b/security/apparmor/apparmor.h -@@ -83,6 +83,7 @@ extern unsigned int apparmor_path_max; - * @flags: flags controlling profile behavior - * @null_profile: if needed per profile learning and null confinement profile - * @isstale: flag indicating if profile is stale -+ * @replacement: profile replacing this profile - * @capabilities: capabilities granted by the process - * @count: reference count of the profile - * -@@ -109,6 +110,7 @@ struct aa_profile { - } flags; - struct aa_profile *null_profile; - int isstale; -+ struct aa_profile *replacement; - - kernel_cap_t capabilities; - struct kref count; ---- a/security/apparmor/module_interface.c -+++ b/security/apparmor/module_interface.c -@@ -346,14 +346,15 @@ static struct aa_profile *aa_unpack_prof - /** - * aa_verify_head - unpack serialized stream header - * @e: serialized data read head -+ * @log: log a message on failure - * @operation: operation header is being verified for - * - * returns error or 0 if header is good - */ --static int aa_verify_header(struct aa_ext *e, const char *operation) -+static int aa_verify_header(struct aa_ext *e, int log, const char *operation) - { - /* get the interface version */ -- if (!aa_is_u32(e, &e->version, "version")) { -+ if (!aa_is_u32(e, &e->version, "version") && log) { - struct aa_audit sa; - memset(&sa, 0, sizeof(sa)); - sa.operation = operation; -@@ -364,7 +365,7 @@ static int aa_verify_header(struct aa_ex - } - - /* check that the interface version is currently supported */ -- if (e->version != 3) { -+ if (e->version != 3 && log) { - struct aa_audit sa; - memset(&sa, 0, sizeof(sa)); - sa.operation = operation; -@@ -376,37 +377,82 @@ static int aa_verify_header(struct aa_ex - return 0; - } - -+static void free_list_of_profiles(struct list_head *lh) -+{ -+ struct aa_profile *profile, *tmp; -+ list_for_each_entry_safe(profile, tmp, lh, list) { -+ list_del_init(&profile->list); -+ aa_put_profile(profile); -+ } -+} -+ -+/** -+ * aa_unpack_profile_set - unpack a set of profiles an place on @lh -+ * @e: serialized data read head -+ * @lh: list to place profiles on (preinit) -+ * @op: which interface operation is unpacking the profile set -+ * -+ * returns error or 0 if all profiles are good -+ */ -+static int aa_unpack_profile_set(struct aa_ext *e, struct list_head *lh, -+ const char *op) -+{ -+ struct aa_profile *profile; -+ size_t error = aa_verify_header(e, 1, op); -+ if (error) -+ return error; -+ -+ while (aa_inbounds(e, 1)) { -+ profile = aa_unpack_profile_wrapper(e, op); -+ if (IS_ERR(profile)) { -+ free_list_of_profiles(lh); -+ return PTR_ERR(profile); -+ } -+ list_add(&profile->list, lh); -+ aa_verify_header(e, 0, op); /* skip header if present */ -+ } -+ return 0; -+} -+ - /** -- * aa_add_profile - Unpack and add a new profile to the profile list -+ * aa_add_profile - Unpack and add a new profile(s) to the profile list - * @data: serialized data stream - * @size: size of the serialized data stream -+ * -+ * The profile load is an all or nothing operation. If any of the -+ * profiles being loaded already exist the load will fail and -+ * non of the profiles will be loaded. - */ - ssize_t aa_add_profile(void *data, size_t size) - { -- struct aa_profile *profile = NULL; -+ LIST_HEAD(add_set); -+ struct aa_profile *profile, *tmp = NULL; - struct aa_ext e = { - .start = data, - .end = data + size, - .pos = data - }; -- ssize_t error = aa_verify_header(&e, "profile_load"); -+ ssize_t error = aa_unpack_profile_set(&e, &add_set, "profile_load"); - if (error) - return error; - -- profile = aa_unpack_profile_wrapper(&e, "profile_load"); -- if (IS_ERR(profile)) -- return PTR_ERR(profile); -- - mutex_lock(&aa_interface_lock); - write_lock(&profile_list_lock); -- if (__aa_find_profile(profile->name, &profile_list)) { -- /* A profile with this name exists already. */ -- write_unlock(&profile_list_lock); -- mutex_unlock(&aa_interface_lock); -- aa_put_profile(profile); -- return -EEXIST; -+ list_for_each_entry(profile, &add_set, list) { -+ if (__aa_find_profile(profile->name, &profile_list)) { -+ /* A profile with this name exists already. -+ * It would be nice if we could return which profile -+ * already exists -+ */ -+ write_unlock(&profile_list_lock); -+ mutex_unlock(&aa_interface_lock); -+ free_list_of_profiles(&add_set); -+ return -EEXIST; -+ } - } -- list_add(&profile->list, &profile_list); -+ list_for_each_entry_safe(profile, tmp, &add_set, list) { -+ list_move(&profile->list, &profile_list); -+ } - write_unlock(&profile_list_lock); - mutex_unlock(&aa_interface_lock); - -@@ -451,47 +497,10 @@ static inline void task_replace(struct t - cxt->hat_magic); - } - --/** -- * aa_replace_profile - replace a profile on the profile list -- * @udata: serialized data stream -- * @size: size of the serialized data stream -- * -- * unpack and replace a profile on the profile list and uses of that profile -- * by any aa_task_context. If the profile does not exist on the profile list -- * it is added. Return %0 or error. -- */ --ssize_t aa_replace_profile(void *udata, size_t size) -+static void replace_profiles_context_list(struct aa_profile *old_profile, -+ struct aa_profile *new_profile) - { -- struct aa_profile *old_profile, *new_profile; - struct aa_task_context *new_cxt; -- struct aa_ext e = { -- .start = udata, -- .end = udata + size, -- .pos = udata -- }; -- ssize_t error = aa_verify_header(&e, "profile_replace"); -- if (error) -- return error; -- -- new_profile = aa_unpack_profile_wrapper(&e, "profile_replace"); -- if (IS_ERR(new_profile)) -- return PTR_ERR(new_profile); -- -- mutex_lock(&aa_interface_lock); -- write_lock(&profile_list_lock); -- old_profile = __aa_find_profile(new_profile->name, &profile_list); -- if (old_profile) { -- lock_profile(old_profile); -- old_profile->isstale = 1; -- unlock_profile(old_profile); -- list_del_init(&old_profile->list); -- } -- list_add(&new_profile->list, &profile_list); -- write_unlock(&profile_list_lock); -- -- if (!old_profile) -- goto out; -- - /* - * Replacement needs to allocate a new aa_task_context for each - * task confined by old_profile. To do this the profile locks -@@ -517,13 +526,67 @@ ssize_t aa_replace_profile(void *udata, - unlock_both_profiles(old_profile, new_profile); - } while (!new_cxt); - aa_free_task_context(new_cxt); -- aa_put_profile(old_profile); -+} -+ -+/** -+ * aa_replace_profile - replace a profile(s) on the profile list -+ * @udata: serialized data stream -+ * @size: size of the serialized data stream -+ * -+ * unpack and replace a profile(s) on the profile list and uses of that profile -+ * by any aa_task_context. If the profile(s) does not exist on the profile -+ * list it is added. Return %0 or error. -+ */ -+ssize_t aa_replace_profile(void *udata, size_t size) -+{ -+ LIST_HEAD(new_set); -+ LIST_HEAD(old_set); -+ struct aa_profile *old_profile, *new_profile, *tmp; -+ struct aa_ext e = { -+ .start = udata, -+ .end = udata + size, -+ .pos = udata -+ }; -+ ssize_t error = aa_unpack_profile_set(&e, &new_set, "profile_replace"); -+ if (error) -+ return error; -+ -+ mutex_lock(&aa_interface_lock); -+ write_lock(&profile_list_lock); -+ list_for_each_entry_safe(new_profile, tmp, &new_set, list) { -+ old_profile = __aa_find_profile(new_profile->name, -+ &profile_list); -+ if (old_profile) { -+ lock_profile(old_profile); -+ old_profile->isstale = 1; -+ old_profile->replacement = aa_dup_profile(new_profile); -+ unlock_profile(old_profile); -+ list_move(&old_profile->list, &old_set); -+ } -+ list_move(&new_profile->list, &profile_list); -+ } -+ write_unlock(&profile_list_lock); -+ -+ if (list_empty(&old_set)) -+ goto out; -+ -+ while(!list_empty(&old_set)) { -+ old_profile = list_entry(old_set.next, struct aa_profile, -+ list); -+ list_del_init(&old_profile->list); -+ replace_profiles_context_list(old_profile, -+ old_profile->replacement); -+ aa_put_profile(old_profile->replacement); -+ old_profile->replacement = NULL; -+ aa_put_profile(old_profile); -+ } - - out: - mutex_unlock(&aa_interface_lock); - return size; - } - -+ - /** - * aa_remove_profile - remove a profile from the system - * @name: name of the profile to remove diff --git a/kernel-patches/for-mainline/no-internal-audit-errors.diff b/kernel-patches/for-mainline/no-internal-audit-errors.diff deleted file mode 100644 index 2379443d7..000000000 --- a/kernel-patches/for-mainline/no-internal-audit-errors.diff +++ /dev/null @@ -1,21 +0,0 @@ ---- - security/apparmor/main.c | 8 -------- - 1 file changed, 8 deletions(-) - ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -432,14 +432,6 @@ int aa_audit(struct aa_profile *profile, - audit = 1; - logcls = "AUDITING"; - } -- } else if (sa->error_code < 0) { -- audit_log(current->audit_context, gfp_mask, AUDIT_APPARMOR, -- "Internal error auditing event type %d (error %d)", -- sa->type, sa->error_code); -- AA_ERROR("Internal error auditing event type %d (error %d)\n", -- sa->type, sa->error_code); -- error = sa->error_code; -- goto out; - } else if (sa->type == AA_AUDITTYPE_SYSCALL) { - /* Currently AA_AUDITTYPE_SYSCALL is for rejects only. - * Values set by aa_audit_syscallreject will get us here. diff --git a/kernel-patches/for-mainline/no-unknown-exec-mod.diff b/kernel-patches/for-mainline/no-unknown-exec-mod.diff deleted file mode 100644 index a4380e154..000000000 --- a/kernel-patches/for-mainline/no-unknown-exec-mod.diff +++ /dev/null @@ -1,75 +0,0 @@ ---- - security/apparmor/apparmor.h | 5 +++++ - security/apparmor/main.c | 12 ------------ - security/apparmor/match.c | 16 ++++++++++++++++ - 3 files changed, 21 insertions(+), 12 deletions(-) - ---- a/security/apparmor/apparmor.h -+++ b/security/apparmor/apparmor.h -@@ -32,8 +32,13 @@ - AA_EXEC_UNCONFINED | \ - AA_EXEC_PROFILE) - -+#define AA_VALID_PERM_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | \ -+ AA_MAY_LINK | AA_EXEC_MODIFIERS | \ -+ AA_EXEC_MMAP | AA_EXEC_UNSAFE) -+ - #define AA_SECURE_EXEC_NEEDED 1 - -+ - /* Control parameters (0 or 1), settable thru module/boot flags or - * via /sys/kernel/security/apparmor/control */ - extern int apparmor_complain; ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -918,18 +918,6 @@ repeat: - buffer, 1, - complain); - break; -- -- default: -- AA_ERROR("Rejecting exec(2) of image '%s'. " -- "Unknown exec qualifier %x " -- "(%d profile %s active %s)\n", -- filename, -- exec_mode & AA_EXEC_MODIFIERS, -- current->pid, -- profile->parent->name, -- profile->name); -- new_profile = ERR_PTR(-EPERM); -- break; - } - - } else if (complain) { ---- a/security/apparmor/match.c -+++ b/security/apparmor/match.c -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include "apparmor.h" - #include "match.h" - - static struct table_header *unpack_table(void *blob, size_t bsize) -@@ -170,6 +171,21 @@ int verify_dfa(struct aa_dfa *dfa) - goto out; - } - -+ /* verify accept permissions */ -+ for (i = 0; i < state_count; i++) { -+ int mode = ACCEPT_TABLE(dfa)[i]; -+ -+ if (mode & ~AA_VALID_PERM_MASK) -+ goto out; -+ -+ /* if MAY_EXEC, exactly one exec modifier must be set */ -+ if (mode & MAY_EXEC) { -+ mode &= AA_EXEC_MODIFIERS; -+ if (mode & (mode - 1)) -+ goto out; -+ } -+ } -+ - error = 0; - out: - return error; diff --git a/kernel-patches/for-mainline/series b/kernel-patches/for-mainline/series index 3d81f96c9..466e3dc29 100644 --- a/kernel-patches/for-mainline/series +++ b/kernel-patches/for-mainline/series @@ -45,22 +45,6 @@ apparmor_ptrace-cleanup.diff apparmor-module_interface.diff apparmor-misc.diff apparmor-intree.diff -apparmor-lockdep.diff -get-rid-of-sa-flags.diff -no-internal-audit-errors.diff -simplify-audit-status.diff -no-unknown-exec-mod.diff -audit-defines.diff -fix-link-name2.diff -audit-remove-mangle.diff -audit-pairs.diff -audit-pairs-2.diff -audit-pairs-3.diff -audit-pairs-4.diff -audit-link-perms.diff -audit-remove-buffer.diff -#multi-profile-load.diff -fix_link_perm.diff change_profile.diff change_profile-2.diff flatten-hats.diff diff --git a/kernel-patches/for-mainline/simplify-audit-status.diff b/kernel-patches/for-mainline/simplify-audit-status.diff deleted file mode 100644 index f1681ddd4..000000000 --- a/kernel-patches/for-mainline/simplify-audit-status.diff +++ /dev/null @@ -1,367 +0,0 @@ ---- - security/apparmor/apparmor.h | 7 -- - security/apparmor/main.c | 140 +++++++++++++++++-------------------------- - 2 files changed, 61 insertions(+), 86 deletions(-) - ---- a/security/apparmor/apparmor.h -+++ b/security/apparmor/apparmor.h -@@ -146,13 +146,12 @@ extern struct aa_profile *null_complain_ - - struct aa_audit { - unsigned short type; -- unsigned int result; - gfp_t gfp_mask; -- int error_code; - const char *name; - char *buffer; -+ int requested_mask, denied_mask; -+ int error_code; - union { -- int mask; - int capability; - struct { - const char *name2; -@@ -191,7 +190,7 @@ enum aa_lock_class { - extern int alloc_null_complain_profile(void); - extern void free_null_complain_profile(void); - extern int attach_nullprofile(struct aa_profile *profile); --extern int aa_audit_message(struct aa_profile *profile, gfp_t gfp, -+extern void aa_audit_message(struct aa_profile *profile, gfp_t gfp, - const char *, ...) - __attribute__ ((format (printf, 3, 4))); - extern int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp, ---- a/security/apparmor/main.c -+++ b/security/apparmor/main.c -@@ -38,17 +38,6 @@ static const char *capability_names[] = - */ - struct aa_profile *null_complain_profile; - --static inline void aa_permerror2result(int perm_result, struct aa_audit *sa) --{ -- if (perm_result == 0) { /* success */ -- sa->result = 1; -- sa->error_code = 0; -- } else { /* -ve internal error code or +ve mask of denied perms */ -- sa->result = 0; -- sa->error_code = perm_result; -- } --} -- - /** - * aa_file_denied - check for @mask access on a file - * @profile: profile to check against -@@ -239,10 +228,9 @@ static inline void aa_put_name_buffer(ch - * 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 mask, -- int check) -+ struct vfsmount *mnt, struct aa_audit *sa, int check) - { -- int denied_mask, error; -+ int error; - - again: - sa->buffer = NULL; -@@ -254,14 +242,16 @@ again: - * accessed through a file descriptor. - */ - if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD)) -- denied_mask = 0; -+ sa->denied_mask = 0; - else -- denied_mask = PTR_ERR(sa->name); -+ sa->denied_mask = PTR_ERR(sa->name); - sa->name = NULL; - } else -- denied_mask = aa_file_denied(profile, sa->name, mask); -+ sa->denied_mask = aa_file_denied(profile, sa->name, -+ sa->requested_mask); - -- aa_permerror2result(denied_mask, sa); -+ if (!sa->denied_mask) -+ sa->error_code = 0; - - error = aa_audit(profile, sa); - -@@ -358,24 +348,22 @@ void free_null_complain_profile(void) - * @flags: audit flags - * @fmt: varargs fmt - */ --int aa_audit_message(struct aa_profile *profile, gfp_t gfp, const char *fmt, -+void aa_audit_message(struct aa_profile *profile, gfp_t gfp, const char *fmt, - ...) - { -- int ret; - struct aa_audit sa; - - sa.type = AA_AUDITTYPE_MSG; - sa.name = fmt; - va_start(sa.vaval, fmt); - sa.gfp_mask = gfp; -- sa.error_code = 0; -- sa.result = 0; /* fake failure: force message to be logged */ -+ sa.requested_mask = 0; -+ sa.denied_mask = 0; -+ sa.error_code = -EAGAIN; /* never reaches user space */ - -- ret = aa_audit(profile, &sa); -+ (void)aa_audit(profile, &sa); - - va_end(sa.vaval); -- -- return ret; - } - - /** -@@ -392,8 +380,9 @@ int aa_audit_syscallreject(struct aa_pro - sa.type = AA_AUDITTYPE_SYSCALL; - sa.name = msg; - sa.gfp_mask = gfp; -- sa.error_code = 0; -- sa.result = 0; /* failure */ -+ sa.requested_mask = 0; -+ sa.denied_mask = 0; -+ sa.error_code = -EPERM; - - return aa_audit(profile, &sa); - } -@@ -409,29 +398,16 @@ int aa_audit(struct aa_profile *profile, - struct audit_context *audit_cxt; - - const char *logcls; -- int audit = 0, -- complain = 0, -- error = -EINVAL, -- opspec_error = -EACCES; -+ int complain = 0; - - const gfp_t gfp_mask = sa->gfp_mask; - -- /* -- * sa->result: 1 success, 0 failure -- * sa->error_code: success: 0 -- * failure: +ve mask of failed permissions or -ve -- * system error -- */ -- -- if (likely(sa->result)) { -+ if (likely(!sa->error_code)) { - if (likely(!PROFILE_AUDIT(profile))) { - /* nothing to log */ -- error = 0; -- goto out; -- } else { -- audit = 1; -+ return 0; -+ } else - logcls = "AUDITING"; -- } - } else if (sa->type == AA_AUDITTYPE_SYSCALL) { - /* Currently AA_AUDITTYPE_SYSCALL is for rejects only. - * Values set by aa_audit_syscallreject will get us here. -@@ -457,16 +433,13 @@ int aa_audit(struct aa_profile *profile, - if (!ab) { - AA_ERROR("Unable to log event (%d) to audit subsys\n", - sa->type); -- if (complain) -- error = 0; -- goto out; -+ return -ENOMEM; /* FIXME: was -EINVAL if !complain: ??? */ - } - - /* messages get special handling */ - if (sa->type == AA_AUDITTYPE_MSG) { - audit_log_vformat(ab, sa->name, sa->vaval); - audit_log_end(ab); -- error = 0; - goto out; - } - -@@ -479,7 +452,6 @@ int aa_audit(struct aa_profile *profile, - sa->name2 = mangle(sa->name2, sa->buffer2); - if (!sa->name2) - return -ENAMETOOLONG; -- - } - - /* log operation */ -@@ -490,16 +462,16 @@ int aa_audit(struct aa_profile *profile, - - switch(NOFLAGS(sa->type)) { - case NOFLAGS(AA_AUDITTYPE_FILE): { -- int perm = audit ? sa->mask : sa->error_code; -+ int mask = PROFILE_AUDIT(profile) ? -+ sa->requested_mask : sa->denied_mask; - - audit_log_format(ab, "%s%s%s%s%s access to %s ", -- perm & AA_EXEC_MMAP ? "m" : "", -- perm & MAY_READ ? "r" : "", -- perm & MAY_WRITE ? "w" : "", -- perm & MAY_EXEC ? "x" : "", -- perm & AA_MAY_LINK ? "l" : "", -+ mask & AA_EXEC_MMAP ? "m" : "", -+ mask & MAY_READ ? "r" : "", -+ mask & MAY_WRITE ? "w" : "", -+ mask & MAY_EXEC ? "x" : "", -+ mask & AA_MAY_LINK ? "l" : "", - sa->name); -- opspec_error = -EPERM; - break; - } - case NOFLAGS(AA_AUDITTYPE_DIR): -@@ -532,15 +504,13 @@ int aa_audit(struct aa_profile *profile, - case NOFLAGS(AA_AUDITTYPE_CAP): - audit_log_format(ab, "access to capability '%s' ", - capability_names[sa->capability]); -- opspec_error = -EPERM; - break; - case NOFLAGS(AA_AUDITTYPE_SYSCALL): - audit_log_format(ab, "access to syscall '%s' ", sa->name); -- opspec_error = -EPERM; - break; - default: - WARN_ON(1); -- return error; -+ return -EINVAL; - } - - #undef NOFLAGS -@@ -550,12 +520,8 @@ int aa_audit(struct aa_profile *profile, - - audit_log_end(ab); - -- if (complain) -- error = 0; -- else -- error = sa->result ? 0 : opspec_error; - out: -- return error; -+ return complain ? 0 : sa->error_code; - } - - /** -@@ -575,6 +541,8 @@ int aa_attr(struct aa_profile *profile, - sa.type = AA_AUDITTYPE_ATTR; - sa.iattr = iattr; - sa.gfp_mask = GFP_KERNEL; -+ sa.requested_mask = MAY_WRITE; -+ sa.error_code = -EACCES; - - check = 0; - if (inode && S_ISDIR(inode->i_mode)) -@@ -582,7 +550,7 @@ int aa_attr(struct aa_profile *profile, - if (iattr->ia_valid & ATTR_FILE) - check |= AA_CHECK_FD; - -- error = aa_perm_dentry(profile, dentry, mnt, &sa, MAY_WRITE, check); -+ error = aa_perm_dentry(profile, dentry, mnt, &sa, check); - - return error; - } -@@ -607,11 +575,13 @@ int aa_perm_xattr(struct aa_profile *pro - sa.type = AA_AUDITTYPE_XATTR; - sa.name2 = operation; - sa.gfp_mask = GFP_KERNEL; -+ sa.requested_mask = mask; -+ sa.error_code = -EACCES; - - if (inode && S_ISDIR(inode->i_mode)) - check |= AA_CHECK_DIR; - -- error = aa_perm_dentry(profile, dentry, mnt, &sa, mask, check); -+ error = aa_perm_dentry(profile, dentry, mnt, &sa, check); - - return error; - } -@@ -637,9 +607,10 @@ int aa_perm(struct aa_profile *profile, - goto out; - - sa.type = AA_AUDITTYPE_FILE; -- sa.mask = mask; - sa.gfp_mask = GFP_KERNEL; -- error = aa_perm_dentry(profile, dentry, mnt, &sa, mask, check); -+ sa.requested_mask = mask; -+ sa.error_code = -EACCES; /* FIXME: was -EPERM before: ??? */ -+ error = aa_perm_dentry(profile, dentry, mnt, &sa, check); - - out: - return error; -@@ -665,22 +636,23 @@ int aa_perm_dir(struct aa_profile *profi - sa.type = AA_AUDITTYPE_DIR; - sa.name2 = operation; - sa.gfp_mask = GFP_KERNEL; -+ sa.requested_mask = mask; -+ sa.error_code = -EACCES; - -- return aa_perm_dentry(profile, dentry, mnt, &sa, mask, AA_CHECK_DIR); -+ return aa_perm_dentry(profile, dentry, mnt, &sa, AA_CHECK_DIR); - } - - int aa_perm_path(struct aa_profile *profile, const char *name, int mask) - { - struct aa_audit sa; -- int denied_mask; - - sa.type = AA_AUDITTYPE_FILE; -- sa.mask = mask; -+ sa.requested_mask = mask; - sa.gfp_mask = GFP_KERNEL; - sa.name = name; - -- denied_mask = aa_file_denied(profile, name, mask); -- aa_permerror2result(denied_mask, &sa); -+ sa.denied_mask = aa_file_denied(profile, name, mask); -+ sa.error_code = sa.denied_mask ? -EACCES : 0; - - return aa_audit(profile, &sa); - } -@@ -715,8 +687,7 @@ int aa_capability(struct aa_task_context - sa.type = AA_AUDITTYPE_CAP; - sa.name = NULL; - sa.capability = cap; -- sa.error_code = 0; -- sa.result = !error; -+ sa.error_code = error; - sa.gfp_mask = GFP_ATOMIC; - - error = aa_audit(cxt->profile, &sa); -@@ -746,7 +717,7 @@ int aa_link(struct aa_profile *profile, - struct dentry *link, struct vfsmount *link_mnt, - struct dentry *target, struct vfsmount *target_mnt) - { -- int denied_mask = -EPERM, error, check = 0; -+ int error, check = 0; - struct aa_audit sa; - - again: -@@ -756,18 +727,23 @@ again: - sa.name2 = aa_get_name(target, target_mnt, &sa.buffer2, check); - - if (IS_ERR(sa.name)) { -- denied_mask = PTR_ERR(sa.name); -+ sa.requested_mask = 0; -+ sa.denied_mask = 0; -+ sa.error_code = PTR_ERR(sa.name); - sa.name = NULL; - } - if (IS_ERR(sa.name2)) { -- denied_mask = PTR_ERR(sa.name2); -+ sa.requested_mask = 0; -+ sa.denied_mask = 0; -+ sa.error_code = PTR_ERR(sa.name); - sa.name2 = NULL; - } - -- if (sa.name && sa.name2) -- denied_mask = aa_link_denied(profile, sa.name, sa.name2); -- -- aa_permerror2result(denied_mask, &sa); -+ if (sa.name && sa.name2) { -+ sa.requested_mask = AA_MAY_LINK; -+ sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2); -+ sa.error_code = sa.denied_mask ? -EPERM : 0; -+ } - - sa.type = AA_AUDITTYPE_LINK; - sa.gfp_mask = GFP_KERNEL;