2007-05-14 11:51:00

by John Johansen

[permalink] [raw]
Subject: [AppArmor 38/45] AppArmor: Module and LSM hooks

Module parameters, LSM hooks, initialization and teardown.

Signed-off-by: John Johansen <[email protected]>
Signed-off-by: Andreas Gruenbacher <[email protected]>

Index: b/security/apparmor/lsm.c
===================================================================
--- /dev/null
+++ b/security/apparmor/lsm.c
@@ -0,0 +1,790 @@
+/*
+ * 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 LSM interface
+ */
+
+#include <linux/security.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+
+#include "apparmor.h"
+#include "inline.h"
+
+static int param_set_aabool(const char *val, struct kernel_param *kp);
+static int param_get_aabool(char *buffer, struct kernel_param *kp);
+#define param_check_aabool(name, p) __param_check(name, p, int)
+
+static int param_set_aauint(const char *val, struct kernel_param *kp);
+static int param_get_aauint(char *buffer, struct kernel_param *kp);
+#define param_check_aauint(name, p) __param_check(name, p, int)
+
+/* Flag values, also controllable via /sys/module/apparmor/parameters
+ * We define special types as we want to do additional mediation.
+ *
+ * Complain mode -- in complain 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, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_complain, "Toggle AppArmor complain mode");
+
+/* Debug mode */
+int apparmor_debug = 0;
+module_param_named(debug, apparmor_debug, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_debug, "Toggle AppArmor debug mode");
+
+/* Audit mode */
+int apparmor_audit = 0;
+module_param_named(audit, apparmor_audit, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_audit, "Toggle AppArmor audit mode");
+
+/* Syscall logging mode */
+int apparmor_logsyscall = 0;
+module_param_named(logsyscall, apparmor_logsyscall, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_logsyscall, "Toggle AppArmor logsyscall mode");
+
+/* Maximum pathname length before accesses will start getting rejected */
+unsigned int apparmor_path_max = 2 * PATH_MAX;
+module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");
+
+static int param_set_aabool(const char *val, struct kernel_param *kp)
+{
+ if (aa_task_context(current))
+ return -EPERM;
+ return param_set_bool(val, kp);
+}
+
+static int param_get_aabool(char *buffer, struct kernel_param *kp)
+{
+ if (aa_task_context(current))
+ return -EPERM;
+ return param_get_bool(buffer, kp);
+}
+
+static int param_set_aauint(const char *val, struct kernel_param *kp)
+{
+ if (aa_task_context(current))
+ return -EPERM;
+ return param_set_uint(val, kp);
+}
+
+static int param_get_aauint(char *buffer, struct kernel_param *kp)
+{
+ if (aa_task_context(current))
+ return -EPERM;
+ return param_get_uint(buffer, kp);
+}
+
+static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
+ const char *name)
+{
+ struct aa_profile *profile = aa_get_profile(task);
+ int error = 0;
+
+ if (profile) {
+ error = aa_audit_syscallreject(profile, flags, name);
+ aa_put_profile(profile);
+ }
+
+ return error;
+}
+
+static int apparmor_ptrace(struct task_struct *parent,
+ struct task_struct *child)
+{
+ struct aa_task_context *cxt;
+ struct aa_task_context *child_cxt;
+ struct aa_profile *child_profile;
+ int error = 0;
+
+ /*
+ * parent can ptrace child when
+ * - parent is unconfined
+ * - 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;
+ if (cxt && (parent->nsproxy != child->nsproxy)) {
+ aa_audit_message(NULL, 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)) {
+ aa_audit_message(cxt->profile, GFP_ATOMIC,
+ "LOGPROF-HINT ptrace pid=%d child=%d "
+ "(%d profile %s active %s)",
+ current->pid, child->pid, current->pid,
+ cxt->profile->parent->name,
+ cxt->profile->name);
+ }
+ }
+ rcu_read_unlock();
+
+ return error;
+}
+
+static int apparmor_capable(struct task_struct *task, int cap)
+{
+ int error;
+
+ /* cap_capable returns 0 on success, else -EPERM */
+ error = cap_capable(task, cap);
+
+ if (!error) {
+ struct aa_task_context *cxt;
+
+ rcu_read_lock();
+ cxt = aa_task_context(task);
+ if (cxt)
+ error = aa_capability(cxt, cap);
+ rcu_read_unlock();
+ }
+
+ return error;
+}
+
+static int apparmor_sysctl(struct ctl_table *table, int op)
+{
+ struct aa_profile *profile = aa_get_profile(current);
+ int error = 0;
+
+ if (profile) {
+ char *buffer, *name;
+ int mask;
+
+ mask = 0;
+ if (op & 4)
+ mask |= MAY_READ;
+ if (op & 2)
+ mask |= MAY_WRITE;
+
+ error = -ENOMEM;
+ buffer = (char*)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ goto out;
+ name = sysctl_pathname(table, buffer, PAGE_SIZE);
+ if (name && name - buffer >= 5) {
+ name -= 5;
+ memcpy(name, "/proc", 5);
+ error = aa_perm_path(profile, name, mask);
+ }
+ free_page((unsigned long)buffer);
+ }
+
+out:
+ return error;
+}
+
+static int apparmor_bprm_set_security(struct linux_binprm *bprm)
+{
+ /* handle capability bits with setuid, etc */
+ cap_bprm_set_security(bprm);
+ /* already set based on script name */
+ if (bprm->sh_bang)
+ return 0;
+ return aa_register(bprm);
+}
+
+static int apparmor_bprm_secureexec(struct linux_binprm *bprm)
+{
+ int ret = cap_bprm_secureexec(bprm);
+
+ if (!ret && (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) {
+ AA_DEBUG("%s: secureexec required for %s\n",
+ __FUNCTION__, bprm->filename);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int apparmor_sb_mount(char *dev_name, struct nameidata *nd, char *type,
+ unsigned long flags, void *data)
+{
+ return aa_reject_syscall(current, GFP_KERNEL, "mount");
+}
+
+static int apparmor_umount(struct vfsmount *mnt, int flags)
+{
+ return aa_reject_syscall(current, GFP_KERNEL, "umount");
+}
+
+static int apparmor_inode_mkdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mask)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (!mnt || !mediated_filesystem(dir))
+ goto out;
+
+ profile = aa_get_profile(current);
+
+ if (profile)
+ error = aa_perm_dir(profile, dentry, mnt, "mkdir", MAY_WRITE);
+
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int apparmor_inode_rmdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (!mnt || !mediated_filesystem(dir))
+ goto out;
+
+ profile = aa_get_profile(current);
+
+ if (profile)
+ error = aa_perm_dir(profile, dentry, mnt, "rmdir", MAY_WRITE);
+
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int aa_permission(struct inode *inode, struct dentry *dentry,
+ struct vfsmount *mnt, int mask, int check)
+{
+ int error = 0;
+
+ if (mnt && mediated_filesystem(inode)) {
+ struct aa_profile *profile;
+
+ profile = aa_get_profile(current);
+ if (profile)
+ error = aa_perm(profile, dentry, mnt, mask, check);
+ aa_put_profile(profile);
+ }
+ return error;
+}
+
+static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mask)
+{
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, 0);
+}
+
+static int apparmor_inode_link(struct dentry *old_dentry,
+ struct vfsmount *old_mnt, struct inode *dir,
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
+{
+ int error = 0;
+ struct aa_profile *profile;
+
+ if (!old_mnt || !new_mnt || !mediated_filesystem(dir))
+ goto out;
+
+ profile = aa_get_profile(current);
+
+ if (profile)
+ error = aa_link(profile, new_dentry, new_mnt,
+ old_dentry, old_mnt);
+
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int apparmor_inode_unlink(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt)
+{
+ int check = 0;
+
+ if (S_ISDIR(dentry->d_inode->i_mode))
+ check |= AA_CHECK_DIR;
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, check);
+}
+
+static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, const char *old_name)
+{
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, 0);
+}
+
+static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode, dev_t dev)
+{
+ return aa_permission(dir, dentry, mnt, MAY_WRITE, 0);
+}
+
+static int apparmor_inode_rename(struct inode *old_dir,
+ struct dentry *old_dentry,
+ struct vfsmount *old_mnt,
+ struct inode *new_dir,
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if ((!old_mnt && !new_mnt) || !mediated_filesystem(old_dir))
+ goto out;
+
+ profile = aa_get_profile(current);
+
+ if (profile) {
+ struct inode *inode = old_dentry->d_inode;
+ int check = 0;
+
+ if (inode && S_ISDIR(inode->i_mode))
+ check |= AA_CHECK_DIR;
+ if (old_mnt)
+ error = aa_perm(profile, old_dentry, old_mnt,
+ MAY_READ | MAY_WRITE, check);
+
+ if (!error && new_mnt) {
+ error = aa_perm(profile, new_dentry, new_mnt,
+ MAY_WRITE, check);
+ }
+ }
+
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int apparmor_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ int check = 0;
+
+ if (!nd || nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE))
+ return 0;
+ mask &= (MAY_READ | MAY_WRITE | MAY_EXEC);
+ if (S_ISDIR(inode->i_mode)) {
+ check |= AA_CHECK_DIR;
+ /* allow traverse accesses to directories */
+ mask &= ~MAY_EXEC;
+ }
+ return aa_permission(inode, nd->dentry, nd->mnt, mask, check);
+}
+
+static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
+ struct iattr *iattr)
+{
+ int error = 0;
+
+ if (!mnt)
+ goto out;
+
+ if (mediated_filesystem(dentry->d_inode)) {
+ struct aa_profile *profile;
+
+ profile = aa_get_profile(current);
+ /*
+ * Mediate any attempt to change attributes of a file
+ * (chmod, chown, chgrp, etc)
+ */
+ if (profile)
+ error = aa_attr(profile, dentry, mnt, iattr);
+
+ aa_put_profile(profile);
+ }
+
+out:
+ return error;
+}
+
+static int aa_xattr_permission(struct dentry *dentry, struct vfsmount *mnt,
+ const char *operation, int mask,
+ struct file *file)
+{
+ int error = 0;
+
+ if (mnt && mediated_filesystem(dentry->d_inode)) {
+ struct aa_profile *profile = aa_get_profile(current);
+ int check = file ? AA_CHECK_FD : 0;
+
+ if (profile)
+ error = aa_perm_xattr(profile, dentry, mnt, operation,
+ mask, check);
+ aa_put_profile(profile);
+ }
+
+ return error;
+}
+
+static int apparmor_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name, void *value, size_t size,
+ int flags, struct file *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, "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, "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, "xattr remove", MAY_WRITE,
+ file);
+}
+
+static int apparmor_file_permission(struct file *file, int mask)
+{
+ struct aa_profile *profile;
+ struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
+ int error = 0;
+
+ if (!file_profile)
+ goto out;
+
+ /*
+ * If this file was opened under a different profile, we
+ * revalidate the access against the current profile.
+ */
+ profile = aa_get_profile(current);
+ if (profile && file_profile != profile) {
+ struct dentry *dentry = file->f_dentry;
+ struct vfsmount *mnt = file->f_vfsmnt;
+ struct inode *inode = dentry->d_inode;
+ int check = AA_CHECK_FD;
+
+ /*
+ * FIXME: We should remember which profiles we revalidated
+ * against.
+ */
+ if (S_ISDIR(inode->i_mode))
+ check |= AA_CHECK_DIR;
+ mask &= (MAY_READ | MAY_WRITE | MAY_EXEC);
+ error = aa_permission(inode, dentry, mnt, mask, check);
+ }
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int apparmor_file_alloc_security(struct file *file)
+{
+ struct aa_profile *profile;
+
+ profile = aa_get_profile(current);
+ if (profile)
+ file->f_security = profile;
+
+ return 0;
+}
+
+static void apparmor_file_free_security(struct file *file)
+{
+ struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
+
+ aa_put_profile(file_profile);
+}
+
+static inline int aa_mmap(struct file *file, unsigned long prot,
+ unsigned long flags)
+{
+ struct dentry *dentry;
+ int mask = 0;
+
+ if (!file || !file->f_security)
+ return 0;
+
+ if (prot & PROT_READ)
+ mask |= MAY_READ;
+ /* Private mappings don't require write perms since they don't
+ * write back to the files */
+ if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
+ mask |= MAY_WRITE;
+ if (prot & PROT_EXEC)
+ mask |= AA_EXEC_MMAP;
+
+ dentry = file->f_dentry;
+ return aa_permission(dentry->d_inode, dentry, file->f_vfsmnt, mask,
+ AA_CHECK_FD);
+}
+
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags)
+{
+ return aa_mmap(file, prot, flags);
+}
+
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
+ unsigned long reqprot, unsigned long prot)
+{
+ return aa_mmap(vma->vm_file, prot,
+ !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
+}
+
+static int apparmor_task_alloc_security(struct task_struct *task)
+{
+ return aa_clone(task);
+}
+
+/*
+ * Called from IRQ context from RCU callback.
+ */
+static void apparmor_task_free_security(struct task_struct *task)
+{
+ aa_release(task);
+}
+
+static int apparmor_getprocattr(struct task_struct *task, char *name,
+ char **value)
+{
+ unsigned len;
+ int error;
+ struct aa_profile *profile;
+
+ /* AppArmor only supports the "current" process attribute */
+ if (strcmp(name, "current") != 0)
+ return -EINVAL;
+
+ /* must be task querying itself or admin */
+ if (current != task && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ profile = aa_get_profile(task);
+ error = aa_getprocattr(profile, value, &len);
+ aa_put_profile(profile);
+ if (!error)
+ error = len;
+
+ return error;
+}
+
+static int apparmor_setprocattr(struct task_struct *task, char *name,
+ void *value, size_t size)
+{
+ char *command, *args;
+ int error;
+
+ if (strcmp(name, "current") != 0 || size == 0 || size >= PAGE_SIZE)
+ return -EINVAL;
+ args = value;
+ args[size] = '\0';
+ args = strstrip(args);
+ command = strsep(&args, " ");
+ if (!args)
+ return -EINVAL;
+ while (isspace(*args))
+ args++;
+ if (!*args)
+ return -EINVAL;
+
+ if (strcmp(command, "changehat") == 0) {
+ if (current != task)
+ return -EACCES;
+ error = aa_setprocattr_changehat(args);
+ } else if (strcmp(command, "setprofile")) {
+ struct aa_profile *profile;
+
+ /* Only an unconfined process with admin capabilities
+ * may change the profile of another task.
+ */
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ profile = aa_get_profile(current);
+ if (profile) {
+ aa_put_profile(profile);
+ aa_audit_message(NULL, GFP_KERNEL, "Attempt by "
+ "confined task %d [user %d] to "
+ "assign profile to task %d",
+ current->pid, current->uid,
+ task->pid);
+ return -EACCES;
+ }
+ error = aa_setprocattr_setprofile(task, args);
+ } else {
+ AA_ERROR("Unknown setprocattr command '%.*s' "
+ "by task %d [user %d] for task %d",
+ size < 16 ? (int)size : 16,
+ command,
+ current->pid,
+ current->uid,
+ task->pid);
+ error = -EINVAL;
+ }
+
+ if (!error)
+ error = size;
+ return error;
+}
+
+struct security_operations apparmor_ops = {
+ .ptrace = apparmor_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .sysctl = apparmor_sysctl,
+ .capable = apparmor_capable,
+ .syslog = cap_syslog,
+
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = apparmor_bprm_set_security,
+ .bprm_secureexec = apparmor_bprm_secureexec,
+
+ .sb_mount = apparmor_sb_mount,
+ .sb_umount = apparmor_umount,
+
+ .inode_mkdir = apparmor_inode_mkdir,
+ .inode_rmdir = apparmor_inode_rmdir,
+ .inode_create = apparmor_inode_create,
+ .inode_link = apparmor_inode_link,
+ .inode_unlink = apparmor_inode_unlink,
+ .inode_symlink = apparmor_inode_symlink,
+ .inode_mknod = apparmor_inode_mknod,
+ .inode_rename = apparmor_inode_rename,
+ .inode_permission = apparmor_inode_permission,
+ .inode_setattr = apparmor_inode_setattr,
+ .inode_setxattr = apparmor_inode_setxattr,
+ .inode_getxattr = apparmor_inode_getxattr,
+ .inode_listxattr = apparmor_inode_listxattr,
+ .inode_removexattr = apparmor_inode_removexattr,
+ .file_permission = apparmor_file_permission,
+ .file_alloc_security = apparmor_file_alloc_security,
+ .file_free_security = apparmor_file_free_security,
+ .file_mmap = apparmor_file_mmap,
+ .file_mprotect = apparmor_file_mprotect,
+
+ .task_alloc_security = apparmor_task_alloc_security,
+ .task_free_security = apparmor_task_free_security,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+
+ .getprocattr = apparmor_getprocattr,
+ .setprocattr = apparmor_setprocattr,
+};
+
+static void info_message(const char *str)
+{
+ printk(KERN_INFO "AppArmor: %s", str);
+ aa_audit_message(NULL, GFP_KERNEL, "%s", str);
+}
+
+static int __init apparmor_init(void)
+{
+ int error;
+
+ 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");
+ goto alloc_out;
+ }
+
+ if ((error = register_security(&apparmor_ops))) {
+ AA_ERROR("Unable to load AppArmor\n");
+ goto register_security_out;
+ }
+
+ if (apparmor_complain)
+ info_message("AppArmor initialized: complainmode enabled");
+ else
+ info_message("AppArmor initialized");
+
+ return error;
+
+register_security_out:
+ free_null_complain_profile();
+
+alloc_out:
+ destroy_apparmorfs();
+
+createfs_out:
+ return error;
+
+}
+
+static void __exit apparmor_exit(void)
+{
+ /* Remove and release all the profiles on the profile list. */
+ mutex_lock(&aa_interface_lock);
+ write_lock(&profile_list_lock);
+ while (!list_empty(&profile_list)) {
+ struct aa_profile *profile =
+ list_entry(profile_list.next, struct aa_profile, list);
+
+ /* Remove the profile from each task context it is on. */
+ lock_profile(profile);
+ profile->isstale = 1;
+ aa_unconfine_tasks(profile);
+ unlock_profile(profile);
+
+ /* Release the profile itself. */
+ list_del_init(&profile->list);
+ aa_put_profile(profile);
+ }
+ write_unlock(&profile_list_lock);
+
+ /* FIXME: cleanup profiles references on files */
+
+ free_null_complain_profile();
+
+ /*
+ * Delay for an rcu cycle to make sure that all active task
+ * context readers have finished, and all profiles have been
+ * freed by their rcu callbacks.
+ */
+ synchronize_rcu();
+
+ destroy_apparmorfs();
+ mutex_unlock(&aa_interface_lock);
+
+ if (unregister_security(&apparmor_ops))
+ info_message("Unable to properly unregister AppArmor");
+
+ info_message("AppArmor protection removed");
+}
+
+module_init(apparmor_init);
+module_exit(apparmor_exit);
+
+MODULE_DESCRIPTION("AppArmor process confinement");
+MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");
+MODULE_LICENSE("GPL");

--


2007-05-16 13:36:35

by Pavel Machek

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks


> Module parameters, LSM hooks, initialization and teardown.
>
> Signed-off-by: John Johansen <[email protected]>
> Signed-off-by: Andreas Gruenbacher <[email protected]>

> +/* Maximum pathname length before accesses will start getting rejected */
> +unsigned int apparmor_path_max = 2 * PATH_MAX;
> +module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR);
> +MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");

