All of lore.kernel.org
 help / color / mirror / Atom feed
From: jjohansen@suse.de
To: linux-kernel@vger.kernel.org
Cc: linux-security-module@vger.kernel.org,
	linux-fsdevel@vger.kernel.org, chrisw@sous-sol.org,
	John Johansen <jjohansen@suse.de>,
	Andreas Gruenbacher <agruen@suse.de>
Subject: [AppArmor 40/41] AppArmor: all the rest
Date: Thu, 12 Apr 2007 02:08:49 -0700	[thread overview]
Message-ID: <20070412090849.824835000@suse.de> (raw)
In-Reply-To: 20070412090809.917795000@suse.de

[-- Attachment #1: apparmor-misc.diff --]
[-- Type: text/plain, Size: 31490 bytes --]

All the things that didn't nicely fit in a category on their own: kbuild
code, declararions and inline functions, /sys/kernel/security/apparmor
filesystem for controlling apparmor from user space, profile list
functions, locking documentation, /proc/$pid/task/$tid/attr/current
access.

Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>

---
 security/apparmor/Kconfig      |    9 +
 security/apparmor/Makefile     |   13 +
 security/apparmor/apparmor.h   |  282 +++++++++++++++++++++++++++++++++++++++++
 security/apparmor/apparmorfs.c |  248 ++++++++++++++++++++++++++++++++++++
 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(+)

--- /dev/null
+++ b/security/apparmor/Kconfig
@@ -0,0 +1,9 @@
+config SECURITY_APPARMOR
+	tristate "AppArmor support"
+	depends on SECURITY!=n
+	help
+	  This enables the AppArmor security module.
+	  Required userspace tools (if they are not included in your
+	  distribution) and further information may be found at
+	  <http://forge.novell.com/modules/xfmod/project/?apparmor>
+	  If you are unsure how to answer this question, answer N.
--- /dev/null
+++ b/security/apparmor/Makefile
@@ -0,0 +1,13 @@
+# Makefile for AppArmor Linux Security Module
+#
+obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
+
+apparmor-y := main.o list.o procattr.o lsm.o apparmorfs.o \
+	      module_interface.o match.o
+
+quiet_cmd_make-caps = GEN     $@
+cmd_make-caps = sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2]  = \"\\1\",/p" $< | tr A-Z a-z > $@
+
+$(obj)/main.o : $(obj)/capability_names.h
+$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
+	$(call cmd,make-caps)
--- /dev/null
+++ b/security/apparmor/apparmor.h
@@ -0,0 +1,282 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor internal prototypes
+ */
+
+#ifndef __APPARMOR_H
+#define __APPARMOR_H
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/binfmts.h>
+#include <linux/rcupdate.h>
+
+/*
+ * We use MAY_READ, MAY_WRITE, MAY_EXEC, and the following flags for
+ * profile permissions (we don't use MAY_APPEND):
+ */
+#define AA_MAY_LINK			0x0010
+#define AA_EXEC_INHERIT			0x0020
+#define AA_EXEC_UNCONFINED		0x0040
+#define AA_EXEC_PROFILE			0x0080
+#define AA_EXEC_MMAP			0x0100
+#define AA_EXEC_UNSAFE			0x0200
+
+#define AA_EXEC_MODIFIERS		(AA_EXEC_INHERIT | \
+					 AA_EXEC_UNCONFINED | \
+					 AA_EXEC_PROFILE)
+
+#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;
+extern int apparmor_debug;
+extern int apparmor_audit;
+extern int apparmor_logsyscall;
+extern unsigned int apparmor_path_max;
+
+#define PROFILE_COMPLAIN(_profile) \
+	(apparmor_complain == 1 || ((_profile) && (_profile)->flags.complain))
+
+#define APPARMOR_COMPLAIN(_cxt) \
+	(apparmor_complain == 1 || \
+	 ((_cxt) && (_cxt)->profile && (_cxt)->profile->flags.complain))
+
+#define PROFILE_AUDIT(_profile) \
+	(apparmor_audit == 1 || ((_profile) && (_profile)->flags.audit))
+
+#define APPARMOR_AUDIT(_cxt) \
+	(apparmor_audit == 1 || \
+	 ((_cxt) && (_cxt)->profile && (_cxt)->profile->flags.audit))
+
+/*
+ * DEBUG remains global (no per profile flag) since it is mostly used in sysctl
+ * which is not related to profile accesses.
+ */
+
+#define AA_DEBUG(fmt, args...)						\
+	do {								\
+		if (apparmor_debug)					\
+			printk(KERN_DEBUG "AppArmor: " fmt, ##args);	\
+	} while (0)
+#define AA_INFO(gfp, fmt, args...) \
+	do { \
+		printk(KERN_INFO "AppArmor: " fmt "\n", ##args); \
+		aa_audit_message(NULL, (gfp), 0, fmt, ##args); \
+	} while (0)
+#define AA_WARN(gfp, fmt, args...) \
+	aa_audit_message(NULL, (gfp), 0, fmt, ##args);
+
+#define AA_REJECT_MSG(p, gfp, fmt, args...) \
+	aa_audit_message((p), (gfp), 0, \
+			"REJECTING " fmt \
+			" (%s(%d) profile %s active %s)", ##args, \
+			current->comm, current->pid, \
+			(p)->parent->name, (p)->name)
+
+#define AA_ERROR(fmt, args...)	printk(KERN_ERR "AppArmor: " fmt, ##args)
+
+/* struct aa_profile - basic confinement data
+ * @parent: non refcounted pointer to parent profile
+ * @name: the profiles name
+ * @file_rules: dfa containing the profiles file rules
+ * @list: list this profile is on
+ * @sub: profiles list of subprofiles (HATS)
+ * @flags: flags controlling profile behavior
+ * @null_profile: if needed per profile learning and null confinement profile
+ * @isstale: flag indicating if profile is stale
+ * @capabilities: capabilities granted by the process
+ * @count: reference count of the profile
+ *
+ * The AppArmor profile contains the basic confinement data.  Each profile
+ * has a name and potentially a list of profile entries. All profiles are
+ * on the profile_list.
+ *
+ * The task_contexts list and the isstale flag are protected by the
+ * profile lock.
+ *
+ * If a task context is moved between two profiles, we first need to grab
+ * both profile locks. lock_both_profiles() does that in a deadlock-safe
+ * way.
+ */
+struct aa_profile {
+	struct aa_profile *parent;
+	char *name;
+	struct aa_dfa *file_rules;
+	struct list_head list;
+	struct list_head sub;
+	struct {
+		int complain;
+		int audit;
+	} flags;
+	struct aa_profile *null_profile;
+	int isstale;
+
+	kernel_cap_t capabilities;
+	struct kref count;
+	struct list_head task_contexts;
+	spinlock_t lock;
+	unsigned long int_flags;
+};
+
+extern struct list_head profile_list;
+extern rwlock_t profile_list_lock;
+extern struct mutex aa_interface_lock;
+
+/**
+ * struct aa_task_context - primary label for confined tasks
+ * @profile: the current profile
+ * @hat_magic: the magic token controling the ability to leave a hat
+ * @list: list this aa_task_context is on
+ * @task: task that the aa_task_context confines
+ * @rcu: rcu head used when freeing the aa_task_context
+ * @caps_logged: caps that have previously generated log entries
+ *
+ * Contains the task's current profile (which could change due to
+ * change_hat).  Plus the hat_magic needed during change_hat.
+ */
+struct aa_task_context {
+	struct aa_profile *profile;	/* The current profile */
+	u64 hat_magic;			/* used with change_hat */
+	struct list_head list;
+	struct task_struct *task;
+	struct rcu_head rcu;
+	kernel_cap_t caps_logged;
+};
+
+extern struct aa_profile *null_complain_profile;
+
+/* aa_audit - AppArmor auditing structure
+ * Structure is populated by access control code and passed to aa_audit which
+ * provides for a single point of logging.
+ */
+
+struct aa_audit {
+	unsigned short type, flags;
+	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;
+		va_list vaval;
+	};
+};
+
+/* audit types */
+#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
+#define AA_AUDITTYPE__END	9
+
+/* 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  */
+
+#define HINT_UNKNOWN_HAT "unknown_hat"
+#define HINT_FORK "fork"
+#define HINT_MANDPROF "missing_mandatory_profile"
+#define HINT_CHGPROF "changing_profile"
+#define HINT_PTRACE "ptrace"
+
+#define LOG_HINT(p, gfp, hint, fmt, args...) \
+	aa_audit_message((p), (gfp), 0, \
+			"LOGPROF-HINT " hint " " fmt \
+			" (%s(%d) profile %s active %s)", ##args, \
+			current->comm, current->pid, \
+			(p)->parent->name, (p)->name)
+
+/* Flags for the permission check functions */
+#define AA_CHECK_LEAF	1  /* this is the leaf lookup component */
+#define AA_CHECK_FD	2  /* coming from a file descriptor */
+#define AA_CHECK_DIR	4  /* file type is directory */
+
+/* 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, int,
+			    const char *, ...);
+extern int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp,
+				  const char *);
+extern int aa_audit(struct aa_profile *profile, const 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,
+			 const char *xattr_xattr, 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_link(struct aa_profile *profile,
+		   struct dentry *link, struct vfsmount *link_mnt,
+		   struct dentry *target, struct vfsmount *target_mnt);
+extern int aa_clone(struct task_struct *task);
+extern int aa_register(struct linux_binprm *bprm);
+extern void aa_release(struct task_struct *task);
+extern int aa_change_hat(const char *id, u64 hat_magic);
+extern struct aa_profile *__aa_find_profile(const char *name,
+					    struct list_head *list);
+extern struct aa_profile *__aa_replace_profile(struct task_struct *task,
+					       struct aa_profile *profile,
+					       u32 hat_magic);
+extern struct aa_task_context *lock_task_and_profiles(struct task_struct *task,
+						      struct aa_profile *profile);
+extern void aa_change_task_context(struct task_struct *task,
+				   struct aa_task_context *new_cxt,
+				   struct aa_profile *profile, u64 hat_magic);
+extern int aa_may_ptrace(struct aa_task_context *cxt,
+			 struct aa_profile *tracee);
+
+/* list.c */
+extern void aa_profilelist_release(void);
+
+/* module_interface.c */
+extern ssize_t aa_add_profile(void *, size_t);
+extern ssize_t aa_replace_profile(void *, size_t);
+extern ssize_t aa_remove_profile(const char *, size_t);
+extern struct aa_profile *alloc_aa_profile(void);
+extern void free_aa_profile(struct aa_profile *profile);
+extern void free_aa_profile_kref(struct kref *kref);
+extern void aa_unconfine_tasks(struct aa_profile *profile);
+
+/* procattr.c */
+extern int aa_getprocattr(struct aa_profile *profile, char **string,
+			  unsigned *len);
+extern int aa_setprocattr_changehat(char *args);
+extern int aa_setprocattr_setprofile(struct task_struct *task, char *args);
+
+/* apparmorfs.c */
+extern int create_apparmorfs(void);
+extern void destroy_apparmorfs(void);
+
+/* match.c */
+extern struct aa_dfa *aa_match_alloc(void);
+extern void aa_match_free(struct aa_dfa *dfa);
+extern int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size);
+extern int verify_dfa(struct aa_dfa *dfa);
+extern unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str);
+
+#endif  /* __APPARMOR_H */
--- /dev/null
+++ b/security/apparmor/apparmorfs.c
@@ -0,0 +1,248 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor filesystem (part of securityfs)
+ */
+
+#include <linux/security.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+#include "apparmor.h"
+#include "inline.h"
+
+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)
+{
+	struct aa_profile *profile;
+	char *data;
+
+	if (*pos != 0) {
+		/* only writes from pos 0, that is complete writes */
+		data = ERR_PTR(-ESPIPE);
+		goto out;
+	}
+
+	/*
+	 * Don't allow confined processes to load/replace/remove profiles.
+	 * No sane person would add rules allowing this to a profile
+	 * but we enforce the restriction anyways.
+	 */
+	profile = aa_get_profile(current);
+	if (profile) {
+		AA_WARN(GFP_KERNEL, "REJECTING access to profile %s (%s(%d) "
+			"profile %s active %s)",
+			msg, current->comm, current->pid,
+			profile->parent->name, profile->name);
+		aa_put_profile(profile);
+
+		data = ERR_PTR(-EPERM);
+		goto out;
+	}
+
+	data = vmalloc(alloc_size);
+	if (data == NULL) {
+		data = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+	if (copy_from_user(data, userbuf, copy_size)) {
+		vfree(data);
+		data = ERR_PTR(-EFAULT);
+		goto out;
+	}
+
+out:
+	return data;
+}
+
+/* apparmor/profiles */
+extern struct seq_operations apparmorfs_profiles_op;
+
+static int aa_profiles_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &apparmorfs_profiles_op);
+}
+
+
+static int aa_profiles_release(struct inode *inode, struct file *file)
+{
+	return seq_release(inode, file);
+}
+
+static struct file_operations apparmorfs_profiles_fops = {
+	.open =		aa_profiles_open,
+	.read =		seq_read,
+	.llseek =	seq_lseek,
+	.release =	aa_profiles_release,
+};
+
+/* apparmor/matching */
+static ssize_t aa_matching_read(struct file *file, char __user *buf,
+			       size_t size, loff_t *ppos)
+{
+	const char *matching = "pattern=aadfa";
+
+	return simple_read_from_buffer(buf, size, ppos, matching,
+				       strlen(matching));
+}
+
+static struct file_operations apparmorfs_matching_fops = {
+	.read = 	aa_matching_read,
+};
+
+/* apparmor/.load */
+static ssize_t aa_profile_load(struct file *f, const char __user *buf,
+			       size_t size, loff_t *pos)
+{
+	char *data;
+	ssize_t error;
+
+	data = aa_simple_write_to_buffer(buf, size, size, pos, "load");
+
+	error = PTR_ERR(data);
+	if (!IS_ERR(data)) {
+		error = aa_add_profile(data, size);
+		vfree(data);
+	}
+
+	return error;
+}
+
+
+static struct file_operations apparmorfs_profile_load = {
+	.write = aa_profile_load
+};
+
+/* apparmor/.replace */
+static ssize_t aa_profile_replace(struct file *f, const char __user *buf,
+				  size_t size, loff_t *pos)
+{
+	char *data;
+	ssize_t error;
+
+	data = aa_simple_write_to_buffer(buf, size, size, pos, "replacement");
+
+	error = PTR_ERR(data);
+	if (!IS_ERR(data)) {
+		error = aa_replace_profile(data, size);
+		vfree(data);
+	}
+
+	return error;
+}
+
+
+static struct file_operations apparmorfs_profile_replace = {
+	.write = aa_profile_replace
+};
+
+/* apparmor/.remove */
+static ssize_t aa_profile_remove(struct file *f, const char __user *buf,
+				  size_t size, loff_t *pos)
+{
+	char *data;
+	ssize_t error;
+
+	/*
+	 * 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");
+
+	error = PTR_ERR(data);
+	if (!IS_ERR(data)) {
+		data[size] = 0;
+		error = aa_remove_profile(data, size);
+		vfree(data);
+	}
+
+	return error;
+}
+
+static struct file_operations apparmorfs_profile_remove = {
+	.write = aa_profile_remove
+};
+
+static struct dentry *apparmor_dentry;
+
+static void aafs_remove(const char *name)
+{
+	struct dentry *dentry;
+
+	dentry = lookup_one_len(name, apparmor_dentry, strlen(name));
+	if (dentry && !IS_ERR(dentry))
+		securityfs_remove(dentry);
+}
+
+static int aafs_create(const char *name, int mask, struct file_operations *fops)
+{
+	struct dentry *dentry;
+
+	dentry = securityfs_create_file(name, S_IFREG | mask, apparmor_dentry,
+					NULL, fops);
+
+	return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
+}
+
+void destroy_apparmorfs(void)
+{
+	if (apparmor_dentry) {
+		aafs_remove(".remove");
+		aafs_remove(".replace");
+		aafs_remove(".load");
+		aafs_remove("matching");
+		aafs_remove("profiles");
+		securityfs_remove(apparmor_dentry);
+		apparmor_dentry = NULL;
+	}
+}
+
+int create_apparmorfs(void)
+{
+	int error;
+
+	if (apparmor_dentry) {
+		AA_ERROR("%s: AppArmor securityfs already exists\n",
+			__FUNCTION__);
+		return -EEXIST;
+	}
+
+	apparmor_dentry = securityfs_create_dir("apparmor", NULL);
+	if (IS_ERR(apparmor_dentry)) {
+		error = PTR_ERR(apparmor_dentry);
+		apparmor_dentry = NULL;
+ 		goto error;
+	}
+	error = aafs_create("profiles", 0440, &apparmorfs_profiles_fops);
+	if (error)
+		goto error;
+	error = aafs_create("matching", 0444, &apparmorfs_matching_fops);
+	if (error)
+		goto error;
+	error = aafs_create(".load", 0640, &apparmorfs_profile_load);
+	if (error)
+		goto error;
+	error = aafs_create(".replace", 0640, &apparmorfs_profile_replace);
+	if (error)
+		goto error;
+	error = aafs_create(".remove", 0640, &apparmorfs_profile_remove);
+	if (error)
+		goto error;
+
+	return 0;
+
+error:
+	destroy_apparmorfs();
+	AA_ERROR("Error creating AppArmor securityfs\n");
+	return error;
+}
+
--- /dev/null
+++ b/security/apparmor/inline.h
@@ -0,0 +1,219 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ */
+
+#ifndef __INLINE_H
+#define __INLINE_H
+
+#include <linux/sched.h>
+
+static inline int mediated_filesystem(struct inode *inode)
+{
+	return !(inode->i_sb->s_flags & MS_NOUSER);
+}
+
+static inline struct aa_task_context *aa_task_context(struct task_struct *task)
+{
+	return rcu_dereference((struct aa_task_context *)task->security);
+}
+
+/**
+ * aa_dup_profile - increment refcount on profile @p
+ * @p: profile
+ */
+static inline struct aa_profile *aa_dup_profile(struct aa_profile *p)
+{
+	if (p)
+		kref_get(&(p->parent->count));
+
+	return p;
+}
+
+/**
+ * aa_put_profile - decrement refcount on profile @p
+ * @p: profile
+ */
+static inline void aa_put_profile(struct aa_profile *p)
+{
+	if (p)
+		kref_put(&p->parent->count, free_aa_profile_kref);
+}
+
+static inline struct aa_profile *aa_get_profile(struct task_struct *task)
+{
+	struct aa_task_context *cxt;
+	struct aa_profile *profile = NULL;
+
+	rcu_read_lock();
+	cxt = aa_task_context(task);
+	if (cxt) {
+		profile = cxt->profile;
+		aa_dup_profile(profile);
+	}
+	rcu_read_unlock();
+
+	return profile;
+}
+
+static inline struct aa_profile *aa_find_profile(const char *name)
+{
+	struct aa_profile *profile = NULL;
+
+	read_lock(&profile_list_lock);
+	profile = aa_dup_profile(__aa_find_profile(name, &profile_list));
+	read_unlock(&profile_list_lock);
+
+	return profile;
+}
+
+static inline struct aa_task_context *aa_alloc_task_context(gfp_t flags)
+{
+	struct aa_task_context *cxt;
+
+	cxt = kzalloc(sizeof(*cxt), flags);
+	if (cxt) {
+		INIT_LIST_HEAD(&cxt->list);
+		INIT_RCU_HEAD(&cxt->rcu);
+	}
+
+	return cxt;
+}
+
+static inline void aa_free_task_context(struct aa_task_context *cxt)
+{
+	if (cxt) {
+		aa_put_profile(cxt->profile);
+		kfree(cxt);
+	}
+}
+
+/**
+ * lock_profile - lock a profile
+ * @profile: the profile to lock
+ *
+ * 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)
+{
+	/* We always lock top-level profiles instead of children. */
+	if (profile)
+		profile = profile->parent;
+
+	/*
+	 * Lock the profile.
+	 *
+	 * Need to disable interrupts here because this lock is used in
+	 * the task_free_security hook, which may run in RCU context.
+	 */
+	if (profile)
+		spin_lock_irqsave(&profile->lock, profile->int_flags);
+}
+
+/**
+ * unlock_profile - unlock a profile
+ * @profile: the profile to unlock
+ */
+static inline void unlock_profile(struct aa_profile *profile)
+{
+	/* We always lock top-level profiles instead of children. */
+	if (profile)
+		profile = profile->parent;
+
+	/* Unlock the profile. */
+	if (profile)
+		spin_unlock_irqrestore(&profile->lock, profile->int_flags);
+}
+
+/**
+ * lock_both_profiles  -  lock two profiles in a deadlock-free way
+ * @profile1:	profile to lock (may be NULL)
+ * @profile2:	profile to lock (may be NULL)
+ *
+ * The order in which profiles are passed into lock_both_profiles() /
+ * unlock_both_profiles() does not matter.
+ * While the profile is locked, local interrupts are disabled. This also
+ * gives us RCU reader safety.
+ */
+static inline void lock_both_profiles(struct aa_profile *profile1,
+				      struct aa_profile *profile2)
+{
+	/* We always lock top-level profiles instead of children. */
+	if (profile1)
+		profile1 = profile1->parent;
+	if (profile2)
+		profile2 = profile2->parent;
+
+	/*
+	 * Lock the two profiles.
+	 *
+	 * We need to disable interrupts because the profile locks are
+	 * used in the task_free_security hook, which may run in RCU
+	 * context.
+	 *
+	 * Do not nest spin_lock_irqsave()/spin_unlock_irqresore():
+	 * interrupts only need to be turned off once.
+	 */
+	if (!profile1 || profile1 == profile2) {
+		if (profile2)
+			spin_lock_irqsave(&profile2->lock, profile2->int_flags);
+	} else if (profile1 > profile2) {
+		/* profile1 cannot be NULL here. */
+		spin_lock_irqsave(&profile1->lock, profile1->int_flags);
+		if (profile2)
+			spin_lock(&profile2->lock);
+
+	} else {
+		/* profile2 cannot be NULL here. */
+		spin_lock_irqsave(&profile2->lock, profile2->int_flags);
+		spin_lock(&profile1->lock);
+	}
+}
+
+/**
+ * unlock_both_profiles  -  unlock two profiles in a deadlock-free way
+ * @profile1:	profile to unlock (may be NULL)
+ * @profile2:	profile to unlock (may be NULL)
+ *
+ * The order in which profiles are passed into lock_both_profiles() /
+ * unlock_both_profiles() does not matter.
+ * While the profile is locked, local interrupts are disabled. This also
+ * gives us RCU reader safety.
+ */
+static inline void unlock_both_profiles(struct aa_profile *profile1,
+				        struct aa_profile *profile2)
+{
+	/* We always lock top-level profiles instead of children. */
+	if (profile1)
+		profile1 = profile1->parent;
+	if (profile2)
+		profile2 = profile2->parent;
+
+	/* Unlock the two profiles. */
+	if (!profile1 || profile1 == profile2) {
+		if (profile2)
+			spin_unlock_irqrestore(&profile2->lock,
+					       profile2->int_flags);
+	} else if (profile1 > profile2) {
+		/* profile1 cannot be NULL here. */
+		if (profile2)
+			spin_unlock(&profile2->lock);
+		spin_unlock_irqrestore(&profile1->lock, profile1->int_flags);
+	} else {
+		/* profile2 cannot be NULL here. */
+		spin_unlock(&profile1->lock);
+		spin_unlock_irqrestore(&profile2->lock, profile2->int_flags);
+	}
+}
+
+static inline unsigned int aa_match(struct aa_dfa *dfa, const char *pathname)
+{
+	        return dfa ? aa_dfa_match(dfa, pathname) : 0;
+}
+
+#endif /* __INLINE_H__ */
--- /dev/null
+++ b/security/apparmor/list.c
@@ -0,0 +1,94 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor Profile List Management
+ */
+
+#include <linux/seq_file.h>
+#include "apparmor.h"
+#include "inline.h"
+
+/* list of all profiles and lock */
+LIST_HEAD(profile_list);
+rwlock_t profile_list_lock = RW_LOCK_UNLOCKED;
+
+/**
+ * __aa_find_profile  -  look up a profile on the profile list
+ * @name: name of profile to find
+ * @head: list to search
+ *
+ * Returns a pointer to the profile on the list, or NULL if no profile
+ * called @name exists. The caller must hold the profile_list_lock.
+ */
+struct aa_profile *__aa_find_profile(const char *name, struct list_head *head)
+{
+	struct aa_profile *profile;
+
+	list_for_each_entry(profile, head, list) {
+		if (!strcmp(profile->name, name))
+			return profile;
+	}
+
+	return NULL;
+}
+
+/**
+ * aa_profilelist_release - Remove all profiles from profile_list
+ */
+void aa_profilelist_release(void)
+{
+	struct aa_profile *p, *tmp;
+
+	write_lock(&profile_list_lock);
+	list_for_each_entry_safe(p, tmp, &profile_list, list) {
+		list_del_init(&p->list);
+		aa_put_profile(p);
+	}
+	write_unlock(&profile_list_lock);
+}
+
+static void *p_start(struct seq_file *f, loff_t *pos)
+{
+	struct aa_profile *node;
+	loff_t l = *pos;
+
+	read_lock(&profile_list_lock);
+	list_for_each_entry(node, &profile_list, list)
+		if (!l--)
+			return node;
+	return NULL;
+}
+
+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
+{
+	struct list_head *lh = ((struct aa_profile *)p)->list.next;
+	(*pos)++;
+	return lh == &profile_list ?
+			NULL : list_entry(lh, struct aa_profile, list);
+}
+
+static void p_stop(struct seq_file *f, void *v)
+{
+	read_unlock(&profile_list_lock);
+}
+
+static int seq_show_profile(struct seq_file *f, void *v)
+{
+	struct aa_profile *profile = (struct aa_profile *)v;
+	seq_printf(f, "%s (%s)\n", profile->name,
+		   PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
+	return 0;
+}
+
+/* Used in apparmorfs.c */
+struct seq_operations apparmorfs_profiles_op = {
+	.start =	p_start,
+	.next =		p_next,
+	.stop =		p_stop,
+	.show =		seq_show_profile,
+};
--- /dev/null
+++ b/security/apparmor/locking.txt
@@ -0,0 +1,59 @@
+Locking in AppArmor
+===================
+
+Lock hierarchy:
+
+	aa_interface_lock
+	  profile_list_lock
+	    aa_profile->lock
+	      task_lock()
+
+
+Which lock protects what?
+
+	/-----------------------+-------------------------------\
+	| Variable		| Lock				|
+	>-----------------------+-------------------------------<
+	| profile_list		| profile_list_lock		|
+	+-----------------------+-------------------------------+
+	| aa_profile		| (reference count)		|
+	+-----------------------+-------------------------------+
+	| aa_profile->		| aa_profile->lock		|
+	|   isstale,		|				|
+	|   task_contexts	|				|
+	+-----------------------+-------------------------------+
+	| task_struct->security	| read: RCU			|
+	|			| write: task_lock()		|
+	+-----------------------+-------------------------------+
+	| aa_profile->sub	| handle on the profile (list	|
+	|			| is never modified)		|
+	\-----------------------+-------------------------------/
+
+(Obviously, the list_heads embedded in data structures are always
+protected with the lock that also protects the list.)
+
+When moving a task context from one profile to another, we grab both
+profile locks with lock_both_profiles(). This ensures that both locks
+are always taken in the same order, and so we won't deadlock.
+
+Since task_struct->security is RCU protected the aa_task_struct it
+references is only guarenteed to exist for the rcu cycle.  Where
+aa_task_context->profile is needed in blocking operations the
+profile's reference count is incremented and the profile reference
+is used.
+
+Profiles on profile_list are never stale: when a profile becomes stale,
+it is removed from profile_list at the same time (under profile_list_lock
+and aa_profile->lock).
+
+The aa_interface_lock is taken whenever user-space modifies the profile
+list, and can sleep. This ensures that profile loading/replacement/removal
+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.
--- /dev/null
+++ b/security/apparmor/procattr.c
@@ -0,0 +1,143 @@
+/*
+ *	Copyright (C) 1998-2007 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ *
+ *	AppArmor /proc/pid/attr handling
+ */
+
+#include "apparmor.h"
+#include "inline.h"
+
+int aa_getprocattr(struct aa_profile *profile, char **string, unsigned *len)
+{
+	char *str;
+
+	if (profile) {
+		const char *mode_str = PROFILE_COMPLAIN(profile) ?
+			" (complain)" : " (enforce)";
+
+		*len = ((profile != profile->parent) ?
+		           strlen(profile->parent->name) + 1 : 0) +
+		       strlen(mode_str) + strlen(profile->name) + 1;
+		str = kmalloc(*len, GFP_ATOMIC);
+		if (!str)
+			return -ENOMEM;
+
+		if (profile != profile->parent) {
+			memcpy(str, profile->parent->name,
+			       strlen(profile->parent->name));
+			str += strlen(profile->parent->name);
+			*str++ = '^';
+		}
+		memcpy(str, profile->name, strlen(profile->name));
+		str += strlen(profile->name);
+		memcpy(str, mode_str, strlen(mode_str));
+		str += strlen(mode_str);
+		*str++ = '\n';
+		str -= *len;
+	} else {
+		const char *unconfined_str = "unconfined\n";
+
+		*len = strlen(unconfined_str);
+		str = kmalloc(*len, GFP_ATOMIC);
+		if (!str)
+			return -ENOMEM;
+
+		memcpy(str, unconfined_str, *len);
+	}
+	*string = str;
+
+	return 0;
+}
+
+int aa_setprocattr_changehat(char *args)
+{
+	char *hat;
+	u64 magic;
+
+	magic = simple_strtoull(args, &hat, 16);
+	if (hat == args || *hat != '^') {
+		AA_ERROR("change_hat: Invalid input '%s'", args);
+		return -EINVAL;
+	}
+	hat++;  /* skip ^ */
+	if (!*hat)
+		hat = NULL;
+	if (!hat && !magic) {
+		AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic");
+		return -EINVAL;
+	}
+
+	AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",
+		 __FUNCTION__, magic, hat ? hat : NULL);
+
+	return aa_change_hat(hat, magic);
+}
+
+int aa_setprocattr_setprofile(struct task_struct *task, char *args)
+{
+	struct aa_profile *old_profile, *new_profile;
+
+	AA_DEBUG("%s: current %s(%d)\n",
+		 __FUNCTION__, current->comm, current->pid);
+
+repeat:
+	if (strcmp(args, "unconfined") == 0)
+		new_profile = NULL;
+	else {
+		new_profile = aa_find_profile(args);
+		if (!new_profile) {
+			AA_WARN(GFP_KERNEL,
+				"Unable to switch task %s(%d) to profile"
+				"'%s'. No such profile.",
+				task->comm, task->pid,
+				args);
+
+			return -EINVAL;
+		}
+	}
+
+	old_profile = __aa_replace_profile(task, new_profile, 0);
+	if (IS_ERR(old_profile)) {
+		int error;
+
+		aa_put_profile(new_profile);
+		error = PTR_ERR(old_profile);
+		if (error == -ESTALE)
+			goto repeat;
+		return error;
+	}
+
+	if (new_profile) {
+		AA_WARN(GFP_KERNEL,
+			"Switching task %s(%d) "
+			"profile %s active %s to new profile %s",
+			task->comm, task->pid,
+			old_profile ? old_profile->parent->name :
+				"unconfined",
+			old_profile ? old_profile->name : "unconfined",
+			args);
+	} else {
+		if (old_profile) {
+			AA_WARN(GFP_KERNEL,
+				"Unconfining task %s(%d) "
+				"profile %s active %s",
+				task->comm, task->pid,
+				old_profile->parent->name,
+				old_profile->name);
+		} else {
+			AA_WARN(GFP_KERNEL,
+				"task %s(%d) is already unconfined",
+				task->comm, task->pid);
+		}
+	}
+
+	aa_put_profile(old_profile);
+	aa_put_profile(new_profile);
+
+	return 0;
+}

