mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 06:16:03 +00:00
Fold patches, and remove obsolete ones.
This commit is contained in:
@@ -5,9 +5,10 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
security/Kconfig | 1 +
|
||||
security/Makefile | 1 +
|
||||
2 files changed, 2 insertions(+)
|
||||
security/Kconfig | 1 +
|
||||
security/Makefile | 1 +
|
||||
security/apparmor/Kconfig | 3 ++-
|
||||
3 files changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/security/Kconfig
|
||||
+++ b/security/Kconfig
|
||||
@@ -28,3 +29,14 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+obj-$(CONFIG_SECURITY_APPARMOR) += commoncap.o apparmor/
|
||||
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
|
||||
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
|
||||
--- a/security/apparmor/Kconfig
|
||||
+++ b/security/apparmor/Kconfig
|
||||
@@ -1,6 +1,7 @@
|
||||
config SECURITY_APPARMOR
|
||||
tristate "AppArmor support"
|
||||
- depends on SECURITY!=n
|
||||
+ depends on SECURITY
|
||||
+ select AUDIT
|
||||
help
|
||||
This enables the AppArmor security module.
|
||||
Required userspace tools (if they are not included in your
|
||||
|
@@ -1,118 +0,0 @@
|
||||
---
|
||||
security/apparmor/lsm.c | 73 +++++-------------------------------------------
|
||||
1 file changed, 9 insertions(+), 64 deletions(-)
|
||||
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -133,30 +133,6 @@ static int apparmor_ptrace(struct task_s
|
||||
return error;
|
||||
}
|
||||
|
||||
-static int apparmor_capget(struct task_struct *task,
|
||||
- kernel_cap_t *effective,
|
||||
- kernel_cap_t *inheritable,
|
||||
- kernel_cap_t *permitted)
|
||||
-{
|
||||
- return cap_capget(task, effective, inheritable, permitted);
|
||||
-}
|
||||
-
|
||||
-static int apparmor_capset_check(struct task_struct *task,
|
||||
- kernel_cap_t *effective,
|
||||
- kernel_cap_t *inheritable,
|
||||
- kernel_cap_t *permitted)
|
||||
-{
|
||||
- return cap_capset_check(task, effective, inheritable, permitted);
|
||||
-}
|
||||
-
|
||||
-static void apparmor_capset_set(struct task_struct *task,
|
||||
- kernel_cap_t *effective,
|
||||
- kernel_cap_t *inheritable,
|
||||
- kernel_cap_t *permitted)
|
||||
-{
|
||||
- cap_capset_set(task, effective, inheritable, permitted);
|
||||
-}
|
||||
-
|
||||
static int apparmor_capable(struct task_struct *task, int cap)
|
||||
{
|
||||
int error;
|
||||
@@ -188,26 +164,6 @@ static int apparmor_sysctl(struct ctl_ta
|
||||
return error;
|
||||
}
|
||||
|
||||
-static int apparmor_syslog(int type)
|
||||
-{
|
||||
- return cap_syslog(type);
|
||||
-}
|
||||
-
|
||||
-static int apparmor_netlink_send(struct sock *sk, struct sk_buff *skb)
|
||||
-{
|
||||
- return cap_netlink_send(sk, skb);
|
||||
-}
|
||||
-
|
||||
-static int apparmor_netlink_recv(struct sk_buff *skb, int cap)
|
||||
-{
|
||||
- return cap_netlink_recv(skb, cap);
|
||||
-}
|
||||
-
|
||||
-static void apparmor_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
|
||||
-{
|
||||
- cap_bprm_apply_creds(bprm, unsafe);
|
||||
-}
|
||||
-
|
||||
static int apparmor_bprm_set_security(struct linux_binprm *bprm)
|
||||
{
|
||||
/* handle capability bits with setuid, etc */
|
||||
@@ -594,17 +550,6 @@ static void apparmor_task_free_security(
|
||||
aa_release(task);
|
||||
}
|
||||
|
||||
-static int apparmor_task_post_setuid(uid_t id0, uid_t id1, uid_t id2,
|
||||
- int flags)
|
||||
-{
|
||||
- return cap_task_post_setuid(id0, id1, id2, flags);
|
||||
-}
|
||||
-
|
||||
-static void apparmor_task_reparent_to_init(struct task_struct *task)
|
||||
-{
|
||||
- cap_task_reparent_to_init(task);
|
||||
-}
|
||||
-
|
||||
static int apparmor_getprocattr(struct task_struct *task, char *name,
|
||||
char **value)
|
||||
{
|
||||
@@ -696,17 +641,17 @@ static int apparmor_setprocattr(struct t
|
||||
|
||||
struct security_operations apparmor_ops = {
|
||||
.ptrace = apparmor_ptrace,
|
||||
- .capget = apparmor_capget,
|
||||
- .capset_check = apparmor_capset_check,
|
||||
- .capset_set = apparmor_capset_set,
|
||||
+ .capget = cap_capget,
|
||||
+ .capset_check = cap_capset_check,
|
||||
+ .capset_set = cap_capset_set,
|
||||
.sysctl = apparmor_sysctl,
|
||||
.capable = apparmor_capable,
|
||||
- .syslog = apparmor_syslog,
|
||||
+ .syslog = cap_syslog,
|
||||
|
||||
- .netlink_send = apparmor_netlink_send,
|
||||
- .netlink_recv = apparmor_netlink_recv,
|
||||
+ .netlink_send = cap_netlink_send,
|
||||
+ .netlink_recv = cap_netlink_recv,
|
||||
|
||||
- .bprm_apply_creds = apparmor_bprm_apply_creds,
|
||||
+ .bprm_apply_creds = cap_bprm_apply_creds,
|
||||
.bprm_set_security = apparmor_bprm_set_security,
|
||||
.bprm_secureexec = apparmor_bprm_secureexec,
|
||||
|
||||
@@ -736,8 +681,8 @@ struct security_operations apparmor_ops
|
||||
.task_create = apparmor_task_create,
|
||||
.task_alloc_security = apparmor_task_alloc_security,
|
||||
.task_free_security = apparmor_task_free_security,
|
||||
- .task_post_setuid = apparmor_task_post_setuid,
|
||||
- .task_reparent_to_init = apparmor_task_reparent_to_init,
|
||||
+ .task_post_setuid = cap_task_post_setuid,
|
||||
+ .task_reparent_to_init = cap_task_reparent_to_init,
|
||||
|
||||
.getprocattr = apparmor_getprocattr,
|
||||
.setprocattr = apparmor_setprocattr,
|
@@ -7,12 +7,12 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/lsm.c | 828 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 828 insertions(+)
|
||||
security/apparmor/lsm.c | 762 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 762 insertions(+)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -0,0 +1,828 @@
|
||||
@@ -0,0 +1,762 @@
|
||||
+/*
|
||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||
+ *
|
||||
@@ -129,49 +129,34 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ /**
|
||||
+ * parent can ptrace child when
|
||||
+ * - parent is unconfined
|
||||
+ * - parent is in complain mode
|
||||
+ * - parent and child are confined by the same profile
|
||||
+ * - parent & child are in the same namespace &&
|
||||
+ * - parent is in complain mode
|
||||
+ * - parent and child are confined by the same profile
|
||||
+ * - parent profile has CAP_SYS_PTRACE
|
||||
+ */
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ cxt = aa_task_context(parent);
|
||||
+ child_cxt = aa_task_context(child);
|
||||
+ child_profile = child_cxt ? child_cxt->profile : NULL;
|
||||
+ error = aa_may_ptrace(cxt, child_profile);
|
||||
+ if (cxt && PROFILE_COMPLAIN(cxt->profile)) {
|
||||
+ LOG_HINT(cxt->profile, GFP_ATOMIC, HINT_PTRACE,
|
||||
+ if (cxt && (parent->nsproxy != child->nsproxy)) {
|
||||
+ AA_WARN(GFP_ATOMIC,
|
||||
+ "REJECTING ptrace across namespace of %d by %d",
|
||||
+ parent->pid, child->pid);
|
||||
+ error = -EPERM;
|
||||
+ } else {
|
||||
+ error = aa_may_ptrace(cxt, child_profile);
|
||||
+ if (cxt && PROFILE_COMPLAIN(cxt->profile)) {
|
||||
+ LOG_HINT(cxt->profile, GFP_ATOMIC, HINT_PTRACE,
|
||||
+ "pid=%d child=%d\n",
|
||||
+ current->pid, child->pid);
|
||||
+ }
|
||||
+ }
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_capget(struct task_struct *task,
|
||||
+ kernel_cap_t *effective,
|
||||
+ kernel_cap_t *inheritable,
|
||||
+ kernel_cap_t *permitted)
|
||||
+{
|
||||
+ return cap_capget(task, effective, inheritable, permitted);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_capset_check(struct task_struct *task,
|
||||
+ kernel_cap_t *effective,
|
||||
+ kernel_cap_t *inheritable,
|
||||
+ kernel_cap_t *permitted)
|
||||
+{
|
||||
+ return cap_capset_check(task, effective, inheritable, permitted);
|
||||
+}
|
||||
+
|
||||
+static void apparmor_capset_set(struct task_struct *task,
|
||||
+ kernel_cap_t *effective,
|
||||
+ kernel_cap_t *inheritable,
|
||||
+ kernel_cap_t *permitted)
|
||||
+{
|
||||
+ cap_capset_set(task, effective, inheritable, permitted);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_capable(struct task_struct *task, int cap)
|
||||
+{
|
||||
+ int error;
|
||||
@@ -203,26 +188,6 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_syslog(int type)
|
||||
+{
|
||||
+ return cap_syslog(type);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_netlink_send(struct sock *sk, struct sk_buff *skb)
|
||||
+{
|
||||
+ return cap_netlink_send(sk, skb);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_netlink_recv(struct sk_buff *skb, int cap)
|
||||
+{
|
||||
+ return cap_netlink_recv(skb, cap);
|
||||
+}
|
||||
+
|
||||
+static void apparmor_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
|
||||
+{
|
||||
+ cap_bprm_apply_creds(bprm, unsafe);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_bprm_set_security(struct linux_binprm *bprm)
|
||||
+{
|
||||
+ /* handle capability bits with setuid, etc */
|
||||
@@ -443,8 +408,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+}
|
||||
+
|
||||
+static int aa_xattr_permission(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const char *operation,
|
||||
+ int mask, struct file *file)
|
||||
+ const char *operation, int mask,
|
||||
+ struct file *file)
|
||||
+{
|
||||
+ int error = 0;
|
||||
+
|
||||
@@ -453,8 +418,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ int check = file ? AA_CHECK_FD : 0;
|
||||
+
|
||||
+ if (profile)
|
||||
+ error = aa_perm_xattr(profile, dentry, mnt, name,
|
||||
+ operation, mask, check);
|
||||
+ error = aa_perm_xattr(profile, dentry, mnt, operation,
|
||||
+ mask, check);
|
||||
+ aa_put_profile(profile);
|
||||
+ }
|
||||
+
|
||||
@@ -465,30 +430,27 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ char *name, void *value, size_t size,
|
||||
+ int flags, struct file *file)
|
||||
+{
|
||||
+ return aa_xattr_permission(dentry, mnt, name, "xattr set", MAY_WRITE,
|
||||
+ file);
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr set", MAY_WRITE, file);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ char *name, struct file *file)
|
||||
+{
|
||||
+ return aa_xattr_permission(dentry, mnt, name, "xattr get", MAY_READ,
|
||||
+ file);
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr get", MAY_READ, file);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct file *file)
|
||||
+{
|
||||
+ return aa_xattr_permission(dentry, mnt, NULL, "xattr list", MAY_READ,
|
||||
+ file);
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr list", MAY_READ, file);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_removexattr(struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, char *name,
|
||||
+ struct file *file)
|
||||
+{
|
||||
+ return aa_xattr_permission(dentry, mnt, name, "xattr remove",
|
||||
+ MAY_WRITE, file);
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr remove", MAY_WRITE,
|
||||
+ file);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_file_permission(struct file *file, int mask)
|
||||
@@ -526,22 +488,6 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_task_create(unsigned long clone_flags)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ profile = aa_get_profile(current);
|
||||
+ if (profile) {
|
||||
+ /* Don't allow to create new namespaces. */
|
||||
+ if (clone_flags & CLONE_NEWNS)
|
||||
+ error = -EPERM;
|
||||
+ }
|
||||
+ aa_put_profile(profile);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_file_alloc_security(struct file *file)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
@@ -609,17 +555,6 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ aa_release(task);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_task_post_setuid(uid_t id0, uid_t id1, uid_t id2,
|
||||
+ int flags)
|
||||
+{
|
||||
+ return cap_task_post_setuid(id0, id1, id2, flags);
|
||||
+}
|
||||
+
|
||||
+static void apparmor_task_reparent_to_init(struct task_struct *task)
|
||||
+{
|
||||
+ cap_task_reparent_to_init(task);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_getprocattr(struct task_struct *task, char *name,
|
||||
+ char **value)
|
||||
+{
|
||||
@@ -711,17 +646,17 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+
|
||||
+struct security_operations apparmor_ops = {
|
||||
+ .ptrace = apparmor_ptrace,
|
||||
+ .capget = apparmor_capget,
|
||||
+ .capset_check = apparmor_capset_check,
|
||||
+ .capset_set = apparmor_capset_set,
|
||||
+ .capget = cap_capget,
|
||||
+ .capset_check = cap_capset_check,
|
||||
+ .capset_set = cap_capset_set,
|
||||
+ .sysctl = apparmor_sysctl,
|
||||
+ .capable = apparmor_capable,
|
||||
+ .syslog = apparmor_syslog,
|
||||
+ .syslog = cap_syslog,
|
||||
+
|
||||
+ .netlink_send = apparmor_netlink_send,
|
||||
+ .netlink_recv = apparmor_netlink_recv,
|
||||
+ .netlink_send = cap_netlink_send,
|
||||
+ .netlink_recv = cap_netlink_recv,
|
||||
+
|
||||
+ .bprm_apply_creds = apparmor_bprm_apply_creds,
|
||||
+ .bprm_apply_creds = cap_bprm_apply_creds,
|
||||
+ .bprm_set_security = apparmor_bprm_set_security,
|
||||
+ .bprm_secureexec = apparmor_bprm_secureexec,
|
||||
+
|
||||
@@ -748,11 +683,10 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ .file_mmap = apparmor_file_mmap,
|
||||
+ .file_mprotect = apparmor_file_mprotect,
|
||||
+
|
||||
+ .task_create = apparmor_task_create,
|
||||
+ .task_alloc_security = apparmor_task_alloc_security,
|
||||
+ .task_free_security = apparmor_task_free_security,
|
||||
+ .task_post_setuid = apparmor_task_post_setuid,
|
||||
+ .task_reparent_to_init = apparmor_task_reparent_to_init,
|
||||
+ .task_post_setuid = cap_task_post_setuid,
|
||||
+ .task_reparent_to_init = cap_task_reparent_to_init,
|
||||
+
|
||||
+ .getprocattr = apparmor_getprocattr,
|
||||
+ .setprocattr = apparmor_setprocattr,
|
||||
|
@@ -1,54 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: Get rid of aa_taskattr_access
|
||||
|
||||
---
|
||||
security/apparmor/main.c | 31 +------------------------------
|
||||
1 file changed, 1 insertion(+), 30 deletions(-)
|
||||
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -38,27 +38,6 @@ static const char *capability_names[] =
|
||||
*/
|
||||
struct aa_profile *null_complain_profile;
|
||||
|
||||
-/**
|
||||
- * aa_taskattr_access
|
||||
- * @name: name of the file to check
|
||||
- *
|
||||
- * Check if name matches /proc/self/attr/current, with self resolved
|
||||
- * to the current pid. This file is the usermode interface for
|
||||
- * changing one's hat.
|
||||
- */
|
||||
-static inline int aa_taskattr_access(const char *name)
|
||||
-{
|
||||
- unsigned long pid;
|
||||
- char *end;
|
||||
-
|
||||
- if (strncmp(name, "/proc/", 6) != 0)
|
||||
- return 0;
|
||||
- pid = simple_strtoul(name + 6, &end, 10);
|
||||
- if (pid != current->pid)
|
||||
- return 0;
|
||||
- return strcmp(end, "/attr/current") == 0;
|
||||
-}
|
||||
-
|
||||
static inline void aa_permerror2result(int perm_result, struct aa_audit *sa)
|
||||
{
|
||||
if (perm_result == 0) { /* success */
|
||||
@@ -82,15 +61,7 @@ static inline void aa_permerror2result(i
|
||||
static int aa_file_denied(struct aa_profile *profile, const char *name,
|
||||
int mask)
|
||||
{
|
||||
- int perms;
|
||||
-
|
||||
- /* Always allow write access to /proc/self/attr/current. */
|
||||
- if (mask == MAY_WRITE && aa_taskattr_access(name))
|
||||
- return 0;
|
||||
-
|
||||
- perms = aa_match(profile->file_rules, name);
|
||||
-
|
||||
- return (mask & ~perms);
|
||||
+ return (mask & ~aa_match(profile->file_rules, name));
|
||||
}
|
||||
|
||||
/**
|
@@ -7,12 +7,12 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/main.c | 1321 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 1321 insertions(+)
|
||||
security/apparmor/main.c | 1340 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 1340 insertions(+)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -0,0 +1,1321 @@
|
||||
@@ -0,0 +1,1340 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2002-2007 Novell/SUSE
|
||||
+ *
|
||||
@@ -53,27 +53,6 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ */
|
||||
+struct aa_profile *null_complain_profile;
|
||||
+
|
||||
+/**
|
||||
+ * aa_taskattr_access
|
||||
+ * @name: name of the file to check
|
||||
+ *
|
||||
+ * Check if name matches /proc/self/attr/current, with self resolved
|
||||
+ * to the current pid. This file is the usermode interface for
|
||||
+ * changing one's hat.
|
||||
+ */
|
||||
+static inline int aa_taskattr_access(const char *name)
|
||||
+{
|
||||
+ unsigned long pid;
|
||||
+ char *end;
|
||||
+
|
||||
+ if (strncmp(name, "/proc/", 6) != 0)
|
||||
+ return 0;
|
||||
+ pid = simple_strtoul(name + 6, &end, 10);
|
||||
+ if (pid != current->pid)
|
||||
+ return 0;
|
||||
+ return strcmp(end, "/attr/current") == 0;
|
||||
+}
|
||||
+
|
||||
+static inline void aa_permerror2result(int perm_result, struct aa_audit *sa)
|
||||
+{
|
||||
+ if (perm_result == 0) { /* success */
|
||||
@@ -97,15 +76,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+static int aa_file_denied(struct aa_profile *profile, const char *name,
|
||||
+ int mask)
|
||||
+{
|
||||
+ int perms;
|
||||
+
|
||||
+ /* Always allow write access to /proc/self/attr/current. */
|
||||
+ if (mask == MAY_WRITE && aa_taskattr_access(name))
|
||||
+ return 0;
|
||||
+
|
||||
+ perms = aa_match(profile->file_rules, name);
|
||||
+
|
||||
+ return (mask & ~perms);
|
||||
+ return (mask & ~aa_match(profile->file_rules, name));
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
@@ -147,6 +118,51 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * mangle -- escape special characters in str
|
||||
+ * @str: string to escape
|
||||
+ * @buffer: buffer containing str
|
||||
+ *
|
||||
+ * Escape special characters in @str, which must be contained in
|
||||
+ * @buffer. The string grows towards @buffer. Returns a pointer
|
||||
+ * to the quoted string, or ERR_PTR(-ENAMETOOLONG) upon failure.
|
||||
+ */
|
||||
+static char *mangle(char *str, char *buffer)
|
||||
+{
|
||||
+ static const char c_escape[] = {
|
||||
+ ['\a'] = 'a', ['\b'] = 'b',
|
||||
+ ['\f'] = 'f', ['\n'] = 'n',
|
||||
+ ['\r'] = 'r', ['\t'] = 't',
|
||||
+ ['\v'] = 'v',
|
||||
+ [' '] = ' ', ['\\'] = '\\',
|
||||
+ };
|
||||
+ char *s, *t, c;
|
||||
+
|
||||
+#define mangle_escape(c) \
|
||||
+ unlikely((unsigned char)(c) < ARRAY_SIZE(c_escape) && \
|
||||
+ c_escape[(unsigned char)c])
|
||||
+
|
||||
+ for (s = str; (c = *s) != '\0'; s++)
|
||||
+ if (mangle_escape(c))
|
||||
+ goto escape;
|
||||
+ return str;
|
||||
+
|
||||
+escape:
|
||||
+ 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
|
||||
@@ -192,12 +208,16 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ buf[size - 1] = '\0';
|
||||
+ }
|
||||
+
|
||||
+ name = mangle(name, buf);
|
||||
+ if (!name)
|
||||
+ goto grow_buffer;
|
||||
+ *buffer = buf;
|
||||
+ return name;
|
||||
+ }
|
||||
+ if (PTR_ERR(name) != -ENAMETOOLONG)
|
||||
+ return name;
|
||||
+
|
||||
+grow_buffer:
|
||||
+ kfree(buf);
|
||||
+ size <<= 1;
|
||||
+ if (size > apparmor_path_max)
|
||||
@@ -398,8 +418,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ opspec_error = -EACCES;
|
||||
+
|
||||
+ const gfp_t gfp_mask = sa->gfp_mask;
|
||||
+
|
||||
+ WARN_ON(sa->type >= AA_AUDITTYPE__END);
|
||||
+ char comm_buffer[2 * sizeof(current->comm)], *comm;
|
||||
+
|
||||
+ /*
|
||||
+ * sa->result: 1 success, 0 failure
|
||||
@@ -475,7 +494,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+
|
||||
+ audit_log_format(ab, "%s ", logcls); /* REJECTING/ALLOWING/etc */
|
||||
+
|
||||
+ if (sa->type == AA_AUDITTYPE_FILE) {
|
||||
+ switch(sa->type) {
|
||||
+ case AA_AUDITTYPE_FILE: {
|
||||
+ int perm = audit ? sa->mask : sa->error_code;
|
||||
+
|
||||
+ audit_log_format(ab, "%s%s%s%s%s access to %s ",
|
||||
@@ -487,12 +507,13 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ sa->name);
|
||||
+
|
||||
+ opspec_error = -EPERM;
|
||||
+
|
||||
+ } else if (sa->type == AA_AUDITTYPE_DIR) {
|
||||
+ audit_log_format(ab, "%s on %s ", sa->operation, sa->name);
|
||||
+
|
||||
+ } else if (sa->type == AA_AUDITTYPE_ATTR) {
|
||||
+ struct iattr *iattr = (struct iattr*)sa->pval;
|
||||
+ 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 ",
|
||||
@@ -506,36 +527,37 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ (iattr->ia_valid & ATTR_MTIME)) ? "mtime," : "",
|
||||
+ iattr->ia_valid & ATTR_CTIME ? "ctime," : "",
|
||||
+ sa->name);
|
||||
+
|
||||
+ } else if (sa->type == AA_AUDITTYPE_XATTR) {
|
||||
+ /* FIXME: how are special characters in sa->name escaped? */
|
||||
+ /* FIXME: check if this can be handled on the stack
|
||||
+ with an inline varargs function. */
|
||||
+ audit_log_format(ab, "%s on %s ", sa->operation, sa->name);
|
||||
+
|
||||
+ } else if (sa->type == AA_AUDITTYPE_LINK) {
|
||||
+ audit_log_format(ab,
|
||||
+ "link access from %s to %s ",
|
||||
+ sa->name,
|
||||
+ (char*)sa->pval);
|
||||
+
|
||||
+ } else if (sa->type == AA_AUDITTYPE_CAP) {
|
||||
+ audit_log_format(ab,
|
||||
+ "access to capability '%s' ",
|
||||
+ 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]);
|
||||
+
|
||||
+ opspec_error = -EPERM;
|
||||
+ } else if (sa->type == AA_AUDITTYPE_SYSCALL) {
|
||||
+ break;
|
||||
+ case AA_AUDITTYPE_SYSCALL:
|
||||
+ audit_log_format(ab, "access to syscall '%s' ", sa->name);
|
||||
+
|
||||
+ opspec_error = -EPERM;
|
||||
+ } else {
|
||||
+ /* -EINVAL -- will WARN_ON above */
|
||||
+ goto out;
|
||||
+ break;
|
||||
+ default:
|
||||
+ WARN_ON(1);
|
||||
+ return error;
|
||||
+ }
|
||||
+
|
||||
+ comm = comm_buffer + sizeof(comm_buffer) - sizeof(current->comm);
|
||||
+ get_task_comm(comm, current);
|
||||
+ comm = mangle(comm, comm_buffer);
|
||||
+ if (!comm)
|
||||
+ comm = "?";
|
||||
+
|
||||
+ audit_log_format(ab, "(%s(%d) profile %s active %s)",
|
||||
+ current->comm, current->pid,
|
||||
+ comm, current->pid,
|
||||
+ profile->parent->name, profile->name);
|
||||
+
|
||||
+ audit_log_end(ab);
|
||||
@@ -544,7 +566,6 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ error = 0;
|
||||
+ else
|
||||
+ error = sa->result ? 0 : opspec_error;
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+}
|
||||
@@ -564,7 +585,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ struct aa_audit sa;
|
||||
+
|
||||
+ sa.type = AA_AUDITTYPE_ATTR;
|
||||
+ sa.pval = iattr;
|
||||
+ sa.iattr = iattr;
|
||||
+ sa.flags = 0;
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+
|
||||
@@ -585,21 +606,19 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ * @dentry: dentry of the file to check
|
||||
+ * @mnt: vfsmount of the file to check
|
||||
+ * @operation: xattr operation being done
|
||||
+ * @xattr_name: name of xattr to check
|
||||
+ * @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,
|
||||
+ const char *xattr_name, int mask, int check)
|
||||
+ int mask, int check)
|
||||
+{
|
||||
+ struct inode *inode = dentry->d_inode;
|
||||
+ int error;
|
||||
+ struct aa_audit sa;
|
||||
+
|
||||
+ sa.type = AA_AUDITTYPE_XATTR;
|
||||
+ sa.operation = operation;
|
||||
+ sa.pval = xattr_name;
|
||||
+ sa.name2 = operation;
|
||||
+ sa.flags = 0;
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+
|
||||
@@ -670,7 +689,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ struct aa_audit sa;
|
||||
+
|
||||
+ sa.type = AA_AUDITTYPE_DIR;
|
||||
+ sa.operation = operation;
|
||||
+ sa.name2 = operation;
|
||||
+ sa.flags = 0;
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+
|
||||
@@ -740,24 +759,24 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ struct dentry *link, struct vfsmount *link_mnt,
|
||||
+ struct dentry *target, struct vfsmount *target_mnt)
|
||||
+{
|
||||
+ char *name_buffer = NULL, *pval_buffer = NULL;
|
||||
+ char *name_buffer = NULL, *name2_buffer = NULL;
|
||||
+ int denied_mask = -EPERM, error;
|
||||
+ struct aa_audit sa;
|
||||
+
|
||||
+ sa.name = aa_get_name(link, link_mnt, &name_buffer, 0);
|
||||
+ sa.pval = aa_get_name(target, target_mnt, &pval_buffer, 0);
|
||||
+ sa.name2 = aa_get_name(target, target_mnt, &name2_buffer, 0);
|
||||
+
|
||||
+ if (IS_ERR(sa.name)) {
|
||||
+ denied_mask = PTR_ERR(sa.name);
|
||||
+ sa.name = NULL;
|
||||
+ }
|
||||
+ if (IS_ERR(sa.pval)) {
|
||||
+ denied_mask = PTR_ERR(sa.pval);
|
||||
+ sa.pval = NULL;
|
||||
+ if (IS_ERR(sa.name2)) {
|
||||
+ denied_mask = PTR_ERR(sa.name2);
|
||||
+ sa.name2 = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (sa.name && sa.pval)
|
||||
+ denied_mask = aa_link_denied(profile, sa.name, sa.pval);
|
||||
+ if (sa.name && sa.name2)
|
||||
+ denied_mask = aa_link_denied(profile, sa.name, sa.name2);
|
||||
+
|
||||
+ aa_permerror2result(denied_mask, &sa);
|
||||
+
|
||||
@@ -768,7 +787,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ error = aa_audit(profile, &sa);
|
||||
+
|
||||
+ aa_put_name_buffer(name_buffer);
|
||||
+ aa_put_name_buffer(pval_buffer);
|
||||
+ aa_put_name_buffer(name2_buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
|
@@ -13,13 +13,13 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
---
|
||||
security/apparmor/Kconfig | 9 +
|
||||
security/apparmor/Makefile | 13 +
|
||||
security/apparmor/apparmor.h | 282 +++++++++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/apparmor.h | 279 +++++++++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/apparmorfs.c | 248 ++++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/inline.h | 219 +++++++++++++++++++++++++++++++
|
||||
security/apparmor/inline.h | 219 ++++++++++++++++++++++++++++++++
|
||||
security/apparmor/list.c | 94 +++++++++++++
|
||||
security/apparmor/locking.txt | 59 ++++++++
|
||||
security/apparmor/procattr.c | 143 ++++++++++++++++++++
|
||||
8 files changed, 1067 insertions(+)
|
||||
security/apparmor/procattr.c | 143 +++++++++++++++++++++
|
||||
8 files changed, 1064 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,282 @@
|
||||
@@ -0,0 +1,279 @@
|
||||
+/*
|
||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||
+ *
|
||||
@@ -217,15 +217,12 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ unsigned int result;
|
||||
+ gfp_t gfp_mask;
|
||||
+ int error_code;
|
||||
+
|
||||
+ const char *operation;
|
||||
+ const char *name;
|
||||
+ union {
|
||||
+ int capability;
|
||||
+ int mask;
|
||||
+ };
|
||||
+ union {
|
||||
+ const void *pval;
|
||||
+ int capability;
|
||||
+ const char *name2;
|
||||
+ struct iattr *iattr;
|
||||
+ va_list vaval;
|
||||
+ };
|
||||
+};
|
||||
@@ -277,8 +274,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+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,
|
||||
+ const char *xattr_xattr, int mask, int check);
|
||||
+ struct vfsmount *mnt, const char *operation, 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);
|
||||
|
@@ -1,91 +0,0 @@
|
||||
---
|
||||
security/apparmor/match.c | 12 ++++++------
|
||||
security/apparmor/match.h | 2 +-
|
||||
security/apparmor/module_interface.c | 10 ++++++----
|
||||
3 files changed, 13 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/security/apparmor/match.c
|
||||
+++ b/security/apparmor/match.c
|
||||
@@ -23,9 +23,9 @@ static struct table_header *unpack_table
|
||||
if (bsize < sizeof(struct table_header))
|
||||
goto out;
|
||||
|
||||
- th.td_id = ntohs(*(u16 *) (blob));
|
||||
- th.td_flags = ntohs(*(u16 *) (blob + 2));
|
||||
- th.td_lolen = ntohl(*(u32 *) (blob + 8));
|
||||
+ th.td_id = be16_to_cpu(*(u16 *) (blob));
|
||||
+ th.td_flags = be16_to_cpu(*(u16 *) (blob + 2));
|
||||
+ th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8));
|
||||
blob += sizeof(struct table_header);
|
||||
|
||||
if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
|
||||
@@ -41,13 +41,13 @@ static struct table_header *unpack_table
|
||||
*table = th;
|
||||
if (th.td_flags == YYTD_DATA8)
|
||||
UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
|
||||
- u8, ntohb);
|
||||
+ u8, byte_to_byte);
|
||||
else if (th.td_flags == YYTD_DATA16)
|
||||
UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
|
||||
- u16, ntohs);
|
||||
+ u16, be16_to_cpu);
|
||||
else
|
||||
UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
|
||||
- u32, ntohl);
|
||||
+ u32, be32_to_cpu);
|
||||
}
|
||||
|
||||
out:
|
||||
--- a/security/apparmor/match.h
|
||||
+++ b/security/apparmor/match.h
|
||||
@@ -63,7 +63,7 @@ struct aa_dfa {
|
||||
struct table_header *tables[YYTD_ID_NXT];
|
||||
};
|
||||
|
||||
-#define ntohb(X) (X)
|
||||
+#define byte_to_byte(X) (X)
|
||||
|
||||
#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
|
||||
do { \
|
||||
--- a/security/apparmor/module_interface.c
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -60,7 +60,7 @@ struct aa_ext {
|
||||
|
||||
static inline int aa_inbounds(struct aa_ext *e, size_t size)
|
||||
{
|
||||
- return (e->pos + size <= e->end);
|
||||
+ return (size <= e->end - e->pos);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,7 +243,7 @@ struct aa_dfa *aa_unpack_dfa(struct aa_e
|
||||
* @e: serialized data extent information
|
||||
* @error: error code returned if unpacking fails
|
||||
*/
|
||||
-static struct aa_profile *aa_unpack_profile(struct aa_ext *e)
|
||||
+static struct aa_profile *aa_unpack_profile(struct aa_ext *e, int depth)
|
||||
{
|
||||
struct aa_profile *profile = NULL;
|
||||
|
||||
@@ -284,9 +284,11 @@ static struct aa_profile *aa_unpack_prof
|
||||
|
||||
/* get optional subprofiles */
|
||||
if (aa_is_nameX(e, AA_LIST, "hats")) {
|
||||
+ if (depth > 0)
|
||||
+ goto fail;
|
||||
while (!aa_is_nameX(e, AA_LISTEND, NULL)) {
|
||||
struct aa_profile *subprofile;
|
||||
- subprofile = aa_unpack_profile(e);
|
||||
+ subprofile = aa_unpack_profile(e, depth + 1);
|
||||
if (IS_ERR(subprofile)) {
|
||||
error = PTR_ERR(subprofile);
|
||||
goto fail;
|
||||
@@ -320,7 +322,7 @@ fail:
|
||||
*/
|
||||
static struct aa_profile *aa_unpack_profile_wrapper(struct aa_ext *e)
|
||||
{
|
||||
- struct aa_profile *profile = aa_unpack_profile(e);
|
||||
+ struct aa_profile *profile = aa_unpack_profile(e, 0);
|
||||
if (!IS_ERR(profile) &&
|
||||
(!list_empty(&profile->sub) || profile->flags.complain)) {
|
||||
int error;
|
@@ -10,8 +10,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
---
|
||||
security/apparmor/match.c | 232 ++++++++++++
|
||||
security/apparmor/match.h | 83 ++++
|
||||
security/apparmor/module_interface.c | 641 +++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 956 insertions(+)
|
||||
security/apparmor/module_interface.c | 643 +++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 958 insertions(+)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/match.c
|
||||
@@ -41,9 +41,9 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ if (bsize < sizeof(struct table_header))
|
||||
+ goto out;
|
||||
+
|
||||
+ th.td_id = ntohs(*(u16 *) (blob));
|
||||
+ th.td_flags = ntohs(*(u16 *) (blob + 2));
|
||||
+ th.td_lolen = ntohl(*(u32 *) (blob + 8));
|
||||
+ th.td_id = be16_to_cpu(*(u16 *) (blob));
|
||||
+ th.td_flags = be16_to_cpu(*(u16 *) (blob + 2));
|
||||
+ th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8));
|
||||
+ blob += sizeof(struct table_header);
|
||||
+
|
||||
+ if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
|
||||
@@ -59,13 +59,13 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ *table = th;
|
||||
+ if (th.td_flags == YYTD_DATA8)
|
||||
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
|
||||
+ u8, ntohb);
|
||||
+ u8, byte_to_byte);
|
||||
+ else if (th.td_flags == YYTD_DATA16)
|
||||
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
|
||||
+ u16, ntohs);
|
||||
+ u16, be16_to_cpu);
|
||||
+ else
|
||||
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
|
||||
+ u32, ntohl);
|
||||
+ u32, be32_to_cpu);
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
@@ -316,7 +316,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ struct table_header *tables[YYTD_ID_NXT];
|
||||
+};
|
||||
+
|
||||
+#define ntohb(X) (X)
|
||||
+#define byte_to_byte(X) (X)
|
||||
+
|
||||
+#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
|
||||
+ do { \
|
||||
@@ -336,7 +336,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+#endif /* __MATCH_H */
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -0,0 +1,641 @@
|
||||
@@ -0,0 +1,643 @@
|
||||
+/*
|
||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||
+ *
|
||||
@@ -399,7 +399,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+
|
||||
+static inline int aa_inbounds(struct aa_ext *e, size_t size)
|
||||
+{
|
||||
+ return (e->pos + size <= e->end);
|
||||
+ return (size <= e->end - e->pos);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
@@ -582,7 +582,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ * @e: serialized data extent information
|
||||
+ * @error: error code returned if unpacking fails
|
||||
+ */
|
||||
+static struct aa_profile *aa_unpack_profile(struct aa_ext *e)
|
||||
+static struct aa_profile *aa_unpack_profile(struct aa_ext *e, int depth)
|
||||
+{
|
||||
+ struct aa_profile *profile = NULL;
|
||||
+
|
||||
@@ -623,9 +623,11 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+
|
||||
+ /* get optional subprofiles */
|
||||
+ if (aa_is_nameX(e, AA_LIST, "hats")) {
|
||||
+ if (depth > 0)
|
||||
+ goto fail;
|
||||
+ while (!aa_is_nameX(e, AA_LISTEND, NULL)) {
|
||||
+ struct aa_profile *subprofile;
|
||||
+ subprofile = aa_unpack_profile(e);
|
||||
+ subprofile = aa_unpack_profile(e, depth + 1);
|
||||
+ if (IS_ERR(subprofile)) {
|
||||
+ error = PTR_ERR(subprofile);
|
||||
+ goto fail;
|
||||
@@ -659,7 +661,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
+ */
|
||||
+static struct aa_profile *aa_unpack_profile_wrapper(struct aa_ext *e)
|
||||
+{
|
||||
+ struct aa_profile *profile = aa_unpack_profile(e);
|
||||
+ struct aa_profile *profile = aa_unpack_profile(e, 0);
|
||||
+ if (!IS_ERR(profile) &&
|
||||
+ (!list_empty(&profile->sub) || profile->flags.complain)) {
|
||||
+ int error;
|
||||
|
@@ -1,41 +0,0 @@
|
||||
---
|
||||
security/apparmor/lsm.c | 19 ++++++++++++++-----
|
||||
1 file changed, 14 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -114,20 +114,29 @@ static int apparmor_ptrace(struct task_s
|
||||
/**
|
||||
* parent can ptrace child when
|
||||
* - parent is unconfined
|
||||
- * - parent is in complain mode
|
||||
- * - parent and child are confined by the same profile
|
||||
+ * - parent & child are in the same namespace &&
|
||||
+ * - parent is in complain mode
|
||||
+ * - parent and child are confined by the same profile
|
||||
+ * - parent profile has CAP_SYS_PTRACE
|
||||
*/
|
||||
|
||||
rcu_read_lock();
|
||||
cxt = aa_task_context(parent);
|
||||
child_cxt = aa_task_context(child);
|
||||
child_profile = child_cxt ? child_cxt->profile : NULL;
|
||||
- error = aa_may_ptrace(cxt, child_profile);
|
||||
- if (cxt && PROFILE_COMPLAIN(cxt->profile)) {
|
||||
- LOG_HINT(cxt->profile, GFP_ATOMIC, HINT_PTRACE,
|
||||
+ if (cxt && (parent->nsproxy != child->nsproxy)) {
|
||||
+ AA_WARN(GFP_ATOMIC,
|
||||
+ "REJECTING ptrace across namespace of %d by %d",
|
||||
+ parent->pid, child->pid);
|
||||
+ error = -EPERM;
|
||||
+ } else {
|
||||
+ error = aa_may_ptrace(cxt, child_profile);
|
||||
+ if (cxt && PROFILE_COMPLAIN(cxt->profile)) {
|
||||
+ LOG_HINT(cxt->profile, GFP_ATOMIC, HINT_PTRACE,
|
||||
"pid=%d child=%d\n",
|
||||
current->pid, child->pid);
|
||||
}
|
||||
+ }
|
||||
rcu_read_unlock();
|
||||
|
||||
return error;
|
@@ -1,291 +0,0 @@
|
||||
The whole way how audit messages are generated is crap, but it's a bad
|
||||
time to fix it right now. Anyway, here are some minor changes that make
|
||||
it slightly less ugly:
|
||||
|
||||
- the xattr name is not use din aa_audit, so don't pass it through.
|
||||
- convert the huge if in aa_audit into a case statement.
|
||||
- get rid of the pval, and put the particular fields into the union
|
||||
instead.
|
||||
- use name2 for the operation.
|
||||
- put some more fields never used together in the union as well.
|
||||
|
||||
---
|
||||
security/apparmor/apparmor.h | 13 ++----
|
||||
security/apparmor/lsm.c | 21 ++++------
|
||||
security/apparmor/main.c | 84 +++++++++++++++++++------------------------
|
||||
3 files changed, 52 insertions(+), 66 deletions(-)
|
||||
|
||||
--- a/security/apparmor/apparmor.h
|
||||
+++ b/security/apparmor/apparmor.h
|
||||
@@ -163,15 +163,12 @@ struct aa_audit {
|
||||
unsigned int result;
|
||||
gfp_t gfp_mask;
|
||||
int error_code;
|
||||
-
|
||||
- const char *operation;
|
||||
const char *name;
|
||||
union {
|
||||
- int capability;
|
||||
int mask;
|
||||
- };
|
||||
- union {
|
||||
- const void *pval;
|
||||
+ int capability;
|
||||
+ const char *name2;
|
||||
+ struct iattr *iattr;
|
||||
va_list vaval;
|
||||
};
|
||||
};
|
||||
@@ -223,8 +220,8 @@ extern int aa_audit(struct aa_profile *p
|
||||
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,
|
||||
- const char *xattr_xattr, int mask, int check);
|
||||
+ struct vfsmount *mnt, const char *operation, 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);
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -393,8 +393,8 @@ out:
|
||||
}
|
||||
|
||||
static int aa_xattr_permission(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name, const char *operation,
|
||||
- int mask, struct file *file)
|
||||
+ const char *operation, int mask,
|
||||
+ struct file *file)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
@@ -403,8 +403,8 @@ static int aa_xattr_permission(struct de
|
||||
int check = file ? AA_CHECK_FD : 0;
|
||||
|
||||
if (profile)
|
||||
- error = aa_perm_xattr(profile, dentry, mnt, name,
|
||||
- operation, mask, check);
|
||||
+ error = aa_perm_xattr(profile, dentry, mnt, operation,
|
||||
+ mask, check);
|
||||
aa_put_profile(profile);
|
||||
}
|
||||
|
||||
@@ -415,30 +415,27 @@ static int apparmor_inode_setxattr(struc
|
||||
char *name, void *value, size_t size,
|
||||
int flags, struct file *file)
|
||||
{
|
||||
- return aa_xattr_permission(dentry, mnt, name, "xattr set", MAY_WRITE,
|
||||
- file);
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr set", MAY_WRITE, file);
|
||||
}
|
||||
|
||||
static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
char *name, struct file *file)
|
||||
{
|
||||
- return aa_xattr_permission(dentry, mnt, name, "xattr get", MAY_READ,
|
||||
- file);
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr get", MAY_READ, file);
|
||||
}
|
||||
|
||||
static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
struct file *file)
|
||||
{
|
||||
- return aa_xattr_permission(dentry, mnt, NULL, "xattr list", MAY_READ,
|
||||
- file);
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr list", MAY_READ, file);
|
||||
}
|
||||
|
||||
static int apparmor_inode_removexattr(struct dentry *dentry,
|
||||
struct vfsmount *mnt, char *name,
|
||||
struct file *file)
|
||||
{
|
||||
- return aa_xattr_permission(dentry, mnt, name, "xattr remove",
|
||||
- MAY_WRITE, file);
|
||||
+ return aa_xattr_permission(dentry, mnt, "xattr remove", MAY_WRITE,
|
||||
+ file);
|
||||
}
|
||||
|
||||
static int apparmor_file_permission(struct file *file, int mask)
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -404,8 +404,6 @@ int aa_audit(struct aa_profile *profile,
|
||||
|
||||
const gfp_t gfp_mask = sa->gfp_mask;
|
||||
|
||||
- WARN_ON(sa->type >= AA_AUDITTYPE__END);
|
||||
-
|
||||
/*
|
||||
* sa->result: 1 success, 0 failure
|
||||
* sa->error_code: success: 0
|
||||
@@ -480,7 +478,8 @@ int aa_audit(struct aa_profile *profile,
|
||||
|
||||
audit_log_format(ab, "%s ", logcls); /* REJECTING/ALLOWING/etc */
|
||||
|
||||
- if (sa->type == AA_AUDITTYPE_FILE) {
|
||||
+ switch(sa->type) {
|
||||
+ case AA_AUDITTYPE_FILE: {
|
||||
int perm = audit ? sa->mask : sa->error_code;
|
||||
|
||||
audit_log_format(ab, "%s%s%s%s%s access to %s ",
|
||||
@@ -492,12 +491,13 @@ int aa_audit(struct aa_profile *profile,
|
||||
sa->name);
|
||||
|
||||
opspec_error = -EPERM;
|
||||
-
|
||||
- } else if (sa->type == AA_AUDITTYPE_DIR) {
|
||||
- audit_log_format(ab, "%s on %s ", sa->operation, sa->name);
|
||||
-
|
||||
- } else if (sa->type == AA_AUDITTYPE_ATTR) {
|
||||
- struct iattr *iattr = (struct iattr*)sa->pval;
|
||||
+ 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 ",
|
||||
@@ -511,32 +511,27 @@ int aa_audit(struct aa_profile *profile,
|
||||
(iattr->ia_valid & ATTR_MTIME)) ? "mtime," : "",
|
||||
iattr->ia_valid & ATTR_CTIME ? "ctime," : "",
|
||||
sa->name);
|
||||
-
|
||||
- } else if (sa->type == AA_AUDITTYPE_XATTR) {
|
||||
- /* FIXME: how are special characters in sa->name escaped? */
|
||||
- /* FIXME: check if this can be handled on the stack
|
||||
- with an inline varargs function. */
|
||||
- audit_log_format(ab, "%s on %s ", sa->operation, sa->name);
|
||||
-
|
||||
- } else if (sa->type == AA_AUDITTYPE_LINK) {
|
||||
- audit_log_format(ab,
|
||||
- "link access from %s to %s ",
|
||||
- sa->name,
|
||||
- (char*)sa->pval);
|
||||
-
|
||||
- } else if (sa->type == AA_AUDITTYPE_CAP) {
|
||||
- audit_log_format(ab,
|
||||
- "access to capability '%s' ",
|
||||
+ 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]);
|
||||
-
|
||||
opspec_error = -EPERM;
|
||||
- } else if (sa->type == AA_AUDITTYPE_SYSCALL) {
|
||||
+ break;
|
||||
+ case AA_AUDITTYPE_SYSCALL:
|
||||
audit_log_format(ab, "access to syscall '%s' ", sa->name);
|
||||
-
|
||||
opspec_error = -EPERM;
|
||||
- } else {
|
||||
- /* -EINVAL -- will WARN_ON above */
|
||||
- goto out;
|
||||
+ break;
|
||||
+ default:
|
||||
+ WARN_ON(1);
|
||||
+ return error;
|
||||
}
|
||||
|
||||
audit_log_format(ab, "(%s(%d) profile %s active %s)",
|
||||
@@ -549,7 +544,6 @@ int aa_audit(struct aa_profile *profile,
|
||||
error = 0;
|
||||
else
|
||||
error = sa->result ? 0 : opspec_error;
|
||||
-
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
@@ -569,7 +563,7 @@ int aa_attr(struct aa_profile *profile,
|
||||
struct aa_audit sa;
|
||||
|
||||
sa.type = AA_AUDITTYPE_ATTR;
|
||||
- sa.pval = iattr;
|
||||
+ sa.iattr = iattr;
|
||||
sa.flags = 0;
|
||||
sa.gfp_mask = GFP_KERNEL;
|
||||
|
||||
@@ -590,21 +584,19 @@ int aa_attr(struct aa_profile *profile,
|
||||
* @dentry: dentry of the file to check
|
||||
* @mnt: vfsmount of the file to check
|
||||
* @operation: xattr operation being done
|
||||
- * @xattr_name: name of xattr to check
|
||||
* @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,
|
||||
- const char *xattr_name, int mask, int check)
|
||||
+ int mask, int check)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
struct aa_audit sa;
|
||||
|
||||
sa.type = AA_AUDITTYPE_XATTR;
|
||||
- sa.operation = operation;
|
||||
- sa.pval = xattr_name;
|
||||
+ sa.name2 = operation;
|
||||
sa.flags = 0;
|
||||
sa.gfp_mask = GFP_KERNEL;
|
||||
|
||||
@@ -675,7 +667,7 @@ int aa_perm_dir(struct aa_profile *profi
|
||||
struct aa_audit sa;
|
||||
|
||||
sa.type = AA_AUDITTYPE_DIR;
|
||||
- sa.operation = operation;
|
||||
+ sa.name2 = operation;
|
||||
sa.flags = 0;
|
||||
sa.gfp_mask = GFP_KERNEL;
|
||||
|
||||
@@ -745,24 +737,24 @@ int aa_link(struct aa_profile *profile,
|
||||
struct dentry *link, struct vfsmount *link_mnt,
|
||||
struct dentry *target, struct vfsmount *target_mnt)
|
||||
{
|
||||
- char *name_buffer = NULL, *pval_buffer = NULL;
|
||||
+ char *name_buffer = NULL, *name2_buffer = NULL;
|
||||
int denied_mask = -EPERM, error;
|
||||
struct aa_audit sa;
|
||||
|
||||
sa.name = aa_get_name(link, link_mnt, &name_buffer, 0);
|
||||
- sa.pval = aa_get_name(target, target_mnt, &pval_buffer, 0);
|
||||
+ sa.name2 = aa_get_name(target, target_mnt, &name2_buffer, 0);
|
||||
|
||||
if (IS_ERR(sa.name)) {
|
||||
denied_mask = PTR_ERR(sa.name);
|
||||
sa.name = NULL;
|
||||
}
|
||||
- if (IS_ERR(sa.pval)) {
|
||||
- denied_mask = PTR_ERR(sa.pval);
|
||||
- sa.pval = NULL;
|
||||
+ if (IS_ERR(sa.name2)) {
|
||||
+ denied_mask = PTR_ERR(sa.name2);
|
||||
+ sa.name2 = NULL;
|
||||
}
|
||||
|
||||
- if (sa.name && sa.pval)
|
||||
- denied_mask = aa_link_denied(profile, sa.name, sa.pval);
|
||||
+ if (sa.name && sa.name2)
|
||||
+ denied_mask = aa_link_denied(profile, sa.name, sa.name2);
|
||||
|
||||
aa_permerror2result(denied_mask, &sa);
|
||||
|
||||
@@ -773,7 +765,7 @@ int aa_link(struct aa_profile *profile,
|
||||
error = aa_audit(profile, &sa);
|
||||
|
||||
aa_put_name_buffer(name_buffer);
|
||||
- aa_put_name_buffer(pval_buffer);
|
||||
+ aa_put_name_buffer(name2_buffer);
|
||||
|
||||
return error;
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
Two bugs:
|
||||
|
||||
- task->comm should be accessed via get_task_comm().
|
||||
- comm is user modifiable via prtcl(PR_SET_NAME), so users may inject
|
||||
special characters. We need to quote.
|
||||
|
||||
What for does user-space use the task names in the log? I hope for
|
||||
nothing...
|
||||
|
||||
---
|
||||
security/apparmor/main.c | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -403,6 +403,7 @@ int aa_audit(struct aa_profile *profile,
|
||||
opspec_error = -EACCES;
|
||||
|
||||
const gfp_t gfp_mask = sa->gfp_mask;
|
||||
+ char comm_buffer[2 * sizeof(current->comm)], *comm;
|
||||
|
||||
/*
|
||||
* sa->result: 1 success, 0 failure
|
||||
@@ -534,8 +535,14 @@ int aa_audit(struct aa_profile *profile,
|
||||
return error;
|
||||
}
|
||||
|
||||
+ comm = comm_buffer + sizeof(comm_buffer) - sizeof(current->comm);
|
||||
+ get_task_comm(comm, current);
|
||||
+ comm = mangle(comm, comm_buffer);
|
||||
+ if (!comm)
|
||||
+ comm = "?";
|
||||
+
|
||||
audit_log_format(ab, "(%s(%d) profile %s active %s)",
|
||||
- current->comm, current->pid,
|
||||
+ comm, current->pid,
|
||||
profile->parent->name, profile->name);
|
||||
|
||||
audit_log_end(ab);
|
||||
--- a/fs/exec.c
|
||||
+++ b/fs/exec.c
|
||||
@@ -806,6 +806,7 @@ void get_task_comm(char *buf, struct tas
|
||||
strncpy(buf, tsk->comm, sizeof(tsk->comm));
|
||||
task_unlock(tsk);
|
||||
}
|
||||
+EXPORT_SYMBOL(get_task_comm);
|
||||
|
||||
void set_task_comm(struct task_struct *tsk, char *buf)
|
||||
{
|
@@ -1,459 +0,0 @@
|
||||
Index: b/security/apparmor/apparmor.h
|
||||
===================================================================
|
||||
--- a/security/apparmor/apparmor.h
|
||||
+++ b/security/apparmor/apparmor.h
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
/* Control parameters (0 or 1), settable thru module/boot flags or
|
||||
* via /sys/kernel/security/apparmor/control */
|
||||
-extern int apparmor_complain;
|
||||
+extern int apparmor_learning;
|
||||
extern int apparmor_debug;
|
||||
extern int apparmor_audit;
|
||||
extern int apparmor_logsyscall;
|
||||
@@ -48,12 +48,12 @@ static inline int mediated_filesystem(st
|
||||
return !(inode->i_sb->s_flags & MS_NOUSER);
|
||||
}
|
||||
|
||||
-#define PROFILE_COMPLAIN(_profile) \
|
||||
- (apparmor_complain == 1 || ((_profile) && (_profile)->flags.complain))
|
||||
+#define PROFILE_LEARNING(_profile) \
|
||||
+ (apparmor_learning == 1 || ((_profile) && (_profile)->flags.learning))
|
||||
|
||||
-#define APPARMOR_COMPLAIN(_cxt) \
|
||||
- (apparmor_complain == 1 || \
|
||||
- ((_cxt) && (_cxt)->profile && (_cxt)->profile->flags.complain))
|
||||
+#define APPARMOR_LEARNING(_cxt) \
|
||||
+ (apparmor_learning == 1 || \
|
||||
+ ((_cxt) && (_cxt)->profile && (_cxt)->profile->flags.learning))
|
||||
|
||||
#define PROFILE_AUDIT(_profile) \
|
||||
(apparmor_audit == 1 || ((_profile) && (_profile)->flags.audit))
|
||||
@@ -116,7 +116,7 @@ struct aa_profile {
|
||||
struct list_head list;
|
||||
struct list_head sub;
|
||||
struct {
|
||||
- int complain;
|
||||
+ int learning;
|
||||
int audit;
|
||||
} flags;
|
||||
struct aa_profile *null_profile;
|
||||
@@ -158,7 +158,7 @@ static inline struct aa_task_context *aa
|
||||
return rcu_dereference((struct aa_task_context *)task->security);
|
||||
}
|
||||
|
||||
-extern struct aa_profile *null_complain_profile;
|
||||
+extern struct aa_profile *null_learning_profile;
|
||||
|
||||
/* aa_audit - AppArmor auditing structure
|
||||
* Structure is populated by access control code and passed to aa_audit which
|
||||
@@ -217,8 +217,8 @@ struct aa_audit {
|
||||
|
||||
/* main.c */
|
||||
extern void free_aa_task_context_rcu_callback(struct rcu_head *head);
|
||||
-extern int alloc_null_complain_profile(void);
|
||||
-extern void free_null_complain_profile(void);
|
||||
+extern int alloc_null_learning_profile(void);
|
||||
+extern void free_null_learning_profile(void);
|
||||
extern int attach_nullprofile(struct aa_profile *profile);
|
||||
extern int aa_audit_message(struct aa_profile *profile, gfp_t gfp, int,
|
||||
const char *, ...);
|
||||
Index: b/security/apparmor/apparmorfs.c
|
||||
===================================================================
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -106,8 +106,8 @@ static struct root_entry {
|
||||
|
||||
/* interface for setting binary config values */
|
||||
{"control", S_IFDIR, 0550},
|
||||
- {"complain", S_IFREG, 0640, &apparmorfs_control_fops,
|
||||
- &apparmor_complain},
|
||||
+ {"learning", S_IFREG, 0640, &apparmorfs_control_fops,
|
||||
+ &apparmor_learning},
|
||||
{"audit", S_IFREG, 0640, &apparmorfs_control_fops,
|
||||
&apparmor_audit},
|
||||
{"debug", S_IFREG, 0640, &apparmorfs_control_fops,
|
||||
Index: b/security/apparmor/list.c
|
||||
===================================================================
|
||||
--- a/security/apparmor/list.c
|
||||
+++ b/security/apparmor/list.c
|
||||
@@ -84,7 +84,7 @@ static int seq_show_profile(struct seq_f
|
||||
{
|
||||
struct aa_profile *profile = (struct aa_profile *)v;
|
||||
seq_printf(f, "%s (%s)\n", profile->name,
|
||||
- PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
|
||||
+ PROFILE_LEARNING(profile) ? "learning" : "enforce");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Index: b/security/apparmor/lsm.c
|
||||
===================================================================
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -26,15 +26,15 @@
|
||||
* /sys/modules/parameters, as we want to do additional mediation and
|
||||
* don't want to add special path code. */
|
||||
|
||||
-/* Complain mode -- in complain mode access failures result in auditing only
|
||||
+/* Learning mode -- in learning mode access failures result in auditing only
|
||||
* and task is allowed access. audit events are processed by userspace to
|
||||
* generate policy. Default is 'enforce' (0).
|
||||
* Value is also togglable per profile and referenced when global value is
|
||||
* enforce.
|
||||
*/
|
||||
-int apparmor_complain = 0;
|
||||
-module_param_named(complain, apparmor_complain, int, S_IRUSR);
|
||||
-MODULE_PARM_DESC(apparmor_complain, "Toggle AppArmor complain mode");
|
||||
+int apparmor_learning = 0;
|
||||
+module_param_named(learning, apparmor_learning, int, S_IRUSR);
|
||||
+MODULE_PARM_DESC(apparmor_learning, "Toggle AppArmor learning mode");
|
||||
|
||||
/* Debug mode */
|
||||
int apparmor_debug = 0;
|
||||
@@ -767,15 +767,15 @@ struct security_operations apparmor_ops
|
||||
static int __init apparmor_init(void)
|
||||
{
|
||||
int error;
|
||||
- const char *complainmsg = ": complainmode enabled";
|
||||
+ const char *learningmsg = ": learningmode enabled";
|
||||
|
||||
if ((error = create_apparmorfs())) {
|
||||
AA_ERROR("Unable to activate AppArmor filesystem\n");
|
||||
goto createfs_out;
|
||||
}
|
||||
|
||||
- if ((error = alloc_null_complain_profile())){
|
||||
- AA_ERROR("Unable to allocate null complain profile\n");
|
||||
+ if ((error = alloc_null_learning_profile())){
|
||||
+ AA_ERROR("Unable to allocate null learning profile\n");
|
||||
goto alloc_out;
|
||||
}
|
||||
|
||||
@@ -785,15 +785,15 @@ static int __init apparmor_init(void)
|
||||
}
|
||||
|
||||
AA_INFO(GFP_KERNEL, "AppArmor initialized%s\n",
|
||||
- apparmor_complain ? complainmsg : "");
|
||||
+ apparmor_learning ? learningmsg : "");
|
||||
aa_audit_message(NULL, GFP_KERNEL, 0,
|
||||
"AppArmor initialized%s\n",
|
||||
- apparmor_complain ? complainmsg : "");
|
||||
+ apparmor_learning ? learningmsg : "");
|
||||
|
||||
return error;
|
||||
|
||||
register_security_out:
|
||||
- free_null_complain_profile();
|
||||
+ free_null_learning_profile();
|
||||
|
||||
alloc_out:
|
||||
(void)destroy_apparmorfs();
|
||||
@@ -825,7 +825,7 @@ static void __exit apparmor_exit(void)
|
||||
|
||||
/* FIXME: cleanup profiles references on files */
|
||||
|
||||
- free_null_complain_profile();
|
||||
+ free_null_learning_profile();
|
||||
|
||||
/**
|
||||
* Delay for an rcu cycle to make sure that all active task
|
||||
Index: b/security/apparmor/main.c
|
||||
===================================================================
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -25,17 +25,17 @@ static const char *capability_names[] =
|
||||
#include "capability_names.h"
|
||||
};
|
||||
|
||||
-/* NULL complain profile
|
||||
+/* NULL learning profile
|
||||
*
|
||||
- * Used when in complain mode, to emit Permitting messages for non-existant
|
||||
+ * Used when in learning mode, to emit Permitting messages for non-existant
|
||||
* profiles and hats. This is necessary because of selective mode, in which
|
||||
- * case we need a complain null_profile and enforce null_profile
|
||||
+ * case we need a learning null_profile and enforce null_profile
|
||||
*
|
||||
- * The null_complain_profile cannot be statically allocated, because it
|
||||
+ * The null_learning_profile cannot be statically allocated, because it
|
||||
* can be associated to files which keep their reference even if apparmor is
|
||||
* unloaded
|
||||
*/
|
||||
-struct aa_profile *null_complain_profile;
|
||||
+struct aa_profile *null_learning_profile;
|
||||
|
||||
/***************************
|
||||
* Private utility functions
|
||||
@@ -237,14 +237,14 @@ int attach_nullprofile(struct aa_profile
|
||||
hat = alloc_aa_profile();
|
||||
if (!hat)
|
||||
goto fail;
|
||||
- if (profile->flags.complain)
|
||||
- hatname = kstrdup("null-complain-profile", GFP_KERNEL);
|
||||
+ if (profile->flags.learning)
|
||||
+ hatname = kstrdup("null-learning-profile", GFP_KERNEL);
|
||||
else
|
||||
hatname = kstrdup("null-profile", GFP_KERNEL);
|
||||
if (!hatname)
|
||||
goto fail;
|
||||
|
||||
- hat->flags.complain = profile->flags.complain;
|
||||
+ hat->flags.learning = profile->flags.learning;
|
||||
hat->name = hatname;
|
||||
hat->parent = profile;
|
||||
|
||||
@@ -261,43 +261,43 @@ fail:
|
||||
|
||||
|
||||
/**
|
||||
- * alloc_null_complain_profile - Allocate the global null_complain_profile.
|
||||
+ * alloc_null_learning_profile - Allocate the global null_learning_profile.
|
||||
*
|
||||
* Return %0 (success) or error (-%ENOMEM)
|
||||
*/
|
||||
-int alloc_null_complain_profile(void)
|
||||
+int alloc_null_learning_profile(void)
|
||||
{
|
||||
- null_complain_profile = alloc_aa_profile();
|
||||
- if (!null_complain_profile)
|
||||
+ null_learning_profile = alloc_aa_profile();
|
||||
+ if (!null_learning_profile)
|
||||
goto fail;
|
||||
|
||||
- null_complain_profile->name =
|
||||
- kstrdup("null-complain-profile", GFP_KERNEL);
|
||||
+ null_learning_profile->name =
|
||||
+ kstrdup("null-learning-profile", GFP_KERNEL);
|
||||
|
||||
- if (!null_complain_profile->name)
|
||||
+ if (!null_learning_profile->name)
|
||||
goto fail;
|
||||
|
||||
- null_complain_profile->flags.complain = 1;
|
||||
- if (attach_nullprofile(null_complain_profile))
|
||||
+ null_learning_profile->flags.learning = 1;
|
||||
+ if (attach_nullprofile(null_learning_profile))
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
/* free_aa_profile is safe for freeing partially constructed objects */
|
||||
- free_aa_profile(null_complain_profile);
|
||||
- null_complain_profile = NULL;
|
||||
+ free_aa_profile(null_learning_profile);
|
||||
+ null_learning_profile = NULL;
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
- * free_null_complain_profile - Free null profiles
|
||||
+ * free_null_learning_profile - Free null profiles
|
||||
*/
|
||||
-void free_null_complain_profile(void)
|
||||
+void free_null_learning_profile(void)
|
||||
{
|
||||
- aa_put_profile(null_complain_profile);
|
||||
- null_complain_profile = NULL;
|
||||
+ aa_put_profile(null_learning_profile);
|
||||
+ null_learning_profile = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,7 +362,7 @@ int aa_audit(struct aa_profile *profile,
|
||||
const char *logcls;
|
||||
unsigned int flags;
|
||||
int audit = 0,
|
||||
- complain = 0,
|
||||
+ learning = 0,
|
||||
error = -EINVAL,
|
||||
opspec_error = -EACCES;
|
||||
|
||||
@@ -400,8 +400,8 @@ int aa_audit(struct aa_profile *profile,
|
||||
*/
|
||||
logcls = "REJECTING";
|
||||
} else {
|
||||
- complain = PROFILE_COMPLAIN(profile);
|
||||
- logcls = complain ? "PERMITTING" : "REJECTING";
|
||||
+ learning = PROFILE_LEARNING(profile);
|
||||
+ logcls = learning ? "PERMITTING" : "REJECTING";
|
||||
}
|
||||
|
||||
/* In future extend w/ per-profile flags
|
||||
@@ -427,7 +427,7 @@ int aa_audit(struct aa_profile *profile,
|
||||
if (!ab) {
|
||||
AA_ERROR("Unable to log event (%d) to audit subsys\n",
|
||||
sa->type);
|
||||
- if (complain)
|
||||
+ if (learning)
|
||||
error = 0;
|
||||
goto out;
|
||||
}
|
||||
@@ -509,7 +509,7 @@ int aa_audit(struct aa_profile *profile,
|
||||
|
||||
audit_log_end(ab);
|
||||
|
||||
- if (complain)
|
||||
+ if (learning)
|
||||
error = 0;
|
||||
else
|
||||
error = sa->result ? 0 : opspec_error;
|
||||
@@ -664,7 +664,7 @@ int aa_capability(struct aa_task_context
|
||||
|
||||
/* test if cap has alread been logged */
|
||||
if (cap_raised(cxt->caps_logged, cap)) {
|
||||
- if (PROFILE_COMPLAIN(cxt->profile))
|
||||
+ if (PROFILE_LEARNING(cxt->profile))
|
||||
error = 0;
|
||||
return error;
|
||||
} else
|
||||
@@ -773,8 +773,8 @@ repeat:
|
||||
cxt->hat_magic);
|
||||
unlock_profile(profile);
|
||||
|
||||
- if (APPARMOR_COMPLAIN(child_cxt) &&
|
||||
- profile == null_complain_profile) {
|
||||
+ if (APPARMOR_LEARNING(child_cxt) &&
|
||||
+ profile == null_learning_profile) {
|
||||
LOG_HINT(profile, GFP_KERNEL, HINT_FORK,
|
||||
"pid=%d child=%d\n",
|
||||
current->pid, child->pid);
|
||||
@@ -788,7 +788,7 @@ repeat:
|
||||
|
||||
static struct aa_profile *
|
||||
aa_register_find(struct aa_profile *profile, const char *name, int mandatory,
|
||||
- int complain)
|
||||
+ int learning)
|
||||
{
|
||||
struct aa_profile *new_profile;
|
||||
|
||||
@@ -798,14 +798,14 @@ aa_register_find(struct aa_profile *prof
|
||||
AA_DEBUG("%s: setting profile %s\n",
|
||||
__FUNCTION__, new_profile->name);
|
||||
} else if (mandatory && profile) {
|
||||
- if (complain) {
|
||||
+ if (learning) {
|
||||
LOG_HINT(profile, GFP_KERNEL, HINT_MANDPROF,
|
||||
"image=%s pid=%d profile=%s active=%s\n",
|
||||
name,
|
||||
current->pid,
|
||||
profile->parent->name, profile->name);
|
||||
|
||||
- profile = aa_dup_profile(null_complain_profile);
|
||||
+ profile = aa_dup_profile(null_learning_profile);
|
||||
} else {
|
||||
AA_WARN(GFP_KERNEL, "REJECTING exec(2) of image '%s'. "
|
||||
"Profile mandatory and not found "
|
||||
@@ -838,7 +838,7 @@ int aa_register(struct linux_binprm *bpr
|
||||
char *filename, *buffer = NULL;
|
||||
struct file *filp = bprm->file;
|
||||
struct aa_profile *profile, *old_profile, *new_profile = NULL;
|
||||
- int exec_mode = AA_EXEC_UNSAFE, complain = 0;
|
||||
+ int exec_mode = AA_EXEC_UNSAFE, learning = 0;
|
||||
|
||||
AA_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
@@ -852,7 +852,7 @@ int aa_register(struct linux_binprm *bpr
|
||||
repeat:
|
||||
profile = aa_get_profile(current);
|
||||
if (profile) {
|
||||
- complain = PROFILE_COMPLAIN(profile);
|
||||
+ learning = PROFILE_LEARNING(profile);
|
||||
|
||||
/* Confined task, determine what mode inherit, unconfined or
|
||||
* mandatory to load new profile
|
||||
@@ -883,7 +883,7 @@ repeat:
|
||||
filename);
|
||||
new_profile = aa_register_find(profile,
|
||||
filename, 1,
|
||||
- complain);
|
||||
+ learning);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -900,12 +900,12 @@ repeat:
|
||||
break;
|
||||
}
|
||||
|
||||
- } else if (complain) {
|
||||
+ } else if (learning) {
|
||||
/* There was no entry in calling profile
|
||||
* describing mode to execute image in.
|
||||
* Drop into null-profile (disabling secure exec).
|
||||
*/
|
||||
- new_profile = aa_dup_profile(null_complain_profile);
|
||||
+ new_profile = aa_dup_profile(null_learning_profile);
|
||||
exec_mode |= AA_EXEC_UNSAFE;
|
||||
} else {
|
||||
AA_WARN(GFP_KERNEL,
|
||||
@@ -957,7 +957,7 @@ repeat:
|
||||
((unsigned long)bprm->security | bprm_flags);
|
||||
}
|
||||
|
||||
- if (complain && new_profile == null_complain_profile) {
|
||||
+ if (learning && new_profile == null_learning_profile) {
|
||||
LOG_HINT(new_profile, GFP_ATOMIC, HINT_CHGPROF,
|
||||
"pid=%d\n",
|
||||
current->pid);
|
||||
@@ -1044,7 +1044,7 @@ static inline int do_change_hat(const ch
|
||||
} else {
|
||||
struct aa_profile *profile = cxt->profile;
|
||||
|
||||
- if (APPARMOR_COMPLAIN(cxt)) {
|
||||
+ if (APPARMOR_LEARNING(cxt)) {
|
||||
LOG_HINT(profile, GFP_ATOMIC, HINT_UNKNOWN_HAT,
|
||||
"%s pid=%d "
|
||||
"profile=%s active=%s\n",
|
||||
@@ -1116,7 +1116,7 @@ int aa_change_hat(const char *hat_name,
|
||||
profile = cxt->profile;
|
||||
|
||||
/* check to see if the confined process has any hats. */
|
||||
- if (list_empty(&profile->parent->sub) && !PROFILE_COMPLAIN(profile)) {
|
||||
+ if (list_empty(&profile->parent->sub) && !PROFILE_LEARNING(profile)) {
|
||||
error = -ECHILD;
|
||||
goto out;
|
||||
}
|
||||
Index: b/security/apparmor/module_interface.c
|
||||
===================================================================
|
||||
--- a/security/apparmor/module_interface.c
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -245,12 +245,12 @@ static struct aa_profile *aa_unpack_prof
|
||||
if (!aa_is_dynstring(e, &profile->name, NULL))
|
||||
goto fail;
|
||||
|
||||
- /* per profile debug flags (complain, audit) */
|
||||
+ /* per profile debug flags (learning, audit) */
|
||||
if (!aa_is_nameX(e, AA_STRUCT, "flags"))
|
||||
goto fail;
|
||||
if (!aa_is_u32(e, NULL, NULL))
|
||||
goto fail;
|
||||
- if (!aa_is_u32(e, &(profile->flags.complain), NULL))
|
||||
+ if (!aa_is_u32(e, &(profile->flags.learning), NULL))
|
||||
goto fail;
|
||||
if (!aa_is_u32(e, &(profile->flags.audit), NULL))
|
||||
goto fail;
|
||||
@@ -308,7 +308,7 @@ static struct aa_profile *aa_unpack_prof
|
||||
{
|
||||
struct aa_profile *profile = aa_unpack_profile(e);
|
||||
if (!IS_ERR(profile) &&
|
||||
- (!list_empty(&profile->sub) || profile->flags.complain)) {
|
||||
+ (!list_empty(&profile->sub) || profile->flags.learning)) {
|
||||
int error;
|
||||
if ((error = attach_nullprofile(profile))) {
|
||||
aa_put_profile(profile);
|
||||
Index: b/security/apparmor/procattr.c
|
||||
===================================================================
|
||||
--- a/security/apparmor/procattr.c
|
||||
+++ b/security/apparmor/procattr.c
|
||||
@@ -19,8 +19,8 @@ int aa_getprocattr(struct aa_profile *pr
|
||||
char *str;
|
||||
|
||||
if (profile) {
|
||||
- const char *mode_str = PROFILE_COMPLAIN(profile) ?
|
||||
- " (complain)" : " (enforce)";
|
||||
+ const char *mode_str = PROFILE_LEARNING(profile) ?
|
||||
+ " (learning)" : " (enforce)";
|
||||
|
||||
*len = ((profile != profile->parent) ?
|
||||
strlen(profile->parent->name) + 1 : 0) +
|
@@ -1,49 +0,0 @@
|
||||
Per the discussion in the email thread beginning with
|
||||
|
||||
Subject: [pdx] Block the CLONE_NEWNS flag in clone(2)
|
||||
Message-Id: <200702241013.09434.agruen@suse.de>
|
||||
|
||||
we decided to drop the outright rejection on CLONE_NEWNS since the kernel
|
||||
currently requires CAP_SYS_ADMIN.
|
||||
|
||||
As an alternative to this patch, we could convert the error = -EPERM
|
||||
line to a capable(CAP_SYS_ADMIN) check, to guarantee that CLONE_NEWNS
|
||||
always requires CAP_SYS_ADMIN under apparmor, even if the kernel changes
|
||||
to not require it.
|
||||
---
|
||||
security/apparmor/lsm.c | 17 -----------------
|
||||
1 file changed, 17 deletions(-)
|
||||
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -467,22 +467,6 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
-static int apparmor_task_create(unsigned long clone_flags)
|
||||
-{
|
||||
- struct aa_profile *profile;
|
||||
- int error = 0;
|
||||
-
|
||||
- profile = aa_get_profile(current);
|
||||
- if (profile) {
|
||||
- /* Don't allow to create new namespaces. */
|
||||
- if (clone_flags & CLONE_NEWNS)
|
||||
- error = -EPERM;
|
||||
- }
|
||||
- aa_put_profile(profile);
|
||||
-
|
||||
- return error;
|
||||
-}
|
||||
-
|
||||
static int apparmor_file_alloc_security(struct file *file)
|
||||
{
|
||||
struct aa_profile *profile;
|
||||
@@ -678,7 +662,6 @@ struct security_operations apparmor_ops
|
||||
.file_mmap = apparmor_file_mmap,
|
||||
.file_mprotect = apparmor_file_mprotect,
|
||||
|
||||
- .task_create = apparmor_task_create,
|
||||
.task_alloc_security = apparmor_task_alloc_security,
|
||||
.task_free_security = apparmor_task_free_security,
|
||||
.task_post_setuid = cap_task_post_setuid,
|
10
kernel-patches/for-mainline/export-get_task_comm.diff
Normal file
10
kernel-patches/for-mainline/export-get_task_comm.diff
Normal file
@@ -0,0 +1,10 @@
|
||||
--- a/fs/exec.c
|
||||
+++ b/fs/exec.c
|
||||
@@ -806,6 +806,7 @@ void get_task_comm(char *buf, struct tas
|
||||
strncpy(buf, tsk->comm, sizeof(tsk->comm));
|
||||
task_unlock(tsk);
|
||||
}
|
||||
+EXPORT_SYMBOL(get_task_comm);
|
||||
|
||||
void set_task_comm(struct task_struct *tsk, char *buf)
|
||||
{
|
@@ -1,15 +0,0 @@
|
||||
---
|
||||
security/apparmor/Kconfig | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/security/apparmor/Kconfig
|
||||
+++ b/security/apparmor/Kconfig
|
||||
@@ -1,6 +1,7 @@
|
||||
config SECURITY_APPARMOR
|
||||
tristate "AppArmor support"
|
||||
- depends on SECURITY!=n
|
||||
+ depends on SECURITY
|
||||
+ select AUDIT
|
||||
help
|
||||
This enables the AppArmor security module.
|
||||
Required userspace tools (if they are not included in your
|
@@ -1,75 +0,0 @@
|
||||
---
|
||||
security/apparmor/main.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 49 insertions(+)
|
||||
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -103,6 +103,51 @@ 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 must be contained in
|
||||
+ * @buffer. The string grows towards @buffer. Returns a pointer
|
||||
+ * to the quoted string, or ERR_PTR(-ENAMETOOLONG) upon failure.
|
||||
+ */
|
||||
+static char *mangle(char *str, char *buffer)
|
||||
+{
|
||||
+ static const char c_escape[] = {
|
||||
+ ['\a'] = 'a', ['\b'] = 'b',
|
||||
+ ['\f'] = 'f', ['\n'] = 'n',
|
||||
+ ['\r'] = 'r', ['\t'] = 't',
|
||||
+ ['\v'] = 'v',
|
||||
+ [' '] = ' ', ['\\'] = '\\',
|
||||
+ };
|
||||
+ char *s, *t, c;
|
||||
+
|
||||
+#define mangle_escape(c) \
|
||||
+ unlikely((unsigned char)(c) < ARRAY_SIZE(c_escape) && \
|
||||
+ c_escape[(unsigned char)c])
|
||||
+
|
||||
+ for (s = str; (c = *s) != '\0'; s++)
|
||||
+ if (mangle_escape(c))
|
||||
+ goto escape;
|
||||
+ return str;
|
||||
+
|
||||
+escape:
|
||||
+ 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
|
||||
@@ -148,12 +193,16 @@ static char *aa_get_name(struct dentry *
|
||||
buf[size - 1] = '\0';
|
||||
}
|
||||
|
||||
+ name = mangle(name, buf);
|
||||
+ if (!name)
|
||||
+ goto grow_buffer;
|
||||
*buffer = buf;
|
||||
return name;
|
||||
}
|
||||
if (PTR_ERR(name) != -ENAMETOOLONG)
|
||||
return name;
|
||||
|
||||
+grow_buffer:
|
||||
kfree(buf);
|
||||
size <<= 1;
|
||||
if (size > apparmor_path_max)
|
@@ -1,61 +0,0 @@
|
||||
From: Andreas Gruenbacher <agruen@suse.de>
|
||||
Subject: Make d_path() consistent across mount operations
|
||||
|
||||
Right now, the path that __d_path() computes can become slightly
|
||||
inconsistent when it races with mount operations: it grabs the
|
||||
vfsmount_lock when traversing mount points, but immediately drops it
|
||||
again, only to re-grab it when it reaches the next mount point.
|
||||
The result is that the filename computed is not always consisent, and
|
||||
the file may never have had that name. (This is unlikely, but still
|
||||
possible.)
|
||||
|
||||
We can easily fix this by grabbing the vfsmount_lock when the first
|
||||
mount point is reached, and holding onto it until the d_cache lookup is
|
||||
completed.
|
||||
|
||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
fs/dcache.c | 14 ++++++++------
|
||||
1 file changed, 8 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/fs/dcache.c
|
||||
+++ b/fs/dcache.c
|
||||
@@ -1754,7 +1754,7 @@ static char *__d_path(struct dentry *den
|
||||
struct dentry *root, struct vfsmount *rootmnt,
|
||||
char *buffer, int buflen, int fail_deleted)
|
||||
{
|
||||
- int namelen, is_slash;
|
||||
+ int namelen, is_slash, vfsmount_locked = 0;
|
||||
|
||||
if (buflen < 2)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
@@ -1777,14 +1777,14 @@ static char *__d_path(struct dentry *den
|
||||
struct dentry * parent;
|
||||
|
||||
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
||||
- spin_lock(&vfsmount_lock);
|
||||
- if (vfsmnt->mnt_parent == vfsmnt) {
|
||||
- spin_unlock(&vfsmount_lock);
|
||||
- goto global_root;
|
||||
+ if (!vfsmount_locked) {
|
||||
+ spin_lock(&vfsmount_lock);
|
||||
+ vfsmount_locked = 1;
|
||||
}
|
||||
+ if (vfsmnt->mnt_parent == vfsmnt)
|
||||
+ goto global_root;
|
||||
dentry = vfsmnt->mnt_mountpoint;
|
||||
vfsmnt = vfsmnt->mnt_parent;
|
||||
- spin_unlock(&vfsmount_lock);
|
||||
continue;
|
||||
}
|
||||
parent = dentry->d_parent;
|
||||
@@ -1803,6 +1803,8 @@ static char *__d_path(struct dentry *den
|
||||
*--buffer = '/';
|
||||
|
||||
out:
|
||||
+ if (vfsmount_locked)
|
||||
+ spin_unlock(&vfsmount_lock);
|
||||
spin_unlock(&dcache_lock);
|
||||
return buffer;
|
||||
|
@@ -39,30 +39,23 @@ proc-mounts-cleanup.diff
|
||||
# fix-d_path.diff
|
||||
file-handle-ops.diff
|
||||
security-xattr-file.diff
|
||||
sysctl-pathname.diff
|
||||
export-get_task_comm.diff
|
||||
apparmor-audit.diff
|
||||
apparmor-main.diff
|
||||
apparmor-main-2.diff
|
||||
mangle.diff
|
||||
apparmor-lsm.diff
|
||||
apparmor-lsm-2.diff
|
||||
drop_CLONE_NEWNS_restriction.diff
|
||||
apparmor-ns-ptrace.diff
|
||||
apparmor-module_interface.diff
|
||||
apparmor-module_interface-2.diff
|
||||
apparmor-misc.diff
|
||||
audit-cleanup.diff
|
||||
comm.diff
|
||||
ecryptfs-d_revalidate.diff
|
||||
nfs-nameidata-check.diff
|
||||
apparmor-intree.diff
|
||||
sysctl-pathname.diff
|
||||
ecryptfs-d_revalidate.diff
|
||||
apparmor-sysctl-pathname.diff
|
||||
vfs_create-nameidata.diff
|
||||
do_path_lookup-nameidata.diff
|
||||
sys_fchdir-nameidata.diff
|
||||
nfsd_permission-nameidata.diff
|
||||
file_permission-nameidata.diff
|
||||
kconfig-dependencies.diff
|
||||
# NOT YET
|
||||
nfs-nameidata-check.diff
|
||||
split-up-nameidata.diff
|
||||
# xattr_permission.diff
|
||||
# vfs_create-args.diff
|
||||
|
@@ -2347,7 +2347,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
+/**
|
||||
+ * Fields shared between nameidata and nameidata2 -- nameidata2 could
|
||||
+ * be embedded in nameidata, but then the vfs code would become
|
||||
+ * simply be embedded in nameidata, but then the vfs code would become
|
||||
+ * cluttered with dereferences.
|
||||
+ */
|
||||
+#define __NAMEIDATA2 \
|
||||
|
Reference in New Issue
Block a user