WTF? Why is this configurable?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2007-05-23 16:17:20

by Andreas Gruenbacher

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Tuesday 15 May 2007 11:14, Pavel Machek wrote:
> Why is this configurable?

The maximum length of a pathname is an arbitrary limit: we don't want to
allocate arbitrary amounts of of kernel memory for pathnames so we introduce
this limit and set it to a reasonable value. In the unlikely case that
someone uses insanely long pathnames, this limit can be increased.

Andreas

2007-06-04 10:55:43

by Pavel Machek

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Wed 2007-05-23 18:16:45, Andreas Gruenbacher wrote:
> On Tuesday 15 May 2007 11:14, Pavel Machek wrote:
> > Why is this configurable?
>
> The maximum length of a pathname is an arbitrary limit: we don't want to
> allocate arbitrary amounts of of kernel memory for pathnames so we introduce
> this limit and set it to a reasonable value. In the unlikely case that
> someone uses insanely long pathnames, this limit can be increased.

vfs does not have configurable pathname limit, and I do not see what
is so special about AA to require this kind of uglyness.

Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2007-06-04 11:25:58

by Andreas Gruenbacher

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Monday 04 June 2007 12:55, Pavel Machek wrote:
> On Wed 2007-05-23 18:16:45, Andreas Gruenbacher wrote:
> > On Tuesday 15 May 2007 11:14, Pavel Machek wrote:
> > > Why is this configurable?
> >
> > The maximum length of a pathname is an arbitrary limit: we don't want to
> > allocate arbitrary amounts of of kernel memory for pathnames so we
> > introduce this limit and set it to a reasonable value. In the unlikely
> > case that someone uses insanely long pathnames, this limit can be
> > increased.
>
> vfs does not have configurable pathname limit, and I do not see what
> is so special about AA to require this kind of uglyness.

