From: jjohansen@suse.de
To: akpm@linux-foundation.org
Cc: linux-kernel@vger.kernel.org,
linux-security-module@vger.kernel.org,
John Johansen <jjohansen@suse.de>,
Andreas Gruenbacher <agruen@suse.de>
Subject: [AppArmor 40/45] AppArmor: all the rest
Date: Thu, 25 Oct 2007 23:41:04 -0700 [thread overview]
Message-ID: <20071026064052.535304043@suse.de> (raw)
In-Reply-To: 20071026064024.243943043@suse.de
[-- Attachment #1: apparmor-misc.diff --]
[-- Type: text/plain, Size: 37499 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 | 326 +++++++++++++++++++++++++++++++++++++++++
security/apparmor/apparmorfs.c | 252 +++++++++++++++++++++++++++++++
security/apparmor/inline.h | 257 ++++++++++++++++++++++++++++++++
security/apparmor/list.c | 156 +++++++++++++++++++
security/apparmor/locking.txt | 68 ++++++++
security/apparmor/procattr.c | 194 ++++++++++++++++++++++++
8 files changed, 1275 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,326 @@
+/*
+ * 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, MAY_APPEND and the following flags
+ * for profile permissions
+ */
+#define AA_MAY_LINK 0x0010
+#define AA_MAY_LOCK 0x0020
+#define AA_EXEC_MMAP 0x0040
+#define AA_EXEC_UNSAFE 0x0080
+#define AA_EXEC_MOD_0 0x0100
+#define AA_EXEC_MOD_1 0x0200
+#define AA_BASE_PERMS (MAY_READ | MAY_WRITE | MAY_EXEC | \
+ MAY_APPEND | AA_MAY_LINK | \
+ AA_MAY_LOCK | AA_EXEC_MMAP | \
+ AA_EXEC_UNSAFE | AA_EXEC_MOD_0 | \
+ AA_EXEC_MOD_1)
+#define AA_LINK_SUBSET_TEST 0x0020
+
+#define AA_EXEC_UNCONFINED 0
+#define AA_EXEC_INHERIT AA_EXEC_MOD_0
+#define AA_EXEC_PROFILE AA_EXEC_MOD_1
+#define AA_EXEC_PIX (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
+
+#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
+
+#define AA_USER_SHIFT 0
+#define AA_GROUP_SHIFT 10
+#define AA_OTHER_SHIFT 20
+
+#define AA_USER_PERMS (AA_BASE_PERMS << AA_USER_SHIFT)
+#define AA_GROUP_PERMS (AA_BASE_PERMS << AA_GROUP_SHIFT)
+#define AA_OTHER_PERMS (AA_BASE_PERMS << AA_OTHER_SHIFT)
+
+#define AA_FILE_PERMS (AA_USER_PERMS | AA_GROUP_PERMS | \
+ AA_OTHER_PERMS)
+
+#define AA_LINK_BITS ((AA_MAY_LINK << AA_USER_SHIFT) | \
+ (AA_MAY_LINK << AA_GROUP_SHIFT) | \
+ (AA_MAY_LINK << AA_OTHER_SHIFT))
+
+#define AA_USER_EXEC (MAY_EXEC << AA_USER_SHIFT)
+#define AA_GROUP_EXEC (MAY_EXEC << AA_GROUP_SHIFT)
+#define AA_OTHER_EXEC (MAY_EXEC << AA_OTHER_SHIFT)
+
+#define AA_USER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_USER_SHIFT)
+#define AA_GROUP_EXEC_MODS (AA_EXEC_MODIFIERS << AA_GROUP_SHIFT)
+#define AA_OTHER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_OTHER_SHIFT)
+
+#define AA_EXEC_BITS (AA_USER_EXEC | AA_GROUP_EXEC | \
+ AA_OTHER_EXEC)
+
+#define AA_ALL_EXEC_MODS (AA_USER_EXEC_MODS | \
+ AA_GROUP_EXEC_MODS | \
+ AA_OTHER_EXEC_MODS)
+
+/* shared permissions that are not duplicated in user:group:other */
+#define AA_CHANGE_PROFILE 0x40000000
+
+#define AA_SHARED_PERMS (AA_CHANGE_PROFILE)
+
+#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_SHARED_PERMS)
+
+#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_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args)
+
+struct aa_profile;
+
+/* struct aa_namespace - namespace for a set of profiles
+ * @name: the name of the namespace
+ * @list: list the namespace is on
+ * @profiles: list of profile in the namespace
+ * @profile_count: the number of profiles in the namespace
+ * @null_complain_profile: special profile used for learning in this namespace
+ * @count: reference count on the namespace
+ * @lock: lock for adding/removing profile to the namespace
+ */
+struct aa_namespace {
+ char *name;
+ struct list_head list;
+ struct list_head profiles;
+ int profile_count;
+ struct aa_profile *null_complain_profile;
+
+ struct kref count;
+ rwlock_t lock;
+};
+
+/* struct aa_profile - basic confinement data
+ * @name: the profiles name
+ * @list: list this profile is on
+ * @ns: namespace the profile is in
+ * @file_rules: dfa containing the profiles file rules
+ * @flags: flags controlling profile behavior
+ * @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 all nonstale profile are in a profile namespace.
+ *
+ * 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 {
+ char *name;
+ struct list_head list;
+ struct aa_namespace *ns;
+
+ struct aa_dfa *file_rules;
+ struct {
+ int complain;
+ int audit;
+ } flags;
+ 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_ns_list;
+extern rwlock_t profile_ns_list_lock;
+extern struct mutex aa_interface_lock;
+
+/**
+ * struct aa_task_context - primary label for confined tasks
+ * @profile: the current profile
+ * @previous_profile: profile the task may return to
+ * @cookie: magic value the task must know for returning to @previous_profile
+ * @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;
+ struct aa_profile *previous_profile;
+ u64 cookie;
+ struct list_head list;
+ struct task_struct *task;
+ struct rcu_head rcu;
+ kernel_cap_t caps_logged;
+};
+
+extern struct aa_namespace *default_namespace;
+
+/* 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 {
+ const char *operation;
+ gfp_t gfp_mask;
+ const char *info;
+ const char *name;
+ const char *name2;
+ const char *name3;
+ int request_mask, denied_mask;
+ struct iattr *iattr;
+ pid_t task, parent;
+ int error_code;
+};
+
+/* Flags for the permission check functions */
+#define AA_CHECK_FD 1 /* coming from a file descriptor */
+#define AA_CHECK_DIR 2 /* file type is directory */
+
+/* lock subtypes so lockdep does not raise false dependencies */
+enum aa_lock_class {
+ aa_lock_normal,
+ aa_lock_nested,
+ aa_lock_task_release
+};
+
+/* main.c */
+extern int alloc_default_namespace(void);
+extern void free_default_namespace(void);
+extern int aa_audit_message(struct aa_profile *profile, struct aa_audit *sa,
+ int type);
+void aa_audit_hint(struct aa_profile *profile, struct aa_audit *sa);
+void aa_audit_status(struct aa_profile *profile, struct aa_audit *sa);
+int aa_audit_reject(struct aa_profile *profile, struct aa_audit *sa);
+extern int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp,
+ const char *);
+extern int aa_audit(struct aa_profile *profile, struct aa_audit *);
+
+extern int aa_attr(struct aa_profile *profile, struct dentry *dentry,
+ struct vfsmount *mnt, struct iattr *iattr);
+extern int aa_perm_xattr(struct aa_profile *profile, const char *operation,
+ struct dentry *dentry, struct vfsmount *mnt,
+ int mask, int check);
+extern int aa_capability(struct aa_task_context *cxt, int cap);
+extern int aa_perm(struct aa_profile *profile, const char *operation,
+ struct dentry *dentry, struct vfsmount *mnt, int mask,
+ int check);
+extern int aa_perm_dir(struct aa_profile *profile, const char *operation,
+ struct dentry *dentry, struct vfsmount *mnt,
+ int mask);
+extern int aa_perm_path(struct aa_profile *, const char *operation,
+ const char *name, int mask, uid_t, uid_t);
+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 int aa_change_profile(const char *ns_name, const char *name);
+extern struct aa_profile *__aa_replace_profile(struct task_struct *task,
+ struct aa_profile *profile);
+extern struct aa_task_context *lock_task_and_profiles(struct task_struct *task,
+ struct aa_profile *profile);
+extern void unlock_task_and_profiles(struct task_struct *task,
+ struct aa_task_context *cxt,
+ 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 cookie,
+ struct aa_profile *previous_profile);
+extern int aa_may_ptrace(struct aa_task_context *cxt,
+ struct aa_profile *tracee);
+
+/* list.c */
+extern struct aa_namespace *__aa_find_namespace(const char *name,
+ struct list_head *list);
+extern struct aa_profile *__aa_find_profile(const char *name,
+ struct list_head *list);
+extern void aa_profile_ns_list_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(char *, size_t);
+extern struct aa_namespace *alloc_aa_namespace(char *name);
+extern void free_aa_namespace(struct aa_namespace *ns);
+extern void free_aa_namespace_kref(struct kref *kref);
+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_changeprofile(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);
+extern unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start,
+ const char *str);
+extern unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
+ unsigned int start);
+
+#endif /* __APPARMOR_H */
--- /dev/null
+++ b/security/apparmor/apparmorfs.c
@@ -0,0 +1,252 @@
+/*
+ * 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 *operation)
+{
+ 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) {
+ struct aa_audit sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.operation = operation;
+ sa.gfp_mask = GFP_KERNEL;
+ sa.error_code = -EACCES;
+ data = ERR_PTR(aa_audit_reject(profile, &sa));
+ aa_put_profile(profile);
+ 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 perms=rwxamlz user:group:other";
+
+ 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, "profile_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,
+ "profile_replace");
+
+ 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,
+ "profile_remove");
+
+ 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 (!IS_ERR(dentry)) {
+ securityfs_remove(dentry);
+ dput(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,257 @@
+/*
+ * 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>
+
+#include "match.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 (struct aa_task_context *) rcu_dereference(task->security);
+}
+
+static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
+{
+ if (ns)
+ kref_get(&(ns->count));
+
+ return ns;
+}
+
+static inline void aa_put_namespace(struct aa_namespace *ns)
+{
+ if (ns)
+ kref_put(&ns->count, free_aa_namespace_kref);
+}
+
+
+static inline struct aa_namespace *aa_find_namespace(const char *name)
+{
+ struct aa_namespace *ns = NULL;
+
+ read_lock(&profile_ns_list_lock);
+ ns = aa_get_namespace(__aa_find_namespace(name, &profile_ns_list));
+ read_unlock(&profile_ns_list_lock);
+
+ return ns;
+}
+
+/**
+ * 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->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->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(struct aa_namespace *ns,
+ const char *name)
+{
+ struct aa_profile *profile = NULL;
+
+ read_lock(&ns->lock);
+ profile = aa_dup_profile(__aa_find_profile(name, &ns->profiles));
+ read_unlock(&ns->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);
+ aa_put_profile(cxt->previous_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_nested(struct aa_profile *profile,
+ enum aa_lock_class lock_class)
+{
+ /*
+ * 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_nested(&profile->lock, profile->int_flags,
+ lock_class);
+}
+
+static inline void lock_profile(struct aa_profile *profile)
+{
+ lock_profile_nested(profile, aa_lock_normal);
+}
+
+/**
+ * unlock_profile - unlock a profile
+ * @profile: the profile to unlock
+ */
+static inline void unlock_profile(struct aa_profile *profile)
+{
+ /* 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)
+{
+ /*
+ * 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_nested(&profile2->lock,
+ profile2->int_flags,
+ aa_lock_normal);
+ } else if (profile1 > profile2) {
+ /* profile1 cannot be NULL here. */
+ spin_lock_irqsave_nested(&profile1->lock, profile1->int_flags,
+ aa_lock_normal);
+ if (profile2)
+ spin_lock_nested(&profile2->lock, aa_lock_nested);
+
+ } else {
+ /* profile2 cannot be NULL here. */
+ spin_lock_irqsave_nested(&profile2->lock, profile2->int_flags,
+ aa_lock_normal);
+ spin_lock_nested(&profile1->lock, aa_lock_nested);
+ }
+}
+
+/**
+ * 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)
+{
+ /* 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;
+}
+
+static inline unsigned int aa_match_state(struct aa_dfa *dfa,
+ unsigned int start,
+ const char *pathname,
+ unsigned int *finish)
+{
+ unsigned int state;
+ if (dfa) {
+ state = aa_dfa_next_state(dfa, start, pathname);
+ if (finish)
+ *finish = state;
+ return ACCEPT_TABLE(dfa)[state];
+ }
+ if (finish)
+ *finish = 0;
+ return 0;
+}
+
+#endif /* __INLINE_H__ */
--- /dev/null
+++ b/security/apparmor/list.c
@@ -0,0 +1,156 @@
+/*
+ * 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 profile namespaces and lock */
+LIST_HEAD(profile_ns_list);
+rwlock_t profile_ns_list_lock = RW_LOCK_UNLOCKED;
+
+/**
+ * __aa_find_namespace - look up a profile namespace on the namespace list
+ * @name: name of namespace to find
+ * @head: list to search
+ *
+ * Returns a pointer to the namespace on the list, or NULL if no namespace
+ * called @name exists. The caller must hold the profile_ns_list_lock.
+ */
+struct aa_namespace *__aa_find_namespace(const char *name,
+ struct list_head *head)
+{
+ struct aa_namespace *ns;
+
+ list_for_each_entry(ns, head, list) {
+ if (!strcmp(ns->name, name))
+ return ns;
+ }
+
+ return NULL;
+}
+
+/**
+ * __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;
+}
+
+static void aa_profile_list_release(struct list_head *head)
+{
+ struct aa_profile *profile, *tmp;
+ list_for_each_entry_safe(profile, tmp, head, list) {
+ /* Remove the profile from each task context it is on. */
+ lock_profile(profile);
+ profile->isstale = 1;
+ aa_unconfine_tasks(profile);
+ list_del_init(&profile->list);
+ unlock_profile(profile);
+ aa_put_profile(profile);
+ }
+}
+
+/**
+ * aa_profilelist_release - Remove all profiles from profile_list
+ */
+void aa_profile_ns_list_release(void)
+{
+ struct aa_namespace *ns, *tmp;
+
+ /* Remove and release all the profiles on namespace profile lists. */
+ write_lock(&profile_ns_list_lock);
+ list_for_each_entry_safe(ns, tmp, &profile_ns_list, list) {
+ write_lock(&ns->lock);
+ aa_profile_list_release(&ns->profiles);
+ list_del_init(&ns->list);
+ write_unlock(&ns->lock);
+ aa_put_namespace(ns);
+ }
+ write_unlock(&profile_ns_list_lock);
+}
+
+static void *p_start(struct seq_file *f, loff_t *pos)
+{
+ struct aa_namespace *ns;
+ struct aa_profile *profile;
+ loff_t l = *pos;
+ read_lock(&profile_ns_list_lock);
+ if (l--)
+ return NULL;
+ list_for_each_entry(ns, &profile_ns_list, list) {
+ read_lock(&ns->lock);
+ list_for_each_entry(profile, &ns->profiles, list)
+ return profile;
+ read_unlock(&ns->lock);
+ }
+ return NULL;
+}
+
+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
+{
+ struct aa_profile *profile = (struct aa_profile *) p;
+ struct list_head *lh = profile->list.next;
+ struct aa_namespace *ns;
+ (*pos)++;
+ if (lh != &profile->ns->profiles)
+ return list_entry(lh, struct aa_profile, list);
+
+ lh = profile->ns->list.next;
+ read_unlock(&profile->ns->lock);
+ while (lh != &profile_ns_list) {
+ ns = list_entry(lh, struct aa_namespace, list);
+ read_lock(&ns->lock);
+ list_for_each_entry(profile, &ns->profiles, list)
+ return profile;
+ read_unlock(&ns->lock);
+ lh = ns->list.next;
+ }
+ return NULL;
+}
+
+static void p_stop(struct seq_file *f, void *v)
+{
+ read_unlock(&profile_ns_list_lock);
+}
+
+static int seq_show_profile(struct seq_file *f, void *v)
+{
+ struct aa_profile *profile = (struct aa_profile *)v;
+ if (profile->ns == default_namespace)
+ seq_printf(f, "%s (%s)\n", profile->name,
+ PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
+ else
+ seq_printf(f, "%s:%s (%s)\n", profile->ns->name, 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,68 @@
+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.
+
+AppArmor uses lock subtyping to avoid false positives from lockdep. The
+profile lock is often taken nested, but it is guaranteed to be in a lock
+safe order and not the same lock when done, so it is safe.
+
+A third lock type (aa_lock_task_release) is given to the profile lock
+when it is taken in soft irq context during task release (aa_release).
+This is to avoid a false positive between the task lock and the profile
+lock. In task context the profile lock wraps the task lock with irqs
+off, but the kernel takes the task lock with irqs enabled. This won't
+result in a deadlock because for a deadlock to occur the kernel must
+take dead task A's lock (irqs on), the rcu callback hook freeing
+dead task A must be run and AppArmor must be changing the profile on
+dead task A. The kernel should not be taking a dead task's task_lock
+at the same time the task is being freed by task rcu cleanup other wise
+the task would not be out of its quiescent period.
--- /dev/null
+++ b/security/apparmor/procattr.c
@@ -0,0 +1,194 @@
+/*
+ * 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)";
+ int mode_len, name_len, ns_len = 0;
+
+ mode_len = strlen(mode_str);
+ name_len = strlen(profile->name);
+ if (profile->ns != default_namespace)
+ ns_len = strlen(profile->ns->name) + 1;
+ *len = mode_len + ns_len + name_len + 1;
+ str = kmalloc(*len, GFP_ATOMIC);
+ if (!str)
+ return -ENOMEM;
+
+ if (ns_len) {
+ memcpy(str, profile->ns->name, ns_len - 1);
+ str += ns_len - 1;
+ *str++ = ':';
+ }
+ memcpy(str, profile->name, name_len);
+ str += name_len;
+ memcpy(str, mode_str, mode_len);
+ str += mode_len;
+ *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;
+}
+
+static char *split_token_from_name(const char *op, char *args, u64 *cookie)
+{
+ char *name;
+
+ *cookie = simple_strtoull(args, &name, 16);
+ if ((name == args) || *name != '^') {
+ AA_ERROR("%s: Invalid input '%s'", op, args);
+ return ERR_PTR(-EINVAL);
+ }
+
+ name++; /* skip ^ */
+ if (!*name)
+ name = NULL;
+ return name;
+}
+
+int aa_setprocattr_changehat(char *args)
+{
+ char *hat;
+ u64 cookie;
+
+ hat = split_token_from_name("change_hat", args, &cookie);
+ if (IS_ERR(hat))
+ return PTR_ERR(hat);
+
+ if (!hat && !cookie) {
+ AA_ERROR("change_hat: Invalid input, NULL hat and NULL magic");
+ return -EINVAL;
+ }
+
+ AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",
+ __FUNCTION__, cookie, hat ? hat : NULL);
+
+ return aa_change_hat(hat, cookie);
+}
+
+int aa_setprocattr_changeprofile(char *args)
+{
+ char *name = args, *ns_name = NULL;
+
+ if (name[0] != '/') {
+ char *split = strchr(name, ':');
+ if (split) {
+ *split = 0;
+ ns_name = name;
+ name = split + 1;
+ }
+ }
+
+ return aa_change_profile(ns_name, name);
+}
+
+int aa_setprocattr_setprofile(struct task_struct *task, char *args)
+{
+ struct aa_profile *old_profile, *new_profile;
+ struct aa_namespace *ns;
+ struct aa_audit sa;
+ char *name, *ns_name = NULL;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.operation = "profile_set";
+ sa.gfp_mask = GFP_KERNEL;
+ sa.task = task->pid;
+
+ AA_DEBUG("%s: current %d\n",
+ __FUNCTION__, current->pid);
+
+ name = args;
+ if (args[0] != '/') {
+ char *split = strchr(args, ':');
+ if (split) {
+ *split = 0;
+ ns_name = args;
+ name = split + 1;
+ }
+ }
+ if (ns_name)
+ ns = aa_find_namespace(ns_name);
+ else
+ ns = aa_get_namespace(default_namespace);
+ if (!ns) {
+ sa.name = ns_name;
+ sa.info = "unknown namespace";
+ aa_audit_reject(NULL, &sa);
+ aa_put_namespace(ns);
+ return -EINVAL;
+ }
+
+repeat:
+ if (strcmp(name, "unconfined") == 0)
+ new_profile = NULL;
+ else {
+ new_profile = aa_find_profile(ns, name);
+ if (!new_profile) {
+ sa.name = ns_name;
+ sa.name2 = name;
+ sa.info = "unknown profile";
+ aa_audit_reject(NULL, &sa);
+ aa_put_namespace(ns);
+ return -EINVAL;
+ }
+ }
+
+ old_profile = __aa_replace_profile(task, new_profile);
+ if (IS_ERR(old_profile)) {
+ int error;
+
+ aa_put_profile(new_profile);
+ error = PTR_ERR(old_profile);
+ if (error == -ESTALE)
+ goto repeat;
+ aa_put_namespace(ns);
+ return error;
+ }
+
+ if (new_profile) {
+ sa.name = ns_name;
+ sa.name2 = name;
+ sa.name3 = old_profile ? old_profile->name :
+ "unconfined";
+ aa_audit_status(NULL, &sa);
+ } else {
+ if (old_profile) {
+ sa.name = "unconfined";
+ sa.name2 = old_profile->name;
+ aa_audit_status(NULL, &sa);
+ } else {
+ sa.info = "task is unconfined";
+ aa_audit_status(NULL, &sa);
+ }
+ }
+ aa_put_namespace(ns);
+ aa_put_profile(old_profile);
+ aa_put_profile(new_profile);
+ return 0;
+}
--
next prev parent reply other threads:[~2007-10-26 7:13 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-10-26 6:40 [AppArmor 00/45] AppArmor security module overview jjohansen
2007-10-26 6:40 ` [AppArmor 01/45] Pass struct vfsmount to the inode_create LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 02/45] Pass struct path down to remove_suid and children jjohansen
2007-10-26 6:40 ` [AppArmor 03/45] Add a vfsmount parameter to notify_change() jjohansen
2007-10-26 6:40 ` [AppArmor 04/45] Pass struct vfsmount to the inode_setattr LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 05/45] Add struct vfsmount parameter to vfs_mkdir() jjohansen
2007-10-26 6:40 ` [AppArmor 06/45] Pass struct vfsmount to the inode_mkdir LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 07/45] Add a struct vfsmount parameter to vfs_mknod() jjohansen
2007-10-26 6:40 ` [AppArmor 08/45] Pass struct vfsmount to the inode_mknod LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 09/45] Add a struct vfsmount parameter to vfs_symlink() jjohansen
2007-10-26 6:40 ` [AppArmor 10/45] Pass struct vfsmount to the inode_symlink LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 11/45] Pass struct vfsmount to the inode_readlink " jjohansen
2007-10-26 6:40 ` [AppArmor 12/45] Add struct vfsmount parameters to vfs_link() jjohansen
2007-10-26 6:40 ` [AppArmor 13/45] Pass the struct vfsmounts to the inode_link LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 14/45] Add a struct vfsmount parameter to vfs_rmdir() jjohansen
2007-10-26 6:40 ` [AppArmor 15/45] Pass struct vfsmount to the inode_rmdir LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 16/45] Call lsm hook before unhashing dentry in vfs_rmdir() jjohansen
2007-10-26 6:40 ` [AppArmor 17/45] Add a struct vfsmount parameter to vfs_unlink() jjohansen
2007-10-26 6:40 ` [AppArmor 18/45] Pass struct vfsmount to the inode_unlink LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 19/45] Add struct vfsmount parameters to vfs_rename() jjohansen
2007-10-26 7:37 ` Al Viro
2007-10-26 18:23 ` John Johansen
2007-10-26 20:33 ` Al Viro
2007-10-26 6:40 ` [AppArmor 20/45] Pass struct vfsmount to the inode_rename LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 21/45] Add a struct vfsmount parameter to vfs_setxattr() jjohansen
2007-10-26 6:40 ` [AppArmor 22/45] Pass struct vfsmount to the inode_setxattr LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 23/45] Add a struct vfsmount parameter to vfs_getxattr() jjohansen
2007-10-26 6:40 ` [AppArmor 24/45] Pass struct vfsmount to the inode_getxattr LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 25/45] Add a struct vfsmount parameter to vfs_listxattr() jjohansen
2007-10-26 6:40 ` [AppArmor 26/45] Pass struct vfsmount to the inode_listxattr LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 27/45] Add a struct vfsmount parameter to vfs_removexattr() jjohansen
2007-10-26 6:40 ` [AppArmor 28/45] Pass struct vfsmount to the inode_removexattr LSM hook jjohansen
2007-10-26 6:40 ` [AppArmor 29/45] Fix __d_path() for lazy unmounts and make it unambiguous jjohansen
2007-10-26 6:40 ` [AppArmor 30/45] Make d_path() consistent across mount operations jjohansen
2007-10-26 6:40 ` [AppArmor 31/45] Add d_namespace_path() to compute namespace relative pathnames jjohansen
2007-10-26 6:40 ` [AppArmor 32/45] Enable LSM hooks to distinguish operations on file descriptors from operations on pathnames jjohansen
2007-10-26 11:30 ` Miklos Szeredi
2007-10-26 11:45 ` Miklos Szeredi
2007-10-26 18:49 ` John Johansen
2007-10-26 20:24 ` Andreas Gruenbacher
2007-10-26 20:58 ` Miklos Szeredi
2007-10-26 21:56 ` Andreas Gruenbacher
2007-10-26 6:40 ` [AppArmor 33/45] Pass struct file down the inode_*xattr security LSM hooks jjohansen
2007-10-26 6:40 ` [AppArmor 34/45] Factor out sysctl pathname code jjohansen
2007-10-26 9:24 ` James Morris
2007-10-26 6:40 ` [AppArmor 35/45] Allow permission functions to tell between parent and leaf checks jjohansen
2007-10-26 12:32 ` Stephen Smalley
2007-10-26 18:26 ` John Johansen
2007-10-26 6:41 ` [AppArmor 36/45] Export audit subsystem for use by modules jjohansen
2007-10-26 6:41 ` [AppArmor 37/45] AppArmor: Main Part jjohansen
2007-10-26 6:41 ` [AppArmor 38/45] AppArmor: Module and LSM hooks jjohansen
2007-10-26 6:41 ` [AppArmor 39/45] AppArmor: Profile loading and manipulation, pathname matching jjohansen
2007-10-26 6:41 ` jjohansen [this message]
2007-10-26 6:41 ` [AppArmor 41/45] add simple network toggles to apparmor jjohansen
2007-10-26 6:41 ` [AppArmor 42/45] Add AppArmor LSM to security/Makefile jjohansen
2007-10-26 6:41 ` [AppArmor 43/45] Switch to vfs_permission() in do_path_lookup() jjohansen
2007-10-26 6:41 ` [AppArmor 44/45] Switch to vfs_permission() in sys_fchdir() jjohansen
2007-10-26 6:41 ` [AppArmor 45/45] Fix file_permission() jjohansen
2007-10-26 7:04 ` [AppArmor 00/45] AppArmor security module overview John Johansen
2007-10-26 14:37 ` Arjan van de Ven
2007-10-26 18:34 ` John Johansen
2007-10-26 20:15 ` Arjan van de Ven
2007-10-26 20:44 ` Andreas Gruenbacher
2007-10-26 21:13 ` Arjan van de Ven
2007-10-26 21:24 ` Andreas Gruenbacher
2007-10-26 22:16 ` Crispin Cowan
2007-10-26 22:23 ` Arjan van de Ven
2007-10-27 20:47 ` Christoph Hellwig
2007-10-28 14:25 ` Andreas Gruenbacher
-- strict thread matches above, loose matches on Subject: below --
2007-05-14 11:06 jjohansen
2007-05-14 11:06 ` [AppArmor 40/45] AppArmor: all the rest jjohansen
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=20071026064052.535304043@suse.de \
--to=jjohansen@suse.de \
--cc=agruen@suse.de \
--cc=akpm@linux-foundation.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.