-- 

  parent reply	other threads:[~2007-04-12  9:42 UTC|newest]

Thread overview: 190+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-04-12  9:08 [AppArmor 00/41] AppArmor security module overview jjohansen
2007-04-12  9:08 ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook jjohansen
2007-04-12 10:06   ` Christoph Hellwig
2007-04-16 16:11     ` [nameidata 1/2] Don't pass NULL nameidata to vfs_create Andreas Gruenbacher
2007-04-16 16:21       ` Christoph Hellwig
2007-04-16 16:40         ` Andreas Gruenbacher
2007-04-16 16:45           ` Christoph Hellwig
2007-04-17 12:09             ` Andreas Gruenbacher
2007-05-11 15:59         ` Andreas Gruenbacher
2007-04-16 16:25       ` Matthew Wilcox
2007-04-16 16:29     ` [nameidata 2/2] Pass no useless nameidata to the create, lookup, and permission IOPs Andreas Gruenbacher
2007-04-16 16:39       ` Christoph Hellwig
2007-04-16 16:42       ` Randy Dunlap
2007-04-16 16:44         ` Andreas Gruenbacher
2007-04-16 16:50           ` Randy Dunlap
2007-04-12 10:12   ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Al Viro
2007-05-23 19:06     ` Andreas Gruenbacher
2007-05-24  1:28       ` James Morris
2007-05-24  9:16         ` Andreas Gruenbacher
2007-05-24 12:51         ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook Tetsuo Handa
     [not found]         ` <200705241112.41101.agruen@suse.de>
2007-05-24 13:19           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook James Morris
2007-05-24 18:10             ` Andreas Gruenbacher
2007-05-24 18:40               ` Al Viro
2007-05-24 21:56                 ` Andreas Gruenbacher
2007-05-24 18:58               ` Casey Schaufler
2007-05-25  4:14                 ` Andreas Gruenbacher
2007-05-25  5:17                 ` Jeremy Maitin-Shepard
2007-05-25 17:43                   ` Casey Schaufler
2007-05-25 18:10                     ` Jeremy Maitin-Shepard
2007-05-25 18:13                       ` Jeremy Maitin-Shepard
2007-05-25 19:06                       ` Casey Schaufler
2007-05-26  1:40                         ` Tetsuo Handa
2007-05-26 12:10                         ` Andreas Gruenbacher
2007-05-26 22:58                           ` Casey Schaufler
2007-05-27  1:33                             ` Valdis.Kletnieks
2007-05-25 20:00                     ` Andreas Gruenbacher
2007-05-25 20:27                       ` Casey Schaufler
2007-05-26  5:27                         ` Crispin Cowan
2007-05-26 13:34                           ` Alan Cox
2007-05-26 14:05                             ` Andreas Gruenbacher
2007-05-26 18:41                           ` James Morris
2007-05-26  5:20                 ` Kyle Moffett
2007-05-26 11:46                   ` Andreas Gruenbacher
2007-05-26 12:09                     ` Tetsuo Handa
2007-05-26 13:41                       ` Andreas Gruenbacher
2007-05-26 14:44                         ` Tetsuo Handa
2007-05-26 16:52                           ` Andreas Gruenbacher
2007-05-26 18:16                           ` Kyle Moffett
2007-05-26 18:45                   ` [AppArmor 01/41] " James Morris
2007-05-26 23:08                     ` Toshiharu Harada
2007-05-27  2:10                       ` Kyle Moffett
2007-05-27  2:37                         ` Valdis.Kletnieks
2007-05-27  5:32                           ` Kyle Moffett
2007-05-28 20:38                             ` Pavel Machek
2007-05-29  2:00                               ` Kyle Moffett
2007-05-27  7:25                         ` Toshiharu Harada
2007-05-27 13:35                           ` Kyle Moffett
2007-05-28 10:41                             ` Toshiharu Harada
2007-05-29  1:54                               ` Kyle Moffett
2007-05-29 21:17                                 ` Valdis.Kletnieks
2007-05-30  5:52                                   ` Crispin Cowan
2007-05-24 14:40                                     ` Pavel Machek
2007-05-30 10:06                                     ` Alan Cox
2007-05-30  2:38                                 ` Toshiharu Harada
2007-05-27  8:34                   ` Cliffe
2007-05-27  8:34                     ` Cliffe
2007-05-27 13:07                     ` Kyle Moffett
2007-05-27 16:12                     ` Casey Schaufler
2007-05-27 16:12                       ` Casey Schaufler
     [not found]                       ` <465AE46B.4090109@iinet.net.au>