You very well know that the vfs has a limit of PATH_MAX characters (4096) for
pathnames. This means that at most that many characters can be passed at
once.

I've really got enough of your perpetual unfounded rants.

2007-06-04 11:35:38

by Pavel Machek

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Mon 2007-06-04 13:25:30, Andreas Gruenbacher wrote:
> On Monday 04 June 2007 12:55, Pavel Machek wrote:
> > On Wed 2007-05-23 18:16:45, Andreas Gruenbacher wrote:
> > > On Tuesday 15 May 2007 11:14, Pavel Machek wrote:
> > > > Why is this configurable?
> > >
> > > The maximum length of a pathname is an arbitrary limit: we don't want to
> > > allocate arbitrary amounts of of kernel memory for pathnames so we
> > > introduce this limit and set it to a reasonable value. In the unlikely
> > > case that someone uses insanely long pathnames, this limit can be
> > > increased.
> >
> > vfs does not have configurable pathname limit, and I do not see what
> > is so special about AA to require this kind of uglyness.
>
> You very well know that the vfs has a limit of PATH_MAX characters (4096) for
> pathnames. This means that at most that many characters can be passed at
> once.

Sorry then. Why not reuse the PATH_MAX when it exists already?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2007-06-04 11:43:18

by Andreas Gruenbacher

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Monday 04 June 2007 13:35, Pavel Machek wrote:
> On Mon 2007-06-04 13:25:30, Andreas Gruenbacher wrote:
> > On Monday 04 June 2007 12:55, Pavel Machek wrote:
> > > On Wed 2007-05-23 18:16:45, Andreas Gruenbacher wrote:
> > > > On Tuesday 15 May 2007 11:14, Pavel Machek wrote:
> > > > > Why is this configurable?
> > > >
> > > > The maximum length of a pathname is an arbitrary limit: we don't want
> > > > to allocate arbitrary amounts of of kernel memory for pathnames so we
> > > > introduce this limit and set it to a reasonable value. In the
> > > > unlikely case that someone uses insanely long pathnames, this limit
> > > > can be increased.
> > >
> > > vfs does not have configurable pathname limit, and I do not see what
> > > is so special about AA to require this kind of uglyness.
> >
> > You very well know that the vfs has a limit of PATH_MAX characters (4096)
> > for pathnames. This means that at most that many characters can be passed
> > at once.

What users can do is something like this:

chdir("some/long/path");
chdir("some/even/longer/path");
...

and the total length of the path can then exceed PATH_MAX characters. We can
only accept pathnames up to some upper limit, and we need to somehow define
what that limit is supposed to be. We could use PATH_MAX or some other
arbitrary number. In most situations PATH_MAX will be fine, but that's not
always guaranteed to be the case. So what's wrong about making this
configurable for special situations that we might run into? Module parameters
are *really* dead cheap.

Andreas

2007-06-04 13:12:59

by Pavel Machek

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

Hi!

> > > You very well know that the vfs has a limit of PATH_MAX characters (4096)
> > > for pathnames. This means that at most that many characters can be passed
> > > at once.
>
> What users can do is something like this:
>
> chdir("some/long/path");
> chdir("some/even/longer/path");
> ...
>
> and the total length of the path can then exceed PATH_MAX characters. We can
> only accept pathnames up to some upper limit, and we need to somehow define
> what that limit is supposed to be. We could use PATH_MAX or some other
> arbitrary number. In most situations PATH_MAX will be fine, but that's not
> always guaranteed to be the case. So what's wrong about making this
> configurable for special situations that we might run into? Module parameters
> are *really* dead cheap.

Parameters are cheap, but this one is ugly.

How will kernel work with very long paths? I'd suspect some problems,
if path is 1MB long and I attempt to print it in /proc
somewhere. Perhaps vfs should be modified not to allow such crazy
paths? But placing limit in aa is ugly.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2007-06-04 14:31:32

by Andreas Gruenbacher

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Monday 04 June 2007 15:12, Pavel Machek wrote:
> How will kernel work with very long paths? I'd suspect some problems,
> if path is 1MB long and I attempt to print it in /proc
> somewhere.

Pathnames are only used for informational purposes in the kernel, except in
AppArmor of course. /proc only uses pathnames in a few places,
but /proc/mounts will silently fail and produce garbage entries. That's not
ideal of course; we should fix that somehow.

Note that this has nothing to do with the AppArmor discussion ...

