Fold together the audit rework.

This commit is contained in:
Andreas Gruenbacher 2007-06-22 18:52:49 +00:00
parent 024b9d702a
commit 97df59697c
22 changed files with 743 additions and 3576 deletions

View file

@ -12,9 +12,9 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
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 <jjohansen@suse.de>
* 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);

View file

@ -1,145 +0,0 @@
From: John Johansen <jjohansen@suse.de>
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 <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Cc: Ingo Molnar <mingo@elte.hu>
---
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);

File diff suppressed because it is too large Load diff

View file

@ -13,13 +13,13 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
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 <agruen@suse.de>
+ $(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 <agruen@suse.de>
+ 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 <agruen@suse.de>
+ */
+
+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 <agruen@suse.de>
+#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 <agruen@suse.de>
+
+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 <agruen@suse.de>
+ */
+ 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 <agruen@suse.de>
+ 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 <agruen@suse.de>
+ 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 <agruen@suse.de>
+ * 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 <agruen@suse.de>
+
--- /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 <agruen@suse.de>
+ * 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 <agruen@suse.de>
+ * 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 <agruen@suse.de>
+ */
+ 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 <agruen@suse.de>
+};
--- /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 <agruen@suse.de>
+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 <agruen@suse.de>
+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 <agruen@suse.de>
+ 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 <agruen@suse.de>
+ }
+
+ 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);
+

View file

@ -8,14 +8,14 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
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 <agruen@suse.de>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#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 <agruen@suse.de>
+ 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 <agruen@suse.de>
+#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 <agruen@suse.de>
+/**
+ * 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 <agruen@suse.de>
+ 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 <agruen@suse.de>
+ 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 <agruen@suse.de>
+ * 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 <agruen@suse.de>
+/**
+ * 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 <agruen@suse.de>
+ .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 <agruen@suse.de>
+ .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);
+

View file

@ -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 <linux/namei.h>
#include <linux/ctype.h>
#include <linux/sysctl.h>
+#include <linux/audit.h>
#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;
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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," : "");
}

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -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 "

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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.

View file

@ -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 <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
+#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;

View file

@ -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

View file

@ -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;