diff options
Diffstat (limited to 'security')
61 files changed, 23351 insertions, 0 deletions
diff --git a/security/Kconfig b/security/Kconfig new file mode 100644 index 00000000000..dcf04a09185 --- /dev/null +++ b/security/Kconfig @@ -0,0 +1,91 @@ +# +# Security configuration +# + +menu "Security options" + +config KEYS + bool "Enable access key retention support" + help + This option provides support for retaining authentication tokens and + access keys in the kernel. + + It also includes provision of methods by which such keys might be + associated with a process so that network filesystems, encryption + support and the like can find them. + + Furthermore, a special type of key is available that acts as keyring: + a searchable sequence of keys. Each process is equipped with access + to five standard keyrings: UID-specific, GID-specific, session, + process and thread. + + If you are unsure as to whether this is required, answer N. + +config KEYS_DEBUG_PROC_KEYS + bool "Enable the /proc/keys file by which all keys may be viewed" + depends on KEYS + help + This option turns on support for the /proc/keys file through which + all the keys on the system can be listed. + + This option is a slight security risk in that it makes it possible + for anyone to see all the keys on the system. Normally the manager + pretends keys that are inaccessible to a process don't exist as far + as that process is concerned. + +config SECURITY + bool "Enable different security models" + help + This allows you to choose different security modules to be + configured into your kernel. + + If this option is not selected, the default Linux security + model will be used. + + If you are unsure how to answer this question, answer N. + +config SECURITY_NETWORK + bool "Socket and Networking Security Hooks" + depends on SECURITY + help + This enables the socket and networking security hooks. + If enabled, a security module can use these hooks to + implement socket and networking access controls. + If you are unsure how to answer this question, answer N. + +config SECURITY_CAPABILITIES + tristate "Default Linux Capabilities" + depends on SECURITY + help + This enables the "default" Linux capabilities functionality. + If you are unsure how to answer this question, answer Y. + +config SECURITY_ROOTPLUG + tristate "Root Plug Support" + depends on USB && SECURITY + help + This is a sample LSM module that should only be used as such. + It prevents any programs running with egid == 0 if a specific + USB device is not present in the system. + + See <http://www.linuxjournal.com/article.php?sid=6279> for + more information about this module. + + If you are unsure how to answer this question, answer N. + +config SECURITY_SECLVL + tristate "BSD Secure Levels" + depends on SECURITY + select CRYPTO + select CRYPTO_SHA1 + help + Implements BSD Secure Levels as an LSM. See + <file:Documentation/seclvl.txt> for instructions on how to use this + module. + + If you are unsure how to answer this question, answer N. + +source security/selinux/Kconfig + +endmenu + diff --git a/security/Makefile b/security/Makefile new file mode 100644 index 00000000000..197cc2f3f1e --- /dev/null +++ b/security/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for the kernel security code +# + +obj-$(CONFIG_KEYS) += keys/ +subdir-$(CONFIG_SECURITY_SELINUX) += selinux + +# if we don't select a security model, use the default capabilities +ifneq ($(CONFIG_SECURITY),y) +obj-y += commoncap.o +endif + +# Object file lists +obj-$(CONFIG_SECURITY) += security.o dummy.o +# Must precede capability.o in order to stack properly. +obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o +obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o +obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o +obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o diff --git a/security/capability.c b/security/capability.c new file mode 100644 index 00000000000..ec18d607562 --- /dev/null +++ b/security/capability.c @@ -0,0 +1,104 @@ +/* + * Capabilities Linux Security Module + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/security.h> +#include <linux/file.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/pagemap.h> +#include <linux/swap.h> +#include <linux/smp_lock.h> +#include <linux/skbuff.h> +#include <linux/netlink.h> +#include <linux/ptrace.h> +#include <linux/moduleparam.h> + +static struct security_operations capability_ops = { + .ptrace = cap_ptrace, + .capget = cap_capget, + .capset_check = cap_capset_check, + .capset_set = cap_capset_set, + .capable = cap_capable, + .settime = cap_settime, + .netlink_send = cap_netlink_send, + .netlink_recv = cap_netlink_recv, + + .bprm_apply_creds = cap_bprm_apply_creds, + .bprm_set_security = cap_bprm_set_security, + .bprm_secureexec = cap_bprm_secureexec, + + .inode_setxattr = cap_inode_setxattr, + .inode_removexattr = cap_inode_removexattr, + + .task_post_setuid = cap_task_post_setuid, + .task_reparent_to_init = cap_task_reparent_to_init, + + .syslog = cap_syslog, + + .vm_enough_memory = cap_vm_enough_memory, +}; + +#define MY_NAME __stringify(KBUILD_MODNAME) + +/* flag to keep track of how we were registered */ +static int secondary; + +static int capability_disable; +module_param_named(disable, capability_disable, int, 0); +MODULE_PARM_DESC(disable, "To disable capabilities module set disable = 1"); + +static int __init capability_init (void) +{ + if (capability_disable) { + printk(KERN_INFO "Capabilities disabled at initialization\n"); + return 0; + } + /* register ourselves with the security framework */ + if (register_security (&capability_ops)) { + /* try registering with primary module */ + if (mod_reg_security (MY_NAME, &capability_ops)) { + printk (KERN_INFO "Failure registering capabilities " + "with primary security module.\n"); + return -EINVAL; + } + secondary = 1; + } + printk (KERN_INFO "Capability LSM initialized%s\n", + secondary ? " as secondary" : ""); + return 0; +} + +static void __exit capability_exit (void) +{ + if (capability_disable) + return; + /* remove ourselves from the security framework */ + if (secondary) { + if (mod_unreg_security (MY_NAME, &capability_ops)) + printk (KERN_INFO "Failure unregistering capabilities " + "with primary module.\n"); + return; + } + + if (unregister_security (&capability_ops)) { + printk (KERN_INFO + "Failure unregistering capabilities with the kernel\n"); + } +} + +security_initcall (capability_init); +module_exit (capability_exit); + +MODULE_DESCRIPTION("Standard Linux Capabilities Security Module"); +MODULE_LICENSE("GPL"); diff --git a/security/commoncap.c b/security/commoncap.c new file mode 100644 index 00000000000..849b8c338ee --- /dev/null +++ b/security/commoncap.c @@ -0,0 +1,345 @@ +/* Common capabilities, needed by capability.o and root_plug.o + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/security.h> +#include <linux/file.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/pagemap.h> +#include <linux/swap.h> +#include <linux/smp_lock.h> +#include <linux/skbuff.h> +#include <linux/netlink.h> +#include <linux/ptrace.h> +#include <linux/xattr.h> +#include <linux/hugetlb.h> + +int cap_netlink_send(struct sock *sk, struct sk_buff *skb) +{ + NETLINK_CB(skb).eff_cap = current->cap_effective; + return 0; +} + +EXPORT_SYMBOL(cap_netlink_send); + +int cap_netlink_recv(struct sk_buff *skb) +{ + if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) + return -EPERM; + return 0; +} + +EXPORT_SYMBOL(cap_netlink_recv); + +int cap_capable (struct task_struct *tsk, int cap) +{ + /* Derived from include/linux/sched.h:capable. */ + if (cap_raised(tsk->cap_effective, cap)) + return 0; + return -EPERM; +} + +int cap_settime(struct timespec *ts, struct timezone *tz) +{ + if (!capable(CAP_SYS_TIME)) + return -EPERM; + return 0; +} + +int cap_ptrace (struct task_struct *parent, struct task_struct *child) +{ + /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */ + if (!cap_issubset (child->cap_permitted, current->cap_permitted) && + !capable(CAP_SYS_PTRACE)) + return -EPERM; + return 0; +} + +int cap_capget (struct task_struct *target, kernel_cap_t *effective, + kernel_cap_t *inheritable, kernel_cap_t *permitted) +{ + /* Derived from kernel/capability.c:sys_capget. */ + *effective = cap_t (target->cap_effective); + *inheritable = cap_t (target->cap_inheritable); + *permitted = cap_t (target->cap_permitted); + return 0; +} + +int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, + kernel_cap_t *inheritable, kernel_cap_t *permitted) +{ + /* Derived from kernel/capability.c:sys_capset. */ + /* verify restrictions on target's new Inheritable set */ + if (!cap_issubset (*inheritable, + cap_combine (target->cap_inheritable, + current->cap_permitted))) { + return -EPERM; + } + + /* verify restrictions on target's new Permitted set */ + if (!cap_issubset (*permitted, + cap_combine (target->cap_permitted, + current->cap_permitted))) { + return -EPERM; + } + + /* verify the _new_Effective_ is a subset of the _new_Permitted_ */ + if (!cap_issubset (*effective, *permitted)) { + return -EPERM; + } + + return 0; +} + +void cap_capset_set (struct task_struct *target, kernel_cap_t *effective, + kernel_cap_t *inheritable, kernel_cap_t *permitted) +{ + target->cap_effective = *effective; + target->cap_inheritable = *inheritable; + target->cap_permitted = *permitted; +} + +int cap_bprm_set_security (struct linux_binprm *bprm) +{ + /* Copied from fs/exec.c:prepare_binprm. */ + + /* We don't have VFS support for capabilities yet */ + cap_clear (bprm->cap_inheritable); + cap_clear (bprm->cap_permitted); + cap_clear (bprm->cap_effective); + + /* To support inheritance of root-permissions and suid-root + * executables under compatibility mode, we raise all three + * capability sets for the file. + * + * If only the real uid is 0, we only raise the inheritable + * and permitted sets of the executable file. + */ + + if (!issecure (SECURE_NOROOT)) { + if (bprm->e_uid == 0 || current->uid == 0) { + cap_set_full (bprm->cap_inheritable); + cap_set_full (bprm->cap_permitted); + } + if (bprm->e_uid == 0) + cap_set_full (bprm->cap_effective); + } + return 0; +} + +void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) +{ + /* Derived from fs/exec.c:compute_creds. */ + kernel_cap_t new_permitted, working; + + new_permitted = cap_intersect (bprm->cap_permitted, cap_bset); + working = cap_intersect (bprm->cap_inheritable, + current->cap_inheritable); + new_permitted = cap_combine (new_permitted, working); + + if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || + !cap_issubset (new_permitted, current->cap_permitted)) { + current->mm->dumpable = 0; + + if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) { + if (!capable(CAP_SETUID)) { + bprm->e_uid = current->uid; + bprm->e_gid = current->gid; + } + if (!capable (CAP_SETPCAP)) { + new_permitted = cap_intersect (new_permitted, + current->cap_permitted); + } + } + } + + current->suid = current->euid = current->fsuid = bprm->e_uid; + current->sgid = current->egid = current->fsgid = bprm->e_gid; + + /* For init, we want to retain the capabilities set + * in the init_task struct. Thus we skip the usual + * capability rules */ + if (current->pid != 1) { + current->cap_permitted = new_permitted; + current->cap_effective = + cap_intersect (new_permitted, bprm->cap_effective); + } + + /* AUD: Audit candidate if current->cap_effective is set */ + + current->keep_capabilities = 0; +} + +int cap_bprm_secureexec (struct linux_binprm *bprm) +{ + /* If/when this module is enhanced to incorporate capability + bits on files, the test below should be extended to also perform a + test between the old and new capability sets. For now, + it simply preserves the legacy decision algorithm used by + the old userland. */ + return (current->euid != current->uid || + current->egid != current->gid); +} + +int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, + size_t size, int flags) +{ + if (!strncmp(name, XATTR_SECURITY_PREFIX, + sizeof(XATTR_SECURITY_PREFIX) - 1) && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; +} + +int cap_inode_removexattr(struct dentry *dentry, char *name) +{ + if (!strncmp(name, XATTR_SECURITY_PREFIX, + sizeof(XATTR_SECURITY_PREFIX) - 1) && + !capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; +} + +/* moved from kernel/sys.c. */ +/* + * cap_emulate_setxuid() fixes the effective / permitted capabilities of + * a process after a call to setuid, setreuid, or setresuid. + * + * 1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of + * {r,e,s}uid != 0, the permitted and effective capabilities are + * cleared. + * + * 2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective + * capabilities of the process are cleared. + * + * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective + * capabilities are set to the permitted capabilities. + * + * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should + * never happen. + * + * -astor + * + * cevans - New behaviour, Oct '99 + * A process may, via prctl(), elect to keep its capabilities when it + * calls setuid() and switches away from uid==0. Both permitted and + * effective sets will be retained. + * Without this change, it was impossible for a daemon to drop only some + * of its privilege. The call to setuid(!=0) would drop all privileges! + * Keeping uid 0 is not an option because uid 0 owns too many vital + * files.. + * Thanks to Olaf Kirch and Peter Benie for spotting this. + */ +static inline void cap_emulate_setxuid (int old_ruid, int old_euid, + int old_suid) +{ + if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && + (current->uid != 0 && current->euid != 0 && current->suid != 0) && + !current->keep_capabilities) { + cap_clear (current->cap_permitted); + cap_clear (current->cap_effective); + } + if (old_euid == 0 && current->euid != 0) { + cap_clear (current->cap_effective); + } + if (old_euid != 0 && current->euid == 0) { + current->cap_effective = current->cap_permitted; + } +} + +int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, + int flags) +{ + switch (flags) { + case LSM_SETID_RE: + case LSM_SETID_ID: + case LSM_SETID_RES: + /* Copied from kernel/sys.c:setreuid/setuid/setresuid. */ + if (!issecure (SECURE_NO_SETUID_FIXUP)) { + cap_emulate_setxuid (old_ruid, old_euid, old_suid); + } + break; + case LSM_SETID_FS: + { + uid_t old_fsuid = old_ruid; + + /* Copied from kernel/sys.c:setfsuid. */ + + /* + * FIXME - is fsuser used for all CAP_FS_MASK capabilities? + * if not, we might be a bit too harsh here. + */ + + if (!issecure (SECURE_NO_SETUID_FIXUP)) { + if (old_fsuid == 0 && current->fsuid != 0) { + cap_t (current->cap_effective) &= + ~CAP_FS_MASK; + } + if (old_fsuid != 0 && current->fsuid == 0) { + cap_t (current->cap_effective) |= + (cap_t (current->cap_permitted) & + CAP_FS_MASK); + } + } + break; + } + default: + return -EINVAL; + } + + return 0; +} + +void cap_task_reparent_to_init (struct task_struct *p) +{ + p->cap_effective = CAP_INIT_EFF_SET; + p->cap_inheritable = CAP_INIT_INH_SET; + p->cap_permitted = CAP_FULL_SET; + p->keep_capabilities = 0; + return; +} + +int cap_syslog (int type) +{ + if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; +} + +int cap_vm_enough_memory(long pages) +{ + int cap_sys_admin = 0; + + if (cap_capable(current, CAP_SYS_ADMIN) == 0) + cap_sys_admin = 1; + return __vm_enough_memory(pages, cap_sys_admin); +} + +EXPORT_SYMBOL(cap_capable); +EXPORT_SYMBOL(cap_settime); +EXPORT_SYMBOL(cap_ptrace); +EXPORT_SYMBOL(cap_capget); +EXPORT_SYMBOL(cap_capset_check); +EXPORT_SYMBOL(cap_capset_set); +EXPORT_SYMBOL(cap_bprm_set_security); +EXPORT_SYMBOL(cap_bprm_apply_creds); +EXPORT_SYMBOL(cap_bprm_secureexec); +EXPORT_SYMBOL(cap_inode_setxattr); +EXPORT_SYMBOL(cap_inode_removexattr); +EXPORT_SYMBOL(cap_task_post_setuid); +EXPORT_SYMBOL(cap_task_reparent_to_init); +EXPORT_SYMBOL(cap_syslog); +EXPORT_SYMBOL(cap_vm_enough_memory); + +MODULE_DESCRIPTION("Standard Linux Common Capabilities Security Module"); +MODULE_LICENSE("GPL"); diff --git a/security/dummy.c b/security/dummy.c new file mode 100644 index 00000000000..b32eff14654 --- /dev/null +++ b/security/dummy.c @@ -0,0 +1,996 @@ +/* + * Stub functions for the default security function pointers in case no + * security model is loaded. + * + * Copyright (C) 2001 WireX Communications, Inc <chris@wirex.com> + * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com> + * + * 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; either version 2 of the License, or + * (at your option) any later version. + */ + +#undef DEBUG + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/mman.h> +#include <linux/pagemap.h> +#include <linux/swap.h> +#include <linux/security.h> +#include <linux/skbuff.h> +#include <linux/netlink.h> +#include <net/sock.h> +#include <linux/xattr.h> +#include <linux/hugetlb.h> +#include <linux/ptrace.h> +#include <linux/file.h> + +static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) +{ + return 0; +} + +static int dummy_capget (struct task_struct *target, kernel_cap_t * effective, + kernel_cap_t * inheritable, kernel_cap_t * permitted) +{ + *effective = *inheritable = *permitted = 0; + if (!issecure(SECURE_NOROOT)) { + if (target->euid == 0) { + *permitted |= (~0 & ~CAP_FS_MASK); + *effective |= (~0 & ~CAP_TO_MASK(CAP_SETPCAP) & ~CAP_FS_MASK); + } + if (target->fsuid == 0) { + *permitted |= CAP_FS_MASK; + *effective |= CAP_FS_MASK; + } + } + return 0; +} + +static int dummy_capset_check (struct task_struct *target, + kernel_cap_t * effective, + kernel_cap_t * inheritable, + kernel_cap_t * permitted) +{ + return -EPERM; +} + +static void dummy_capset_set (struct task_struct *target, + kernel_cap |