> Perhaps vfs should be modified not to allow such crazy paths? But placing
> limit in aa is ugly.

Dream on. Redefining fundamental vfs semantics is not an option; we should
rather make sure that we fail gracefully. Considering the alternatives, I
still prefer the configurable limit. That's way more useful than allowing a
process to DOS the kernel with AppArmor.

Andreas

2007-06-06 13:10:24

by Stephen Smalley

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Mon, 2007-06-04 at 16:30 +0200, Andreas Gruenbacher wrote:
> On Monday 04 June 2007 15:12, Pavel Machek wrote:
> > How will kernel work with very long paths? I'd suspect some problems,
> > if path is 1MB long and I attempt to print it in /proc
> > somewhere.
>
> Pathnames are only used for informational purposes in the kernel, except in
> AppArmor of course.

I don't mean this as a flame, but isn't the above statement the very
crux of this discussion? Why should AppArmor be different from the rest
of the kernel in its usage of pathnames (basis for decisions vs.
informational reporting to userspace)? And if it is ok for AppArmor to
generate and use pathnames as its basis of decisions on each open, then
is it also ok for audit, inotify, and others to use them in the same
manner? If the audit developers or inotify developers had come with
patches that used d_path or equivalent in the same manner as AppArmor,
don't you think they would have gotten the same resistance? And if you
are truly trying to create a mechanism (in AppArmor) that you can
ultimately apply widely to the system (going beyond AppArmor's original
limited focus on a small set of network-facing daemons), aren't you
concerned about the implications of having to generate a pathname on
each open just to decide what to do? Is this really the "path" you want
to take ;)?

Another question: it seems like the read-only bind mount folks gave up
on propagating the vfsmounts down and switched to a rather different
approach (checking near the entry points, using mount writer counters).
So similarly, what makes AppArmor fundamentally different that it
wouldn't take a similar approach to what they are doing vs. propagating
the vfsmounts down? Or do you think they made the wrong choice? If so,
why?

Just trying to understand your position better...

--
Stephen Smalley
National Security Agency

2007-06-09 12:58:56

by Pavel Machek

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

Hi!

> > How will kernel work with very long paths? I'd suspect some problems,
> > if path is 1MB long and I attempt to print it in /proc
> > somewhere.
>
> Pathnames are only used for informational purposes in the kernel, except in
> AppArmor of course. /proc only uses pathnames in a few places,
> but /proc/mounts will silently fail and produce garbage entries. That's not
> ideal of course; we should fix that somehow.

> Note that this has nothing to do with the AppArmor discussion ...

This has everything to do with AA discussion. You took unreliable,
for-user-info kernel subsystem, and made security subsystem depend on
it. Oops.

> > Perhaps vfs should be modified not to allow such crazy paths? But placing
> > limit in aa is ugly.
>
> Dream on. Redefining fundamental vfs semantics is not an option; we should
> rather make sure that we fail gracefully. Considering the

And instead of fixing "too long pathnames are problem in kernel" in
any clean way, you "simply" included
configurable-but-impossible-to-configure-right limit into
apparmor. And now you want that merged. Dream on.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2007-06-09 13:44:45

by Andreas Gruenbacher

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Saturday 09 June 2007 14:58, Pavel Machek wrote:
> > > How will kernel work with very long paths? I'd suspect some problems,
> > > if path is 1MB long and I attempt to print it in /proc
> > > somewhere.
> >
> > Pathnames are only used for informational purposes in the kernel, except
> > in AppArmor of course. /proc only uses pathnames in a few places,
> > but /proc/mounts will silently fail and produce garbage entries. That's
> > not ideal of course; we should fix that somehow.
>
> > Note that this has nothing to do with the AppArmor discussion ...
>
> This has everything to do with AA discussion.

How pathnames are used in /proc has *nothing* to do with AppAmor.

> You took unreliable, for-user-info kernel subsystem, and made security
> subsystem depend on it. Oops.

Wrong. I said that the kernel uses pathnames for informational purposes only,
not that they are unreliable. Don't turn words around in my mouth. The dcache
has a *very* precise idea of pathnames, because this is what it is there for.

The pathnames that d_path computes exactly reflect what the dcache knows.
(This requires the d_path fixes that are included in the AppArmor series and
have also been posted independently, and the reasons why these fixes are
needed are well explained in the mails.) The resulting pathnames are anything
but unreliable.

> > > Perhaps vfs should be modified not to allow such crazy paths? But
> > > placing limit in aa is ugly.
> >
> > Dream on. Redefining fundamental vfs semantics is not an option; we should
> > rather make sure that we fail gracefully. Considering the
>
> And instead of fixing "too long pathnames are problem in kernel" in any
> clean way, you "simply" included
> configurable-but-impossible-to-configure-right limit into
> apparmor. And now you want that merged. Dream on.

The choice here is between the following two things: either allow pathnames to
grow to arbitrary lengths, or cap them at some point. The former has the
benefit of working with all possible pathnames, and the drawback that users
can consume arbitrary amounts of kernel memory by constructing arbitrarily
long paths.

The latter has the benefit of limiting the amount of kernel memory consumed to
some upper bound, and the drawback that access to exceptionally long paths
(beyond the arbitrary limit) is denied. So in a sense, the limit in AppArmor
does what you are asking for: it modifies things so that the kernel does not
allow "such crazy paths". It does not introduce this as a vfs limit though,
because the vfs has all right not to care.

Andreas

2007-06-10 23:10:50

by Andreas Gruenbacher

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Wednesday 06 June 2007 15:09, Stephen Smalley wrote:
> On Mon, 2007-06-04 at 16:30 +0200, Andreas Gruenbacher wrote:
> > On Monday 04 June 2007 15:12, Pavel Machek wrote:
> > > How will kernel work with very long paths? I'd suspect some problems,
> > > if path is 1MB long and I attempt to print it in /proc
> > > somewhere.
> >
> > Pathnames are only used for informational purposes in the kernel, except
> > in AppArmor of course.
>
> I don't mean this as a flame, but isn't the above statement the very
> crux of this discussion?

I think the question at the core of it all is, shall a pathname based security
mechanism be allowed. I was under the impression that this question had
already been answered affirmatively. If the answer here was no, then we could
stop the entire discussion right there.

> Why should AppArmor be different from the rest of the kernel in its usage of
> pathnames (basis for decisions vs. informational reporting to userspace)?
> And if it is ok for AppArmor to generate and use pathnames as its basis of
> decisions on each open, then is it also ok for audit, inotify, and others to
> use them in the same manner?

Audit and inotify don't make any decisions based on pathnames, or on SELinux
labels for that matter, they only report. That being said, sure those parts
of the kernel that report pathnames should report them correctly -- I guess
there is no disagreement about that.

> Another question: it seems like the read-only bind mount folks gave up
> on propagating the vfsmounts down and switched to a rather different
> approach (checking near the entry points, using mount writer counters).
> So similarly, what makes AppArmor fundamentally different that it
> wouldn't take a similar approach to what they are doing vs. propagating
> the vfsmounts down?

Without the vfsmounts propagated down you won't know the pathnames. Whether
or not a different problem can be solved without the vfsmounts is not really
relevant.

Thanks,
Andreas

2007-06-11 14:34:00

by Stephen Smalley

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Mon, 2007-06-11 at 01:10 +0200, Andreas Gruenbacher wrote:
> On Wednesday 06 June 2007 15:09, Stephen Smalley wrote:
> > On Mon, 2007-06-04 at 16:30 +0200, Andreas Gruenbacher wrote:
> > > On Monday 04 June 2007 15:12, Pavel Machek wrote:
> > > > How will kernel work with very long paths? I'd suspect some problems,
> > > > if path is 1MB long and I attempt to print it in /proc
> > > > somewhere.
> > >
> > > Pathnames are only used for informational purposes in the kernel, except
> > > in AppArmor of course.
> >
> > I don't mean this as a flame, but isn't the above statement the very
> > crux of this discussion?
>
> I think the question at the core of it all is, shall a pathname based security
> mechanism be allowed. I was under the impression that this question had
> already been answered affirmatively. If the answer here was no, then we could
> stop the entire discussion right there.

There is a difference between using the pathname at the kernel/userland
interface as part of configuring a security mechanism and using it as
the basis for the runtime checking itself. Further, there is a
difference between generating and matching full pathnames on each access
vs. caching information in the parent dentry and making decisions based
on that cached information and the last component-name. The only
question I saw being answered was the abstract one of "can a pathname
play a role in the security mechanism" not "should the kernel be
regenerating a full path on each open and glob matching it against a
list of file globs."

