diff options
Diffstat (limited to 'security')
74 files changed, 13186 insertions, 4571 deletions
diff --git a/security/Kconfig b/security/Kconfig index 226b9556b25..bd72ae62349 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -140,6 +140,7 @@ config LSM_MMAP_MIN_ADDR source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig +source security/apparmor/Kconfig source security/integrity/ima/Kconfig @@ -148,6 +149,7 @@ choice default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX default DEFAULT_SECURITY_SMACK if SECURITY_SMACK default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO + default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR default DEFAULT_SECURITY_DAC help @@ -163,6 +165,9 @@ choice config DEFAULT_SECURITY_TOMOYO bool "TOMOYO" if SECURITY_TOMOYO=y + config DEFAULT_SECURITY_APPARMOR + bool "AppArmor" if SECURITY_APPARMOR=y + config DEFAULT_SECURITY_DAC bool "Unix Discretionary Access Controls" @@ -173,6 +178,7 @@ config DEFAULT_SECURITY default "selinux" if DEFAULT_SECURITY_SELINUX default "smack" if DEFAULT_SECURITY_SMACK default "tomoyo" if DEFAULT_SECURITY_TOMOYO + default "apparmor" if DEFAULT_SECURITY_APPARMOR default "" if DEFAULT_SECURITY_DAC endmenu diff --git a/security/Makefile b/security/Makefile index da20a193c8d..8bb0fe9e1ca 100644 --- a/security/Makefile +++ b/security/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_KEYS) += keys/ subdir-$(CONFIG_SECURITY_SELINUX) += selinux subdir-$(CONFIG_SECURITY_SMACK) += smack subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo +subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor # always enable default capabilities obj-y += commoncap.o @@ -19,6 +20,7 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o obj-$(CONFIG_AUDIT) += lsm_audit.o obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o +obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/built-in.o obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore new file mode 100644 index 00000000000..0a0a99f3b08 --- /dev/null +++ b/security/apparmor/.gitignore @@ -0,0 +1,5 @@ +# +# Generated include files +# +af_names.h +capability_names.h diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig new file mode 100644 index 00000000000..9b9013b2e32 --- /dev/null +++ b/security/apparmor/Kconfig @@ -0,0 +1,31 @@ +config SECURITY_APPARMOR + bool "AppArmor support" + depends on SECURITY && NET + select AUDIT + select SECURITY_PATH + select SECURITYFS + select SECURITY_NETWORK + default 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://apparmor.wiki.kernel.org + + If you are unsure how to answer this question, answer N. + +config SECURITY_APPARMOR_BOOTPARAM_VALUE + int "AppArmor boot parameter default value" + depends on SECURITY_APPARMOR + range 0 1 + default 1 + help + This option sets the default value for the kernel parameter + 'apparmor', which allows AppArmor to be enabled or disabled + at boot. If this option is set to 0 (zero), the AppArmor + kernel parameter will default to 0, disabling AppArmor at + boot. If this option is set to 1 (one), the AppArmor + kernel parameter will default to 1, enabling AppArmor at + boot. + + If you are unsure how to answer this question, answer 1. diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile new file mode 100644 index 00000000000..f204869399e --- /dev/null +++ b/security/apparmor/Makefile @@ -0,0 +1,24 @@ +# Makefile for AppArmor Linux Security Module +# +obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o + +apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ + path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ + resource.o sid.o file.o + +clean-files: capability_names.h af_names.h + +quiet_cmd_make-caps = GEN $@ +cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ; 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 >> $@ ; echo "};" >> $@ + +quiet_cmd_make-rlim = GEN $@ +cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ; sed -n --e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+RLIMIT_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@ ; echo "static const int rlim_map[] = {" >> $@ ; sed -n -e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+\\(RLIMIT_[A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/\\1,/p" $< >> $@ ; echo "};" >> $@ + +$(obj)/capability.o : $(obj)/capability_names.h +$(obj)/resource.o : $(obj)/rlim_names.h +$(obj)/capability_names.h : $(srctree)/include/linux/capability.h + $(call cmd,make-caps) +$(obj)/af_names.h : $(srctree)/include/linux/socket.h + $(call cmd,make-af) +$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h + $(call cmd,make-rlim) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c new file mode 100644 index 00000000000..7320331b44a --- /dev/null +++ b/security/apparmor/apparmorfs.c @@ -0,0 +1,239 @@ +/* + * AppArmor security module + * + * This file contains AppArmor /sys/kernel/security/apparmor interface functions + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2010 Canonical Ltd. + * + * 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. + */ + +#include <linux/security.h> +#include <linux/vmalloc.h> +#include <linux/module.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h> +#include <linux/namei.h> + +#include "include/apparmor.h" +#include "include/apparmorfs.h" +#include "include/audit.h" +#include "include/context.h" +#include "include/policy.h" + +/** + * aa_simple_write_to_buffer - common routine for getting policy from user + * @op: operation doing the user buffer copy + * @userbuf: user buffer to copy data from (NOT NULL) + * @alloc_size: size of user buffer + * @copy_size: size of data to copy from user buffer + * @pos: position write is at in the file (NOT NULL) + * + * Returns: kernel buffer containing copy of user buffer data or an + * ERR_PTR on failure. + */ +static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, + size_t alloc_size, size_t copy_size, + loff_t *pos) +{ + char *data; + + if (*pos != 0) + /* only writes from pos 0, that is complete writes */ + return ERR_PTR(-ESPIPE); + + /* + * Don't allow profile load/replace/remove from profiles that don't + * have CAP_MAC_ADMIN + */ + if (!aa_may_manage_policy(op)) + return ERR_PTR(-EACCES); + + /* freed by caller to simple_write_to_buffer */ + data = kvmalloc(alloc_size); + if (data == NULL) + return ERR_PTR(-ENOMEM); + + if (copy_from_user(data, userbuf, copy_size)) { + kvfree(data); + return ERR_PTR(-EFAULT); + } + + return data; +} + + +/* .load file hook fn to load policy */ +static ssize_t 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(OP_PROF_LOAD, buf, size, size, pos); + + error = PTR_ERR(data); + if (!IS_ERR(data)) { + error = aa_replace_profiles(data, size, PROF_ADD); + kvfree(data); + } + + return error; +} + +static const struct file_operations aa_fs_profile_load = { + .write = profile_load +}; + +/* .replace file hook fn to load and/or replace policy */ +static ssize_t 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(OP_PROF_REPL, buf, size, size, pos); + error = PTR_ERR(data); + if (!IS_ERR(data)) { + error = aa_replace_profiles(data, size, PROF_REPLACE); + kvfree(data); + } + + return error; +} + +static const struct file_operations aa_fs_profile_replace = { + .write = profile_replace +}; + +/* .remove file hook fn to remove loaded policy */ +static ssize_t 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(OP_PROF_RM, buf, size + 1, size, pos); + + error = PTR_ERR(data); + if (!IS_ERR(data)) { + data[size] = 0; + error = aa_remove_profiles(data, size); + kvfree(data); + } + + return error; +} + +static const struct file_operations aa_fs_profile_remove = { + .write = profile_remove +}; + +/** Base file system setup **/ + +static struct dentry *aa_fs_dentry __initdata; + +static void __init aafs_remove(const char *name) +{ + struct dentry *dentry; + + dentry = lookup_one_len(name, aa_fs_dentry, strlen(name)); + if (!IS_ERR(dentry)) { + securityfs_remove(dentry); + dput(dentry); + } +} + +/** + * aafs_create - create an entry in the apparmor filesystem + * @name: name of the entry (NOT NULL) + * @mask: file permission mask of the file + * @fops: file operations for the file (NOT NULL) + * + * Used aafs_remove to remove entries created with this fn. + */ +static int __init aafs_create(const char *name, int mask, + const struct file_operations *fops) +{ + struct dentry *dentry; + + dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry, + NULL, fops); + + return IS_ERR(dentry) ? PTR_ERR(dentry) : 0; +} + +/** + * aa_destroy_aafs - cleanup and free aafs + * + * releases dentries allocated by aa_create_aafs + */ +void __init aa_destroy_aafs(void) +{ + if (aa_fs_dentry) { + aafs_remove(".remove"); + aafs_remove(".replace"); + aafs_remove(".load"); + + securityfs_remove(aa_fs_dentry); + aa_fs_dentry = NULL; + } +} + +/** + * aa_create_aafs - create the apparmor security filesystem + * + * dentries created here are released by aa_destroy_aafs + * + * Returns: error on failure + */ +int __init aa_create_aafs(void) +{ + int error; + + if (!apparmor_initialized) + return 0; + + if (aa_fs_dentry) { + AA_ERROR("%s: AppArmor securityfs already exists\n", __func__); + return -EEXIST; + } + + aa_fs_dentry = securityfs_create_dir("apparmor", NULL); + if (IS_ERR(aa_fs_dentry)) { + error = PTR_ERR(aa_fs_dentry); + aa_fs_dentry = NULL; + goto error; + } + + error = aafs_create(".load", 0640, &aa_fs_profile_load); + if (error) + goto error; + error = aafs_create(".replace", 0640, &aa_fs_profile_replace); + if (error) + goto error; + error = aafs_create(".remove", 0640, &aa_fs_profile_remove); + if (error) + goto error; + + /* TODO: add support for apparmorfs_null and apparmorfs_mnt */ + + /* Report that AppArmor fs is enabled */ + aa_info_message("AppArmor Filesystem Enabled"); + return 0; + +error: + aa_destroy_aafs(); + AA_ERROR("Error creating AppArmor securityfs\n"); + return error; +} + +fs_initcall(aa_create_aafs); diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c new file mode 100644 index 00000000000..96502b22b26 --- /dev/null +++ b/security/apparmor/audit.c @@ -0,0 +1,215 @@ +/* + * AppArmor security module + * + * This file contains AppArmor auditing functions + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2010 Canonical Ltd. + * + * 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. + */ + +#include <linux/audit.h> +#include <linux/socket.h> + +#include "include/apparmor.h" +#include "include/audit.h" +#include "include/policy.h" + +const char *op_table[] = { + "null", + + "sysctl", + "capable", + + "unlink", + "mkdir", + "rmdir", + "mknod", + "truncate", + "link", + "symlink", + "rename_src", + "rename_dest", + "chmod", + "chown", + "getattr", + "open", + + "file_perm", + "file_lock", + "file_mmap", + "file_mprotect", + + "create", + "post_create", + "bind", + "connect", + "listen", + "accept", + "sendmsg", + "recvmsg", + "getsockname", + "getpeername", + "getsockopt", + "setsockopt", + "socket_shutdown", + + "ptrace", + + "exec", + "change_hat", + "change_profile", + "change_onexec", + + "setprocattr", + "setrlimit", + + "profile_replace", + "profile_load", + "profile_remove" +}; + +const char *audit_mode_names[] = { + "normal", + "quiet_denied", + "quiet", + "noquiet", + "all" +}; + +static char *aa_audit_type[] = { + "AUDIT", + "ALLOWED", + "DENIED", + "HINT", + "STATUS", + "ERROR", + "KILLED" +}; + +/* + * Currently AppArmor auditing is fed straight into the audit framework. + * + * TODO: + * netlink interface for complain mode + * user auditing, - send user auditing to netlink interface + * system control of whether user audit messages go to system log + */ + +/** + * audit_base - core AppArmor function. + * @ab: audit buffer to fill (NOT NULL) + * @ca: audit structure containing data to audit (NOT NULL) + * + * Record common AppArmor audit data from @sa + */ +static void audit_pre(struct audit_buffer *ab, void *ca) +{ + struct common_audit_data *sa = ca; + struct task_struct *tsk = sa->tsk ? sa->tsk : current; + + if (aa_g_audit_header) { + audit_log_format(ab, "apparmor="); + audit_log_string(ab, aa_audit_type[sa->aad.type]); + } + + if (sa->aad.op) { + audit_log_for |