2007-05-28 22:29                         ` Crispin Cowan
2007-05-29 10:46                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSMhook Tetsuo Handa
2007-05-29 15:52                             ` Casey Schaufler
2007-05-29 19:58                               ` James Morris
2007-05-29 17:07                             ` Andreas Gruenbacher
2007-05-29 20:47                               ` Tetsuo Handa
2007-05-29 22:10                                 ` Andreas Gruenbacher
2007-05-30 11:38                                   ` Tetsuo Handa
2007-05-29 14:45                           ` [AppArmor 01/41] Pass struct vfsmount to the inode_create LSM hook Pavel Machek
2007-05-29 23:25                             ` david
2007-05-29 23:30                               ` Pavel Machek
2007-05-30  1:46                                 ` David Wagner
2007-05-24 14:47                                   ` Pavel Machek
2007-06-01 17:44                                     ` Valdis.Kletnieks
2007-06-01 18:00                                       ` david
2007-06-04 11:07                                         ` Pavel Machek
2007-06-02  4:30                                       ` David Wagner
2007-06-02  7:40                                         ` Valdis.Kletnieks
2007-06-02 14:27                                           ` david
2007-06-02 19:14                                             ` Valdis.Kletnieks
2007-06-02 19:51                                               ` david
2007-06-03  4:52                                                 ` Valdis.Kletnieks
2007-06-08 20:24                                         ` Pavel Machek
2007-06-08 21:54                                           ` Casey Schaufler
2007-05-30  5:42                             ` Crispin Cowan
2007-05-25  8:01             ` Toshiharu Harada
2007-04-12  9:08 ` [AppArmor 02/41] Remove redundant check from proc_setattr() jjohansen
2007-04-12  9:08 ` [AppArmor 03/41] Remove redundant check from proc_sys_setattr() jjohansen
2007-04-12 10:10   ` Alan Cox
2007-04-12  9:08 ` [AppArmor 04/41] Pass struct file down to remove_suid and children jjohansen
2007-04-12  9:08 ` [AppArmor 05/41] Add a vfsmount parameter to notify_change() jjohansen
2007-04-12  9:08 ` [AppArmor 06/41] Pass struct vfsmount to the inode_setattr LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 07/41] Add struct vfsmount parameter to vfs_mkdir() jjohansen
2007-04-12  9:08 ` [AppArmor 08/41] Pass struct vfsmount to the inode_mkdir LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 09/41] Add a struct vfsmount parameter to vfs_mknod() jjohansen
2007-04-12  9:08 ` [AppArmor 10/41] Pass struct vfsmount to the inode_mknod LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 11/41] Add a struct vfsmount parameter to vfs_symlink() jjohansen
2007-04-12  9:08 ` [AppArmor 12/41] Pass struct vfsmount to the inode_symlink LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 13/41] Pass struct vfsmount to the inode_readlink " jjohansen
2007-04-12  9:08 ` [AppArmor 14/41] Add struct vfsmount parameters to vfs_link() jjohansen
2007-04-12  9:08 ` [AppArmor 15/41] Pass the struct vfsmounts to the inode_link LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 16/41] Add a struct vfsmount parameter to vfs_rmdir() jjohansen
2007-04-12  9:08 ` [AppArmor 17/41] Pass struct vfsmount to the inode_rmdir LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 18/41] call lsm hook before unhashing dentry in vfs_rmdir() jjohansen
2007-04-12  9:08 ` [AppArmor 19/41] Add a struct vfsmount parameter to vfs_unlink() jjohansen
2007-04-12  9:08 ` [AppArmor 20/41] Pass struct vfsmount to the inode_unlink LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 21/41] Add struct vfsmount parameters to vfs_rename() jjohansen
2007-04-12  9:08 ` [AppArmor 22/41] Pass struct vfsmount to the inode_rename LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 23/41] Add a struct vfsmount parameter to vfs_setxattr() jjohansen
2007-04-12  9:08 ` [AppArmor 24/41] Pass struct vfsmount to the inode_setxattr LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 25/41] Add a struct vfsmount parameter to vfs_getxattr() jjohansen
2007-04-12  9:08 ` [AppArmor 26/41] Pass struct vfsmount to the inode_getxattr LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 27/41] Add a struct vfsmount parameter to vfs_listxattr() jjohansen
2007-04-12  9:08 ` [AppArmor 28/41] Pass struct vfsmount to the inode_listxattr LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 29/41] Add a struct vfsmount parameter to vfs_removexattr() jjohansen
2007-04-12  9:08 ` [AppArmor 30/41] Pass struct vfsmount to the inode_removexattr LSM hook jjohansen
2007-04-12  9:08 ` [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts jjohansen
2007-04-12  9:58   ` Alan Cox
2007-04-15 17:40     ` Andreas Gruenbacher
2007-04-16 21:57       ` Alan Cox
2007-04-17  1:35         ` Andreas Gruenbacher
2007-04-17 17:21           ` Alan Cox
2007-04-19 23:23             ` [d_path 0/7] Fixes to d_path: Respin Andreas Gruenbacher
2007-04-20  9:30               ` Alan Cox
2007-04-20 11:45                 ` Andreas Gruenbacher
2007-04-20 15:15                   ` Ulrich Drepper
2007-04-20 15:21                     ` Andreas Gruenbacher
2007-04-20 15:24                       ` Ulrich Drepper
2007-04-20 16:40                         ` Andreas Gruenbacher
2007-04-20 19:17                           ` Ulrich Drepper
2007-04-20 20:44                             ` Miklos Szeredi
2007-04-21 19:04                             ` Andreas Gruenbacher
2007-04-21 19:46                               ` Ulrich Drepper
2007-04-22  9:10                               ` Christoph Hellwig
2007-04-22 15:48                                 ` Andreas Gruenbacher
2007-04-19 23:23             ` [d_path 1/7] Fix __d_path() for lazy unmounts and make it unambiguous Andreas Gruenbacher
2007-04-20  9:32               ` Alan Cox
2007-04-19 23:23             ` [d_path 2/7] Make d_path() consistent across mount operations Andreas Gruenbacher
2007-04-19 23:23             ` [d_path 3/7] Add d_namespace_path() to compute namespace relative pathnames Andreas Gruenbacher
2007-04-21 12:57               ` Tetsuo Handa
2007-04-21 16:16                 ` Andreas Gruenbacher
2007-04-19 23:23             ` [d_path 4/7] Make getcwd() only return valid paths Andreas Gruenbacher
2007-04-19 23:23             ` [d_path 5/7] Remove duplicate proc code Andreas Gruenbacher
2007-04-19 23:23             ` [d_path 6/7] Filter out disconnected paths from /proc/mounts Andreas Gruenbacher
2007-04-20  9:34               ` Alan Cox
2007-04-19 23:23             ` [d_path 7/7] Distinguish between connected and disconnected paths in d_path() Andreas Gruenbacher
2007-04-17  6:30         ` [AppArmor 31/41] Fix __d_path() for lazy unmounts and make it unambiguous; exclude unreachable mount points from /proc/mounts Rob Meijer
2007-04-17  6:30           ` Rob Meijer
2007-04-12  9:08 ` [AppArmor 32/41] Make d_path() consistent across mount operations jjohansen
2007-04-12  9:08 ` [AppArmor 33/41] Add d_namespace_path() to obtain namespace relative pathnames jjohansen
2007-04-12 10:49   ` Al Viro
2007-04-12  9:08 ` [AppArmor 34/41] Enable LSM hooks to distinguish operations on file descriptors from operations on pathnames jjohansen
2007-04-12  9:08 ` [AppArmor 35/41] Pass struct file down the inode_*xattr security LSM hooks jjohansen
2007-04-12  9:08 ` [AppArmor 36/41] Export audit subsystem for use by modules jjohansen
2007-04-12  9:08 ` [AppArmor 37/41] AppArmor: Main Part jjohansen
2007-04-12 10:37   ` Alan Cox
2007-04-13  8:17     ` Andreas Gruenbacher
2007-04-13  8:48     ` Andreas Gruenbacher
2007-04-13  8:52       ` Nick Piggin
2007-04-12  9:08 ` [AppArmor 38/41] AppArmor: Module and LSM hooks jjohansen
2007-04-12 10:21   ` Alan Cox
2007-04-16 21:37     ` John Johansen
2007-04-12  9:08 ` [AppArmor 39/41] AppArmor: Profile loading and manipulation, pathname matching jjohansen
2007-04-12 10:28   ` Alan Cox
2007-04-12 13:46   ` Andi Kleen
2007-04-15 14:21     ` Andreas Gruenbacher
2007-04-16  6:27       ` Andi Kleen
2007-04-16 20:56         ` John Johansen
2007-04-16  7:39       ` Pavel Machek
2007-04-16 22:00       ` Alan Cox
2007-04-16 22:11         ` John Johansen
2007-04-12  9:08 ` jjohansen [this message]
2007-04-12 10:32   ` [AppArmor 40/41] AppArmor: all the rest Al Viro
2007-04-12 11:32     ` Al Viro
2007-04-12  9:08 ` [AppArmor 41/41] Add AppArmor LSM to security/Makefile jjohansen
2007-04-12 10:33 ` [AppArmor 00/41] AppArmor security module overview Shaya Potter
2007-04-12 13:50 ` Pavel Machek
2007-04-12 21:13   ` David Wagner
2007-04-16  7:46     ` Pavel Machek
2007-04-16 18:24       ` David Wagner
2007-04-13  8:04 ` Rob Meijer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070412090849.824835000@suse.de \
    --to=jjohansen@suse.de \
    --cc=agruen@suse.de \
    --cc=chrisw@sous-sol.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.