> > Why should AppArmor be different from the rest of the kernel in its usage of
> > pathnames (basis for decisions vs. informational reporting to userspace)?
> > And if it is ok for AppArmor to generate and use pathnames as its basis of
> > decisions on each open, then is it also ok for audit, inotify, and others to
> > use them in the same manner?
>
> Audit and inotify don't make any decisions based on pathnames, or on SELinux
> labels for that matter, they only report. That being said, sure those parts
> of the kernel that report pathnames should report them correctly -- I guess
> there is no disagreement about that.

>From a userland perspective, audit and inotify allow you to specify
watches on pathnames, and those watches trigger actions by the audit and
inotify subsystems when those files are accessed. The kernel mechanism
however is inode-based, not pathname-based; the pathname is merely
looked up when the watch is added and mapped to an inode. That's my
point - why should AA be different? Would you really recommend that
audit or inotify call d_path() on each open and glob match the result
against a list of audit or inotify watches? BTW, audit does allow
filters on SELinux labels these days.

> > Another question: it seems like the read-only bind mount folks gave up
> > on propagating the vfsmounts down and switched to a rather different
> > approach (checking near the entry points, using mount writer counters).
> > So similarly, what makes AppArmor fundamentally different that it
> > wouldn't take a similar approach to what they are doing vs. propagating
> > the vfsmounts down?
>
> Without the vfsmounts propagated down you won't know the pathnames. Whether
> or not a different problem can be solved without the vfsmounts is not really
> relevant.

Well, that presumes that your mechanism has to generate full pathnames
on each access check. But even if so, you could be doing your checking
in the higher level code then where you have a vfsmount available.

--
Stephen Smalley
National Security Agency

2007-06-11 15:56:17

by Andreas Gruenbacher

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Monday 11 June 2007 16:33, Stephen Smalley wrote:
> On Mon, 2007-06-11 at 01:10 +0200, Andreas Gruenbacher wrote:
> > On Wednesday 06 June 2007 15:09, Stephen Smalley wrote:
> > > On Mon, 2007-06-04 at 16:30 +0200, Andreas Gruenbacher wrote:
> > > > On Monday 04 June 2007 15:12, Pavel Machek wrote:
> > > > > How will kernel work with very long paths? I'd suspect some
> > > > > problems, if path is 1MB long and I attempt to print it in /proc
> > > > > somewhere.
> > > >
> > > > Pathnames are only used for informational purposes in the kernel,
> > > > except in AppArmor of course.
> > >
> > > I don't mean this as a flame, but isn't the above statement the very
> > > crux of this discussion?
> >
> > I think the question at the core of it all is, shall a pathname based
> > security mechanism be allowed. I was under the impression that this
> > question had already been answered affirmatively. If the answer here was
> > no, then we could stop the entire discussion right there.
>
> There is a difference between using the pathname at the kernel/userland
> interface as part of configuring a security mechanism and using it as
> the basis for the runtime checking itself.

Yes, there is a difference. When I say pathname based security mechanism, I
literally mean a pathname based security mechanism, meaning the pathnames
determine the outcome o the decision. This includes designs that are based on
different abstractions internally, but the bahavior observable from
user-space must be the same (or else, it's a different model).

Unfortunately, translating pathnames to labels destroys this fundamental
abstraction. We explained why this is so in the following postings:

http://lkml.org/lkml/2007/6/9/94
http://lkml.org/lkml/2007/6/10/141

> Further, there is a difference between generating and matching full
> pathnames on each access vs. caching information in the parent dentry and
> making decisions based on that cached information and the last
> component-name.

Wait, you are mixing two issues here: access checks on existing files, and the
creation of new files. For AppArmor as it stands today the two are the same,
but when looking at emulating AppArmor using labels, they are not. Let's look
at things one at a time.

Generating and matching full pathnames on each access takes time, no question
about that. (In fact we are not checking on each access but only when
pathnames are involved, such as on open. Filehandle based operations do not
require access checks, but that's not a very important difference at this
level of discussion.) That's a quantitative statement though, not a
qualitative one: retrieving xattrs and checking labels also takes time;
additional checks are never for free. We find that doing the pathname checks
is easily fast enough. You may disagree, but then you don't have to use
AppArmor, and we are not standing in your way.

As far as new files are concerned, basing decisions on the parent dentry and
component name requires that you know where in the filesystem hierarchy this
dentry is located: with bind mounts, the same dentry shows up in multiple
locations in a process's namespace, corresponding to different pathnames. In
other words, to make the right decision, the dentry alone is not enough; it
takes a <dentry, vfsmount> pair. So there we are again.

>From the point on where you have a <dentry, vfsmount> pair of objects, you can
do two things: you can compute the full pathname and base your decision on
that, or you can do some caching to hopefully cut some of that work short
frequently enough to set off the additional cost. The difference between the
two approaches is quantitative -- if there is a difference in results, then
that's obviously a bug. I believe that caching could speed up things
measurably, but up to this point, neither I nor anybody else had the time to
look into it, and so we are not doing it -- not yet, any perhaps never at
all. It may be counter to your intuition, but doing those checks is not a big
issue.

> The only question I saw being answered was the abstract one of "can a
> pathname play a role in the security mechanism" not "should the kernel be
> regenerating a full path on each open and glob matching it against a
> list of file globs."

No glob matching involved, and no list of patterns. There is a single DFA per
profile (and each process is in at most one profile at any one time), and
each access check involves exactly one DFA traversal.

[cut here for lack of time right now -- will take another look later]

> > Without the vfsmounts propagated down you won't know the pathnames.
> > Whether or not a different problem can be solved without the vfsmounts is
> > not really relevant.
>
> Well, that presumes that your mechanism has to generate full pathnames
> on each access check. But even if so, you could be doing your checking
> in the higher level code then where you have a vfsmount available.

The LSM hooks are pretty high-level, meant for being able to plug in different
access checks. That's the right level of abstraction. We just need the
vfsmounts passed down as well. That's what the bulk of common code patches
are there for.

Andreas

2007-06-11 19:02:46

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

Quoting Andreas Gruenbacher ([email protected]):
> On Monday 11 June 2007 16:33, Stephen Smalley wrote:
> > On Mon, 2007-06-11 at 01:10 +0200, Andreas Gruenbacher wrote:
> > > On Wednesday 06 June 2007 15:09, Stephen Smalley wrote:
> > > > On Mon, 2007-06-04 at 16:30 +0200, Andreas Gruenbacher wrote:
> > > > > On Monday 04 June 2007 15:12, Pavel Machek wrote:
> > > > > > How will kernel work with very long paths? I'd suspect some
> > > > > > problems, if path is 1MB long and I attempt to print it in /proc
> > > > > > somewhere.
> > > > >
> > > > > Pathnames are only used for informational purposes in the kernel,
> > > > > except in AppArmor of course.
> > > >
> > > > I don't mean this as a flame, but isn't the above statement the very
> > > > crux of this discussion?
> > >
> > > I think the question at the core of it all is, shall a pathname based
> > > security mechanism be allowed. I was under the impression that this
> > > question had already been answered affirmatively. If the answer here was

That was the decision at ksummit last year, yes.

> > > no, then we could stop the entire discussion right there.
> >
> > There is a difference between using the pathname at the kernel/userland
> > interface as part of configuring a security mechanism and using it as
> > the basis for the runtime checking itself.
>
> Yes, there is a difference. When I say pathname based security mechanism, I
> literally mean a pathname based security mechanism, meaning the pathnames
> determine the outcome o the decision. This includes designs that are based on
> different abstractions internally, but the bahavior observable from
> user-space must be the same (or else, it's a different model).
>
> Unfortunately, translating pathnames to labels destroys this fundamental
> abstraction. We explained why this is so in the following postings:
>
> http://lkml.org/lkml/2007/6/9/94
> http://lkml.org/lkml/2007/6/10/141
>
> > Further, there is a difference between generating and matching full
> > pathnames on each access vs. caching information in the parent dentry and
> > making decisions based on that cached information and the last
> > component-name.
>
> Wait, you are mixing two issues here: access checks on existing files, and the
> creation of new files. For AppArmor as it stands today the two are the same,
> but when looking at emulating AppArmor using labels, they are not. Let's look
> at things one at a time.
>
> Generating and matching full pathnames on each access takes time, no question
> about that. (In fact we are not checking on each access but only when
> pathnames are involved, such as on open. Filehandle based operations do not
> require access checks, but that's not a very important difference at this
> level of discussion.) That's a quantitative statement though, not a
> qualitative one: retrieving xattrs and checking labels also takes time;
> additional checks are never for free. We find that doing the pathname checks
> is easily fast enough. You may disagree, but then you don't have to use
> AppArmor, and we are not standing in your way.
>
> As far as new files are concerned, basing decisions on the parent dentry and
> component name requires that you know where in the filesystem hierarchy this
> dentry is located: with bind mounts, the same dentry shows up in multiple
> locations in a process's namespace, corresponding to different pathnames. In
> other words, to make the right decision, the dentry alone is not enough; it
> takes a <dentry, vfsmount> pair. So there we are again.
>
> >From the point on where you have a <dentry, vfsmount> pair of objects, you can
> do two things: you can compute the full pathname and base your decision on
> that, or you can do some caching to hopefully cut some of that work short
> frequently enough to set off the additional cost. The difference between the
> two approaches is quantitative -- if there is a difference in results, then
> that's obviously a bug. I believe that caching could speed up things
> measurably, but up to this point, neither I nor anybody else had the time to
> look into it, and so we are not doing it -- not yet, any perhaps never at
> all. It may be counter to your intuition, but doing those checks is not a big
> issue.

My approach in DTE, which used pathnames to assign TE labels in the
kernel, was to use a 'shadow tree' to the vfsmnt+dentry tree, filled out
at policy load time to the depth of the deepest policy rule. For the
behavior I was after, bind mounts were handled by storing pointers from
the new mount to the original, but the behavior AA wants would be
different. Namespace clones are easily handled this way by copying the
cached pointers to the shadow tree. And it was pretty fast.

When I talked about this with Tony last year, the biggest shortcoming to
use this for AA was the wildcards. For instance, if there is a rule for
/var/log/HOSTS/*/messages, then when /var/log/HOSTS/sergelap/ is
created, a new rule would have to be created on the fly to tag
/var/log/HOSTS/sergelap/messages if it is created. How to represent
that when only /var/log or /var/log/HOSTS exists at policy load time
would be, well, a fun problem to solve actually :)

-serge

> > The only question I saw being answered was the abstract one of "can a
> > pathname play a role in the security mechanism" not "should the kernel be
> > regenerating a full path on each open and glob matching it against a
> > list of file globs."
>
> No glob matching involved, and no list of patterns. There is a single DFA per
> profile (and each process is in at most one profile at any one time), and
> each access check involves exactly one DFA traversal.
>
> [cut here for lack of time right now -- will take another look later]
>
> > > Without the vfsmounts propagated down you won't know the pathnames.
> > > Whether or not a different problem can be solved without the vfsmounts is
> > > not really relevant.
> >
> > Well, that presumes that your mechanism has to generate full pathnames
> > on each access check. But even if so, you could be doing your checking
> > in the higher level code then where you have a vfsmount available.
>
> The LSM hooks are pretty high-level, meant for being able to plug in different
> access checks. That's the right level of abstraction. We just need the
> vfsmounts passed down as well. That's what the bulk of common code patches
> are there for.
>
> Andreas
> -
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2007-06-12 13:00:57

by Stephen Smalley

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Mon, 2007-06-11 at 14:02 -0500, Serge E. Hallyn wrote:
> Quoting Andreas Gruenbacher ([email protected]):
> > On Monday 11 June 2007 16:33, Stephen Smalley wrote:
> > > On Mon, 2007-06-11 at 01:10 +0200, Andreas Gruenbacher wrote:
> > > > On Wednesday 06 June 2007 15:09, Stephen Smalley wrote:
> > > > > On Mon, 2007-06-04 at 16:30 +0200, Andreas Gruenbacher wrote:
> > > > > > On Monday 04 June 2007 15:12, Pavel Machek wrote:
> > > > > > > How will kernel work with very long paths? I'd suspect some
> > > > > > > problems, if path is 1MB long and I attempt to print it in /proc
> > > > > > > somewhere.
> > > > > >
> > > > > > Pathnames are only used for informational purposes in the kernel,
> > > > > > except in AppArmor of course.
> > > > >
> > > > > I don't mean this as a flame, but isn't the above statement the very
> > > > > crux of this discussion?
> > > >
> > > > I think the question at the core of it all is, shall a pathname based
> > > > security mechanism be allowed. I was under the impression that this
> > > > question had already been answered affirmatively. If the answer here was
>
> That was the decision at ksummit last year, yes.
>
> > > > no, then we could stop the entire discussion right there.
> > >
> > > There is a difference between using the pathname at the kernel/userland
> > > interface as part of configuring a security mechanism and using it as
> > > the basis for the runtime checking itself.
> >
> > Yes, there is a difference. When I say pathname based security mechanism, I
> > literally mean a pathname based security mechanism, meaning the pathnames
> > determine the outcome o the decision. This includes designs that are based on
> > different abstractions internally, but the bahavior observable from
> > user-space must be the same (or else, it's a different model).
> >
> > Unfortunately, translating pathnames to labels destroys this fundamental
> > abstraction. We explained why this is so in the following postings:
> >
> > http://lkml.org/lkml/2007/6/9/94
> > http://lkml.org/lkml/2007/6/10/141
> >
> > > Further, there is a difference between generating and matching full
> > > pathnames on each access vs. caching information in the parent dentry and
> > > making decisions based on that cached information and the last
> > > component-name.
> >
> > Wait, you are mixing two issues here: access checks on existing files, and the
> > creation of new files. For AppArmor as it stands today the two are the same,
> > but when looking at emulating AppArmor using labels, they are not. Let's look
> > at things one at a time.
> >
> > Generating and matching full pathnames on each access takes time, no question
> > about that. (In fact we are not checking on each access but only when
> > pathnames are involved, such as on open. Filehandle based operations do not
> > require access checks, but that's not a very important difference at this
> > level of discussion.) That's a quantitative statement though, not a
> > qualitative one: retrieving xattrs and checking labels also takes time;
> > additional checks are never for free. We find that doing the pathname checks
> > is easily fast enough. You may disagree, but then you don't have to use
> > AppArmor, and we are not standing in your way.
> >
> > As far as new files are concerned, basing decisions on the parent dentry and
> > component name requires that you know where in the filesystem hierarchy this
> > dentry is located: with bind mounts, the same dentry shows up in multiple
> > locations in a process's namespace, corresponding to different pathnames. In
> > other words, to make the right decision, the dentry alone is not enough; it
> > takes a <dentry, vfsmount> pair. So there we are again.
> >
> > >From the point on where you have a <dentry, vfsmount> pair of objects, you can
> > do two things: you can compute the full pathname and base your decision on
> > that, or you can do some caching to hopefully cut some of that work short
> > frequently enough to set off the additional cost. The difference between the
> > two approaches is quantitative -- if there is a difference in results, then
> > that's obviously a bug. I believe that caching could speed up things
> > measurably, but up to this point, neither I nor anybody else had the time to
> > look into it, and so we are not doing it -- not yet, any perhaps never at
> > all. It may be counter to your intuition, but doing those checks is not a big
> > issue.
>
> My approach in DTE, which used pathnames to assign TE labels in the
> kernel, was to use a 'shadow tree' to the vfsmnt+dentry tree, filled out
> at policy load time to the depth of the deepest policy rule. For the
> behavior I was after, bind mounts were handled by storing pointers from
> the new mount to the original, but the behavior AA wants would be
> different. Namespace clones are easily handled this way by copying the
> cached pointers to the shadow tree. And it was pretty fast.
>
> When I talked about this with Tony last year, the biggest shortcoming to
> use this for AA was the wildcards. For instance, if there is a rule for
> /var/log/HOSTS/*/messages, then when /var/log/HOSTS/sergelap/ is
> created, a new rule would have to be created on the fly to tag
> /var/log/HOSTS/sergelap/messages if it is created. How to represent
> that when only /var/log or /var/log/HOSTS exists at policy load time
> would be, well, a fun problem to solve actually :)

If we added support for named type transitions to SELinux, as proposed
earlier by Kyle Moffett during this discussion, wouldn't that address
that issue without needing a DTE-like approach? The concept is to add
the last component name as a further input to the labeling decision for
new files, in addition to the existing use of the creating process'
label, the parent directory label, and the kind of file. Then, you
could have something like:
type_transition <domain> var_log_hosts_t:file "messages" messages_t;

The last component name is already available, so that doesn't require
any changes to LSM, and it would be a straightforward extension of
SELinux to support the above - it doesn't change the model at all, just
adds a further input to the new file labeling logic.

--
Stephen Smalley
National Security Agency

2007-06-12 13:06:49

by Pavel Machek

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

Hi!

> > > > How will kernel work with very long paths? I'd suspect some problems,
> > > > if path is 1MB long and I attempt to print it in /proc
> > > > somewhere.
> > >
> > > Pathnames are only used for informational purposes in the kernel, except
> > > in AppArmor of course. /proc only uses pathnames in a few places,
> > > but /proc/mounts will silently fail and produce garbage entries. That's
> > > not ideal of course; we should fix that somehow.
> >
> > > Note that this has nothing to do with the AppArmor discussion ...
> >
> > This has everything to do with AA discussion.
>
> How pathnames are used in /proc has *nothing* to do with AppAmor.
>
> > You took unreliable, for-user-info kernel subsystem, and made security
> > subsystem depend on it. Oops.
>
> Wrong. I said that the kernel uses pathnames for informational purposes only,
> not that they are unreliable. Don't turn words around in my

Well, we know they are unreliable from other sources.

> The pathnames that d_path computes exactly reflect what the dcache knows.
> (This requires the d_path fixes that are included in the AppArmor series and
> have also been posted independently, and the reasons why these fixes are
> needed are well explained in the mails.) The resulting pathnames are anything
> but unreliable.

Yes?

Like... everything but AA works with very long paths?

Like... deleted files handling, where AA used to pick random name?

Like... races during tree renames, where AA may use name file never
ever had?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2007-06-12 13:14:20

by Stephen Smalley

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Mon, 2007-06-11 at 17:55 +0200, Andreas Gruenbacher wrote:
> On Monday 11 June 2007 16:33, Stephen Smalley wrote:
> > On Mon, 2007-06-11 at 01:10 +0200, Andreas Gruenbacher wrote:
> > > On Wednesday 06 June 2007 15:09, Stephen Smalley wrote:
> > > > On Mon, 2007-06-04 at 16:30 +0200, Andreas Gruenbacher wrote:
> > > > > On Monday 04 June 2007 15:12, Pavel Machek wrote:
> > > > > > How will kernel work with very long paths? I'd suspect some
> > > > > > problems, if path is 1MB long and I attempt to print it in /proc
> > > > > > somewhere.
> > > > >
> > > > > Pathnames are only used for informational purposes in the kernel,
> > > > > except in AppArmor of course.
> > > >
> > > > I don't mean this as a flame, but isn't the above statement the very
> > > > crux of this discussion?
> > >
> > > I think the question at the core of it all is, shall a pathname based
> > > security mechanism be allowed. I was under the impression that this
> > > question had already been answered affirmatively. If the answer here was
> > > no, then we could stop the entire discussion right there.
> >
> > There is a difference between using the pathname at the kernel/userland
> > interface as part of configuring a security mechanism and using it as
> > the basis for the runtime checking itself.
>
> Yes, there is a difference. When I say pathname based security mechanism, I
> literally mean a pathname based security mechanism, meaning the pathnames
> determine the outcome o the decision. This includes designs that are based on
> different abstractions internally, but the bahavior observable from
> user-space must be the same (or else, it's a different model).
>
> Unfortunately, translating pathnames to labels destroys this fundamental
> abstraction. We explained why this is so in the following postings:
>
> http://lkml.org/lkml/2007/6/9/94
> http://lkml.org/lkml/2007/6/10/141

I don't really see the specific reasons explained in the first posting;
the second one has a list of problems, but I'd question their validity:
- New files: Adding the last component name as a further input to the
logic for determining the label of a new file would address many of the
concerns here.
- Renaming: Do you honestly believe that renaming a file or directory
tree should automatically change its protection without explicit action
by the user/admin? I don't, naturally, and Linux DAC certainly doesn't
work that way. I view the change-protections-on-rename behavior of AA
as a flaw, not something to be emulated.
- New Policies: So there may be more work to be done up front in the
label-based approach when developing policies. Isn't that where you
want to front load the work? Versus doing it at runtime? Do you expect
users to be rewriting their policies constantly on their production
systems?
- File systems that do not support labels: I'm a bit surprised that you
would advocate this given your experience in developing EA and ACL
support for local filesystems and NFS. The pathname-based approach in
NFS seems even scarier than in the local case - the clients may have
different views of the namespace than one another or the server and the
potential for inconsistent views of the tree (particularly as it is
being modified) during access checks is only greater in the NFS case,
right? It may be more expedient to implement, but is it the right
technical approach?

But possibly the larger question here is whether your abstraction is
fundamentally broken/leaky. Even with your "native" implementation in
AA, you concede that there are cases where it breaks down, right? e.g.
as the path returned by d_path may in fact differ from the path that was
looked up, as the tree can change between time-of-lookup and
time-of-path-generation?

> [cut here for lack of time right now -- will take another look later]

I'm hoping you'll ultimately respond to the questions I have raised (a
couple times now) about why this fundamentally differs from audit and/or
inotify, which take pathnames as part of configuring the mechanism but
do not generate them and match them on each access.

>
> > > Without the vfsmounts propagated down you won't know the pathnames.
> > > Whether or not a different problem can be solved without the vfsmounts is
> > > not really relevant.
> >
> > Well, that presumes that your mechanism has to generate full pathnames
> > on each access check. But even if so, you could be doing your checking
> > in the higher level code then where you have a vfsmount available.
>
> The LSM hooks are pretty high-level, meant for being able to plug in different
> access checks. That's the right level of abstraction. We just need the
> vfsmounts passed down as well. That's what the bulk of common code patches
> are there for.

Well, if you succeed in that, does that mean that the read-only bind
mount folks should go back to that approach? Just looking for a little
bit of consistency among different efforts...

--
Stephen Smalley
National Security Agency

2007-06-12 15:45:29

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

Quoting Stephen Smalley ([email protected]):
> On Mon, 2007-06-11 at 14:02 -0500, Serge E. Hallyn wrote:
> > Quoting Andreas Gruenbacher ([email protected]):
> > > On Monday 11 June 2007 16:33, Stephen Smalley wrote:
> > > > On Mon, 2007-06-11 at 01:10 +0200, Andreas Gruenbacher wrote:
> > > > > On Wednesday 06 June 2007 15:09, Stephen Smalley wrote:
> > > > > > On Mon, 2007-06-04 at 16:30 +0200, Andreas Gruenbacher wrote:
> > > > > > > On Monday 04 June 2007 15:12, Pavel Machek wrote:
> > > > > > > > How will kernel work with very long paths? I'd suspect some
> > > > > > > > problems, if path is 1MB long and I attempt to print it in /proc
> > > > > > > > somewhere.
> > > > > > >
> > > > > > > Pathnames are only used for informational purposes in the kernel,
> > > > > > > except in AppArmor of course.
> > > > > >
> > > > > > I don't mean this as a flame, but isn't the above statement the very
> > > > > > crux of this discussion?
> > > > >
> > > > > I think the question at the core of it all is, shall a pathname based
> > > > > security mechanism be allowed. I was under the impression that this
> > > > > question had already been answered affirmatively. If the answer here was
> >
> > That was the decision at ksummit last year, yes.
> >
> > > > > no, then we could stop the entire discussion right there.
> > > >
> > > > There is a difference between using the pathname at the kernel/userland
> > > > interface as part of configuring a security mechanism and using it as
> > > > the basis for the runtime checking itself.
> > >
> > > Yes, there is a difference. When I say pathname based security mechanism, I
> > > literally mean a pathname based security mechanism, meaning the pathnames
> > > determine the outcome o the decision. This includes designs that are based on
> > > different abstractions internally, but the bahavior observable from
> > > user-space must be the same (or else, it's a different model).
> > >
> > > Unfortunately, translating pathnames to labels destroys this fundamental
> > > abstraction. We explained why this is so in the following postings:
> > >
> > > http://lkml.org/lkml/2007/6/9/94
> > > http://lkml.org/lkml/2007/6/10/141
> > >
> > > > Further, there is a difference between generating and matching full
> > > > pathnames on each access vs. caching information in the parent dentry and
> > > > making decisions based on that cached information and the last
> > > > component-name.
> > >
> > > Wait, you are mixing two issues here: access checks on existing files, and the
> > > creation of new files. For AppArmor as it stands today the two are the same,
> > > but when looking at emulating AppArmor using labels, they are not. Let's look
> > > at things one at a time.
> > >
> > > Generating and matching full pathnames on each access takes time, no question
> > > about that. (In fact we are not checking on each access but only when
> > > pathnames are involved, such as on open. Filehandle based operations do not
> > > require access checks, but that's not a very important difference at this
> > > level of discussion.) That's a quantitative statement though, not a
> > > qualitative one: retrieving xattrs and checking labels also takes time;
> > > additional checks are never for free. We find that doing the pathname checks
> > > is easily fast enough. You may disagree, but then you don't have to use
> > > AppArmor, and we are not standing in your way.
> > >
> > > As far as new files are concerned, basing decisions on the parent dentry and
> > > component name requires that you know where in the filesystem hierarchy this
> > > dentry is located: with bind mounts, the same dentry shows up in multiple
> > > locations in a process's namespace, corresponding to different pathnames. In
> > > other words, to make the right decision, the dentry alone is not enough; it
> > > takes a <dentry, vfsmount> pair. So there we are again.
> > >
> > > >From the point on where you have a <dentry, vfsmount> pair of objects, you can
> > > do two things: you can compute the full pathname and base your decision on
> > > that, or you can do some caching to hopefully cut some of that work short
> > > frequently enough to set off the additional cost. The difference between the
> > > two approaches is quantitative -- if there is a difference in results, then
> > > that's obviously a bug. I believe that caching could speed up things
> > > measurably, but up to this point, neither I nor anybody else had the time to
> > > look into it, and so we are not doing it -- not yet, any perhaps never at
> > > all. It may be counter to your intuition, but doing those checks is not a big
> > > issue.
> >
> > My approach in DTE, which used pathnames to assign TE labels in the
> > kernel, was to use a 'shadow tree' to the vfsmnt+dentry tree, filled out
> > at policy load time to the depth of the deepest policy rule. For the
> > behavior I was after, bind mounts were handled by storing pointers from
> > the new mount to the original, but the behavior AA wants would be
> > different. Namespace clones are easily handled this way by copying the
> > cached pointers to the shadow tree. And it was pretty fast.
> >
> > When I talked about this with Tony last year, the biggest shortcoming to
> > use this for AA was the wildcards. For instance, if there is a rule for
> > /var/log/HOSTS/*/messages, then when /var/log/HOSTS/sergelap/ is
> > created, a new rule would have to be created on the fly to tag
> > /var/log/HOSTS/sergelap/messages if it is created. How to represent
> > that when only /var/log or /var/log/HOSTS exists at policy load time
> > would be, well, a fun problem to solve actually :)
>
> If we added support for named type transitions to SELinux, as proposed
> earlier by Kyle Moffett during this discussion, wouldn't that address
> that issue without needing a DTE-like approach? The concept is to add

Haven't read his message, but based on what you laid out here sure, that
sounds good. It still, like my dte approach, might have some trouble
with the wildcard/regex rules AA allows. And while it might perfectly
reproduce my original DTE behavior, I don't think it does what AA wants
on bind mounts. (Whether what AA wants for bind mounts makes sense I'm
still not convinced, especially with user mounts coming soon (or already
here?), but I'm staying out of that discussion for now)

> the last component name as a further input to the labeling decision for
> new files, in addition to the existing use of the creating process'
> label, the parent directory label, and the kind of file. Then, you
> could have something like:
> type_transition <domain> var_log_hosts_t:file "messages" messages_t;
>
> The last component name is already available, so that doesn't require
> any changes to LSM, and it would be a straightforward extension of
> SELinux to support the above - it doesn't change the model at all, just
> adds a further input to the new file labeling logic.

And eliminates the need for restorecond?

thanks,
-serge

2007-06-12 17:53:32

by Karl MacMillan

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Tue, 2007-06-12 at 10:34 -0500, Serge E. Hallyn wrote:
> Quoting Stephen Smalley ([email protected]):

[...]

> >
> > If we added support for named type transitions to SELinux, as proposed
> > earlier by Kyle Moffett during this discussion, wouldn't that address
> > that issue without needing a DTE-like approach? The concept is to add
>
> Haven't read his message, but based on what you laid out here sure, that
> sounds good. It still, like my dte approach, might have some trouble
> with the wildcard/regex rules AA allows. And while it might perfectly
> reproduce my original DTE behavior, I don't think it does what AA wants
> on bind mounts. (Whether what AA wants for bind mounts makes sense I'm
> still not convinced, especially with user mounts coming soon (or already
> here?), but I'm staying out of that discussion for now)
>
> > the last component name as a further input to the labeling decision for
> > new files, in addition to the existing use of the creating process'
> > label, the parent directory label, and the kind of file. Then, you
> > could have something like:
> > type_transition <domain> var_log_hosts_t:file "messages" messages_t;
> >
> > The last component name is already available, so that doesn't require
> > any changes to LSM, and it would be a straightforward extension of
> > SELinux to support the above - it doesn't change the model at all, just
> > adds a further input to the new file labeling logic.
>
> And eliminates the need for restorecond?
>

Unlikely in the short term - restorecond is also used to reset contexts
on critical files in /etc that might loose the context because tools
used to update them are not correctly preserving contexts
(e.g., /etc/mtab, etc/resolv.conf).

Actually - this whole notion restorecond as a critical component of
SELinux because of a "new file problem" is pretty overblown. The default
config file ships with:

/etc/resolv.conf
/etc/samba/secrets.tdb
/etc/mtab
/var/run/utmp
/var/log/wtmp
~/public_html
~/.mozilla/plugins/libflashplayer.so

So the only things that would be helped by type_transition rules with a
name component would be public_html and libflashplayer.so.

Karl

2007-06-12 19:01:04

by Serge E. Hallyn

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

Quoting Karl MacMillan ([email protected]):
> On Tue, 2007-06-12 at 10:34 -0500, Serge E. Hallyn wrote:
> > Quoting Stephen Smalley ([email protected]):
>
> [...]
>
> > >
> > > If we added support for named type transitions to SELinux, as proposed
> > > earlier by Kyle Moffett during this discussion, wouldn't that address
> > > that issue without needing a DTE-like approach? The concept is to add
> >
> > Haven't read his message, but based on what you laid out here sure, that
> > sounds good. It still, like my dte approach, might have some trouble
> > with the wildcard/regex rules AA allows. And while it might perfectly
> > reproduce my original DTE behavior, I don't think it does what AA wants
> > on bind mounts. (Whether what AA wants for bind mounts makes sense I'm
> > still not convinced, especially with user mounts coming soon (or already
> > here?), but I'm staying out of that discussion for now)
> >
> > > the last component name as a further input to the labeling decision for
> > > new files, in addition to the existing use of the creating process'
> > > label, the parent directory label, and the kind of file. Then, you
> > > could have something like:
> > > type_transition <domain> var_log_hosts_t:file "messages" messages_t;
> > >
> > > The last component name is already available, so that doesn't require
> > > any changes to LSM, and it would be a straightforward extension of
> > > SELinux to support the above - it doesn't change the model at all, just
> > > adds a further input to the new file labeling logic.
> >
> > And eliminates the need for restorecond?
> >
>
> Unlikely in the short term - restorecond is also used to reset contexts
> on critical files in /etc that might loose the context because tools
> used to update them are not correctly preserving contexts
> (e.g., /etc/mtab, etc/resolv.conf).

Confused - why wouldn't the new type_transition rule extension handle
that?

thanks,
-serge

> Actually - this whole notion restorecond as a critical component of
> SELinux because of a "new file problem" is pretty overblown. The default
> config file ships with:
>
> /etc/resolv.conf
> /etc/samba/secrets.tdb
> /etc/mtab
> /var/run/utmp
> /var/log/wtmp
> ~/public_html
> ~/.mozilla/plugins/libflashplayer.so
>
> So the only things that would be helped by type_transition rules with a
> name component would be public_html and libflashplayer.so.
>
> Karl
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2007-06-12 23:51:09

by Andreas Gruenbacher

[permalink] [raw]
Subject: Re: [AppArmor 38/45] AppArmor: Module and LSM hooks

On Monday 11 June 2007 16:33, Stephen Smalley wrote:
>From a userland perspective, audit and inotify allow you to specify
> watches on pathnames, and those watches trigger actions by the audit and
> inotify subsystems when those files are accessed. The kernel mechanism
> however is inode-based, not pathname-based; the pathname is merely
> looked up when the watch is added and mapped to an inode. That's my
> point - why should AA be different?

Audit watches are not entirely object based (contrary to what the man page
says): with simple file renames the watches sticks with the names; with
directory renames, watches below the directory get dropped. That's rather
weird, and I would say bad for audit.

Inotify really watches objects. I can imagine cases where this is exactly what
you want, and others where this is exactly what you don't want -- it's pick
your poison.

AppArmor deliberately is pathname based. There are good reasons for that, and
we really, definitely want this pathname based model, with all its benefits
and disadvantages. Arguing that AppArmor shouldn't be pathname based because
other parts of the kernel try to balance names vs. objects differently, and
not even always the same way either, is pretty narrow-minded.

If one thing is clear from this entire discussion, it is that there is no
agreement on the One True Model, and different solutions are being used.

> Would you really recommend that audit or inotify call d_path() on each
> open and glob match the result against a list of audit or inotify watches?

I don't remember doing so.

Thanks,
Andreas