(2006-08-06) rescue-bootcd

This commit is contained in:
2006-08-06 00:00:00 +02:00
parent 2f796b816a
commit decb062d20
21091 changed files with 7076462 additions and 0 deletions

View File

@@ -0,0 +1 @@
cmd_security/built-in.o := ld -m elf_i386 -r -o security/built-in.o security/commoncap.o

View File

@@ -0,0 +1,288 @@
cmd_security/commoncap.o := gcc -Wp,-MD,security/.commoncap.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=commoncap -DKBUILD_MODNAME=commoncap -c -o security/commoncap.o security/commoncap.c
deps_security/commoncap.o := \
security/commoncap.c \
include/linux/config.h \
$(wildcard include/config/h.h) \
include/linux/module.h \
$(wildcard include/config/modules.h) \
$(wildcard include/config/modversions.h) \
$(wildcard include/config/module/unload.h) \
$(wildcard include/config/kallsyms.h) \
include/linux/sched.h \
$(wildcard include/config/keys.h) \
$(wildcard include/config/schedstats.h) \
$(wildcard include/config/smp.h) \
$(wildcard include/config/numa.h) \
$(wildcard include/config/security.h) \
$(wildcard include/config/preempt.h) \
$(wildcard include/config/magic/sysrq.h) \
include/asm/param.h \
include/linux/capability.h \
include/linux/types.h \
$(wildcard include/config/uid16.h) \
include/linux/posix_types.h \
include/linux/stddef.h \
include/linux/compiler.h \
include/linux/compiler-gcc3.h \
include/linux/compiler-gcc.h \
include/asm/posix_types.h \
include/asm/types.h \
$(wildcard include/config/highmem64g.h) \
$(wildcard include/config/lbd.h) \
include/linux/spinlock.h \
$(wildcard include/config/debug/spinlock.h) \
$(wildcard include/config/lockmeter.h) \
include/linux/preempt.h \
include/linux/linkage.h \
include/asm/linkage.h \
$(wildcard include/config/regparm.h) \
$(wildcard include/config/x86/alignment/16.h) \
include/linux/thread_info.h \
include/linux/bitops.h \
include/asm/bitops.h \
include/asm/thread_info.h \
$(wildcard include/config/4kstacks.h) \
$(wildcard include/config/debug/stack/usage.h) \
include/asm/page.h \
$(wildcard include/config/x86/use/3dnow.h) \
$(wildcard include/config/x86/pae.h) \
$(wildcard include/config/hugetlb/page.h) \
$(wildcard include/config/highmem4g.h) \
$(wildcard include/config/discontigmem.h) \
include/asm/processor.h \
$(wildcard include/config/mk8.h) \
$(wildcard include/config/mk7.h) \
include/asm/vm86.h \
include/asm/math_emu.h \
include/asm/sigcontext.h \
include/asm/segment.h \
include/asm/cpufeature.h \
include/asm/msr.h \
include/asm/system.h \
$(wildcard include/config/x86/cmpxchg.h) \
$(wildcard include/config/x86/oostore.h) \
include/linux/kernel.h \
$(wildcard include/config/debug/spinlock/sleep.h) \
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
include/asm/byteorder.h \
$(wildcard include/config/x86/bswap.h) \
include/linux/byteorder/little_endian.h \
include/linux/byteorder/swab.h \
include/linux/byteorder/generic.h \
include/asm/bug.h \
include/asm-generic/bug.h \
include/linux/cache.h \
include/asm/cache.h \
$(wildcard include/config/x86/l1/cache/shift.h) \
include/linux/threads.h \
$(wildcard include/config/nr/cpus.h) \
include/asm/percpu.h \
include/asm-generic/percpu.h \
include/linux/stringify.h \
include/linux/timex.h \
$(wildcard include/config/time/interpolation.h) \
include/linux/time.h \
include/linux/seqlock.h \
include/asm/timex.h \
$(wildcard include/config/x86/elan.h) \
$(wildcard include/config/x86/tsc.h) \
$(wildcard include/config/x86/generic.h) \
include/linux/jiffies.h \
include/asm/div64.h \
include/linux/rbtree.h \
include/linux/cpumask.h \
$(wildcard include/config/hotplug/cpu.h) \
include/linux/bitmap.h \
include/linux/string.h \
include/asm/string.h \
include/asm/semaphore.h \
include/asm/atomic.h \
$(wildcard include/config/m386.h) \
include/linux/wait.h \
include/linux/list.h \
include/linux/prefetch.h \
include/asm/current.h \
include/linux/rwsem.h \
$(wildcard include/config/rwsem/generic/spinlock.h) \
include/asm/rwsem.h \
include/asm/ptrace.h \
$(wildcard include/config/frame/pointer.h) \
include/asm/mmu.h \
include/linux/smp.h \
include/linux/sem.h \
$(wildcard include/config/sysvipc.h) \
include/linux/ipc.h \
include/asm/ipcbuf.h \
include/asm/sembuf.h \
include/linux/signal.h \
include/asm/signal.h \
include/asm/siginfo.h \
include/asm-generic/siginfo.h \
include/linux/resource.h \
include/asm/resource.h \
include/linux/securebits.h \
include/linux/fs_struct.h \
include/linux/completion.h \
include/linux/pid.h \
include/linux/percpu.h \
include/linux/slab.h \
$(wildcard include/config/.h) \
include/linux/gfp.h \
include/linux/mmzone.h \
$(wildcard include/config/force/max/zoneorder.h) \
include/linux/numa.h \
include/linux/topology.h \
$(wildcard include/config/sched/smt.h) \
include/asm/topology.h \
include/asm-generic/topology.h \
include/linux/init.h \
$(wildcard include/config/hotplug.h) \
include/linux/kmalloc_sizes.h \
$(wildcard include/config/mmu.h) \
$(wildcard include/config/large/allocs.h) \
include/linux/param.h \
include/linux/timer.h \
include/linux/aio.h \
include/linux/workqueue.h \
include/linux/aio_abi.h \
include/linux/stat.h \
include/asm/stat.h \
include/linux/kmod.h \
$(wildcard include/config/kmod.h) \
include/linux/errno.h \
include/asm/errno.h \
include/asm-generic/errno.h \
include/asm-generic/errno-base.h \
include/linux/elf.h \
include/asm/elf.h \
include/asm/user.h \
include/linux/utsname.h \
include/linux/kobject.h \
include/linux/sysfs.h \
$(wildcard include/config/sysfs.h) \
include/linux/kref.h \
include/linux/kobject_uevent.h \
$(wildcard include/config/kobject/uevent.h) \
include/linux/moduleparam.h \
include/asm/local.h \
include/asm/module.h \
$(wildcard include/config/m486.h) \
$(wildcard include/config/m586.h) \
$(wildcard include/config/m586tsc.h) \
$(wildcard include/config/m586mmx.h) \
$(wildcard include/config/m686.h) \
$(wildcard include/config/mpentiumii.h) \
$(wildcard include/config/mpentiumiii.h) \
$(wildcard include/config/mpentiumm.h) \
$(wildcard include/config/mpentium4.h) \
$(wildcard include/config/mk6.h) \
$(wildcard include/config/mcrusoe.h) \
$(wildcard include/config/mefficeon.h) \
$(wildcard include/config/mwinchipc6.h) \
$(wildcard include/config/mwinchip2.h) \
$(wildcard include/config/mwinchip3d.h) \
$(wildcard include/config/mcyrixiii.h) \
$(wildcard include/config/mviac3/2.h) \
include/linux/security.h \
$(wildcard include/config/security/network.h) \
include/linux/fs.h \
$(wildcard include/config/dnotify.h) \
$(wildcard include/config/quota.h) \
$(wildcard include/config/epoll.h) \
$(wildcard include/config/auditsyscall.h) \
include/linux/limits.h \
include/linux/kdev_t.h \
include/linux/ioctl.h \
include/asm/ioctl.h \
include/linux/dcache.h \
include/linux/rcupdate.h \
include/linux/prio_tree.h \
include/linux/radix-tree.h \
include/linux/audit.h \
$(wildcard include/config/audit.h) \
include/linux/quota.h \
include/linux/dqblk_xfs.h \
include/linux/dqblk_v1.h \
include/linux/dqblk_v2.h \
include/linux/nfs_fs_i.h \
include/linux/nfs.h \
include/linux/sunrpc/msg_prot.h \
include/linux/fcntl.h \
include/asm/fcntl.h \
include/linux/err.h \
include/linux/binfmts.h \
include/linux/shm.h \
include/asm/shmparam.h \
include/asm/shmbuf.h \
include/linux/msg.h \
include/asm/msgbuf.h \
include/linux/file.h \
include/linux/mm.h \
$(wildcard include/config/sysctl.h) \
$(wildcard include/config/stack/growsup.h) \
$(wildcard include/config/highmem.h) \
$(wildcard include/config/shmem.h) \
$(wildcard include/config/proc/fs.h) \
$(wildcard include/config/debug/pagealloc.h) \
$(wildcard include/config/arch/gate/area.h) \
include/asm/pgtable.h \
$(wildcard include/config/highpte.h) \
include/asm/fixmap.h \
$(wildcard include/config/x86/local/apic.h) \
$(wildcard include/config/x86/io/apic.h) \
$(wildcard include/config/x86/visws/apic.h) \
$(wildcard include/config/x86/f00f/bug.h) \
$(wildcard include/config/x86/cyclone/timer.h) \
$(wildcard include/config/acpi/boot.h) \
$(wildcard include/config/pci/mmconfig.h) \
include/asm/acpi.h \
$(wildcard include/config/acpi/pci.h) \
$(wildcard include/config/acpi/sleep.h) \
include/asm/apicdef.h \
include/asm/pgtable-2level-defs.h \
include/asm/pgtable-2level.h \
include/asm-generic/pgtable.h \
include/linux/page-flags.h \
$(wildcard include/config/swap.h) \
include/linux/mman.h \
include/asm/mman.h \
include/linux/pagemap.h \
include/linux/highmem.h \
include/asm/cacheflush.h \
include/asm/uaccess.h \
$(wildcard include/config/x86/intel/usercopy.h) \
$(wildcard include/config/x86/wp/works/ok.h) \
include/linux/swap.h \
include/linux/smp_lock.h \
$(wildcard include/config/lock/kernel.h) \
include/linux/skbuff.h \
$(wildcard include/config/netfilter.h) \
$(wildcard include/config/bridge/netfilter.h) \
$(wildcard include/config/vlan/8021q.h) \
$(wildcard include/config/vlan/8021q/module.h) \
$(wildcard include/config/netfilter/debug.h) \
$(wildcard include/config/hippi.h) \
$(wildcard include/config/net/sched.h) \
$(wildcard include/config/net/cls/act.h) \
include/linux/poll.h \
include/asm/poll.h \
include/linux/net.h \
include/asm/socket.h \
include/asm/sockios.h \
include/net/checksum.h \
include/asm/checksum.h \
include/linux/in6.h \
include/linux/netlink.h \
include/linux/socket.h \
$(wildcard include/config/compat.h) \
include/linux/sockios.h \
include/linux/uio.h \
include/linux/ptrace.h \
include/linux/xattr.h \
include/linux/hugetlb.h \
$(wildcard include/config/hugetlbfs.h) \
security/commoncap.o: $(deps_security/commoncap.o)
$(deps_security/commoncap.o):

View File

@@ -0,0 +1,90 @@
#
# 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_SHA1
help
Implements BSD Secure Levels as an LSM. See
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

View File

@@ -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

Binary file not shown.

View File

@@ -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");

View File

@@ -0,0 +1,414 @@
/* 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;
}
/*
* Check that a process has enough memory to allocate a new virtual
* mapping. 0 means there is enough memory for the allocation to
* succeed and -ENOMEM implies there is not.
*
* We currently support three overcommit policies, which are set via the
* vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting
*
* Strict overcommit modes added 2002 Feb 26 by Alan Cox.
* Additional code 2002 Jul 20 by Robert Love.
*/
int cap_vm_enough_memory(long pages)
{
unsigned long free, allowed;
vm_acct_memory(pages);
/*
* Sometimes we want to use more memory than we have
*/
if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS)
return 0;
if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) {
unsigned long n;
free = get_page_cache_size();
free += nr_swap_pages;
/*
* Any slabs which are created with the
* SLAB_RECLAIM_ACCOUNT flag claim to have contents
* which are reclaimable, under pressure. The dentry
* cache and most inode caches should fall into this
*/
free += atomic_read(&slab_reclaim_pages);
/*
* Leave the last 3% for root
*/
if (!capable(CAP_SYS_ADMIN))
free -= free / 32;
if (free > pages)
return 0;
/*
* nr_free_pages() is very expensive on large systems,
* only call if we're about to fail.
*/
n = nr_free_pages();
if (!capable(CAP_SYS_ADMIN))
n -= n / 32;
free += n;
if (free > pages)
return 0;
vm_unacct_memory(pages);
return -ENOMEM;
}
allowed = (totalram_pages - hugetlb_total_pages())
* sysctl_overcommit_ratio / 100;
/*
* Leave the last 3% for root
*/
if (!capable(CAP_SYS_ADMIN))
allowed -= allowed / 32;
allowed += total_swap_pages;
if (atomic_read(&vm_committed_space) < allowed)
return 0;
vm_unacct_memory(pages);
return -ENOMEM;
}
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");

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
#
# Makefile for key management
#
obj-y := \
key.o \
keyring.o \
keyctl.o \
process_keys.o \
user_defined.o \
request_key.o
obj-$(CONFIG_KEYS_COMPAT) += compat.o
obj-$(CONFIG_PROC_FS) += proc.o

View File

@@ -0,0 +1,78 @@
/* compat.c: 32-bit compatibility syscall for 64-bit systems
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.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.
*/
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/keyctl.h>
#include <linux/compat.h>
#include "internal.h"
/*****************************************************************************/
/*
* the key control system call, 32-bit compatibility version for 64-bit archs
* - this should only be called if the 64-bit arch uses weird pointers in
* 32-bit mode or doesn't guarantee that the top 32-bits of the argument
* registers on taking a 32-bit syscall are zero
* - if you can, you should call sys_keyctl directly
*/
asmlinkage long compat_sys_keyctl(u32 option,
u32 arg2, u32 arg3, u32 arg4, u32 arg5)
{
switch (option) {
case KEYCTL_GET_KEYRING_ID:
return keyctl_get_keyring_ID(arg2, arg3);
case KEYCTL_JOIN_SESSION_KEYRING:
return keyctl_join_session_keyring(compat_ptr(arg3));
case KEYCTL_UPDATE:
return keyctl_update_key(arg2, compat_ptr(arg3), arg4);
case KEYCTL_REVOKE:
return keyctl_revoke_key(arg2);
case KEYCTL_DESCRIBE:
return keyctl_describe_key(arg2, compat_ptr(arg3), arg4);
case KEYCTL_CLEAR:
return keyctl_keyring_clear(arg2);
case KEYCTL_LINK:
return keyctl_keyring_link(arg2, arg3);
case KEYCTL_UNLINK:
return keyctl_keyring_unlink(arg2, arg3);
case KEYCTL_SEARCH:
return keyctl_keyring_search(arg2, compat_ptr(arg3),
compat_ptr(arg4), arg5);
case KEYCTL_READ:
return keyctl_read_key(arg2, compat_ptr(arg3), arg4);
case KEYCTL_CHOWN:
return keyctl_chown_key(arg2, arg3, arg4);
case KEYCTL_SETPERM:
return keyctl_setperm_key(arg2, arg3);
case KEYCTL_INSTANTIATE:
return keyctl_instantiate_key(arg2, compat_ptr(arg3), arg4,
arg5);
case KEYCTL_NEGATE:
return keyctl_negate_key(arg2, arg3, arg4);
default:
return -EOPNOTSUPP;
}
} /* end compat_sys_keyctl() */

View File

@@ -0,0 +1,123 @@
/* internal.h: authentication token and access key management internal defs
*
* Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.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.
*/
#ifndef _INTERNAL_H
#define _INTERNAL_H
#include <linux/key.h>
#include <linux/key-ui.h>
extern struct key_type key_type_dead;
extern struct key_type key_type_user;
/*****************************************************************************/
/*
* keep track of keys for a user
* - this needs to be separate to user_struct to avoid a refcount-loop
* (user_struct pins some keyrings which pin this struct)
* - this also keeps track of keys under request from userspace for this UID
*/
struct key_user {
struct rb_node node;
struct list_head consq; /* construction queue */
spinlock_t lock;
atomic_t usage; /* for accessing qnkeys & qnbytes */
atomic_t nkeys; /* number of keys */
atomic_t nikeys; /* number of instantiated keys */
uid_t uid;
int qnkeys; /* number of keys allocated to this user */
int qnbytes; /* number of bytes allocated to this user */
};
#define KEYQUOTA_MAX_KEYS 100
#define KEYQUOTA_MAX_BYTES 10000
#define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */
extern struct rb_root key_user_tree;
extern spinlock_t key_user_lock;
extern struct key_user root_key_user;
extern struct key_user *key_user_lookup(uid_t uid);
extern void key_user_put(struct key_user *user);
extern struct rb_root key_serial_tree;
extern spinlock_t key_serial_lock;
extern struct semaphore key_alloc_sem;
extern struct rw_semaphore key_construction_sem;
extern wait_queue_head_t request_key_conswq;
extern void keyring_publish_name(struct key *keyring);
extern int __key_link(struct key *keyring, struct key *key);
extern struct key *__keyring_search_one(struct key *keyring,
const struct key_type *type,
const char *description,
key_perm_t perm);
typedef int (*key_match_func_t)(const struct key *, const void *);
extern struct key *keyring_search_aux(struct key *keyring,
struct key_type *type,
const void *description,
key_match_func_t match);
extern struct key *search_process_keyrings_aux(struct key_type *type,
const void *description,
key_match_func_t match);
extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
extern int install_thread_keyring(struct task_struct *tsk);
/*
* keyctl functions
*/
extern long keyctl_get_keyring_ID(key_serial_t, int);
extern long keyctl_join_session_keyring(const char __user *);
extern long keyctl_update_key(key_serial_t, const void __user *, size_t);
extern long keyctl_revoke_key(key_serial_t);
extern long keyctl_keyring_clear(key_serial_t);
extern long keyctl_keyring_link(key_serial_t, key_serial_t);
extern long keyctl_keyring_unlink(key_serial_t, key_serial_t);
extern long keyctl_describe_key(key_serial_t, char __user *, size_t);
extern long keyctl_keyring_search(key_serial_t, const char __user *,
const char __user *, key_serial_t);
extern long keyctl_read_key(key_serial_t, char __user *, size_t);
extern long keyctl_chown_key(key_serial_t, uid_t, gid_t);
extern long keyctl_setperm_key(key_serial_t, key_perm_t);
extern long keyctl_instantiate_key(key_serial_t, const void __user *,
size_t, key_serial_t);
extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t);
/*
* debugging key validation
*/
#ifdef KEY_DEBUGGING
extern void __key_check(const struct key *);
static inline void key_check(const struct key *key)
{
if (key && (IS_ERR(key) || key->magic != KEY_DEBUG_MAGIC))
__key_check(key);
}
#else
#define key_check(key) do {} while(0)
#endif
#endif /* _INTERNAL_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,987 @@
/* keyctl.c: userspace keyctl operations
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/keyctl.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <asm/uaccess.h>
#include "internal.h"
/*****************************************************************************/
/*
* extract the description of a new key from userspace and either add it as a
* new key to the specified keyring or update a matching key in that keyring
* - the keyring must be writable
* - returns the new key's serial number
* - implements add_key()
*/
asmlinkage long sys_add_key(const char __user *_type,
const char __user *_description,
const void __user *_payload,
size_t plen,
key_serial_t ringid)
{
struct key *keyring, *key;
char type[32], *description;
void *payload;
long dlen, ret;
ret = -EINVAL;
if (plen > 32767)
goto error;
/* draw all the data into kernel space */
ret = strncpy_from_user(type, _type, sizeof(type) - 1);
if (ret < 0)
goto error;
type[31] = '\0';
ret = -EFAULT;
dlen = strnlen_user(_description, PAGE_SIZE - 1);
if (dlen <= 0)
goto error;
ret = -EINVAL;
if (dlen > PAGE_SIZE - 1)
goto error;
ret = -ENOMEM;
description = kmalloc(dlen + 1, GFP_KERNEL);
if (!description)
goto error;
ret = -EFAULT;
if (copy_from_user(description, _description, dlen + 1) != 0)
goto error2;
/* pull the payload in if one was supplied */
payload = NULL;
if (_payload) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL);
if (!payload)
goto error2;
ret = -EFAULT;
if (copy_from_user(payload, _payload, plen) != 0)
goto error3;
}
/* find the target keyring (which must be writable) */
keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error3;
}
/* create or update the requested key and add it to the target
* keyring */
key = key_create_or_update(keyring, type, description,
payload, plen, 0);
if (!IS_ERR(key)) {
ret = key->serial;
key_put(key);
}
else {
ret = PTR_ERR(key);
}
key_put(keyring);
error3:
kfree(payload);
error2:
kfree(description);
error:
return ret;
} /* end sys_add_key() */
/*****************************************************************************/
/*
* search the process keyrings for a matching key
* - nested keyrings may also be searched if they have Search permission
* - if a key is found, it will be attached to the destination keyring if
* there's one specified
* - /sbin/request-key will be invoked if _callout_info is non-NULL
* - the _callout_info string will be passed to /sbin/request-key
* - if the _callout_info string is empty, it will be rendered as "-"
* - implements request_key()
*/
asmlinkage long sys_request_key(const char __user *_type,
const char __user *_description,
const char __user *_callout_info,
key_serial_t destringid)
{
struct key_type *ktype;
struct key *key, *dest;
char type[32], *description, *callout_info;
long dlen, ret;
/* pull the type into kernel space */
ret = strncpy_from_user(type, _type, sizeof(type) - 1);
if (ret < 0)
goto error;
type[31] = '\0';
/* pull the description into kernel space */
ret = -EFAULT;
dlen = strnlen_user(_description, PAGE_SIZE - 1);
if (dlen <= 0)
goto error;
ret = -EINVAL;
if (dlen > PAGE_SIZE - 1)
goto error;
ret = -ENOMEM;
description = kmalloc(dlen + 1, GFP_KERNEL);
if (!description)
goto error;
ret = -EFAULT;
if (copy_from_user(description, _description, dlen + 1) != 0)
goto error2;
/* pull the callout info into kernel space */
callout_info = NULL;
if (_callout_info) {
ret = -EFAULT;
dlen = strnlen_user(_callout_info, PAGE_SIZE - 1);
if (dlen <= 0)
goto error2;
ret = -EINVAL;
if (dlen > PAGE_SIZE - 1)
goto error2;
ret = -ENOMEM;
callout_info = kmalloc(dlen + 1, GFP_KERNEL);
if (!callout_info)
goto error2;
ret = -EFAULT;
if (copy_from_user(callout_info, _callout_info, dlen + 1) != 0)
goto error3;
}
/* get the destination keyring if specified */
dest = NULL;
if (destringid) {
dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
if (IS_ERR(dest)) {
ret = PTR_ERR(dest);
goto error3;
}
}
/* find the key type */
ktype = key_type_lookup(type);
if (IS_ERR(ktype)) {
ret = PTR_ERR(ktype);
goto error4;
}
/* do the search */
key = request_key(ktype, description, callout_info);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error5;
}
/* link the resulting key to the destination keyring */
if (dest) {
ret = key_link(dest, key);
if (ret < 0)
goto error6;
}
ret = key->serial;
error6:
key_put(key);
error5:
key_type_put(ktype);
error4:
key_put(dest);
error3:
kfree(callout_info);
error2:
kfree(description);
error:
return ret;
} /* end sys_request_key() */
/*****************************************************************************/
/*
* get the ID of the specified process keyring
* - the keyring must have search permission to be found
* - implements keyctl(KEYCTL_GET_KEYRING_ID)
*/
long keyctl_get_keyring_ID(key_serial_t id, int create)
{
struct key *key;
long ret;
key = lookup_user_key(id, create, 0, KEY_SEARCH);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
}
ret = key->serial;
key_put(key);
error:
return ret;
} /* end keyctl_get_keyring_ID() */
/*****************************************************************************/
/*
* join the session keyring
* - implements keyctl(KEYCTL_JOIN_SESSION_KEYRING)
*/
long keyctl_join_session_keyring(const char __user *_name)
{
char *name;
long nlen, ret;
/* fetch the name from userspace */
name = NULL;
if (_name) {
ret = -EFAULT;
nlen = strnlen_user(_name, PAGE_SIZE - 1);
if (nlen <= 0)
goto error;
ret = -EINVAL;
if (nlen > PAGE_SIZE - 1)
goto error;
ret = -ENOMEM;
name = kmalloc(nlen + 1, GFP_KERNEL);
if (!name)
goto error;
ret = -EFAULT;
if (copy_from_user(name, _name, nlen + 1) != 0)
goto error2;
}
/* join the session */
ret = join_session_keyring(name);
error2:
kfree(name);
error:
return ret;
} /* end keyctl_join_session_keyring() */
/*****************************************************************************/
/*
* update a key's data payload
* - the key must be writable
* - implements keyctl(KEYCTL_UPDATE)
*/
long keyctl_update_key(key_serial_t id,
const void __user *_payload,
size_t plen)
{
struct key *key;
void *payload;
long ret;
ret = -EINVAL;
if (plen > PAGE_SIZE)
goto error;
/* pull the payload in if one was supplied */
payload = NULL;
if (_payload) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL);
if (!payload)
goto error;
ret = -EFAULT;
if (copy_from_user(payload, _payload, plen) != 0)
goto error2;
}
/* find the target key (which must be writable) */
key = lookup_user_key(id, 0, 0, KEY_WRITE);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error2;
}
/* update the key */
ret = key_update(key, payload, plen);
key_put(key);
error2:
kfree(payload);
error:
return ret;
} /* end keyctl_update_key() */
/*****************************************************************************/
/*
* revoke a key
* - the key must be writable
* - implements keyctl(KEYCTL_REVOKE)
*/
long keyctl_revoke_key(key_serial_t id)
{
struct key *key;
long ret;
key = lookup_user_key(id, 0, 0, KEY_WRITE);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
}
key_revoke(key);
ret = 0;
key_put(key);
error:
return 0;
} /* end keyctl_revoke_key() */
/*****************************************************************************/
/*
* clear the specified process keyring
* - the keyring must be writable
* - implements keyctl(KEYCTL_CLEAR)
*/
long keyctl_keyring_clear(key_serial_t ringid)
{
struct key *keyring;
long ret;
keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
ret = keyring_clear(keyring);
key_put(keyring);
error:
return ret;
} /* end keyctl_keyring_clear() */
/*****************************************************************************/
/*
* link a key into a keyring
* - the keyring must be writable
* - the key must be linkable
* - implements keyctl(KEYCTL_LINK)
*/
long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
{
struct key *keyring, *key;
long ret;
keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
key = lookup_user_key(id, 1, 0, KEY_LINK);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error2;
}
ret = key_link(keyring, key);
key_put(key);
error2:
key_put(keyring);
error:
return ret;
} /* end keyctl_keyring_link() */
/*****************************************************************************/
/*
* unlink the first attachment of a key from a keyring
* - the keyring must be writable
* - we don't need any permissions on the key
* - implements keyctl(KEYCTL_UNLINK)
*/
long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
{
struct key *keyring, *key;
long ret;
keyring = lookup_user_key(ringid, 0, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
key = lookup_user_key(id, 0, 0, 0);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error2;
}
ret = key_unlink(keyring, key);
key_put(key);
error2:
key_put(keyring);
error:
return ret;
} /* end keyctl_keyring_unlink() */
/*****************************************************************************/
/*
* describe a user key
* - the key must have view permission
* - if there's a buffer, we place up to buflen bytes of data into it
* - unless there's an error, we return the amount of description available,
* irrespective of how much we may have copied
* - the description is formatted thus:
* type;uid;gid;perm;description<NUL>
* - implements keyctl(KEYCTL_DESCRIBE)
*/
long keyctl_describe_key(key_serial_t keyid,
char __user *buffer,
size_t buflen)
{
struct key *key;
char *tmpbuf;
long ret;
key = lookup_user_key(keyid, 0, 1, KEY_VIEW);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
}
/* calculate how much description we're going to return */
ret = -ENOMEM;
tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!tmpbuf)
goto error2;
ret = snprintf(tmpbuf, PAGE_SIZE - 1,
"%s;%d;%d;%06x;%s",
key->type->name,
key->uid,
key->gid,
key->perm,
key->description ? key->description :""
);
/* include a NUL char at the end of the data */
if (ret > PAGE_SIZE - 1)
ret = PAGE_SIZE - 1;
tmpbuf[ret] = 0;
ret++;
/* consider returning the data */
if (buffer && buflen > 0) {
if (buflen > ret)
buflen = ret;
if (copy_to_user(buffer, tmpbuf, buflen) != 0)
ret = -EFAULT;
}
kfree(tmpbuf);
error2:
key_put(key);
error:
return ret;
} /* end keyctl_describe_key() */
/*****************************************************************************/
/*
* search the specified keyring for a matching key
* - the start keyring must be searchable
* - nested keyrings may also be searched if they are searchable
* - only keys with search permission may be found
* - if a key is found, it will be attached to the destination keyring if
* there's one specified
* - implements keyctl(KEYCTL_SEARCH)
*/
long keyctl_keyring_search(key_serial_t ringid,
const char __user *_type,
const char __user *_description,
key_serial_t destringid)
{
struct key_type *ktype;
struct key *keyring, *key, *dest;
char type[32], *description;
long dlen, ret;
/* pull the type and description into kernel space */
ret = strncpy_from_user(type, _type, sizeof(type) - 1);
if (ret < 0)
goto error;
type[31] = '\0';
ret = -EFAULT;
dlen = strnlen_user(_description, PAGE_SIZE - 1);
if (dlen <= 0)
goto error;
ret = -EINVAL;
if (dlen > PAGE_SIZE - 1)
goto error;
ret = -ENOMEM;
description = kmalloc(dlen + 1, GFP_KERNEL);
if (!description)
goto error;
ret = -EFAULT;
if (copy_from_user(description, _description, dlen + 1) != 0)
goto error2;
/* get the keyring at which to begin the search */
keyring = lookup_user_key(ringid, 0, 0, KEY_SEARCH);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
}
/* get the destination keyring if specified */
dest = NULL;
if (destringid) {
dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
if (IS_ERR(dest)) {
ret = PTR_ERR(dest);
goto error3;
}
}
/* find the key type */
ktype = key_type_lookup(type);
if (IS_ERR(ktype)) {
ret = PTR_ERR(ktype);
goto error4;
}
/* do the search */
key = keyring_search(keyring, ktype, description);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
/* treat lack or presence of a negative key the same */
if (ret == -EAGAIN)
ret = -ENOKEY;
goto error5;
}
/* link the resulting key to the destination keyring if we can */
if (dest) {
ret = -EACCES;
if (!key_permission(key, KEY_LINK))
goto error6;
ret = key_link(dest, key);
if (ret < 0)
goto error6;
}
ret = key->serial;
error6:
key_put(key);
error5:
key_type_put(ktype);
error4:
key_put(dest);
error3:
key_put(keyring);
error2:
kfree(description);
error:
return ret;
} /* end keyctl_keyring_search() */
/*****************************************************************************/
/*
* see if the key we're looking at is the target key
*/
static int keyctl_read_key_same(const struct key *key, const void *target)
{
return key == target;
} /* end keyctl_read_key_same() */
/*****************************************************************************/
/*
* read a user key's payload
* - the keyring must be readable or the key must be searchable from the
* process's keyrings
* - if there's a buffer, we place up to buflen bytes of data into it
* - unless there's an error, we return the amount of data in the key,
* irrespective of how much we may have copied
* - implements keyctl(KEYCTL_READ)
*/
long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
{
struct key *key, *skey;
long ret;
/* find the key first */
key = lookup_user_key(keyid, 0, 0, 0);
if (!IS_ERR(key)) {
/* see if we can read it directly */
if (key_permission(key, KEY_READ))
goto can_read_key;
/* can't; see if it's searchable from this process's
* keyrings */
ret = -ENOKEY;
if (key_permission(key, KEY_SEARCH)) {
/* okay - we do have search permission on the key
* itself, but do we have the key? */
skey = search_process_keyrings_aux(key->type, key,
keyctl_read_key_same);
if (!IS_ERR(skey))
goto can_read_key2;
}
goto error2;
}
ret = -ENOKEY;
goto error;
/* the key is probably readable - now try to read it */
can_read_key2:
key_put(skey);
can_read_key:
ret = key_validate(key);
if (ret == 0) {
ret = -EOPNOTSUPP;
if (key->type->read) {
/* read the data with the semaphore held (since we
* might sleep) */
down_read(&key->sem);
ret = key->type->read(key, buffer, buflen);
up_read(&key->sem);
}
}
error2:
key_put(key);
error:
return ret;
} /* end keyctl_read_key() */
/*****************************************************************************/
/*
* change the ownership of a key
* - the keyring owned by the changer
* - if the uid or gid is -1, then that parameter is not changed
* - implements keyctl(KEYCTL_CHOWN)
*/
long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
{
struct key *key;
long ret;
ret = 0;
if (uid == (uid_t) -1 && gid == (gid_t) -1)
goto error;
key = lookup_user_key(id, 1, 1, 0);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
}
/* make the changes with the locks held to prevent chown/chown races */
ret = -EACCES;
down_write(&key->sem);
write_lock(&key->lock);
if (!capable(CAP_SYS_ADMIN)) {
/* only the sysadmin can chown a key to some other UID */
if (uid != (uid_t) -1 && key->uid != uid)
goto no_access;
/* only the sysadmin can set the key's GID to a group other
* than one of those that the current process subscribes to */
if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
goto no_access;
}
/* change the UID (have to update the quotas) */
if (uid != (uid_t) -1 && uid != key->uid) {
/* don't support UID changing yet */
ret = -EOPNOTSUPP;
goto no_access;
}
/* change the GID */
if (gid != (gid_t) -1)
key->gid = gid;
ret = 0;
no_access:
write_unlock(&key->lock);
up_write(&key->sem);
key_put(key);
error:
return ret;
} /* end keyctl_chown_key() */
/*****************************************************************************/
/*
* change the permission mask on a key
* - the keyring owned by the changer
* - implements keyctl(KEYCTL_SETPERM)
*/
long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
{
struct key *key;
long ret;
ret = -EINVAL;
if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
goto error;
key = lookup_user_key(id, 1, 1, 0);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
}
/* make the changes with the locks held to prevent chown/chmod
* races */
ret = -EACCES;
down_write(&key->sem);
write_lock(&key->lock);
/* if we're not the sysadmin, we can only chmod a key that we
* own */
if (!capable(CAP_SYS_ADMIN) && key->uid != current->fsuid)
goto no_access;
/* changing the permissions mask */
key->perm = perm;
ret = 0;
no_access:
write_unlock(&key->lock);
up_write(&key->sem);
key_put(key);
error:
return ret;
} /* end keyctl_setperm_key() */
/*****************************************************************************/
/*
* instantiate the key with the specified payload, and, if one is given, link
* the key into the keyring
*/
long keyctl_instantiate_key(key_serial_t id,
const void __user *_payload,
size_t plen,
key_serial_t ringid)
{
struct key *key, *keyring;
void *payload;
long ret;
ret = -EINVAL;
if (plen > 32767)
goto error;
/* pull the payload in if one was supplied */
payload = NULL;
if (_payload) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL);
if (!payload)
goto error;
ret = -EFAULT;
if (copy_from_user(payload, _payload, plen) != 0)
goto error2;
}
/* find the target key (which must be writable) */
key = lookup_user_key(id, 0, 1, KEY_WRITE);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error2;
}
/* find the destination keyring if present (which must also be
* writable) */
keyring = NULL;
if (ringid) {
keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error3;
}
}
/* instantiate the key and link it into a keyring */
ret = key_instantiate_and_link(key, payload, plen, keyring);
key_put(keyring);
error3:
key_put(key);
error2:
kfree(payload);
error:
return ret;
} /* end keyctl_instantiate_key() */
/*****************************************************************************/
/*
* negatively instantiate the key with the given timeout (in seconds), and, if
* one is given, link the key into the keyring
*/
long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
{
struct key *key, *keyring;
long ret;
/* find the target key (which must be writable) */
key = lookup_user_key(id, 0, 1, KEY_WRITE);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
}
/* find the destination keyring if present (which must also be
* writable) */
keyring = NULL;
if (ringid) {
keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
}
}
/* instantiate the key and link it into a keyring */
ret = key_negate_and_link(key, timeout, keyring);
key_put(keyring);
error2:
key_put(key);
error:
return ret;
} /* end keyctl_negate_key() */
/*****************************************************************************/
/*
* the key control system call
*/
asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
switch (option) {
case KEYCTL_GET_KEYRING_ID:
return keyctl_get_keyring_ID((key_serial_t) arg2,
(int) arg3);
case KEYCTL_JOIN_SESSION_KEYRING:
return keyctl_join_session_keyring((const char __user *) arg3);
case KEYCTL_UPDATE:
return keyctl_update_key((key_serial_t) arg2,
(const void __user *) arg3,
(size_t) arg4);
case KEYCTL_REVOKE:
return keyctl_revoke_key((key_serial_t) arg2);
case KEYCTL_DESCRIBE:
return keyctl_describe_key((key_serial_t) arg2,
(char __user *) arg3,
(unsigned) arg4);
case KEYCTL_CLEAR:
return keyctl_keyring_clear((key_serial_t) arg2);
case KEYCTL_LINK:
return keyctl_keyring_link((key_serial_t) arg2,
(key_serial_t) arg3);
case KEYCTL_UNLINK:
return keyctl_keyring_unlink((key_serial_t) arg2,
(key_serial_t) arg3);
case KEYCTL_SEARCH:
return keyctl_keyring_search((key_serial_t) arg2,
(const char __user *) arg3,
(const char __user *) arg4,
(key_serial_t) arg5);
case KEYCTL_READ:
return keyctl_read_key((key_serial_t) arg2,
(char __user *) arg3,
(size_t) arg4);
case KEYCTL_CHOWN:
return keyctl_chown_key((key_serial_t) arg2,
(uid_t) arg3,
(gid_t) arg4);
case KEYCTL_SETPERM:
return keyctl_setperm_key((key_serial_t) arg2,
(key_perm_t) arg3);
case KEYCTL_INSTANTIATE:
return keyctl_instantiate_key((key_serial_t) arg2,
(const void __user *) arg3,
(size_t) arg4,
(key_serial_t) arg5);
case KEYCTL_NEGATE:
return keyctl_negate_key((key_serial_t) arg2,
(unsigned) arg3,
(key_serial_t) arg4);
default:
return -EOPNOTSUPP;
}
} /* end sys_keyctl() */

View File

@@ -0,0 +1,895 @@
/* keyring.c: keyring handling
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/err.h>
#include <asm/uaccess.h>
#include "internal.h"
/*
* when plumbing the depths of the key tree, this sets a hard limit set on how
* deep we're willing to go
*/
#define KEYRING_SEARCH_MAX_DEPTH 6
/*
* we keep all named keyrings in a hash to speed looking them up
*/
#define KEYRING_NAME_HASH_SIZE (1 << 5)
static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE];
static rwlock_t keyring_name_lock = RW_LOCK_UNLOCKED;
static inline unsigned keyring_hash(const char *desc)
{
unsigned bucket = 0;
for (; *desc; desc++)
bucket += (unsigned char) *desc;
return bucket & (KEYRING_NAME_HASH_SIZE - 1);
}
/*
* the keyring type definition
*/
static int keyring_instantiate(struct key *keyring,
const void *data, size_t datalen);
static int keyring_duplicate(struct key *keyring, const struct key *source);
static int keyring_match(const struct key *keyring, const void *criterion);
static void keyring_destroy(struct key *keyring);
static void keyring_describe(const struct key *keyring, struct seq_file *m);
static long keyring_read(const struct key *keyring,
char __user *buffer, size_t buflen);
struct key_type key_type_keyring = {
.name = "keyring",
.def_datalen = sizeof(struct keyring_list),
.instantiate = keyring_instantiate,
.duplicate = keyring_duplicate,
.match = keyring_match,
.destroy = keyring_destroy,
.describe = keyring_describe,
.read = keyring_read,
};
/*
* semaphore to serialise link/link calls to prevent two link calls in parallel
* introducing a cycle
*/
DECLARE_RWSEM(keyring_serialise_link_sem);
/*****************************************************************************/
/*
* publish the name of a keyring so that it can be found by name (if it has
* one)
*/
void keyring_publish_name(struct key *keyring)
{
int bucket;
if (keyring->description) {
bucket = keyring_hash(keyring->description);
write_lock(&keyring_name_lock);
if (!keyring_name_hash[bucket].next)
INIT_LIST_HEAD(&keyring_name_hash[bucket]);
list_add_tail(&keyring->type_data.link,
&keyring_name_hash[bucket]);
write_unlock(&keyring_name_lock);
}
} /* end keyring_publish_name() */
/*****************************************************************************/
/*
* initialise a keyring
* - we object if we were given any data
*/
static int keyring_instantiate(struct key *keyring,
const void *data, size_t datalen)
{
int ret;
ret = -EINVAL;
if (datalen == 0) {
/* make the keyring available by name if it has one */
keyring_publish_name(keyring);
ret = 0;
}
return ret;
} /* end keyring_instantiate() */
/*****************************************************************************/
/*
* duplicate the list of subscribed keys from a source keyring into this one
*/
static int keyring_duplicate(struct key *keyring, const struct key *source)
{
struct keyring_list *sklist, *klist;
unsigned max;
size_t size;
int loop, ret;
const unsigned limit =
(PAGE_SIZE - sizeof(*klist)) / sizeof(struct key);
ret = 0;
sklist = source->payload.subscriptions;
if (sklist && sklist->nkeys > 0) {
max = sklist->nkeys;
BUG_ON(max > limit);
max = (max + 3) & ~3;
if (max > limit)
max = limit;
ret = -ENOMEM;
size = sizeof(*klist) + sizeof(struct key) * max;
klist = kmalloc(size, GFP_KERNEL);
if (!klist)
goto error;
klist->maxkeys = max;
klist->nkeys = sklist->nkeys;
memcpy(klist->keys,
sklist->keys,
sklist->nkeys * sizeof(struct key));
for (loop = klist->nkeys - 1; loop >= 0; loop--)
atomic_inc(&klist->keys[loop]->usage);
keyring->payload.subscriptions = klist;
ret = 0;
}
error:
return ret;
} /* end keyring_duplicate() */
/*****************************************************************************/
/*
* match keyrings on their name
*/
static int keyring_match(const struct key *keyring, const void *description)
{
return keyring->description &&
strcmp(keyring->description, description) == 0;
} /* end keyring_match() */
/*****************************************************************************/
/*
* dispose of the data dangling from the corpse of a keyring
*/
static void keyring_destroy(struct key *keyring)
{
struct keyring_list *klist;
int loop;
if (keyring->description) {
write_lock(&keyring_name_lock);
list_del(&keyring->type_data.link);
write_unlock(&keyring_name_lock);
}
klist = keyring->payload.subscriptions;
if (klist) {
for (loop = klist->nkeys - 1; loop >= 0; loop--)
key_put(klist->keys[loop]);
kfree(klist);
}
} /* end keyring_destroy() */
/*****************************************************************************/
/*
* describe the keyring
*/
static void keyring_describe(const struct key *keyring, struct seq_file *m)
{
struct keyring_list *klist;
if (keyring->description) {
seq_puts(m, keyring->description);
}
else {
seq_puts(m, "[anon]");
}
klist = keyring->payload.subscriptions;
if (klist)
seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
else
seq_puts(m, ": empty");
} /* end keyring_describe() */
/*****************************************************************************/
/*
* read a list of key IDs from the keyring's contents
*/
static long keyring_read(const struct key *keyring,
char __user *buffer, size_t buflen)
{
struct keyring_list *klist;
struct key *key;
size_t qty, tmp;
int loop, ret;
ret = 0;
klist = keyring->payload.subscriptions;
if (klist) {
/* calculate how much data we could return */
qty = klist->nkeys * sizeof(key_serial_t);
if (buffer && buflen > 0) {
if (buflen > qty)
buflen = qty;
/* copy the IDs of the subscribed keys into the
* buffer */
ret = -EFAULT;
for (loop = 0; loop < klist->nkeys; loop++) {
key = klist->keys[loop];
tmp = sizeof(key_serial_t);
if (tmp > buflen)
tmp = buflen;
if (copy_to_user(buffer,
&key->serial,
tmp) != 0)
goto error;
buflen -= tmp;
if (buflen == 0)
break;
buffer += tmp;
}
}
ret = qty;
}
error:
return ret;
} /* end keyring_read() */
/*****************************************************************************/
/*
* allocate a keyring and link into the destination keyring
*/
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
int not_in_quota, struct key *dest)
{
struct key *keyring;
int ret;
keyring = key_alloc(&key_type_keyring, description,
uid, gid, KEY_USR_ALL, not_in_quota);
if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest);
if (ret < 0) {
key_put(keyring);
keyring = ERR_PTR(ret);
}
}
return keyring;
} /* end keyring_alloc() */
/*****************************************************************************/
/*
* search the supplied keyring tree for a key that matches the criterion
* - perform a breadth-then-depth search up to the prescribed limit
* - we only find keys on which we have search permission
* - we use the supplied match function to see if the description (or other
* feature of interest) matches
* - we readlock the keyrings as we search down the tree
* - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we only found negative matching keys
*/
struct key *keyring_search_aux(struct key *keyring,
struct key_type *type,
const void *description,
key_match_func_t match)
{
struct {
struct key *keyring;
int kix;
} stack[KEYRING_SEARCH_MAX_DEPTH];
struct keyring_list *keylist;
struct timespec now;
struct key *key;
long err;
int sp, psp, kix;
key_check(keyring);
/* top keyring must have search permission to begin the search */
key = ERR_PTR(-EACCES);
if (!key_permission(keyring, KEY_SEARCH))
goto error;
key = ERR_PTR(-ENOTDIR);
if (keyring->type != &key_type_keyring)
goto error;
now = current_kernel_time();
err = -EAGAIN;
sp = 0;
/* start processing a new keyring */
descend:
read_lock(&keyring->lock);
if (keyring->flags & KEY_FLAG_REVOKED)
goto not_this_keyring;
keylist = keyring->payload.subscriptions;
if (!keylist)
goto not_this_keyring;
/* iterate through the keys in this keyring first */
for (kix = 0; kix < keylist->nkeys; kix++) {
key = keylist->keys[kix];
/* ignore keys not of this type */
if (key->type != type)
continue;
/* skip revoked keys and expired keys */
if (key->flags & KEY_FLAG_REVOKED)
continue;
if (key->expiry && now.tv_sec >= key->expiry)
continue;
/* keys that don't match */
if (!match(key, description))
continue;
/* key must have search permissions */
if (!key_permission(key, KEY_SEARCH))
continue;
/* we set a different error code if we find a negative key */
if (key->flags & KEY_FLAG_NEGATIVE) {
err = -ENOKEY;
continue;
}
goto found;
}
/* search through the keyrings nested in this one */
kix = 0;
ascend:
while (kix < keylist->nkeys) {
key = keylist->keys[kix];
if (key->type != &key_type_keyring)
goto next;
/* recursively search nested keyrings
* - only search keyrings for which we have search permission
*/
if (sp >= KEYRING_SEARCH_MAX_DEPTH)
goto next;
if (!key_permission(key, KEY_SEARCH))
goto next;
/* evade loops in the keyring tree */
for (psp = 0; psp < sp; psp++)
if (stack[psp].keyring == keyring)
goto next;
/* stack the current position */
stack[sp].keyring = keyring;
stack[sp].kix = kix;
sp++;
/* begin again with the new keyring */
keyring = key;
goto descend;
next:
kix++;
}
/* the keyring we're looking at was disqualified or didn't contain a
* matching key */
not_this_keyring:
read_unlock(&keyring->lock);
if (sp > 0) {
/* resume the processing of a keyring higher up in the tree */
sp--;
keyring = stack[sp].keyring;
keylist = keyring->payload.subscriptions;
kix = stack[sp].kix + 1;
goto ascend;
}
key = ERR_PTR(err);
goto error;
/* we found a viable match */
found:
atomic_inc(&key->usage);
read_unlock(&keyring->lock);
/* unwind the keyring stack */
while (sp > 0) {
sp--;
read_unlock(&stack[sp].keyring->lock);
}
key_check(key);
error:
return key;
} /* end keyring_search_aux() */
/*****************************************************************************/
/*
* search the supplied keyring tree for a key that matches the criterion
* - perform a breadth-then-depth search up to the prescribed limit
* - we only find keys on which we have search permission
* - we readlock the keyrings as we search down the tree
* - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we only found negative matching keys
*/
struct key *keyring_search(struct key *keyring,
struct key_type *type,
const char *description)
{
return keyring_search_aux(keyring, type, description, type->match);
} /* end keyring_search() */
EXPORT_SYMBOL(keyring_search);
/*****************************************************************************/
/*
* search the given keyring only (no recursion)
* - keyring must be locked by caller
*/
struct key *__keyring_search_one(struct key *keyring,
const struct key_type *ktype,
const char *description,
key_perm_t perm)
{
struct keyring_list *klist;
struct key *key;
int loop;
klist = keyring->payload.subscriptions;
if (klist) {
for (loop = 0; loop < klist->nkeys; loop++) {
key = klist->keys[loop];
if (key->type == ktype &&
key->type->match(key, description) &&
key_permission(key, perm) &&
!(key->flags & KEY_FLAG_REVOKED)
)
goto found;
}
}
key = ERR_PTR(-ENOKEY);
goto error;
found:
atomic_inc(&key->usage);
error:
return key;
} /* end __keyring_search_one() */
/*****************************************************************************/
/*
* find a keyring with the specified name
* - all named keyrings are searched
* - only find keyrings with search permission for the process
* - only find keyrings with a serial number greater than the one specified
*/
struct key *find_keyring_by_name(const char *name, key_serial_t bound)
{
struct key *keyring;
int bucket;
keyring = ERR_PTR(-EINVAL);
if (!name)
goto error;
bucket = keyring_hash(name);
read_lock(&keyring_name_lock);
if (keyring_name_hash[bucket].next) {
/* search this hash bucket for a keyring with a matching name
* that's readable and that hasn't been revoked */
list_for_each_entry(keyring,
&keyring_name_hash[bucket],
type_data.link
) {
if (keyring->flags & KEY_FLAG_REVOKED)
continue;
if (strcmp(keyring->description, name) != 0)
continue;
if (!key_permission(keyring, KEY_SEARCH))
continue;
/* found a potential candidate, but we still need to
* check the serial number */
if (keyring->serial <= bound)
continue;
/* we've got a match */
atomic_inc(&keyring->usage);
read_unlock(&keyring_name_lock);
goto error;
}
}
read_unlock(&keyring_name_lock);
keyring = ERR_PTR(-ENOKEY);
error:
return keyring;
} /* end find_keyring_by_name() */
/*****************************************************************************/
/*
* see if a cycle will will be created by inserting acyclic tree B in acyclic
* tree A at the topmost level (ie: as a direct child of A)
* - since we are adding B to A at the top level, checking for cycles should
* just be a matter of seeing if node A is somewhere in tree B
*/
static int keyring_detect_cycle(struct key *A, struct key *B)
{
struct {
struct key *subtree;
int kix;
} stack[KEYRING_SEARCH_MAX_DEPTH];
struct keyring_list *keylist;
struct key *subtree, *key;
int sp, kix, ret;
ret = -EDEADLK;
if (A == B)
goto error;
subtree = B;
sp = 0;
/* start processing a new keyring */
descend:
read_lock(&subtree->lock);
if (subtree->flags & KEY_FLAG_REVOKED)
goto not_this_keyring;
keylist = subtree->payload.subscriptions;
if (!keylist)
goto not_this_keyring;
kix = 0;
ascend:
/* iterate through the remaining keys in this keyring */
for (; kix < keylist->nkeys; kix++) {
key = keylist->keys[kix];
if (key == A)
goto cycle_detected;
/* recursively check nested keyrings */
if (key->type == &key_type_keyring) {
if (sp >= KEYRING_SEARCH_MAX_DEPTH)
goto too_deep;
/* stack the current position */
stack[sp].subtree = subtree;
stack[sp].kix = kix;
sp++;
/* begin again with the new keyring */
subtree = key;
goto descend;
}
}
/* the keyring we're looking at was disqualified or didn't contain a
* matching key */
not_this_keyring:
read_unlock(&subtree->lock);
if (sp > 0) {
/* resume the checking of a keyring higher up in the tree */
sp--;
subtree = stack[sp].subtree;
keylist = subtree->payload.subscriptions;
kix = stack[sp].kix + 1;
goto ascend;
}
ret = 0; /* no cycles detected */
error:
return ret;
too_deep:
ret = -ELOOP;
goto error_unwind;
cycle_detected:
ret = -EDEADLK;
error_unwind:
read_unlock(&subtree->lock);
/* unwind the keyring stack */
while (sp > 0) {
sp--;
read_unlock(&stack[sp].subtree->lock);
}
goto error;
} /* end keyring_detect_cycle() */
/*****************************************************************************/
/*
* link a key into to a keyring
* - must be called with the keyring's semaphore held
*/
int __key_link(struct key *keyring, struct key *key)
{
struct keyring_list *klist, *nklist;
unsigned max;
size_t size;
int ret;
ret = -EKEYREVOKED;
if (keyring->flags & KEY_FLAG_REVOKED)
goto error;
ret = -ENOTDIR;
if (keyring->type != &key_type_keyring)
goto error;
/* serialise link/link calls to prevent parallel calls causing a
* cycle when applied to two keyring in opposite orders */
down_write(&keyring_serialise_link_sem);
/* check that we aren't going to create a cycle adding one keyring to
* another */
if (key->type == &key_type_keyring) {
ret = keyring_detect_cycle(keyring, key);
if (ret < 0)
goto error2;
}
/* check that we aren't going to overrun the user's quota */
ret = key_payload_reserve(keyring,
keyring->datalen + KEYQUOTA_LINK_BYTES);
if (ret < 0)
goto error2;
klist = keyring->payload.subscriptions;
if (klist && klist->nkeys < klist->maxkeys) {
/* there's sufficient slack space to add directly */
atomic_inc(&key->usage);
write_lock(&keyring->lock);
klist->keys[klist->nkeys++] = key;
write_unlock(&keyring->lock);
ret = 0;
}
else {
/* grow the key list */
max = 4;
if (klist)
max += klist->maxkeys;
ret = -ENFILE;
size = sizeof(*klist) + sizeof(*key) * max;
if (size > PAGE_SIZE)
goto error3;
ret = -ENOMEM;
nklist = kmalloc(size, GFP_KERNEL);
if (!nklist)
goto error3;
nklist->maxkeys = max;
nklist->nkeys = 0;
if (klist) {
nklist->nkeys = klist->nkeys;
memcpy(nklist->keys,
klist->keys,
sizeof(struct key *) * klist->nkeys);
}
/* add the key into the new space */
atomic_inc(&key->usage);
write_lock(&keyring->lock);
keyring->payload.subscriptions = nklist;
nklist->keys[nklist->nkeys++] = key;
write_unlock(&keyring->lock);
/* dispose of the old keyring list */
kfree(klist);
ret = 0;
}
error2:
up_write(&keyring_serialise_link_sem);
error:
return ret;
error3:
/* undo the quota changes */
key_payload_reserve(keyring,
keyring->datalen - KEYQUOTA_LINK_BYTES);
goto error2;
} /* end __key_link() */
/*****************************************************************************/
/*
* link a key to a keyring
*/
int key_link(struct key *keyring, struct key *key)
{
int ret;
key_check(keyring);
key_check(key);
down_write(&keyring->sem);
ret = __key_link(keyring, key);
up_write(&keyring->sem);
return ret;
} /* end key_link() */
EXPORT_SYMBOL(key_link);
/*****************************************************************************/
/*
* unlink the first link to a key from a keyring
*/
int key_unlink(struct key *keyring, struct key *key)
{
struct keyring_list *klist;
int loop, ret;
key_check(keyring);
key_check(key);
ret = -ENOTDIR;
if (keyring->type != &key_type_keyring)
goto error;
down_write(&keyring->sem);
klist = keyring->payload.subscriptions;
if (klist) {
/* search the keyring for the key */
for (loop = 0; loop < klist->nkeys; loop++)
if (klist->keys[loop] == key)
goto key_is_present;
}
up_write(&keyring->sem);
ret = -ENOENT;
goto error;
key_is_present:
/* adjust the user's quota */
key_payload_reserve(keyring,
keyring->datalen - KEYQUOTA_LINK_BYTES);
/* shuffle down the key pointers
* - it might be worth shrinking the allocated memory, but that runs
* the risk of ENOMEM as we would have to copy
*/
write_lock(&keyring->lock);
klist->nkeys--;
if (loop < klist->nkeys)
memcpy(&klist->keys[loop],
&klist->keys[loop + 1],
(klist->nkeys - loop) * sizeof(struct key *));
write_unlock(&keyring->lock);
up_write(&keyring->sem);
key_put(key);
ret = 0;
error:
return ret;
} /* end key_unlink() */
EXPORT_SYMBOL(key_unlink);
/*****************************************************************************/
/*
* clear the specified process keyring
* - implements keyctl(KEYCTL_CLEAR)
*/
int keyring_clear(struct key *keyring)
{
struct keyring_list *klist;
int loop, ret;
ret = -ENOTDIR;
if (keyring->type == &key_type_keyring) {
/* detach the pointer block with the locks held */
down_write(&keyring->sem);
klist = keyring->payload.subscriptions;
if (klist) {
/* adjust the quota */
key_payload_reserve(keyring,
sizeof(struct keyring_list));
write_lock(&keyring->lock);
keyring->payload.subscriptions = NULL;
write_unlock(&keyring->lock);
}
up_write(&keyring->sem);
/* free the keys after the locks have been dropped */
if (klist) {
for (loop = klist->nkeys - 1; loop >= 0; loop--)
key_put(klist->keys[loop]);
kfree(klist);
}
ret = 0;
}
return ret;
} /* end keyring_clear() */
EXPORT_SYMBOL(keyring_clear);

View File

@@ -0,0 +1,251 @@
/* proc.c: proc files for key database enumeration
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/errno.h>
#include "internal.h"
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
static int proc_keys_open(struct inode *inode, struct file *file);
static void *proc_keys_start(struct seq_file *p, loff_t *_pos);
static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos);
static void proc_keys_stop(struct seq_file *p, void *v);
static int proc_keys_show(struct seq_file *m, void *v);
static struct seq_operations proc_keys_ops = {
.start = proc_keys_start,
.next = proc_keys_next,
.stop = proc_keys_stop,
.show = proc_keys_show,
};
static struct file_operations proc_keys_fops = {
.open = proc_keys_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
#endif
static int proc_key_users_open(struct inode *inode, struct file *file);
static void *proc_key_users_start(struct seq_file *p, loff_t *_pos);
static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos);
static void proc_key_users_stop(struct seq_file *p, void *v);
static int proc_key_users_show(struct seq_file *m, void *v);
static struct seq_operations proc_key_users_ops = {
.start = proc_key_users_start,
.next = proc_key_users_next,
.stop = proc_key_users_stop,
.show = proc_key_users_show,
};
static struct file_operations proc_key_users_fops = {
.open = proc_key_users_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
/*****************************************************************************/
/*
* declare the /proc files
*/
static int __init key_proc_init(void)
{
struct proc_dir_entry *p;
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
p = create_proc_entry("keys", 0, NULL);
if (!p)
panic("Cannot create /proc/keys\n");
p->proc_fops = &proc_keys_fops;
#endif
p = create_proc_entry("key-users", 0, NULL);
if (!p)
panic("Cannot create /proc/key-users\n");
p->proc_fops = &proc_key_users_fops;
return 0;
} /* end key_proc_init() */
__initcall(key_proc_init);
/*****************************************************************************/
/*
* implement "/proc/keys" to provides a list of the keys on the system
*/
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
static int proc_keys_open(struct inode *inode, struct file *file)
{
return seq_open(file, &proc_keys_ops);
}
static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
{
struct rb_node *_p;
loff_t pos = *_pos;
spin_lock(&key_serial_lock);
_p = rb_first(&key_serial_tree);
while (pos > 0 && _p) {
pos--;
_p = rb_next(_p);
}
return _p;
}
static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
{
(*_pos)++;
return rb_next((struct rb_node *) v);
}
static void proc_keys_stop(struct seq_file *p, void *v)
{
spin_unlock(&key_serial_lock);
}
static int proc_keys_show(struct seq_file *m, void *v)
{
struct rb_node *_p = v;
struct key *key = rb_entry(_p, struct key, serial_node);
struct timespec now;
unsigned long timo;
char xbuf[12];
now = current_kernel_time();
read_lock(&key->lock);
/* come up with a suitable timeout value */
if (key->expiry == 0) {
memcpy(xbuf, "perm", 5);
}
else if (now.tv_sec >= key->expiry) {
memcpy(xbuf, "expd", 5);
}
else {
timo = key->expiry - now.tv_sec;
if (timo < 60)
sprintf(xbuf, "%lus", timo);
else if (timo < 60*60)
sprintf(xbuf, "%lum", timo / 60);
else if (timo < 60*60*24)
sprintf(xbuf, "%luh", timo / (60*60));
else if (timo < 60*60*24*7)
sprintf(xbuf, "%lud", timo / (60*60*24));
else
sprintf(xbuf, "%luw", timo / (60*60*24*7));
}
seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ",
key->serial,
key->flags & KEY_FLAG_INSTANTIATED ? 'I' : '-',
key->flags & KEY_FLAG_REVOKED ? 'R' : '-',
key->flags & KEY_FLAG_DEAD ? 'D' : '-',
key->flags & KEY_FLAG_IN_QUOTA ? 'Q' : '-',
key->flags & KEY_FLAG_USER_CONSTRUCT ? 'U' : '-',
key->flags & KEY_FLAG_NEGATIVE ? 'N' : '-',
atomic_read(&key->usage),
xbuf,
key->perm,
key->uid,
key->gid,
key->type->name);
if (key->type->describe)
key->type->describe(key, m);
seq_putc(m, '\n');
read_unlock(&key->lock);
return 0;
}
#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
/*****************************************************************************/
/*
* implement "/proc/key-users" to provides a list of the key users
*/
static int proc_key_users_open(struct inode *inode, struct file *file)
{
return seq_open(file, &proc_key_users_ops);
}
static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
{
struct rb_node *_p;
loff_t pos = *_pos;
spin_lock(&key_user_lock);
_p = rb_first(&key_user_tree);
while (pos > 0 && _p) {
pos--;
_p = rb_next(_p);
}
return _p;
}
static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
{
(*_pos)++;
return rb_next((struct rb_node *) v);
}
static void proc_key_users_stop(struct seq_file *p, void *v)
{
spin_unlock(&key_user_lock);
}
static int proc_key_users_show(struct seq_file *m, void *v)
{
struct rb_node *_p = v;
struct key_user *user = rb_entry(_p, struct key_user, node);
seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
user->uid,
atomic_read(&user->usage),
atomic_read(&user->nkeys),
atomic_read(&user->nikeys),
user->qnkeys,
KEYQUOTA_MAX_KEYS,
user->qnbytes,
KEYQUOTA_MAX_BYTES
);
return 0;
}

View File

@@ -0,0 +1,640 @@
/* process_keys.c: management of a process's keyrings
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/keyctl.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <asm/uaccess.h>
#include "internal.h"
/* session keyring create vs join semaphore */
static DECLARE_MUTEX(key_session_sem);
/* the root user's tracking struct */
struct key_user root_key_user = {
.usage = ATOMIC_INIT(3),
.consq = LIST_HEAD_INIT(root_key_user.consq),
.lock = SPIN_LOCK_UNLOCKED,
.nkeys = ATOMIC_INIT(2),
.nikeys = ATOMIC_INIT(2),
.uid = 0,
};
/* the root user's UID keyring */
struct key root_user_keyring = {
.usage = ATOMIC_INIT(1),
.serial = 2,
.type = &key_type_keyring,
.user = &root_key_user,
.lock = RW_LOCK_UNLOCKED,
.sem = __RWSEM_INITIALIZER(root_user_keyring.sem),
.perm = KEY_USR_ALL,
.flags = KEY_FLAG_INSTANTIATED,
.description = "_uid.0",
#ifdef KEY_DEBUGGING
.magic = KEY_DEBUG_MAGIC,
#endif
};
/* the root user's default session keyring */
struct key root_session_keyring = {
.usage = ATOMIC_INIT(1),
.serial = 1,
.type = &key_type_keyring,
.user = &root_key_user,
.lock = RW_LOCK_UNLOCKED,
.sem = __RWSEM_INITIALIZER(root_session_keyring.sem),
.perm = KEY_USR_ALL,
.flags = KEY_FLAG_INSTANTIATED,
.description = "_uid_ses.0",
#ifdef KEY_DEBUGGING
.magic = KEY_DEBUG_MAGIC,
#endif
};
/*****************************************************************************/
/*
* allocate the keyrings to be associated with a UID
*/
int alloc_uid_keyring(struct user_struct *user)
{
struct key *uid_keyring, *session_keyring;
char buf[20];
int ret;
/* concoct a default session keyring */
sprintf(buf, "_uid_ses.%u", user->uid);
session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL);
if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring);
goto error;
}
/* and a UID specific keyring, pointed to by the default session
* keyring */
sprintf(buf, "_uid.%u", user->uid);
uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0,
session_keyring);
if (IS_ERR(uid_keyring)) {
key_put(session_keyring);
ret = PTR_ERR(uid_keyring);
goto error;
}
/* install the keyrings */
user->uid_keyring = uid_keyring;
user->session_keyring = session_keyring;
ret = 0;
error:
return ret;
} /* end alloc_uid_keyring() */
/*****************************************************************************/
/*
* deal with the UID changing
*/
void switch_uid_keyring(struct user_struct *new_user)
{
#if 0 /* do nothing for now */
struct key *old;
/* switch to the new user's session keyring if we were running under
* root's default session keyring */
if (new_user->uid != 0 &&
current->session_keyring == &root_session_keyring
) {
atomic_inc(&new_user->session_keyring->usage);
task_lock(current);
old = current->session_keyring;
current->session_keyring = new_user->session_keyring;
task_unlock(current);
key_put(old);
}
#endif
} /* end switch_uid_keyring() */
/*****************************************************************************/
/*
* install a fresh thread keyring, discarding the old one
*/
int install_thread_keyring(struct task_struct *tsk)
{
struct key *keyring, *old;
char buf[20];
int ret;
sprintf(buf, "_tid.%u", tsk->pid);
keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
task_lock(tsk);
old = tsk->thread_keyring;
tsk->thread_keyring = keyring;
task_unlock(tsk);
ret = 0;
key_put(old);
error:
return ret;
} /* end install_thread_keyring() */
/*****************************************************************************/
/*
* install a fresh process keyring, discarding the old one
*/
static int install_process_keyring(struct task_struct *tsk)
{
struct key *keyring, *old;
char buf[20];
int ret;
sprintf(buf, "_pid.%u", tsk->tgid);
keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
task_lock(tsk);
old = tsk->process_keyring;
tsk->process_keyring = keyring;
task_unlock(tsk);
ret = 0;
key_put(old);
error:
return ret;
} /* end install_process_keyring() */
/*****************************************************************************/
/*
* install a session keyring, discarding the old one
* - if a keyring is not supplied, an empty one is invented
*/
static int install_session_keyring(struct task_struct *tsk,
struct key *keyring)
{
struct key *old;
char buf[20];
int ret;
/* create an empty session keyring */
if (!keyring) {
sprintf(buf, "_ses.%u", tsk->tgid);
keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
}
else {
atomic_inc(&keyring->usage);
}
/* install the keyring */
task_lock(tsk);
old = tsk->session_keyring;
tsk->session_keyring = keyring;
task_unlock(tsk);
ret = 0;
key_put(old);
error:
return ret;
} /* end install_session_keyring() */
/*****************************************************************************/
/*
* copy the keys for fork
*/
int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
{
int ret = 0;
key_check(tsk->session_keyring);
key_check(tsk->process_keyring);
key_check(tsk->thread_keyring);
if (tsk->session_keyring)
atomic_inc(&tsk->session_keyring->usage);
if (tsk->process_keyring) {
if (clone_flags & CLONE_THREAD) {
atomic_inc(&tsk->process_keyring->usage);
}
else {
tsk->process_keyring = NULL;
ret = install_process_keyring(tsk);
}
}
tsk->thread_keyring = NULL;
return ret;
} /* end copy_keys() */
/*****************************************************************************/
/*
* dispose of keys upon exit
*/
void exit_keys(struct task_struct *tsk)
{
key_put(tsk->session_keyring);
key_put(tsk->process_keyring);
key_put(tsk->thread_keyring);
} /* end exit_keys() */
/*****************************************************************************/
/*
* deal with execve()
*/
int exec_keys(struct task_struct *tsk)
{
struct key *old;
/* newly exec'd tasks don't get a thread keyring */
task_lock(tsk);
old = tsk->thread_keyring;
tsk->thread_keyring = NULL;
task_unlock(tsk);
key_put(old);
/* newly exec'd tasks get a fresh process keyring */
return install_process_keyring(tsk);
} /* end exec_keys() */
/*****************************************************************************/
/*
* deal with SUID programs
* - we might want to make this invent a new session keyring
*/
int suid_keys(struct task_struct *tsk)
{
return 0;
} /* end suid_keys() */
/*****************************************************************************/
/*
* the filesystem user ID changed
*/
void key_fsuid_changed(struct task_struct *tsk)
{
/* update the ownership of the process keyring */
if (tsk->process_keyring) {
down_write(&tsk->process_keyring->sem);
write_lock(&tsk->process_keyring->lock);
tsk->process_keyring->uid = tsk->fsuid;
write_unlock(&tsk->process_keyring->lock);
up_write(&tsk->process_keyring->sem);
}
/* update the ownership of the thread keyring */
if (tsk->thread_keyring) {
down_write(&tsk->thread_keyring->sem);
write_lock(&tsk->thread_keyring->lock);
tsk->thread_keyring->uid = tsk->fsuid;
write_unlock(&tsk->thread_keyring->lock);
up_write(&tsk->thread_keyring->sem);
}
} /* end key_fsuid_changed() */
/*****************************************************************************/
/*
* the filesystem group ID changed
*/
void key_fsgid_changed(struct task_struct *tsk)
{
/* update the ownership of the process keyring */
if (tsk->process_keyring) {
down_write(&tsk->process_keyring->sem);
write_lock(&tsk->process_keyring->lock);
tsk->process_keyring->gid = tsk->fsgid;
write_unlock(&tsk->process_keyring->lock);
up_write(&tsk->process_keyring->sem);
}
/* update the ownership of the thread keyring */
if (tsk->thread_keyring) {
down_write(&tsk->thread_keyring->sem);
write_lock(&tsk->thread_keyring->lock);
tsk->thread_keyring->gid = tsk->fsgid;
write_unlock(&tsk->thread_keyring->lock);
up_write(&tsk->thread_keyring->sem);
}
} /* end key_fsgid_changed() */
/*****************************************************************************/
/*
* search the process keyrings for the first matching key
* - we use the supplied match function to see if the description (or other
* feature of interest) matches
* - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we found only negative matching keys
*/
struct key *search_process_keyrings_aux(struct key_type *type,
const void *description,
key_match_func_t match)
{
struct task_struct *tsk = current;
struct key *key, *ret, *err, *session;
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
* otherwise we want to return a sample error (probably -EACCES) if
* none of the keyrings were searchable
*
* in terms of priority: success > -ENOKEY > -EAGAIN > other error
*/
key = NULL;
ret = NULL;
err = ERR_PTR(-EAGAIN);
/* search the thread keyring first */
if (tsk->thread_keyring) {
key = keyring_search_aux(tsk->thread_keyring, type,
description, match);
if (!IS_ERR(key))
goto found;
switch (PTR_ERR(key)) {
case -EAGAIN: /* no key */
if (ret)
break;
case -ENOKEY: /* negative key */
ret = key;
break;
default:
err = key;
break;
}
}
/* search the process keyring second */
if (tsk->process_keyring) {
key = keyring_search_aux(tsk->process_keyring, type,
description, match);
if (!IS_ERR(key))
goto found;
switch (PTR_ERR(key)) {
case -EAGAIN: /* no key */
if (ret)
break;
case -ENOKEY: /* negative key */
ret = key;
break;
default:
err = key;
break;
}
}
/* search the session keyring last */
session = tsk->session_keyring;
if (!session)
session = tsk->user->session_keyring;
key = keyring_search_aux(session, type,
description, match);
if (!IS_ERR(key))
goto found;
switch (PTR_ERR(key)) {
case -EAGAIN: /* no key */
if (ret)
break;
case -ENOKEY: /* negative key */
ret = key;
break;
default:
err = key;
break;
}
/* no key - decide on the error we're going to go for */
key = ret ? ret : err;
found:
return key;
} /* end search_process_keyrings_aux() */
/*****************************************************************************/
/*
* search the process keyrings for the first matching key
* - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we found only negative matching keys
*/
struct key *search_process_keyrings(struct key_type *type,
const char *description)
{
return search_process_keyrings_aux(type, description, type->match);
} /* end search_process_keyrings() */
/*****************************************************************************/
/*
* lookup a key given a key ID from userspace with a given permissions mask
* - don't create special keyrings unless so requested
* - partially constructed keys aren't found unless requested
*/
struct key *lookup_user_key(key_serial_t id, int create, int partial,
key_perm_t perm)
{
struct task_struct *tsk = current;
struct key *key;
int ret;
key = ERR_PTR(-ENOKEY);
switch (id) {
case KEY_SPEC_THREAD_KEYRING:
if (!tsk->thread_keyring) {
if (!create)
goto error;
ret = install_thread_keyring(tsk);
if (ret < 0) {
key = ERR_PTR(ret);
goto error;
}
}
key = tsk->thread_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_PROCESS_KEYRING:
if (!tsk->process_keyring) {
if (!create)
goto error;
ret = install_process_keyring(tsk);
if (ret < 0) {
key = ERR_PTR(ret);
goto error;
}
}
key = tsk->process_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_SESSION_KEYRING:
if (!tsk->session_keyring) {
/* always install a session keyring upon access if one
* doesn't exist yet */
ret = install_session_keyring(
tsk, tsk->user->session_keyring);
if (ret < 0)
goto error;
}
key = tsk->session_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_USER_KEYRING:
key = tsk->user->uid_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_USER_SESSION_KEYRING:
key = tsk->user->session_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_GROUP_KEYRING:
/* group keyrings are not yet supported */
key = ERR_PTR(-EINVAL);
goto error;
default:
key = ERR_PTR(-EINVAL);
if (id < 1)
goto error;
key = key_lookup(id);
if (IS_ERR(key))
goto error;
break;
}
/* check the status and permissions */
if (perm) {
ret = key_validate(key);
if (ret < 0)
goto invalid_key;
}
ret = -EIO;
if (!partial && !(key->flags & KEY_FLAG_INSTANTIATED))
goto invalid_key;
ret = -EACCES;
if (!key_permission(key, perm))
goto invalid_key;
error:
return key;
invalid_key:
key_put(key);
key = ERR_PTR(ret);
goto error;
} /* end lookup_user_key() */
/*****************************************************************************/
/*
* join the named keyring as the session keyring if possible, or attempt to
* create a new one of that name if not
* - if the name is NULL, an empty anonymous keyring is installed instead
* - named session keyring joining is done with a semaphore held
*/
long join_session_keyring(const char *name)
{
struct task_struct *tsk = current;
struct key *keyring;
long ret;
/* if no name is provided, install an anonymous keyring */
if (!name) {
ret = install_session_keyring(tsk, NULL);
if (ret < 0)
goto error;
ret = tsk->session_keyring->serial;
goto error;
}
/* allow the user to join or create a named keyring */
down(&key_session_sem);
/* look for an existing keyring of this name */
keyring = find_keyring_by_name(name, 0);
if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */
keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
}
else if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
}
/* we've got a keyring - now to install it */
ret = install_session_keyring(tsk, keyring);
if (ret < 0)
goto error2;
key_put(keyring);
ret = tsk->session_keyring->serial;
error2:
up(&key_session_sem);
error:
return ret;
} /* end join_session_keyring() */

View File

@@ -0,0 +1,337 @@
/* request_key.c: request a key from userspace
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.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.
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kmod.h>
#include <linux/err.h>
#include "internal.h"
struct key_construction {
struct list_head link; /* link in construction queue */
struct key *key; /* key being constructed */
};
/* when waiting for someone else's keys, you get added to this */
DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
/*****************************************************************************/
/*
* request userspace finish the construction of a key
* - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>"
* - if callout_info is an empty string, it'll be rendered as a "-" instead
*/
static int call_request_key(struct key *key,
const char *op,
const char *callout_info)
{
struct task_struct *tsk = current;
char *argv[10], *envp[3], uid_str[12], gid_str[12];
char key_str[12], keyring_str[3][12];
int i;
/* record the UID and GID */
sprintf(uid_str, "%d", current->fsuid);
sprintf(gid_str, "%d", current->fsgid);
/* we say which key is under construction */
sprintf(key_str, "%d", key->serial);
/* we specify the process's default keyrings */
task_lock(current);
sprintf(keyring_str[0], "%d",
tsk->thread_keyring ? tsk->thread_keyring->serial : 0);
sprintf(keyring_str[1], "%d",
tsk->process_keyring ? tsk->process_keyring->serial : 0);
sprintf(keyring_str[2], "%d",
(tsk->session_keyring ?
tsk->session_keyring->serial :
tsk->user->session_keyring->serial));
task_unlock(tsk);
/* set up a minimal environment */
i = 0;
envp[i++] = "HOME=/";
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp[i] = NULL;
/* set up the argument list */
i = 0;
argv[i++] = "/sbin/request-key";
argv[i++] = (char *) op;
argv[i++] = key_str;
argv[i++] = uid_str;
argv[i++] = gid_str;
argv[i++] = keyring_str[0];
argv[i++] = keyring_str[1];
argv[i++] = keyring_str[2];
argv[i++] = callout_info[0] ? (char *) callout_info : "-";
argv[i] = NULL;
/* do it */
return call_usermodehelper(argv[0], argv, envp, 1);
} /* end call_request_key() */
/*****************************************************************************/
/*
* call out to userspace for the key
* - called with the construction sem held, but the sem is dropped here
* - we ignore program failure and go on key status instead
*/
static struct key *__request_key_construction(struct key_type *type,
const char *description,
const char *callout_info)
{
struct key_construction cons;
struct timespec now;
struct key *key;
int ret, negative;
/* create a key and add it to the queue */
key = key_alloc(type, description,
current->fsuid, current->fsgid, KEY_USR_ALL, 0);
if (IS_ERR(key))
goto alloc_failed;
write_lock(&key->lock);
key->flags |= KEY_FLAG_USER_CONSTRUCT;
write_unlock(&key->lock);
cons.key = key;
list_add_tail(&cons.link, &key->user->consq);
/* we drop the construction sem here on behalf of the caller */
up_write(&key_construction_sem);
/* make the call */
ret = call_request_key(key, "create", callout_info);
if (ret < 0)
goto request_failed;
/* if the key wasn't instantiated, then we want to give an error */
ret = -ENOKEY;
if (!(key->flags & KEY_FLAG_INSTANTIATED))
goto request_failed;
down_write(&key_construction_sem);
list_del(&cons.link);
up_write(&key_construction_sem);
/* also give an error if the key was negatively instantiated */
check_not_negative:
if (key->flags & KEY_FLAG_NEGATIVE) {
key_put(key);
key = ERR_PTR(-ENOKEY);
}
out:
return key;
request_failed:
/* it wasn't instantiated
* - remove from construction queue
* - mark the key as dead
*/
negative = 0;
down_write(&key_construction_sem);
list_del(&cons.link);
write_lock(&key->lock);
key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
/* check it didn't get instantiated between the check and the down */
if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE;
negative = 1;
}
write_unlock(&key->lock);
up_write(&key_construction_sem);
if (!negative)
goto check_not_negative; /* surprisingly, the key got
* instantiated */
/* set the timeout and store in the session keyring if we can */
now = current_kernel_time();
key->expiry = now.tv_sec + key_negative_timeout;
if (current->session_keyring)
key_link(current->session_keyring, key);
key_put(key);
/* notify anyone who was waiting */
wake_up_all(&request_key_conswq);
key = ERR_PTR(ret);
goto out;
alloc_failed:
up_write(&key_construction_sem);
goto out;
} /* end __request_key_construction() */
/*****************************************************************************/
/*
* call out to userspace to request the key
* - we check the construction queue first to see if an appropriate key is
* already being constructed by userspace
*/
static struct key *request_key_construction(struct key_type *type,
const char *description,
struct key_user *user,
const char *callout_info)
{
struct key_construction *pcons;
struct key *key, *ckey;
DECLARE_WAITQUEUE(myself, current);
/* see if there's such a key under construction already */
down_write(&key_construction_sem);
list_for_each_entry(pcons, &user->consq, link) {
ckey = pcons->key;
if (ckey->type != type)
continue;
if (type->match(ckey, description))
goto found_key_under_construction;
}
/* see about getting userspace to construct the key */
key = __request_key_construction(type, description, callout_info);
error:
return key;
/* someone else has the same key under construction
* - we want to keep an eye on their key
*/
found_key_under_construction:
atomic_inc(&ckey->usage);
up_write(&key_construction_sem);
/* wait for the key to be completed one way or another */
add_wait_queue(&request_key_conswq, &myself);
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (!(ckey->flags & KEY_FLAG_USER_CONSTRUCT))
break;
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&request_key_conswq, &myself);
/* we'll need to search this process's keyrings to see if the key is
* now there since we can't automatically assume it's also available
* there */
key_put(ckey);
ckey = NULL;
key = NULL; /* request a retry */
goto error;
} /* end request_key_construction() */
/*****************************************************************************/
/*
* request a key
* - search the process's keyrings
* - check the list of keys being created or updated
* - call out to userspace for a key if requested (supplementary info can be
* passed)
*/
struct key *request_key(struct key_type *type,
const char *description,
const char *callout_info)
{
struct key_user *user;
struct key *key;
/* search all the process keyrings for a key */
key = search_process_keyrings_aux(type, description, type->match);
if (PTR_ERR(key) == -EAGAIN) {
/* the search failed, but the keyrings were searchable, so we
* should consult userspace if we can */
key = ERR_PTR(-ENOKEY);
if (!callout_info)
goto error;
/* - get hold of the user's construction queue */
user = key_user_lookup(current->fsuid);
if (IS_ERR(user)) {
key = ERR_PTR(PTR_ERR(user));
goto error;
}
for (;;) {
/* ask userspace (returns NULL if it waited on a key
* being constructed) */
key = request_key_construction(type, description,
user, callout_info);
if (key)
break;
/* someone else made the key we want, so we need to
* search again as it might now be available to us */
key = search_process_keyrings_aux(type, description,
type->match);
if (PTR_ERR(key) != -EAGAIN)
break;
}
key_user_put(user);
}
error:
return key;
} /* end request_key() */
EXPORT_SYMBOL(request_key);
/*****************************************************************************/
/*
* validate a key
*/
int key_validate(struct key *key)
{
struct timespec now;
int ret = 0;
if (key) {
/* check it's still accessible */
ret = -EKEYREVOKED;
if (key->flags & (KEY_FLAG_REVOKED | KEY_FLAG_DEAD))
goto error;
/* check it hasn't expired */
ret = 0;
if (key->expiry) {
now = current_kernel_time();
if (now.tv_sec >= key->expiry)
ret = -EKEYEXPIRED;
}
}
error:
return ret;
} /* end key_validate() */
EXPORT_SYMBOL(key_validate);

View File

@@ -0,0 +1,191 @@
/* user_defined.c: user defined key type
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/err.h>
#include <asm/uaccess.h>
#include "internal.h"
static int user_instantiate(struct key *key, const void *data, size_t datalen);
static int user_duplicate(struct key *key, const struct key *source);
static int user_update(struct key *key, const void *data, size_t datalen);
static int user_match(const struct key *key, const void *criterion);
static void user_destroy(struct key *key);
static void user_describe(const struct key *user, struct seq_file *m);
static long user_read(const struct key *key,
char __user *buffer, size_t buflen);
/*
* user defined keys take an arbitrary string as the description and an
* arbitrary blob of data as the payload
*/
struct key_type key_type_user = {
.name = "user",
.instantiate = user_instantiate,
.duplicate = user_duplicate,
.update = user_update,
.match = user_match,
.destroy = user_destroy,
.describe = user_describe,
.read = user_read,
};
/*****************************************************************************/
/*
* instantiate a user defined key
*/
static int user_instantiate(struct key *key, const void *data, size_t datalen)
{
int ret;
ret = -EINVAL;
if (datalen <= 0 || datalen > 32767 || !data)
goto error;
ret = key_payload_reserve(key, datalen);
if (ret < 0)
goto error;
/* attach the data */
ret = -ENOMEM;
key->payload.data = kmalloc(datalen, GFP_KERNEL);
if (!key->payload.data)
goto error;
memcpy(key->payload.data, data, datalen);
ret = 0;
error:
return ret;
} /* end user_instantiate() */
/*****************************************************************************/
/*
* duplicate a user defined key
*/
static int user_duplicate(struct key *key, const struct key *source)
{
int ret;
/* just copy the payload */
ret = -ENOMEM;
key->payload.data = kmalloc(source->datalen, GFP_KERNEL);
if (key->payload.data) {
key->datalen = source->datalen;
memcpy(key->payload.data, source->payload.data, source->datalen);
ret = 0;
}
return ret;
} /* end user_duplicate() */
/*****************************************************************************/
/*
* update a user defined key
*/
static int user_update(struct key *key, const void *data, size_t datalen)
{
void *new, *zap;
int ret;
ret = -EINVAL;
if (datalen <= 0 || datalen > 32767 || !data)
goto error;
/* copy the data */
ret = -ENOMEM;
new = kmalloc(datalen, GFP_KERNEL);
if (!new)
goto error;
memcpy(new, data, datalen);
/* check the quota and attach the new data */
zap = new;
write_lock(&key->lock);
ret = key_payload_reserve(key, datalen);
if (ret == 0) {
/* attach the new data, displacing the old */
zap = key->payload.data;
key->payload.data = new;
key->expiry = 0;
}
write_unlock(&key->lock);
kfree(zap);
error:
return ret;
} /* end user_update() */
/*****************************************************************************/
/*
* match users on their name
*/
static int user_match(const struct key *key, const void *description)
{
return strcmp(key->description, description) == 0;
} /* end user_match() */
/*****************************************************************************/
/*
* dispose of the data dangling from the corpse of a user
*/
static void user_destroy(struct key *key)
{
kfree(key->payload.data);
} /* end user_destroy() */
/*****************************************************************************/
/*
* describe the user
*/
static void user_describe(const struct key *key, struct seq_file *m)
{
seq_puts(m, key->description);
seq_printf(m, ": %u", key->datalen);
} /* end user_describe() */
/*****************************************************************************/
/*
* read the key data
*/
static long user_read(const struct key *key,
char __user *buffer, size_t buflen)
{
long ret = key->datalen;
/* we can return the data as is */
if (buffer && buflen > 0) {
if (buflen > key->datalen)
buflen = key->datalen;
if (copy_to_user(buffer, key->payload.data, buflen) != 0)
ret = -EFAULT;
}
return ret;
} /* end user_read() */

View File

@@ -0,0 +1,142 @@
/*
* Root Plug sample LSM module
*
* Originally written for a Linux Journal.
*
* Copyright (C) 2002 Greg Kroah-Hartman <greg@kroah.com>
*
* Prevents any programs running with egid == 0 if a specific USB device
* is not present in the system. Yes, it can be gotten around, but is a
* nice starting point for people to play with, and learn the LSM
* interface.
*
* If you want to turn this into something with a semblance of security,
* you need to hook the task_* functions also.
*
* See http://www.linuxjournal.com/article.php?sid=6279 for more information
* about this code.
*
* 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/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/security.h>
#include <linux/usb.h>
/* flag to keep track of how we were registered */
static int secondary;
/* default is a generic type of usb to serial converter */
static int vendor_id = 0x0557;
static int product_id = 0x2008;
module_param(vendor_id, uint, 0400);
MODULE_PARM_DESC(vendor_id, "USB Vendor ID of device to look for");
module_param(product_id, uint, 0400);
MODULE_PARM_DESC(product_id, "USB Product ID of device to look for");
/* should we print out debug messages */
static int debug = 0;
module_param(debug, bool, 0600);
MODULE_PARM_DESC(debug, "Debug enabled or not");
#if defined(CONFIG_SECURITY_ROOTPLUG_MODULE)
#define MY_NAME THIS_MODULE->name
#else
#define MY_NAME "root_plug"
#endif
#define root_dbg(fmt, arg...) \
do { \
if (debug) \
printk(KERN_DEBUG "%s: %s: " fmt , \
MY_NAME , __FUNCTION__ , \
## arg); \
} while (0)
static int rootplug_bprm_check_security (struct linux_binprm *bprm)
{
struct usb_device *dev;
root_dbg("file %s, e_uid = %d, e_gid = %d\n",
bprm->filename, bprm->e_uid, bprm->e_gid);
if (bprm->e_gid == 0) {
dev = usb_find_device(vendor_id, product_id);
if (!dev) {
root_dbg("e_gid = 0, and device not found, "
"task not allowed to run...\n");
return -EPERM;
}
usb_put_dev(dev);
}
return 0;
}
static struct security_operations rootplug_security_ops = {
/* Use the capability functions for some of the hooks */
.ptrace = cap_ptrace,
.capget = cap_capget,
.capset_check = cap_capset_check,
.capset_set = cap_capset_set,
.capable = cap_capable,
.bprm_apply_creds = cap_bprm_apply_creds,
.bprm_set_security = cap_bprm_set_security,
.task_post_setuid = cap_task_post_setuid,
.task_reparent_to_init = cap_task_reparent_to_init,
.bprm_check_security = rootplug_bprm_check_security,
};
static int __init rootplug_init (void)
{
/* register ourselves with the security framework */
if (register_security (&rootplug_security_ops)) {
printk (KERN_INFO
"Failure registering Root Plug module with the kernel\n");
/* try registering with primary module */
if (mod_reg_security (MY_NAME, &rootplug_security_ops)) {
printk (KERN_INFO "Failure registering Root Plug "
" module with primary security module.\n");
return -EINVAL;
}
secondary = 1;
}
printk (KERN_INFO "Root Plug module initialized, "
"vendor_id = %4.4x, product id = %4.4x\n", vendor_id, product_id);
return 0;
}
static void __exit rootplug_exit (void)
{
/* remove ourselves from the security framework */
if (secondary) {
if (mod_unreg_security (MY_NAME, &rootplug_security_ops))
printk (KERN_INFO "Failure unregistering Root Plug "
" module with primary module.\n");
} else {
if (unregister_security (&rootplug_security_ops)) {
printk (KERN_INFO "Failure unregistering Root Plug "
"module with the kernel\n");
}
}
printk (KERN_INFO "Root Plug module removed\n");
}
security_initcall (rootplug_init);
module_exit (rootplug_exit);
MODULE_DESCRIPTION("Root Plug sample LSM module, written for Linux Journal article");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,747 @@
/**
* BSD Secure Levels LSM
*
* Maintainers:
* Michael A. Halcrow <mike@halcrow.us>
* Serge Hallyn <hallyn@cs.wm.edu>
*
* Copyright (c) 2001 WireX Communications, Inc <chris@wirex.com>
* Copyright (c) 2001 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (c) 2002 International Business Machines <robb@austin.ibm.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.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/security.h>
#include <linux/netlink.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/capability.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/kobject.h>
#include <linux/crypto.h>
#include <asm/scatterlist.h>
#include <linux/gfp.h>
#include <linux/sysfs.h>
#define SHA1_DIGEST_SIZE 20
/**
* Module parameter that defines the initial secure level.
*
* When built as a module, it defaults to seclvl 1, which is the
* behavior of BSD secure levels. Note that this default behavior
* wrecks havoc on a machine when the seclvl module is compiled into
* the kernel. In that case, we default to seclvl 0.
*/
#ifdef CONFIG_SECURITY_SECLVL_MODULE
static int initlvl = 1;
#else
static int initlvl;
#endif
module_param(initlvl, int, 0);
MODULE_PARM_DESC(initlvl, "Initial secure level (defaults to 1)");
/* Module parameter that defines the verbosity level */
static int verbosity;
module_param(verbosity, int, 0);
MODULE_PARM_DESC(verbosity, "Initial verbosity level (0 or 1; defaults to "
"0, which is Quiet)");
/**
* Optional password which can be passed in to bring seclvl to 0
* (i.e., for halt/reboot). Defaults to NULL (the passwd attribute
* file will not be registered in sysfs).
*
* This gets converted to its SHA1 hash when stored. It's probably
* not a good idea to use this parameter when loading seclvl from a
* script; use sha1_passwd instead.
*/
#define MAX_PASSWD_SIZE 32
static char passwd[MAX_PASSWD_SIZE];
module_param_string(passwd, passwd, sizeof(passwd), 0);
MODULE_PARM_DESC(passwd,
"Plaintext of password that sets seclvl=0 when written to "
"(sysfs mount point)/seclvl/passwd\n");
/**
* SHA1 hashed version of the optional password which can be passed in
* to bring seclvl to 0 (i.e., for halt/reboot). Must be in
* hexadecimal format (40 characters). Defaults to NULL (the passwd
* attribute file will not be registered in sysfs).
*
* Use the sha1sum utility to generate the SHA1 hash of a password:
*
* echo -n "secret" | sha1sum
*/
#define MAX_SHA1_PASSWD 41
static char sha1_passwd[MAX_SHA1_PASSWD];
module_param_string(sha1_passwd, sha1_passwd, sizeof(sha1_passwd), 0);
MODULE_PARM_DESC(sha1_passwd,
"SHA1 hash (40 hexadecimal characters) of password that "
"sets seclvl=0 when plaintext password is written to "
"(sysfs mount point)/seclvl/passwd\n");
static int hideHash = 1;
module_param(hideHash, int, 0);
MODULE_PARM_DESC(hideHash, "When set to 0, reading seclvl/passwd from sysfs "
"will return the SHA1-hashed value of the password that "
"lowers the secure level to 0.\n");
#define MY_NAME "seclvl"
/**
* This time-limits log writes to one per second.
*/
#define seclvl_printk(verb, type, fmt, arg...) \
do { \
if (verbosity >= verb) { \
static unsigned long _prior; \
unsigned long _now = jiffies; \
if ((_now - _prior) > HZ) { \
printk(type "%s: %s: " fmt, \
MY_NAME, __FUNCTION__ , \
## arg); \
_prior = _now; \
} \
} \
} while (0)
/**
* kobject stuff
*/
struct subsystem seclvl_subsys;
struct seclvl_obj {
char *name;
struct list_head slot_list;
struct kobject kobj;
};
/**
* There is a seclvl_attribute struct for each file in sysfs.
*
* In our case, we have one of these structs for "passwd" and another
* for "seclvl".
*/
struct seclvl_attribute {
struct attribute attr;
ssize_t(*show) (struct seclvl_obj *, char *);
ssize_t(*store) (struct seclvl_obj *, const char *, size_t);
};
/**
* When this function is called, one of the files in sysfs is being
* written to. attribute->store is a function pointer to whatever the
* struct seclvl_attribute store function pointer points to. It is
* unique for "passwd" and "seclvl".
*/
static ssize_t
seclvl_attr_store(struct kobject *kobj,
struct attribute *attr, const char *buf, size_t len)
{
struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
struct seclvl_attribute *attribute =
container_of(attr, struct seclvl_attribute, attr);
return (attribute->store ? attribute->store(obj, buf, len) : 0);
}
static ssize_t
seclvl_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
struct seclvl_attribute *attribute =
container_of(attr, struct seclvl_attribute, attr);
return (attribute->show ? attribute->show(obj, buf) : 0);
}
/**
* Callback function pointers for show and store
*/
struct sysfs_ops seclvlfs_sysfs_ops = {
.show = seclvl_attr_show,
.store = seclvl_attr_store,
};
static struct kobj_type seclvl_ktype = {
.sysfs_ops = &seclvlfs_sysfs_ops
};
decl_subsys(seclvl, &seclvl_ktype, NULL);
/**
* The actual security level. Ranges between -1 and 2 inclusive.
*/
static int seclvl;
/**
* flag to keep track of how we were registered
*/
static int secondary;
/**
* Verifies that the requested secure level is valid, given the current
* secure level.
*/
static int seclvl_sanity(int reqlvl)
{
if ((reqlvl < -1) || (reqlvl > 2)) {
seclvl_printk(1, KERN_WARNING, "Attempt to set seclvl out of "
"range: [%d]\n", reqlvl);
return -EINVAL;
}
if ((seclvl == 0) && (reqlvl == -1))
return 0;
if (reqlvl < seclvl) {
seclvl_printk(1, KERN_WARNING, "Attempt to lower seclvl to "
"[%d]\n", reqlvl);
return -EPERM;
}
return 0;
}
/**
* Called whenever the user reads the sysfs handle to this kernel
* object
*/
static ssize_t seclvl_read_file(struct seclvl_obj *obj, char *buff)
{
return snprintf(buff, PAGE_SIZE, "%d\n", seclvl);
}
/**
* security level advancement rules:
* Valid levels are -1 through 2, inclusive.
* From -1, stuck. [ in case compiled into kernel ]
* From 0 or above, can only increment.
*/
static int do_seclvl_advance(int newlvl)
{
if (newlvl <= seclvl) {
seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
"[%d]\n", newlvl);
return -EINVAL;
}
if (newlvl > 2) {
seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
"[%d]\n", newlvl);
return -EINVAL;
}
if (seclvl == -1) {
seclvl_printk(1, KERN_WARNING, "Not allowed to advance to "
"seclvl [%d]\n", seclvl);
return -EPERM;
}
seclvl = newlvl;
return 0;
}
/**
* Called whenever the user writes to the sysfs handle to this kernel
* object (seclvl/seclvl). It expects a single-digit number.
*/
static ssize_t
seclvl_write_file(struct seclvl_obj *obj, const char *buff, size_t count)
{
unsigned long val;
if (count > 2 || (count == 2 && buff[1] != '\n')) {
seclvl_printk(1, KERN_WARNING, "Invalid value passed to "
"seclvl: [%s]\n", buff);
return -EINVAL;
}
val = buff[0] - 48;
if (seclvl_sanity(val)) {
seclvl_printk(1, KERN_WARNING, "Illegal secure level "
"requested: [%d]\n", (int)val);
return -EPERM;
}
if (do_seclvl_advance(val)) {
seclvl_printk(0, KERN_ERR, "Failure advancing security level "
"to %lu\n", val);
}
return count;
}
/* Generate sysfs_attr_seclvl */
struct seclvl_attribute sysfs_attr_seclvl =
__ATTR(seclvl, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_file,
seclvl_write_file);
static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
/**
* Called whenever the user reads the sysfs passwd handle.
*/
static ssize_t seclvl_read_passwd(struct seclvl_obj *obj, char *buff)
{
/* So just how good *is* your password? :-) */
char tmp[3];
int i = 0;
buff[0] = '\0';
if (hideHash) {
/* Security through obscurity */
return 0;
}
while (i < SHA1_DIGEST_SIZE) {
snprintf(tmp, 3, "%02x", hashedPassword[i]);
strncat(buff, tmp, 2);
i++;
}
strcat(buff, "\n");
return ((SHA1_DIGEST_SIZE * 2) + 1);
}
/**
* Converts a block of plaintext of into its SHA1 hashed value.
*
* It would be nice if crypto had a wrapper to do this for us linear
* people...
*/
static int
plaintext_to_sha1(unsigned char *hash, const char *plaintext, int len)
{
char *pgVirtAddr;
struct crypto_tfm *tfm;
struct scatterlist sg[1];
if (len > PAGE_SIZE) {
seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d "
"characters). Largest possible is %lu "
"bytes.\n", len, PAGE_SIZE);
return -ENOMEM;
}
tfm = crypto_alloc_tfm("sha1", 0);
if (tfm == NULL) {
seclvl_printk(0, KERN_ERR,
"Failed to load transform for SHA1\n");
return -ENOSYS;
}
// Just get a new page; don't play around with page boundaries
// and scatterlists.
pgVirtAddr = (char *)__get_free_page(GFP_KERNEL);
sg[0].page = virt_to_page(pgVirtAddr);
sg[0].offset = 0;
sg[0].length = len;
strncpy(pgVirtAddr, plaintext, len);
crypto_digest_init(tfm);
crypto_digest_update(tfm, sg, 1);
crypto_digest_final(tfm, hash);
crypto_free_tfm(tfm);
free_page((unsigned long)pgVirtAddr);
return 0;
}
/**
* Called whenever the user writes to the sysfs passwd handle to this kernel
* object. It hashes the password and compares the hashed results.
*/
static ssize_t
seclvl_write_passwd(struct seclvl_obj *obj, const char *buff, size_t count)
{
int i;
unsigned char tmp[SHA1_DIGEST_SIZE];
int rc;
int len;
if (!*passwd && !*sha1_passwd) {
seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
"seclvl module, but neither a plain text "
"password nor a SHA1 hashed password was "
"passed in as a module parameter! This is a "
"bug, since it should not be possible to be in "
"this part of the module; please tell a "
"maintainer about this event.\n");
return -EINVAL;
}
len = strlen(buff);
/* ``echo "secret" > seclvl/passwd'' includes a newline */
if (buff[len - 1] == '\n') {
len--;
}
/* Hash the password, then compare the hashed values */
if ((rc = plaintext_to_sha1(tmp, buff, len))) {
seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
"[%d]\n", rc);
return rc;
}
for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
if (hashedPassword[i] != tmp[i]) {
return -EPERM;
}
}
seclvl_printk(0, KERN_INFO,
"Password accepted; seclvl reduced to 0.\n");
seclvl = 0;
return count;
}
/* Generate sysfs_attr_passwd */
struct seclvl_attribute sysfs_attr_passwd =
__ATTR(passwd, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_passwd,
seclvl_write_passwd);
/**
* Explicitely disallow ptrace'ing the init process.
*/
static int seclvl_ptrace(struct task_struct *parent, struct task_struct *child)
{
if (seclvl >= 0) {
if (child->pid == 1) {
seclvl_printk(1, KERN_WARNING, "Attempt to ptrace "
"the init process dissallowed in "
"secure level %d\n", seclvl);
return -EPERM;
}
}
return 0;
}
/**
* Capability checks for seclvl. The majority of the policy
* enforcement for seclvl takes place here.
*/
static int seclvl_capable(struct task_struct *tsk, int cap)
{
/* init can do anything it wants */
if (tsk->pid == 1)
return 0;
switch (seclvl) {
case 2:
/* fall through */
case 1:
if (cap == CAP_LINUX_IMMUTABLE) {
seclvl_printk(1, KERN_WARNING, "Attempt to modify "
"the IMMUTABLE and/or APPEND extended "
"attribute on a file with the IMMUTABLE "
"and/or APPEND extended attribute set "
"denied in seclvl [%d]\n", seclvl);
return -EPERM;
} else if (cap == CAP_SYS_RAWIO) { // Somewhat broad...
seclvl_printk(1, KERN_WARNING, "Attempt to perform "
"raw I/O while in secure level [%d] "
"denied\n", seclvl);
return -EPERM;
} else if (cap == CAP_NET_ADMIN) {
seclvl_printk(1, KERN_WARNING, "Attempt to perform "
"network administrative task while "
"in secure level [%d] denied\n", seclvl);
return -EPERM;
} else if (cap == CAP_SETUID) {
seclvl_printk(1, KERN_WARNING, "Attempt to setuid "
"while in secure level [%d] denied\n",
seclvl);
return -EPERM;
} else if (cap == CAP_SETGID) {
seclvl_printk(1, KERN_WARNING, "Attempt to setgid "
"while in secure level [%d] denied\n",
seclvl);
} else if (cap == CAP_SYS_MODULE) {
seclvl_printk(1, KERN_WARNING, "Attempt to perform "
"a module operation while in secure "
"level [%d] denied\n", seclvl);
return -EPERM;
}
break;
default:
break;
}
/* from dummy.c */
if (cap_is_fs_cap(cap) ? tsk->fsuid == 0 : tsk->euid == 0)
return 0; /* capability granted */
seclvl_printk(1, KERN_WARNING, "Capability denied\n");
return -EPERM; /* capability denied */
}
/**
* Disallow reversing the clock in seclvl > 1
*/
static int seclvl_settime(struct timespec *tv, struct timezone *tz)
{
struct timespec now;
if (seclvl > 1) {
now = current_kernel_time();
if (tv->tv_sec < now.tv_sec ||
(tv->tv_sec == now.tv_sec && tv->tv_nsec < now.tv_nsec)) {
seclvl_printk(1, KERN_WARNING, "Attempt to decrement "
"time in secure level %d denied: "
"current->pid = [%d], "
"current->group_leader->pid = [%d]\n",
seclvl, current->pid,
current->group_leader->pid);
return -EPERM;
} /* if attempt to decrement time */
} /* if seclvl > 1 */
return 0;
}
/* claim the blockdev to exclude mounters, release on file close */
static int seclvl_bd_claim(struct inode *inode)
{
int holder;
struct block_device *bdev = NULL;
dev_t dev = inode->i_rdev;
bdev = open_by_devnum(dev, FMODE_WRITE);
if (bdev) {
if (bd_claim(bdev, &holder)) {
blkdev_put(bdev);
return -EPERM;
}
/* claimed, mark it to release on close */
inode->i_security = current;
}
return 0;
}
/* release the blockdev if you claimed it */
static void seclvl_bd_release(struct inode *inode)
{
if (inode && S_ISBLK(inode->i_mode) && inode->i_security == current) {
struct block_device *bdev = inode->i_bdev;
if (bdev) {
bd_release(bdev);
blkdev_put(bdev);
inode->i_security = NULL;
}
}
}
/**
* Security for writes to block devices is regulated by this seclvl
* function. Deny all writes to block devices in seclvl 2. In
* seclvl 1, we only deny writes to *mounted* block devices.
*/
static int
seclvl_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
{
if (current->pid != 1 && S_ISBLK(inode->i_mode) && (mask & MAY_WRITE)) {
switch (seclvl) {
case 2:
seclvl_printk(1, KERN_WARNING, "Write to block device "
"denied in secure level [%d]\n", seclvl);
return -EPERM;
case 1:
if (seclvl_bd_claim(inode)) {
seclvl_printk(1, KERN_WARNING,
"Write to mounted block device "
"denied in secure level [%d]\n",
seclvl);
return -EPERM;
}
}
}
return 0;
}
/**
* The SUID and SGID bits cannot be set in seclvl >= 1
*/
static int seclvl_inode_setattr(struct dentry *dentry, struct iattr *iattr)
{
if (seclvl > 0) {
if (iattr->ia_valid & ATTR_MODE)
if (iattr->ia_mode & S_ISUID ||
iattr->ia_mode & S_ISGID) {
seclvl_printk(1, KERN_WARNING, "Attempt to "
"modify SUID or SGID bit "
"denied in seclvl [%d]\n",
seclvl);
return -EPERM;
}
}
return 0;
}
/* release busied block devices */
static void seclvl_file_free_security(struct file *filp)
{
struct dentry *dentry = filp->f_dentry;
struct inode *inode = NULL;
if (dentry) {
inode = dentry->d_inode;
seclvl_bd_release(inode);
}
}
/**
* Cannot unmount in secure level 2
*/
static int seclvl_umount(struct vfsmount *mnt, int flags)
{
if (current->pid == 1) {
return 0;
}
if (seclvl == 2) {
seclvl_printk(1, KERN_WARNING, "Attempt to unmount in secure "
"level %d\n", seclvl);
return -EPERM;
}
return 0;
}
static struct security_operations seclvl_ops = {
.ptrace = seclvl_ptrace,
.capable = seclvl_capable,
.inode_permission = seclvl_inode_permission,
.inode_setattr = seclvl_inode_setattr,
.file_free_security = seclvl_file_free_security,
.settime = seclvl_settime,
.sb_umount = seclvl_umount,
};
/**
* Process the password-related module parameters
*/
static int processPassword(void)
{
int rc = 0;
hashedPassword[0] = '\0';
if (*passwd) {
if (*sha1_passwd) {
seclvl_printk(0, KERN_ERR, "Error: Both "
"passwd and sha1_passwd "
"were set, but they are mutually "
"exclusive.\n");
return -EINVAL;
}
if ((rc = plaintext_to_sha1(hashedPassword, passwd,
strlen(passwd)))) {
seclvl_printk(0, KERN_ERR, "Error: SHA1 support not "
"in kernel\n");
return rc;
}
/* All static data goes to the BSS, which zero's the
* plaintext password out for us. */
} else if (*sha1_passwd) { // Base 16
int i;
i = strlen(sha1_passwd);
if (i != (SHA1_DIGEST_SIZE * 2)) {
seclvl_printk(0, KERN_ERR, "Received [%d] bytes; "
"expected [%d] for the hexadecimal "
"representation of the SHA1 hash of "
"the password.\n",
i, (SHA1_DIGEST_SIZE * 2));
return -EINVAL;
}
while ((i -= 2) + 2) {
unsigned char tmp;
tmp = sha1_passwd[i + 2];
sha1_passwd[i + 2] = '\0';
hashedPassword[i / 2] = (unsigned char)
simple_strtol(&sha1_passwd[i], NULL, 16);
sha1_passwd[i + 2] = tmp;
}
}
return 0;
}
/**
* Sysfs registrations
*/
static int doSysfsRegistrations(void)
{
int rc = 0;
if ((rc = subsystem_register(&seclvl_subsys))) {
seclvl_printk(0, KERN_WARNING,
"Error [%d] registering seclvl subsystem\n", rc);
return rc;
}
sysfs_create_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
if (*passwd || *sha1_passwd) {
sysfs_create_file(&seclvl_subsys.kset.kobj,
&sysfs_attr_passwd.attr);
}
return 0;
}
/**
* Initialize the seclvl module.
*/
static int __init seclvl_init(void)
{
int rc = 0;
if (verbosity < 0 || verbosity > 1) {
printk(KERN_ERR "Error: bad verbosity [%d]; only 0 or 1 "
"are valid values\n", verbosity);
rc = -EINVAL;
goto exit;
}
sysfs_attr_seclvl.attr.owner = THIS_MODULE;
sysfs_attr_passwd.attr.owner = THIS_MODULE;
if (initlvl < -1 || initlvl > 2) {
seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "
"[%d].\n", initlvl);
rc = -EINVAL;
goto exit;
}
seclvl = initlvl;
if ((rc = processPassword())) {
seclvl_printk(0, KERN_ERR, "Error processing the password "
"module parameter(s): rc = [%d]\n", rc);
goto exit;
}
/* register ourselves with the security framework */
if (register_security(&seclvl_ops)) {
seclvl_printk(0, KERN_ERR,
"seclvl: Failure registering with the "
"kernel.\n");
/* try registering with primary module */
rc = mod_reg_security(MY_NAME, &seclvl_ops);
if (rc) {
seclvl_printk(0, KERN_ERR, "seclvl: Failure "
"registering with primary security "
"module.\n");
goto exit;
} /* if primary module registered */
secondary = 1;
} /* if we registered ourselves with the security framework */
if ((rc = doSysfsRegistrations())) {
seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
goto exit;
}
seclvl_printk(0, KERN_INFO, "seclvl: Successfully initialized.\n");
exit:
if (rc) {
printk(KERN_ERR "seclvl: Error during initialization: rc = "
"[%d]\n", rc);
}
return rc;
}
/**
* Remove the seclvl module.
*/
static void __exit seclvl_exit(void)
{
sysfs_remove_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
if (*passwd || *sha1_passwd) {
sysfs_remove_file(&seclvl_subsys.kset.kobj,
&sysfs_attr_passwd.attr);
}
subsystem_unregister(&seclvl_subsys);
if (secondary == 1) {
mod_unreg_security(MY_NAME, &seclvl_ops);
} else if (unregister_security(&seclvl_ops)) {
seclvl_printk(0, KERN_INFO,
"seclvl: Failure unregistering with the "
"kernel\n");
}
}
module_init(seclvl_init);
module_exit(seclvl_exit);
MODULE_AUTHOR("Michael A. Halcrow <mike@halcrow.us>");
MODULE_DESCRIPTION("LSM implementation of the BSD Secure Levels");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,203 @@
/*
* Security plug functions
*
* 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.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/security.h>
#define SECURITY_FRAMEWORK_VERSION "1.0.0"
/* things that live in dummy.c */
extern struct security_operations dummy_security_ops;
extern void security_fixup_ops(struct security_operations *ops);
struct security_operations *security_ops; /* Initialized to NULL */
static inline int verify(struct security_operations *ops)
{
/* verify the security_operations structure exists */
if (!ops)
return -EINVAL;
security_fixup_ops(ops);
return 0;
}
static void __init do_security_initcalls(void)
{
initcall_t *call;
call = &__security_initcall_start;
while (call < &__security_initcall_end) {
(*call) ();
call++;
}
}
/**
* security_init - initializes the security framework
*
* This should be called early in the kernel initialization sequence.
*/
int __init security_init(void)
{
printk(KERN_INFO "Security Framework v" SECURITY_FRAMEWORK_VERSION
" initialized\n");
if (verify(&dummy_security_ops)) {
printk(KERN_ERR "%s could not verify "
"dummy_security_ops structure.\n", __FUNCTION__);
return -EIO;
}
security_ops = &dummy_security_ops;
do_security_initcalls();
return 0;
}
/**
* register_security - registers a security framework with the kernel
* @ops: a pointer to the struct security_options that is to be registered
*
* This function is to allow a security module to register itself with the
* kernel security subsystem. Some rudimentary checking is done on the @ops
* value passed to this function. A call to unregister_security() should be
* done to remove this security_options structure from the kernel.
*
* If there is already a security module registered with the kernel,
* an error will be returned. Otherwise 0 is returned on success.
*/
int register_security(struct security_operations *ops)
{
if (verify(ops)) {
printk(KERN_DEBUG "%s could not verify "
"security_operations structure.\n", __FUNCTION__);
return -EINVAL;
}
if (security_ops != &dummy_security_ops)
return -EAGAIN;
security_ops = ops;
return 0;
}
/**
* unregister_security - unregisters a security framework with the kernel
* @ops: a pointer to the struct security_options that is to be registered
*
* This function removes a struct security_operations variable that had
* previously been registered with a successful call to register_security().
*
* If @ops does not match the valued previously passed to register_security()
* an error is returned. Otherwise the default security options is set to the
* the dummy_security_ops structure, and 0 is returned.
*/
int unregister_security(struct security_operations *ops)
{
if (ops != security_ops) {
printk(KERN_INFO "%s: trying to unregister "
"a security_opts structure that is not "
"registered, failing.\n", __FUNCTION__);
return -EINVAL;
}
security_ops = &dummy_security_ops;
return 0;
}
/**
* mod_reg_security - allows security modules to be "stacked"
* @name: a pointer to a string with the name of the security_options to be registered
* @ops: a pointer to the struct security_options that is to be registered
*
* This function allows security modules to be stacked if the currently loaded
* security module allows this to happen. It passes the @name and @ops to the
* register_security function of the currently loaded security module.
*
* The return value depends on the currently loaded security module, with 0 as
* success.
*/
int mod_reg_security(const char *name, struct security_operations *ops)
{
if (verify(ops)) {
printk(KERN_INFO "%s could not verify "
"security operations.\n", __FUNCTION__);
return -EINVAL;
}
if (ops == security_ops) {
printk(KERN_INFO "%s security operations "
"already registered.\n", __FUNCTION__);
return -EINVAL;
}
return security_ops->register_security(name, ops);
}
/**
* mod_unreg_security - allows a security module registered with mod_reg_security() to be unloaded
* @name: a pointer to a string with the name of the security_options to be removed
* @ops: a pointer to the struct security_options that is to be removed
*
* This function allows security modules that have been successfully registered
* with a call to mod_reg_security() to be unloaded from the system.
* This calls the currently loaded security module's unregister_security() call
* with the @name and @ops variables.
*
* The return value depends on the currently loaded security module, with 0 as
* success.
*/
int mod_unreg_security(const char *name, struct security_operations *ops)
{
if (ops == security_ops) {
printk(KERN_INFO "%s invalid attempt to unregister "
" primary security ops.\n", __FUNCTION__);
return -EINVAL;
}
return security_ops->unregister_security(name, ops);
}
/**
* capable - calls the currently loaded security module's capable() function with the specified capability
* @cap: the requested capability level.
*
* This function calls the currently loaded security module's capable()
* function with a pointer to the current task and the specified @cap value.
*
* This allows the security module to implement the capable function call
* however it chooses to.
*/
int capable(int cap)
{
if (security_ops->capable(current, cap)) {
/* capability denied */
return 0;
}
/* capability granted */
current->flags |= PF_SUPERPRIV;
return 1;
}
EXPORT_SYMBOL_GPL(register_security);
EXPORT_SYMBOL_GPL(unregister_security);
EXPORT_SYMBOL_GPL(mod_reg_security);
EXPORT_SYMBOL_GPL(mod_unreg_security);
EXPORT_SYMBOL(capable);
EXPORT_SYMBOL(security_ops);

View File

@@ -0,0 +1,78 @@
config SECURITY_SELINUX
bool "NSA SELinux Support"
depends on SECURITY && NET
default n
help
This selects NSA Security-Enhanced Linux (SELinux).
You will also need a policy configuration and a labeled filesystem.
You can obtain the policy compiler (checkpolicy), the utility for
labeling filesystems (setfiles), and an example policy configuration
from <http://www.nsa.gov/selinux/>.
If you are unsure how to answer this question, answer N.
config SECURITY_SELINUX_BOOTPARAM
bool "NSA SELinux boot parameter"
depends on SECURITY_SELINUX
default n
help
This option adds a kernel parameter 'selinux', which allows SELinux
to be disabled at boot. If this option is selected, SELinux
functionality can be disabled with selinux=0 on the kernel
command line. The purpose of this option is to allow a single
kernel image to be distributed with SELinux built in, but not
necessarily enabled.
If you are unsure how to answer this question, answer N.
config SECURITY_SELINUX_BOOTPARAM_VALUE
int "NSA SELinux boot parameter default value"
depends on SECURITY_SELINUX_BOOTPARAM
range 0 1
default 1
help
This option sets the default value for the kernel parameter
'selinux', which allows SELinux to be disabled at boot. If this
option is set to 0 (zero), the SELinux kernel parameter will
default to 0, disabling SELinux at bootup. If this option is
set to 1 (one), the SELinux kernel paramater will default to 1,
enabling SELinux at bootup.
If you are unsure how to answer this question, answer 1.
config SECURITY_SELINUX_DISABLE
bool "NSA SELinux runtime disable"
depends on SECURITY_SELINUX
default n
help
This option enables writing to a selinuxfs node 'disable', which
allows SELinux to be disabled at runtime prior to the policy load.
SELinux will then remain disabled until the next boot.
This option is similar to the selinux=0 boot parameter, but is to
support runtime disabling of SELinux, e.g. from /sbin/init, for
portability across platforms where boot parameters are difficult
to employ.
If you are unsure how to answer this question, answer N.
config SECURITY_SELINUX_DEVELOP
bool "NSA SELinux Development Support"
depends on SECURITY_SELINUX
default y
help
This enables the development support option of NSA SELinux,
which is useful for experimenting with SELinux and developing
policies. If unsure, say Y. With this option enabled, the
kernel will start in permissive mode (log everything, deny nothing)
unless you specify enforcing=1 on the kernel command line. You
can interactively toggle the kernel between enforcing mode and
permissive mode (if permitted by the policy) via /selinux/enforce.
config SECURITY_SELINUX_MLS
bool "NSA SELinux MLS policy (EXPERIMENTAL)"
depends on SECURITY_SELINUX && EXPERIMENTAL
default n
help
This enables the NSA SELinux Multi-Level Security (MLS) policy in
addition to the default RBAC/TE policy. This policy is
experimental and has not been configured for use. Unless you
specifically want to experiment with MLS, say N.

View File

@@ -0,0 +1,12 @@
#
# Makefile for building the SELinux module as part of the kernel tree.
#
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o
selinux-$(CONFIG_SECURITY_NETWORK) += netif.o
EXTRA_CFLAGS += -Isecurity/selinux/include

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
/* This file is automatically generated. Do not edit. */
/* FLASK */
struct av_inherit
{
u16 tclass;
char **common_pts;
u32 common_base;
};
static struct av_inherit av_inherit[] = {
{ SECCLASS_DIR, common_file_perm_to_string, 0x00020000UL },
{ SECCLASS_FILE, common_file_perm_to_string, 0x00020000UL },
{ SECCLASS_LNK_FILE, common_file_perm_to_string, 0x00020000UL },
{ SECCLASS_CHR_FILE, common_file_perm_to_string, 0x00020000UL },
{ SECCLASS_BLK_FILE, common_file_perm_to_string, 0x00020000UL },
{ SECCLASS_SOCK_FILE, common_file_perm_to_string, 0x00020000UL },
{ SECCLASS_FIFO_FILE, common_file_perm_to_string, 0x00020000UL },
{ SECCLASS_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_TCP_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_UDP_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_RAWIP_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_NETLINK_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_PACKET_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_KEY_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_UNIX_STREAM_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_UNIX_DGRAM_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_IPC, common_ipc_perm_to_string, 0x00000200UL },
{ SECCLASS_SEM, common_ipc_perm_to_string, 0x00000200UL },
{ SECCLASS_MSGQ, common_ipc_perm_to_string, 0x00000200UL },
{ SECCLASS_SHM, common_ipc_perm_to_string, 0x00000200UL },
{ SECCLASS_NETLINK_ROUTE_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_NETLINK_FIREWALL_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_NETLINK_TCPDIAG_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_NETLINK_NFLOG_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_NETLINK_XFRM_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_NETLINK_SELINUX_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_NETLINK_AUDIT_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_NETLINK_IP6FW_SOCKET, common_socket_perm_to_string, 0x00400000UL },
{ SECCLASS_NETLINK_DNRT_SOCKET, common_socket_perm_to_string, 0x00400000UL },
};
/* FLASK */

View File

@@ -0,0 +1,225 @@
/* This file is automatically generated. Do not edit. */
/* FLASK */
struct av_perm_to_string
{
u16 tclass;
u32 value;
char *name;
};
static struct av_perm_to_string av_perm_to_string[] = {
{ SECCLASS_FILESYSTEM, FILESYSTEM__MOUNT, "mount" },
{ SECCLASS_FILESYSTEM, FILESYSTEM__REMOUNT, "remount" },
{ SECCLASS_FILESYSTEM, FILESYSTEM__UNMOUNT, "unmount" },
{ SECCLASS_FILESYSTEM, FILESYSTEM__GETATTR, "getattr" },
{ SECCLASS_FILESYSTEM, FILESYSTEM__RELABELFROM, "relabelfrom" },
{ SECCLASS_FILESYSTEM, FILESYSTEM__RELABELTO, "relabelto" },
{ SECCLASS_FILESYSTEM, FILESYSTEM__TRANSITION, "transition" },
{ SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE, "associate" },
{ SECCLASS_FILESYSTEM, FILESYSTEM__QUOTAMOD, "quotamod" },
{ SECCLASS_FILESYSTEM, FILESYSTEM__QUOTAGET, "quotaget" },
{ SECCLASS_DIR, DIR__ADD_NAME, "add_name" },
{ SECCLASS_DIR, DIR__REMOVE_NAME, "remove_name" },
{ SECCLASS_DIR, DIR__REPARENT, "reparent" },
{ SECCLASS_DIR, DIR__SEARCH, "search" },
{ SECCLASS_DIR, DIR__RMDIR, "rmdir" },
{ SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, "execute_no_trans" },
{ SECCLASS_FILE, FILE__ENTRYPOINT, "entrypoint" },
{ SECCLASS_FD, FD__USE, "use" },
{ SECCLASS_TCP_SOCKET, TCP_SOCKET__CONNECTTO, "connectto" },
{ SECCLASS_TCP_SOCKET, TCP_SOCKET__NEWCONN, "newconn" },
{ SECCLASS_TCP_SOCKET, TCP_SOCKET__ACCEPTFROM, "acceptfrom" },
{ SECCLASS_TCP_SOCKET, TCP_SOCKET__NODE_BIND, "node_bind" },
{ SECCLASS_UDP_SOCKET, UDP_SOCKET__NODE_BIND, "node_bind" },
{ SECCLASS_RAWIP_SOCKET, RAWIP_SOCKET__NODE_BIND, "node_bind" },
{ SECCLASS_NODE, NODE__TCP_RECV, "tcp_recv" },
{ SECCLASS_NODE, NODE__TCP_SEND, "tcp_send" },
{ SECCLASS_NODE, NODE__UDP_RECV, "udp_recv" },
{ SECCLASS_NODE, NODE__UDP_SEND, "udp_send" },
{ SECCLASS_NODE, NODE__RAWIP_RECV, "rawip_recv" },
{ SECCLASS_NODE, NODE__RAWIP_SEND, "rawip_send" },
{ SECCLASS_NODE, NODE__ENFORCE_DEST, "enforce_dest" },
{ SECCLASS_NETIF, NETIF__TCP_RECV, "tcp_recv" },
{ SECCLASS_NETIF, NETIF__TCP_SEND, "tcp_send" },
{ SECCLASS_NETIF, NETIF__UDP_RECV, "udp_recv" },
{ SECCLASS_NETIF, NETIF__UDP_SEND, "udp_send" },
{ SECCLASS_NETIF, NETIF__RAWIP_RECV, "rawip_recv" },
{ SECCLASS_NETIF, NETIF__RAWIP_SEND, "rawip_send" },
{ SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__CONNECTTO, "connectto" },
{ SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__NEWCONN, "newconn" },
{ SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__ACCEPTFROM, "acceptfrom" },
{ SECCLASS_PROCESS, PROCESS__FORK, "fork" },
{ SECCLASS_PROCESS, PROCESS__TRANSITION, "transition" },
{ SECCLASS_PROCESS, PROCESS__SIGCHLD, "sigchld" },
{ SECCLASS_PROCESS, PROCESS__SIGKILL, "sigkill" },
{ SECCLASS_PROCESS, PROCESS__SIGSTOP, "sigstop" },
{ SECCLASS_PROCESS, PROCESS__SIGNULL, "signull" },
{ SECCLASS_PROCESS, PROCESS__SIGNAL, "signal" },
{ SECCLASS_PROCESS, PROCESS__PTRACE, "ptrace" },
{ SECCLASS_PROCESS, PROCESS__GETSCHED, "getsched" },
{ SECCLASS_PROCESS, PROCESS__SETSCHED, "setsched" },
{ SECCLASS_PROCESS, PROCESS__GETSESSION, "getsession" },
{ SECCLASS_PROCESS, PROCESS__GETPGID, "getpgid" },
{ SECCLASS_PROCESS, PROCESS__SETPGID, "setpgid" },
{ SECCLASS_PROCESS, PROCESS__GETCAP, "getcap" },
{ SECCLASS_PROCESS, PROCESS__SETCAP, "setcap" },
{ SECCLASS_PROCESS, PROCESS__SHARE, "share" },
{ SECCLASS_PROCESS, PROCESS__GETATTR, "getattr" },
{ SECCLASS_PROCESS, PROCESS__SETEXEC, "setexec" },
{ SECCLASS_PROCESS, PROCESS__SETFSCREATE, "setfscreate" },
{ SECCLASS_PROCESS, PROCESS__NOATSECURE, "noatsecure" },
{ SECCLASS_PROCESS, PROCESS__SIGINH, "siginh" },
{ SECCLASS_PROCESS, PROCESS__SETRLIMIT, "setrlimit" },
{ SECCLASS_PROCESS, PROCESS__RLIMITINH, "rlimitinh" },
{ SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue" },
{ SECCLASS_MSG, MSG__SEND, "send" },
{ SECCLASS_MSG, MSG__RECEIVE, "receive" },
{ SECCLASS_SHM, SHM__LOCK, "lock" },
{ SECCLASS_SECURITY, SECURITY__COMPUTE_AV, "compute_av" },
{ SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, "compute_create" },
{ SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER, "compute_member" },
{ SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, "check_context" },
{ SECCLASS_SECURITY, SECURITY__LOAD_POLICY, "load_policy" },
{ SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, "compute_relabel" },
{ SECCLASS_SECURITY, SECURITY__COMPUTE_USER, "compute_user" },
{ SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce" },
{ SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool" },
{ SECCLASS_SYSTEM, SYSTEM__IPC_INFO, "ipc_info" },
{ SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read" },
{ SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod" },
{ SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console" },
{ SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown" },
{ SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override" },
{ SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search" },
{ SECCLASS_CAPABILITY, CAPABILITY__FOWNER, "fowner" },
{ SECCLASS_CAPABILITY, CAPABILITY__FSETID, "fsetid" },
{ SECCLASS_CAPABILITY, CAPABILITY__KILL, "kill" },
{ SECCLASS_CAPABILITY, CAPABILITY__SETGID, "setgid" },
{ SECCLASS_CAPABILITY, CAPABILITY__SETUID, "setuid" },
{ SECCLASS_CAPABILITY, CAPABILITY__SETPCAP, "setpcap" },
{ SECCLASS_CAPABILITY, CAPABILITY__LINUX_IMMUTABLE, "linux_immutable" },
{ SECCLASS_CAPABILITY, CAPABILITY__NET_BIND_SERVICE, "net_bind_service" },
{ SECCLASS_CAPABILITY, CAPABILITY__NET_BROADCAST, "net_broadcast" },
{ SECCLASS_CAPABILITY, CAPABILITY__NET_ADMIN, "net_admin" },
{ SECCLASS_CAPABILITY, CAPABILITY__NET_RAW, "net_raw" },
{ SECCLASS_CAPABILITY, CAPABILITY__IPC_LOCK, "ipc_lock" },
{ SECCLASS_CAPABILITY, CAPABILITY__IPC_OWNER, "ipc_owner" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_MODULE, "sys_module" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_RAWIO, "sys_rawio" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_CHROOT, "sys_chroot" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_PTRACE, "sys_ptrace" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_PACCT, "sys_pacct" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_ADMIN, "sys_admin" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_BOOT, "sys_boot" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_NICE, "sys_nice" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_RESOURCE, "sys_resource" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_TIME, "sys_time" },
{ SECCLASS_CAPABILITY, CAPABILITY__SYS_TTY_CONFIG, "sys_tty_config" },
{ SECCLASS_CAPABILITY, CAPABILITY__MKNOD, "mknod" },
{ SECCLASS_CAPABILITY, CAPABILITY__LEASE, "lease" },
{ SECCLASS_PASSWD, PASSWD__PASSWD, "passwd" },
{ SECCLASS_PASSWD, PASSWD__CHFN, "chfn" },
{ SECCLASS_PASSWD, PASSWD__CHSH, "chsh" },
{ SECCLASS_PASSWD, PASSWD__ROOTOK, "rootok" },
{ SECCLASS_DRAWABLE, DRAWABLE__CREATE, "create" },
{ SECCLASS_DRAWABLE, DRAWABLE__DESTROY, "destroy" },
{ SECCLASS_DRAWABLE, DRAWABLE__DRAW, "draw" },
{ SECCLASS_DRAWABLE, DRAWABLE__COPY, "copy" },
{ SECCLASS_DRAWABLE, DRAWABLE__GETATTR, "getattr" },
{ SECCLASS_GC, GC__CREATE, "create" },
{ SECCLASS_GC, GC__FREE, "free" },
{ SECCLASS_GC, GC__GETATTR, "getattr" },
{ SECCLASS_GC, GC__SETATTR, "setattr" },
{ SECCLASS_WINDOW, WINDOW__ADDCHILD, "addchild" },
{ SECCLASS_WINDOW, WINDOW__CREATE, "create" },
{ SECCLASS_WINDOW, WINDOW__DESTROY, "destroy" },
{ SECCLASS_WINDOW, WINDOW__MAP, "map" },
{ SECCLASS_WINDOW, WINDOW__UNMAP, "unmap" },
{ SECCLASS_WINDOW, WINDOW__CHSTACK, "chstack" },
{ SECCLASS_WINDOW, WINDOW__CHPROPLIST, "chproplist" },
{ SECCLASS_WINDOW, WINDOW__CHPROP, "chprop" },
{ SECCLASS_WINDOW, WINDOW__LISTPROP, "listprop" },
{ SECCLASS_WINDOW, WINDOW__GETATTR, "getattr" },
{ SECCLASS_WINDOW, WINDOW__SETATTR, "setattr" },
{ SECCLASS_WINDOW, WINDOW__SETFOCUS, "setfocus" },
{ SECCLASS_WINDOW, WINDOW__MOVE, "move" },
{ SECCLASS_WINDOW, WINDOW__CHSELECTION, "chselection" },
{ SECCLASS_WINDOW, WINDOW__CHPARENT, "chparent" },
{ SECCLASS_WINDOW, WINDOW__CTRLLIFE, "ctrllife" },
{ SECCLASS_WINDOW, WINDOW__ENUMERATE, "enumerate" },
{ SECCLASS_WINDOW, WINDOW__TRANSPARENT, "transparent" },
{ SECCLASS_WINDOW, WINDOW__MOUSEMOTION, "mousemotion" },
{ SECCLASS_WINDOW, WINDOW__CLIENTCOMEVENT, "clientcomevent" },
{ SECCLASS_WINDOW, WINDOW__INPUTEVENT, "inputevent" },
{ SECCLASS_WINDOW, WINDOW__DRAWEVENT, "drawevent" },
{ SECCLASS_WINDOW, WINDOW__WINDOWCHANGEEVENT, "windowchangeevent" },
{ SECCLASS_WINDOW, WINDOW__WINDOWCHANGEREQUEST, "windowchangerequest" },
{ SECCLASS_WINDOW, WINDOW__SERVERCHANGEEVENT, "serverchangeevent" },
{ SECCLASS_WINDOW, WINDOW__EXTENSIONEVENT, "extensionevent" },
{ SECCLASS_FONT, FONT__LOAD, "load" },
{ SECCLASS_FONT, FONT__FREE, "free" },
{ SECCLASS_FONT, FONT__GETATTR, "getattr" },
{ SECCLASS_FONT, FONT__USE, "use" },
{ SECCLASS_COLORMAP, COLORMAP__CREATE, "create" },
{ SECCLASS_COLORMAP, COLORMAP__FREE, "free" },
{ SECCLASS_COLORMAP, COLORMAP__INSTALL, "install" },
{ SECCLASS_COLORMAP, COLORMAP__UNINSTALL, "uninstall" },
{ SECCLASS_COLORMAP, COLORMAP__LIST, "list" },
{ SECCLASS_COLORMAP, COLORMAP__READ, "read" },
{ SECCLASS_COLORMAP, COLORMAP__STORE, "store" },
{ SECCLASS_COLORMAP, COLORMAP__GETATTR, "getattr" },
{ SECCLASS_COLORMAP, COLORMAP__SETATTR, "setattr" },
{ SECCLASS_PROPERTY, PROPERTY__CREATE, "create" },
{ SECCLASS_PROPERTY, PROPERTY__FREE, "free" },
{ SECCLASS_PROPERTY, PROPERTY__READ, "read" },
{ SECCLASS_PROPERTY, PROPERTY__WRITE, "write" },
{ SECCLASS_CURSOR, CURSOR__CREATE, "create" },
{ SECCLASS_CURSOR, CURSOR__CREATEGLYPH, "createglyph" },
{ SECCLASS_CURSOR, CURSOR__FREE, "free" },
{ SECCLASS_CURSOR, CURSOR__ASSIGN, "assign" },
{ SECCLASS_CURSOR, CURSOR__SETATTR, "setattr" },
{ SECCLASS_XCLIENT, XCLIENT__KILL, "kill" },
{ SECCLASS_XINPUT, XINPUT__LOOKUP, "lookup" },
{ SECCLASS_XINPUT, XINPUT__GETATTR, "getattr" },
{ SECCLASS_XINPUT, XINPUT__SETATTR, "setattr" },
{ SECCLASS_XINPUT, XINPUT__SETFOCUS, "setfocus" },
{ SECCLASS_XINPUT, XINPUT__WARPPOINTER, "warppointer" },
{ SECCLASS_XINPUT, XINPUT__ACTIVEGRAB, "activegrab" },
{ SECCLASS_XINPUT, XINPUT__PASSIVEGRAB, "passivegrab" },
{ SECCLASS_XINPUT, XINPUT__UNGRAB, "ungrab" },
{ SECCLASS_XINPUT, XINPUT__BELL, "bell" },
{ SECCLASS_XINPUT, XINPUT__MOUSEMOTION, "mousemotion" },
{ SECCLASS_XINPUT, XINPUT__RELABELINPUT, "relabelinput" },
{ SECCLASS_XSERVER, XSERVER__SCREENSAVER, "screensaver" },
{ SECCLASS_XSERVER, XSERVER__GETHOSTLIST, "gethostlist" },
{ SECCLASS_XSERVER, XSERVER__SETHOSTLIST, "sethostlist" },
{ SECCLASS_XSERVER, XSERVER__GETFONTPATH, "getfontpath" },
{ SECCLASS_XSERVER, XSERVER__SETFONTPATH, "setfontpath" },
{ SECCLASS_XSERVER, XSERVER__GETATTR, "getattr" },
{ SECCLASS_XSERVER, XSERVER__GRAB, "grab" },
{ SECCLASS_XSERVER, XSERVER__UNGRAB, "ungrab" },
{ SECCLASS_XEXTENSION, XEXTENSION__QUERY, "query" },
{ SECCLASS_XEXTENSION, XEXTENSION__USE, "use" },
{ SECCLASS_PAX, PAX__PAGEEXEC, "pageexec" },
{ SECCLASS_PAX, PAX__EMUTRAMP, "emutramp" },
{ SECCLASS_PAX, PAX__MPROTECT, "mprotect" },
{ SECCLASS_PAX, PAX__RANDMMAP, "randmmap" },
{ SECCLASS_PAX, PAX__RANDEXEC, "randexec" },
{ SECCLASS_PAX, PAX__SEGMEXEC, "segmexec" },
{ SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ, "nlmsg_read" },
{ SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE, "nlmsg_write" },
{ SECCLASS_NETLINK_FIREWALL_SOCKET, NETLINK_FIREWALL_SOCKET__NLMSG_READ, "nlmsg_read" },
{ SECCLASS_NETLINK_FIREWALL_SOCKET, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE, "nlmsg_write" },
{ SECCLASS_NETLINK_TCPDIAG_SOCKET, NETLINK_TCPDIAG_SOCKET__NLMSG_READ, "nlmsg_read" },
{ SECCLASS_NETLINK_TCPDIAG_SOCKET, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE, "nlmsg_write" },
{ SECCLASS_NETLINK_XFRM_SOCKET, NETLINK_XFRM_SOCKET__NLMSG_READ, "nlmsg_read" },
{ SECCLASS_NETLINK_XFRM_SOCKET, NETLINK_XFRM_SOCKET__NLMSG_WRITE, "nlmsg_write" },
{ SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READ, "nlmsg_read" },
{ SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE, "nlmsg_write" },
{ SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_READ, "nlmsg_read" },
{ SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_WRITE, "nlmsg_write" },
};
/* FLASK */

View File

@@ -0,0 +1,880 @@
/* This file is automatically generated. Do not edit. */
/* FLASK */
#define COMMON_FILE__IOCTL 0x00000001UL
#define COMMON_FILE__READ 0x00000002UL
#define COMMON_FILE__WRITE 0x00000004UL
#define COMMON_FILE__CREATE 0x00000008UL
#define COMMON_FILE__GETATTR 0x00000010UL
#define COMMON_FILE__SETATTR 0x00000020UL
#define COMMON_FILE__LOCK 0x00000040UL
#define COMMON_FILE__RELABELFROM 0x00000080UL
#define COMMON_FILE__RELABELTO 0x00000100UL
#define COMMON_FILE__APPEND 0x00000200UL
#define COMMON_FILE__UNLINK 0x00000400UL
#define COMMON_FILE__LINK 0x00000800UL
#define COMMON_FILE__RENAME 0x00001000UL
#define COMMON_FILE__EXECUTE 0x00002000UL
#define COMMON_FILE__SWAPON 0x00004000UL
#define COMMON_FILE__QUOTAON 0x00008000UL
#define COMMON_FILE__MOUNTON 0x00010000UL
#define COMMON_SOCKET__IOCTL 0x00000001UL
#define COMMON_SOCKET__READ 0x00000002UL
#define COMMON_SOCKET__WRITE 0x00000004UL
#define COMMON_SOCKET__CREATE 0x00000008UL
#define COMMON_SOCKET__GETATTR 0x00000010UL
#define COMMON_SOCKET__SETATTR 0x00000020UL
#define COMMON_SOCKET__LOCK 0x00000040UL
#define COMMON_SOCKET__RELABELFROM 0x00000080UL
#define COMMON_SOCKET__RELABELTO 0x00000100UL
#define COMMON_SOCKET__APPEND 0x00000200UL
#define COMMON_SOCKET__BIND 0x00000400UL
#define COMMON_SOCKET__CONNECT 0x00000800UL
#define COMMON_SOCKET__LISTEN 0x00001000UL
#define COMMON_SOCKET__ACCEPT 0x00002000UL
#define COMMON_SOCKET__GETOPT 0x00004000UL
#define COMMON_SOCKET__SETOPT 0x00008000UL
#define COMMON_SOCKET__SHUTDOWN 0x00010000UL
#define COMMON_SOCKET__RECVFROM 0x00020000UL
#define COMMON_SOCKET__SENDTO 0x00040000UL
#define COMMON_SOCKET__RECV_MSG 0x00080000UL
#define COMMON_SOCKET__SEND_MSG 0x00100000UL
#define COMMON_SOCKET__NAME_BIND 0x00200000UL
#define COMMON_IPC__CREATE 0x00000001UL
#define COMMON_IPC__DESTROY 0x00000002UL
#define COMMON_IPC__GETATTR 0x00000004UL
#define COMMON_IPC__SETATTR 0x00000008UL
#define COMMON_IPC__READ 0x00000010UL
#define COMMON_IPC__WRITE 0x00000020UL
#define COMMON_IPC__ASSOCIATE 0x00000040UL
#define COMMON_IPC__UNIX_READ 0x00000080UL
#define COMMON_IPC__UNIX_WRITE 0x00000100UL
#define FILESYSTEM__MOUNT 0x00000001UL
#define FILESYSTEM__REMOUNT 0x00000002UL
#define FILESYSTEM__UNMOUNT 0x00000004UL
#define FILESYSTEM__GETATTR 0x00000008UL
#define FILESYSTEM__RELABELFROM 0x00000010UL
#define FILESYSTEM__RELABELTO 0x00000020UL
#define FILESYSTEM__TRANSITION 0x00000040UL
#define FILESYSTEM__ASSOCIATE 0x00000080UL
#define FILESYSTEM__QUOTAMOD 0x00000100UL
#define FILESYSTEM__QUOTAGET 0x00000200UL
#define DIR__IOCTL 0x00000001UL
#define DIR__READ 0x00000002UL
#define DIR__WRITE 0x00000004UL
#define DIR__CREATE 0x00000008UL
#define DIR__GETATTR 0x00000010UL
#define DIR__SETATTR 0x00000020UL
#define DIR__LOCK 0x00000040UL
#define DIR__RELABELFROM 0x00000080UL
#define DIR__RELABELTO 0x00000100UL
#define DIR__APPEND 0x00000200UL
#define DIR__UNLINK 0x00000400UL
#define DIR__LINK 0x00000800UL
#define DIR__RENAME 0x00001000UL
#define DIR__EXECUTE 0x00002000UL
#define DIR__SWAPON 0x00004000UL
#define DIR__QUOTAON 0x00008000UL
#define DIR__MOUNTON 0x00010000UL
#define DIR__ADD_NAME 0x00020000UL
#define DIR__REMOVE_NAME 0x00040000UL
#define DIR__REPARENT 0x00080000UL
#define DIR__SEARCH 0x00100000UL
#define DIR__RMDIR 0x00200000UL
#define FILE__IOCTL 0x00000001UL
#define FILE__READ 0x00000002UL
#define FILE__WRITE 0x00000004UL
#define FILE__CREATE 0x00000008UL
#define FILE__GETATTR 0x00000010UL
#define FILE__SETATTR 0x00000020UL
#define FILE__LOCK 0x00000040UL
#define FILE__RELABELFROM 0x00000080UL
#define FILE__RELABELTO 0x00000100UL
#define FILE__APPEND 0x00000200UL
#define FILE__UNLINK 0x00000400UL
#define FILE__LINK 0x00000800UL
#define FILE__RENAME 0x00001000UL
#define FILE__EXECUTE 0x00002000UL
#define FILE__SWAPON 0x00004000UL
#define FILE__QUOTAON 0x00008000UL
#define FILE__MOUNTON 0x00010000UL
#define FILE__EXECUTE_NO_TRANS 0x00020000UL
#define FILE__ENTRYPOINT 0x00040000UL
#define LNK_FILE__IOCTL 0x00000001UL
#define LNK_FILE__READ 0x00000002UL
#define LNK_FILE__WRITE 0x00000004UL
#define LNK_FILE__CREATE 0x00000008UL
#define LNK_FILE__GETATTR 0x00000010UL
#define LNK_FILE__SETATTR 0x00000020UL
#define LNK_FILE__LOCK 0x00000040UL
#define LNK_FILE__RELABELFROM 0x00000080UL
#define LNK_FILE__RELABELTO 0x00000100UL
#define LNK_FILE__APPEND 0x00000200UL
#define LNK_FILE__UNLINK 0x00000400UL
#define LNK_FILE__LINK 0x00000800UL
#define LNK_FILE__RENAME 0x00001000UL
#define LNK_FILE__EXECUTE 0x00002000UL
#define LNK_FILE__SWAPON 0x00004000UL
#define LNK_FILE__QUOTAON 0x00008000UL
#define LNK_FILE__MOUNTON 0x00010000UL
#define CHR_FILE__IOCTL 0x00000001UL
#define CHR_FILE__READ 0x00000002UL
#define CHR_FILE__WRITE 0x00000004UL
#define CHR_FILE__CREATE 0x00000008UL
#define CHR_FILE__GETATTR 0x00000010UL
#define CHR_FILE__SETATTR 0x00000020UL
#define CHR_FILE__LOCK 0x00000040UL
#define CHR_FILE__RELABELFROM 0x00000080UL
#define CHR_FILE__RELABELTO 0x00000100UL
#define CHR_FILE__APPEND 0x00000200UL
#define CHR_FILE__UNLINK 0x00000400UL
#define CHR_FILE__LINK 0x00000800UL
#define CHR_FILE__RENAME 0x00001000UL
#define CHR_FILE__EXECUTE 0x00002000UL
#define CHR_FILE__SWAPON 0x00004000UL
#define CHR_FILE__QUOTAON 0x00008000UL
#define CHR_FILE__MOUNTON 0x00010000UL
#define BLK_FILE__IOCTL 0x00000001UL
#define BLK_FILE__READ 0x00000002UL
#define BLK_FILE__WRITE 0x00000004UL
#define BLK_FILE__CREATE 0x00000008UL
#define BLK_FILE__GETATTR 0x00000010UL
#define BLK_FILE__SETATTR 0x00000020UL
#define BLK_FILE__LOCK 0x00000040UL
#define BLK_FILE__RELABELFROM 0x00000080UL
#define BLK_FILE__RELABELTO 0x00000100UL
#define BLK_FILE__APPEND 0x00000200UL
#define BLK_FILE__UNLINK 0x00000400UL
#define BLK_FILE__LINK 0x00000800UL
#define BLK_FILE__RENAME 0x00001000UL
#define BLK_FILE__EXECUTE 0x00002000UL
#define BLK_FILE__SWAPON 0x00004000UL
#define BLK_FILE__QUOTAON 0x00008000UL
#define BLK_FILE__MOUNTON 0x00010000UL
#define SOCK_FILE__IOCTL 0x00000001UL
#define SOCK_FILE__READ 0x00000002UL
#define SOCK_FILE__WRITE 0x00000004UL
#define SOCK_FILE__CREATE 0x00000008UL
#define SOCK_FILE__GETATTR 0x00000010UL
#define SOCK_FILE__SETATTR 0x00000020UL
#define SOCK_FILE__LOCK 0x00000040UL
#define SOCK_FILE__RELABELFROM 0x00000080UL
#define SOCK_FILE__RELABELTO 0x00000100UL
#define SOCK_FILE__APPEND 0x00000200UL
#define SOCK_FILE__UNLINK 0x00000400UL
#define SOCK_FILE__LINK 0x00000800UL
#define SOCK_FILE__RENAME 0x00001000UL
#define SOCK_FILE__EXECUTE 0x00002000UL
#define SOCK_FILE__SWAPON 0x00004000UL
#define SOCK_FILE__QUOTAON 0x00008000UL
#define SOCK_FILE__MOUNTON 0x00010000UL
#define FIFO_FILE__IOCTL 0x00000001UL
#define FIFO_FILE__READ 0x00000002UL
#define FIFO_FILE__WRITE 0x00000004UL
#define FIFO_FILE__CREATE 0x00000008UL
#define FIFO_FILE__GETATTR 0x00000010UL
#define FIFO_FILE__SETATTR 0x00000020UL
#define FIFO_FILE__LOCK 0x00000040UL
#define FIFO_FILE__RELABELFROM 0x00000080UL
#define FIFO_FILE__RELABELTO 0x00000100UL
#define FIFO_FILE__APPEND 0x00000200UL
#define FIFO_FILE__UNLINK 0x00000400UL
#define FIFO_FILE__LINK 0x00000800UL
#define FIFO_FILE__RENAME 0x00001000UL
#define FIFO_FILE__EXECUTE 0x00002000UL
#define FIFO_FILE__SWAPON 0x00004000UL
#define FIFO_FILE__QUOTAON 0x00008000UL
#define FIFO_FILE__MOUNTON 0x00010000UL
#define FD__USE 0x00000001UL
#define SOCKET__IOCTL 0x00000001UL
#define SOCKET__READ 0x00000002UL
#define SOCKET__WRITE 0x00000004UL
#define SOCKET__CREATE 0x00000008UL
#define SOCKET__GETATTR 0x00000010UL
#define SOCKET__SETATTR 0x00000020UL
#define SOCKET__LOCK 0x00000040UL
#define SOCKET__RELABELFROM 0x00000080UL
#define SOCKET__RELABELTO 0x00000100UL
#define SOCKET__APPEND 0x00000200UL
#define SOCKET__BIND 0x00000400UL
#define SOCKET__CONNECT 0x00000800UL
#define SOCKET__LISTEN 0x00001000UL
#define SOCKET__ACCEPT 0x00002000UL
#define SOCKET__GETOPT 0x00004000UL
#define SOCKET__SETOPT 0x00008000UL
#define SOCKET__SHUTDOWN 0x00010000UL
#define SOCKET__RECVFROM 0x00020000UL
#define SOCKET__SENDTO 0x00040000UL
#define SOCKET__RECV_MSG 0x00080000UL
#define SOCKET__SEND_MSG 0x00100000UL
#define SOCKET__NAME_BIND 0x00200000UL
#define TCP_SOCKET__IOCTL 0x00000001UL
#define TCP_SOCKET__READ 0x00000002UL
#define TCP_SOCKET__WRITE 0x00000004UL
#define TCP_SOCKET__CREATE 0x00000008UL
#define TCP_SOCKET__GETATTR 0x00000010UL
#define TCP_SOCKET__SETATTR 0x00000020UL
#define TCP_SOCKET__LOCK 0x00000040UL
#define TCP_SOCKET__RELABELFROM 0x00000080UL
#define TCP_SOCKET__RELABELTO 0x00000100UL
#define TCP_SOCKET__APPEND 0x00000200UL
#define TCP_SOCKET__BIND 0x00000400UL
#define TCP_SOCKET__CONNECT 0x00000800UL
#define TCP_SOCKET__LISTEN 0x00001000UL
#define TCP_SOCKET__ACCEPT 0x00002000UL
#define TCP_SOCKET__GETOPT 0x00004000UL
#define TCP_SOCKET__SETOPT 0x00008000UL
#define TCP_SOCKET__SHUTDOWN 0x00010000UL
#define TCP_SOCKET__RECVFROM 0x00020000UL
#define TCP_SOCKET__SENDTO 0x00040000UL
#define TCP_SOCKET__RECV_MSG 0x00080000UL
#define TCP_SOCKET__SEND_MSG 0x00100000UL
#define TCP_SOCKET__NAME_BIND 0x00200000UL
#define TCP_SOCKET__CONNECTTO 0x00400000UL
#define TCP_SOCKET__NEWCONN 0x00800000UL
#define TCP_SOCKET__ACCEPTFROM 0x01000000UL
#define TCP_SOCKET__NODE_BIND 0x02000000UL
#define UDP_SOCKET__IOCTL 0x00000001UL
#define UDP_SOCKET__READ 0x00000002UL
#define UDP_SOCKET__WRITE 0x00000004UL
#define UDP_SOCKET__CREATE 0x00000008UL
#define UDP_SOCKET__GETATTR 0x00000010UL
#define UDP_SOCKET__SETATTR 0x00000020UL
#define UDP_SOCKET__LOCK 0x00000040UL
#define UDP_SOCKET__RELABELFROM 0x00000080UL
#define UDP_SOCKET__RELABELTO 0x00000100UL
#define UDP_SOCKET__APPEND 0x00000200UL
#define UDP_SOCKET__BIND 0x00000400UL
#define UDP_SOCKET__CONNECT 0x00000800UL
#define UDP_SOCKET__LISTEN 0x00001000UL
#define UDP_SOCKET__ACCEPT 0x00002000UL
#define UDP_SOCKET__GETOPT 0x00004000UL
#define UDP_SOCKET__SETOPT 0x00008000UL
#define UDP_SOCKET__SHUTDOWN 0x00010000UL
#define UDP_SOCKET__RECVFROM 0x00020000UL
#define UDP_SOCKET__SENDTO 0x00040000UL
#define UDP_SOCKET__RECV_MSG 0x00080000UL
#define UDP_SOCKET__SEND_MSG 0x00100000UL
#define UDP_SOCKET__NAME_BIND 0x00200000UL
#define UDP_SOCKET__NODE_BIND 0x00400000UL
#define RAWIP_SOCKET__IOCTL 0x00000001UL
#define RAWIP_SOCKET__READ 0x00000002UL
#define RAWIP_SOCKET__WRITE 0x00000004UL
#define RAWIP_SOCKET__CREATE 0x00000008UL
#define RAWIP_SOCKET__GETATTR 0x00000010UL
#define RAWIP_SOCKET__SETATTR 0x00000020UL
#define RAWIP_SOCKET__LOCK 0x00000040UL
#define RAWIP_SOCKET__RELABELFROM 0x00000080UL
#define RAWIP_SOCKET__RELABELTO 0x00000100UL
#define RAWIP_SOCKET__APPEND 0x00000200UL
#define RAWIP_SOCKET__BIND 0x00000400UL
#define RAWIP_SOCKET__CONNECT 0x00000800UL
#define RAWIP_SOCKET__LISTEN 0x00001000UL
#define RAWIP_SOCKET__ACCEPT 0x00002000UL
#define RAWIP_SOCKET__GETOPT 0x00004000UL
#define RAWIP_SOCKET__SETOPT 0x00008000UL
#define RAWIP_SOCKET__SHUTDOWN 0x00010000UL
#define RAWIP_SOCKET__RECVFROM 0x00020000UL
#define RAWIP_SOCKET__SENDTO 0x00040000UL
#define RAWIP_SOCKET__RECV_MSG 0x00080000UL
#define RAWIP_SOCKET__SEND_MSG 0x00100000UL
#define RAWIP_SOCKET__NAME_BIND 0x00200000UL
#define RAWIP_SOCKET__NODE_BIND 0x00400000UL
#define NODE__TCP_RECV 0x00000001UL
#define NODE__TCP_SEND 0x00000002UL
#define NODE__UDP_RECV 0x00000004UL
#define NODE__UDP_SEND 0x00000008UL
#define NODE__RAWIP_RECV 0x00000010UL
#define NODE__RAWIP_SEND 0x00000020UL
#define NODE__ENFORCE_DEST 0x00000040UL
#define NETIF__TCP_RECV 0x00000001UL
#define NETIF__TCP_SEND 0x00000002UL
#define NETIF__UDP_RECV 0x00000004UL
#define NETIF__UDP_SEND 0x00000008UL
#define NETIF__RAWIP_RECV 0x00000010UL
#define NETIF__RAWIP_SEND 0x00000020UL
#define NETLINK_SOCKET__IOCTL 0x00000001UL
#define NETLINK_SOCKET__READ 0x00000002UL
#define NETLINK_SOCKET__WRITE 0x00000004UL
#define NETLINK_SOCKET__CREATE 0x00000008UL
#define NETLINK_SOCKET__GETATTR 0x00000010UL
#define NETLINK_SOCKET__SETATTR 0x00000020UL
#define NETLINK_SOCKET__LOCK 0x00000040UL
#define NETLINK_SOCKET__RELABELFROM 0x00000080UL
#define NETLINK_SOCKET__RELABELTO 0x00000100UL
#define NETLINK_SOCKET__APPEND 0x00000200UL
#define NETLINK_SOCKET__BIND 0x00000400UL
#define NETLINK_SOCKET__CONNECT 0x00000800UL
#define NETLINK_SOCKET__LISTEN 0x00001000UL
#define NETLINK_SOCKET__ACCEPT 0x00002000UL
#define NETLINK_SOCKET__GETOPT 0x00004000UL
#define NETLINK_SOCKET__SETOPT 0x00008000UL
#define NETLINK_SOCKET__SHUTDOWN 0x00010000UL
#define NETLINK_SOCKET__RECVFROM 0x00020000UL
#define NETLINK_SOCKET__SENDTO 0x00040000UL
#define NETLINK_SOCKET__RECV_MSG 0x00080000UL
#define NETLINK_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_SOCKET__NAME_BIND 0x00200000UL
#define PACKET_SOCKET__IOCTL 0x00000001UL
#define PACKET_SOCKET__READ 0x00000002UL
#define PACKET_SOCKET__WRITE 0x00000004UL
#define PACKET_SOCKET__CREATE 0x00000008UL
#define PACKET_SOCKET__GETATTR 0x00000010UL
#define PACKET_SOCKET__SETATTR 0x00000020UL
#define PACKET_SOCKET__LOCK 0x00000040UL
#define PACKET_SOCKET__RELABELFROM 0x00000080UL
#define PACKET_SOCKET__RELABELTO 0x00000100UL
#define PACKET_SOCKET__APPEND 0x00000200UL
#define PACKET_SOCKET__BIND 0x00000400UL
#define PACKET_SOCKET__CONNECT 0x00000800UL
#define PACKET_SOCKET__LISTEN 0x00001000UL
#define PACKET_SOCKET__ACCEPT 0x00002000UL
#define PACKET_SOCKET__GETOPT 0x00004000UL
#define PACKET_SOCKET__SETOPT 0x00008000UL
#define PACKET_SOCKET__SHUTDOWN 0x00010000UL
#define PACKET_SOCKET__RECVFROM 0x00020000UL
#define PACKET_SOCKET__SENDTO 0x00040000UL
#define PACKET_SOCKET__RECV_MSG 0x00080000UL
#define PACKET_SOCKET__SEND_MSG 0x00100000UL
#define PACKET_SOCKET__NAME_BIND 0x00200000UL
#define KEY_SOCKET__IOCTL 0x00000001UL
#define KEY_SOCKET__READ 0x00000002UL
#define KEY_SOCKET__WRITE 0x00000004UL
#define KEY_SOCKET__CREATE 0x00000008UL
#define KEY_SOCKET__GETATTR 0x00000010UL
#define KEY_SOCKET__SETATTR 0x00000020UL
#define KEY_SOCKET__LOCK 0x00000040UL
#define KEY_SOCKET__RELABELFROM 0x00000080UL
#define KEY_SOCKET__RELABELTO 0x00000100UL
#define KEY_SOCKET__APPEND 0x00000200UL
#define KEY_SOCKET__BIND 0x00000400UL
#define KEY_SOCKET__CONNECT 0x00000800UL
#define KEY_SOCKET__LISTEN 0x00001000UL
#define KEY_SOCKET__ACCEPT 0x00002000UL
#define KEY_SOCKET__GETOPT 0x00004000UL
#define KEY_SOCKET__SETOPT 0x00008000UL
#define KEY_SOCKET__SHUTDOWN 0x00010000UL
#define KEY_SOCKET__RECVFROM 0x00020000UL
#define KEY_SOCKET__SENDTO 0x00040000UL
#define KEY_SOCKET__RECV_MSG 0x00080000UL
#define KEY_SOCKET__SEND_MSG 0x00100000UL
#define KEY_SOCKET__NAME_BIND 0x00200000UL
#define UNIX_STREAM_SOCKET__IOCTL 0x00000001UL
#define UNIX_STREAM_SOCKET__READ 0x00000002UL
#define UNIX_STREAM_SOCKET__WRITE 0x00000004UL
#define UNIX_STREAM_SOCKET__CREATE 0x00000008UL
#define UNIX_STREAM_SOCKET__GETATTR 0x00000010UL
#define UNIX_STREAM_SOCKET__SETATTR 0x00000020UL
#define UNIX_STREAM_SOCKET__LOCK 0x00000040UL
#define UNIX_STREAM_SOCKET__RELABELFROM 0x00000080UL
#define UNIX_STREAM_SOCKET__RELABELTO 0x00000100UL
#define UNIX_STREAM_SOCKET__APPEND 0x00000200UL
#define UNIX_STREAM_SOCKET__BIND 0x00000400UL
#define UNIX_STREAM_SOCKET__CONNECT 0x00000800UL
#define UNIX_STREAM_SOCKET__LISTEN 0x00001000UL
#define UNIX_STREAM_SOCKET__ACCEPT 0x00002000UL
#define UNIX_STREAM_SOCKET__GETOPT 0x00004000UL
#define UNIX_STREAM_SOCKET__SETOPT 0x00008000UL
#define UNIX_STREAM_SOCKET__SHUTDOWN 0x00010000UL
#define UNIX_STREAM_SOCKET__RECVFROM 0x00020000UL
#define UNIX_STREAM_SOCKET__SENDTO 0x00040000UL
#define UNIX_STREAM_SOCKET__RECV_MSG 0x00080000UL
#define UNIX_STREAM_SOCKET__SEND_MSG 0x00100000UL
#define UNIX_STREAM_SOCKET__NAME_BIND 0x00200000UL
#define UNIX_STREAM_SOCKET__CONNECTTO 0x00400000UL
#define UNIX_STREAM_SOCKET__NEWCONN 0x00800000UL
#define UNIX_STREAM_SOCKET__ACCEPTFROM 0x01000000UL
#define UNIX_DGRAM_SOCKET__IOCTL 0x00000001UL
#define UNIX_DGRAM_SOCKET__READ 0x00000002UL
#define UNIX_DGRAM_SOCKET__WRITE 0x00000004UL
#define UNIX_DGRAM_SOCKET__CREATE 0x00000008UL
#define UNIX_DGRAM_SOCKET__GETATTR 0x00000010UL
#define UNIX_DGRAM_SOCKET__SETATTR 0x00000020UL
#define UNIX_DGRAM_SOCKET__LOCK 0x00000040UL
#define UNIX_DGRAM_SOCKET__RELABELFROM 0x00000080UL
#define UNIX_DGRAM_SOCKET__RELABELTO 0x00000100UL
#define UNIX_DGRAM_SOCKET__APPEND 0x00000200UL
#define UNIX_DGRAM_SOCKET__BIND 0x00000400UL
#define UNIX_DGRAM_SOCKET__CONNECT 0x00000800UL
#define UNIX_DGRAM_SOCKET__LISTEN 0x00001000UL
#define UNIX_DGRAM_SOCKET__ACCEPT 0x00002000UL
#define UNIX_DGRAM_SOCKET__GETOPT 0x00004000UL
#define UNIX_DGRAM_SOCKET__SETOPT 0x00008000UL
#define UNIX_DGRAM_SOCKET__SHUTDOWN 0x00010000UL
#define UNIX_DGRAM_SOCKET__RECVFROM 0x00020000UL
#define UNIX_DGRAM_SOCKET__SENDTO 0x00040000UL
#define UNIX_DGRAM_SOCKET__RECV_MSG 0x00080000UL
#define UNIX_DGRAM_SOCKET__SEND_MSG 0x00100000UL
#define UNIX_DGRAM_SOCKET__NAME_BIND 0x00200000UL
#define PROCESS__FORK 0x00000001UL
#define PROCESS__TRANSITION 0x00000002UL
#define PROCESS__SIGCHLD 0x00000004UL
#define PROCESS__SIGKILL 0x00000008UL
#define PROCESS__SIGSTOP 0x00000010UL
#define PROCESS__SIGNULL 0x00000020UL
#define PROCESS__SIGNAL 0x00000040UL
#define PROCESS__PTRACE 0x00000080UL
#define PROCESS__GETSCHED 0x00000100UL
#define PROCESS__SETSCHED 0x00000200UL
#define PROCESS__GETSESSION 0x00000400UL
#define PROCESS__GETPGID 0x00000800UL
#define PROCESS__SETPGID 0x00001000UL
#define PROCESS__GETCAP 0x00002000UL
#define PROCESS__SETCAP 0x00004000UL
#define PROCESS__SHARE 0x00008000UL
#define PROCESS__GETATTR 0x00010000UL
#define PROCESS__SETEXEC 0x00020000UL
#define PROCESS__SETFSCREATE 0x00040000UL
#define PROCESS__NOATSECURE 0x00080000UL
#define PROCESS__SIGINH 0x00100000UL
#define PROCESS__SETRLIMIT 0x00200000UL
#define PROCESS__RLIMITINH 0x00400000UL
#define IPC__CREATE 0x00000001UL
#define IPC__DESTROY 0x00000002UL
#define IPC__GETATTR 0x00000004UL
#define IPC__SETATTR 0x00000008UL
#define IPC__READ 0x00000010UL
#define IPC__WRITE 0x00000020UL
#define IPC__ASSOCIATE 0x00000040UL
#define IPC__UNIX_READ 0x00000080UL
#define IPC__UNIX_WRITE 0x00000100UL
#define SEM__CREATE 0x00000001UL
#define SEM__DESTROY 0x00000002UL
#define SEM__GETATTR 0x00000004UL
#define SEM__SETATTR 0x00000008UL
#define SEM__READ 0x00000010UL
#define SEM__WRITE 0x00000020UL
#define SEM__ASSOCIATE 0x00000040UL
#define SEM__UNIX_READ 0x00000080UL
#define SEM__UNIX_WRITE 0x00000100UL
#define MSGQ__CREATE 0x00000001UL
#define MSGQ__DESTROY 0x00000002UL
#define MSGQ__GETATTR 0x00000004UL
#define MSGQ__SETATTR 0x00000008UL
#define MSGQ__READ 0x00000010UL
#define MSGQ__WRITE 0x00000020UL
#define MSGQ__ASSOCIATE 0x00000040UL
#define MSGQ__UNIX_READ 0x00000080UL
#define MSGQ__UNIX_WRITE 0x00000100UL
#define MSGQ__ENQUEUE 0x00000200UL
#define MSG__SEND 0x00000001UL
#define MSG__RECEIVE 0x00000002UL
#define SHM__CREATE 0x00000001UL
#define SHM__DESTROY 0x00000002UL
#define SHM__GETATTR 0x00000004UL
#define SHM__SETATTR 0x00000008UL
#define SHM__READ 0x00000010UL
#define SHM__WRITE 0x00000020UL
#define SHM__ASSOCIATE 0x00000040UL
#define SHM__UNIX_READ 0x00000080UL
#define SHM__UNIX_WRITE 0x00000100UL
#define SHM__LOCK 0x00000200UL
#define SECURITY__COMPUTE_AV 0x00000001UL
#define SECURITY__COMPUTE_CREATE 0x00000002UL
#define SECURITY__COMPUTE_MEMBER 0x00000004UL
#define SECURITY__CHECK_CONTEXT 0x00000008UL
#define SECURITY__LOAD_POLICY 0x00000010UL
#define SECURITY__COMPUTE_RELABEL 0x00000020UL
#define SECURITY__COMPUTE_USER 0x00000040UL
#define SECURITY__SETENFORCE 0x00000080UL
#define SECURITY__SETBOOL 0x00000100UL
#define SYSTEM__IPC_INFO 0x00000001UL
#define SYSTEM__SYSLOG_READ 0x00000002UL
#define SYSTEM__SYSLOG_MOD 0x00000004UL
#define SYSTEM__SYSLOG_CONSOLE 0x00000008UL
#define CAPABILITY__CHOWN 0x00000001UL
#define CAPABILITY__DAC_OVERRIDE 0x00000002UL
#define CAPABILITY__DAC_READ_SEARCH 0x00000004UL
#define CAPABILITY__FOWNER 0x00000008UL
#define CAPABILITY__FSETID 0x00000010UL
#define CAPABILITY__KILL 0x00000020UL
#define CAPABILITY__SETGID 0x00000040UL
#define CAPABILITY__SETUID 0x00000080UL
#define CAPABILITY__SETPCAP 0x00000100UL
#define CAPABILITY__LINUX_IMMUTABLE 0x00000200UL
#define CAPABILITY__NET_BIND_SERVICE 0x00000400UL
#define CAPABILITY__NET_BROADCAST 0x00000800UL
#define CAPABILITY__NET_ADMIN 0x00001000UL
#define CAPABILITY__NET_RAW 0x00002000UL
#define CAPABILITY__IPC_LOCK 0x00004000UL
#define CAPABILITY__IPC_OWNER 0x00008000UL
#define CAPABILITY__SYS_MODULE 0x00010000UL
#define CAPABILITY__SYS_RAWIO 0x00020000UL
#define CAPABILITY__SYS_CHROOT 0x00040000UL
#define CAPABILITY__SYS_PTRACE 0x00080000UL
#define CAPABILITY__SYS_PACCT 0x00100000UL
#define CAPABILITY__SYS_ADMIN 0x00200000UL
#define CAPABILITY__SYS_BOOT 0x00400000UL
#define CAPABILITY__SYS_NICE 0x00800000UL
#define CAPABILITY__SYS_RESOURCE 0x01000000UL
#define CAPABILITY__SYS_TIME 0x02000000UL
#define CAPABILITY__SYS_TTY_CONFIG 0x04000000UL
#define CAPABILITY__MKNOD 0x08000000UL
#define CAPABILITY__LEASE 0x10000000UL
#define PASSWD__PASSWD 0x00000001UL
#define PASSWD__CHFN 0x00000002UL
#define PASSWD__CHSH 0x00000004UL
#define PASSWD__ROOTOK 0x00000008UL
#define DRAWABLE__CREATE 0x00000001UL
#define DRAWABLE__DESTROY 0x00000002UL
#define DRAWABLE__DRAW 0x00000004UL
#define DRAWABLE__COPY 0x00000008UL
#define DRAWABLE__GETATTR 0x00000010UL
#define GC__CREATE 0x00000001UL
#define GC__FREE 0x00000002UL
#define GC__GETATTR 0x00000004UL
#define GC__SETATTR 0x00000008UL
#define WINDOW__ADDCHILD 0x00000001UL
#define WINDOW__CREATE 0x00000002UL
#define WINDOW__DESTROY 0x00000004UL
#define WINDOW__MAP 0x00000008UL
#define WINDOW__UNMAP 0x00000010UL
#define WINDOW__CHSTACK 0x00000020UL
#define WINDOW__CHPROPLIST 0x00000040UL
#define WINDOW__CHPROP 0x00000080UL
#define WINDOW__LISTPROP 0x00000100UL
#define WINDOW__GETATTR 0x00000200UL
#define WINDOW__SETATTR 0x00000400UL
#define WINDOW__SETFOCUS 0x00000800UL
#define WINDOW__MOVE 0x00001000UL
#define WINDOW__CHSELECTION 0x00002000UL
#define WINDOW__CHPARENT 0x00004000UL
#define WINDOW__CTRLLIFE 0x00008000UL
#define WINDOW__ENUMERATE 0x00010000UL
#define WINDOW__TRANSPARENT 0x00020000UL
#define WINDOW__MOUSEMOTION 0x00040000UL
#define WINDOW__CLIENTCOMEVENT 0x00080000UL
#define WINDOW__INPUTEVENT 0x00100000UL
#define WINDOW__DRAWEVENT 0x00200000UL
#define WINDOW__WINDOWCHANGEEVENT 0x00400000UL
#define WINDOW__WINDOWCHANGEREQUEST 0x00800000UL
#define WINDOW__SERVERCHANGEEVENT 0x01000000UL
#define WINDOW__EXTENSIONEVENT 0x02000000UL
#define FONT__LOAD 0x00000001UL
#define FONT__FREE 0x00000002UL
#define FONT__GETATTR 0x00000004UL
#define FONT__USE 0x00000008UL
#define COLORMAP__CREATE 0x00000001UL
#define COLORMAP__FREE 0x00000002UL
#define COLORMAP__INSTALL 0x00000004UL
#define COLORMAP__UNINSTALL 0x00000008UL
#define COLORMAP__LIST 0x00000010UL
#define COLORMAP__READ 0x00000020UL
#define COLORMAP__STORE 0x00000040UL
#define COLORMAP__GETATTR 0x00000080UL
#define COLORMAP__SETATTR 0x00000100UL
#define PROPERTY__CREATE 0x00000001UL
#define PROPERTY__FREE 0x00000002UL
#define PROPERTY__READ 0x00000004UL
#define PROPERTY__WRITE 0x00000008UL
#define CURSOR__CREATE 0x00000001UL
#define CURSOR__CREATEGLYPH 0x00000002UL
#define CURSOR__FREE 0x00000004UL
#define CURSOR__ASSIGN 0x00000008UL
#define CURSOR__SETATTR 0x00000010UL
#define XCLIENT__KILL 0x00000001UL
#define XINPUT__LOOKUP 0x00000001UL
#define XINPUT__GETATTR 0x00000002UL
#define XINPUT__SETATTR 0x00000004UL
#define XINPUT__SETFOCUS 0x00000008UL
#define XINPUT__WARPPOINTER 0x00000010UL
#define XINPUT__ACTIVEGRAB 0x00000020UL
#define XINPUT__PASSIVEGRAB 0x00000040UL
#define XINPUT__UNGRAB 0x00000080UL
#define XINPUT__BELL 0x00000100UL
#define XINPUT__MOUSEMOTION 0x00000200UL
#define XINPUT__RELABELINPUT 0x00000400UL
#define XSERVER__SCREENSAVER 0x00000001UL
#define XSERVER__GETHOSTLIST 0x00000002UL
#define XSERVER__SETHOSTLIST 0x00000004UL
#define XSERVER__GETFONTPATH 0x00000008UL
#define XSERVER__SETFONTPATH 0x00000010UL
#define XSERVER__GETATTR 0x00000020UL
#define XSERVER__GRAB 0x00000040UL
#define XSERVER__UNGRAB 0x00000080UL
#define XEXTENSION__QUERY 0x00000001UL
#define XEXTENSION__USE 0x00000002UL
#define PAX__PAGEEXEC 0x00000001UL
#define PAX__EMUTRAMP 0x00000002UL
#define PAX__MPROTECT 0x00000004UL
#define PAX__RANDMMAP 0x00000008UL
#define PAX__RANDEXEC 0x00000010UL
#define PAX__SEGMEXEC 0x00000020UL
#define NETLINK_ROUTE_SOCKET__IOCTL 0x00000001UL
#define NETLINK_ROUTE_SOCKET__READ 0x00000002UL
#define NETLINK_ROUTE_SOCKET__WRITE 0x00000004UL
#define NETLINK_ROUTE_SOCKET__CREATE 0x00000008UL
#define NETLINK_ROUTE_SOCKET__GETATTR 0x00000010UL
#define NETLINK_ROUTE_SOCKET__SETATTR 0x00000020UL
#define NETLINK_ROUTE_SOCKET__LOCK 0x00000040UL
#define NETLINK_ROUTE_SOCKET__RELABELFROM 0x00000080UL
#define NETLINK_ROUTE_SOCKET__RELABELTO 0x00000100UL
#define NETLINK_ROUTE_SOCKET__APPEND 0x00000200UL
#define NETLINK_ROUTE_SOCKET__BIND 0x00000400UL
#define NETLINK_ROUTE_SOCKET__CONNECT 0x00000800UL
#define NETLINK_ROUTE_SOCKET__LISTEN 0x00001000UL
#define NETLINK_ROUTE_SOCKET__ACCEPT 0x00002000UL
#define NETLINK_ROUTE_SOCKET__GETOPT 0x00004000UL
#define NETLINK_ROUTE_SOCKET__SETOPT 0x00008000UL
#define NETLINK_ROUTE_SOCKET__SHUTDOWN 0x00010000UL
#define NETLINK_ROUTE_SOCKET__RECVFROM 0x00020000UL
#define NETLINK_ROUTE_SOCKET__SENDTO 0x00040000UL
#define NETLINK_ROUTE_SOCKET__RECV_MSG 0x00080000UL
#define NETLINK_ROUTE_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_ROUTE_SOCKET__NAME_BIND 0x00200000UL
#define NETLINK_ROUTE_SOCKET__NLMSG_READ 0x00400000UL
#define NETLINK_ROUTE_SOCKET__NLMSG_WRITE 0x00800000UL
#define NETLINK_FIREWALL_SOCKET__IOCTL 0x00000001UL
#define NETLINK_FIREWALL_SOCKET__READ 0x00000002UL
#define NETLINK_FIREWALL_SOCKET__WRITE 0x00000004UL
#define NETLINK_FIREWALL_SOCKET__CREATE 0x00000008UL
#define NETLINK_FIREWALL_SOCKET__GETATTR 0x00000010UL
#define NETLINK_FIREWALL_SOCKET__SETATTR 0x00000020UL
#define NETLINK_FIREWALL_SOCKET__LOCK 0x00000040UL
#define NETLINK_FIREWALL_SOCKET__RELABELFROM 0x00000080UL
#define NETLINK_FIREWALL_SOCKET__RELABELTO 0x00000100UL
#define NETLINK_FIREWALL_SOCKET__APPEND 0x00000200UL
#define NETLINK_FIREWALL_SOCKET__BIND 0x00000400UL
#define NETLINK_FIREWALL_SOCKET__CONNECT 0x00000800UL
#define NETLINK_FIREWALL_SOCKET__LISTEN 0x00001000UL
#define NETLINK_FIREWALL_SOCKET__ACCEPT 0x00002000UL
#define NETLINK_FIREWALL_SOCKET__GETOPT 0x00004000UL
#define NETLINK_FIREWALL_SOCKET__SETOPT 0x00008000UL
#define NETLINK_FIREWALL_SOCKET__SHUTDOWN 0x00010000UL
#define NETLINK_FIREWALL_SOCKET__RECVFROM 0x00020000UL
#define NETLINK_FIREWALL_SOCKET__SENDTO 0x00040000UL
#define NETLINK_FIREWALL_SOCKET__RECV_MSG 0x00080000UL
#define NETLINK_FIREWALL_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_FIREWALL_SOCKET__NAME_BIND 0x00200000UL
#define NETLINK_FIREWALL_SOCKET__NLMSG_READ 0x00400000UL
#define NETLINK_FIREWALL_SOCKET__NLMSG_WRITE 0x00800000UL
#define NETLINK_TCPDIAG_SOCKET__IOCTL 0x00000001UL
#define NETLINK_TCPDIAG_SOCKET__READ 0x00000002UL
#define NETLINK_TCPDIAG_SOCKET__WRITE 0x00000004UL
#define NETLINK_TCPDIAG_SOCKET__CREATE 0x00000008UL
#define NETLINK_TCPDIAG_SOCKET__GETATTR 0x00000010UL
#define NETLINK_TCPDIAG_SOCKET__SETATTR 0x00000020UL
#define NETLINK_TCPDIAG_SOCKET__LOCK 0x00000040UL
#define NETLINK_TCPDIAG_SOCKET__RELABELFROM 0x00000080UL
#define NETLINK_TCPDIAG_SOCKET__RELABELTO 0x00000100UL
#define NETLINK_TCPDIAG_SOCKET__APPEND 0x00000200UL
#define NETLINK_TCPDIAG_SOCKET__BIND 0x00000400UL
#define NETLINK_TCPDIAG_SOCKET__CONNECT 0x00000800UL
#define NETLINK_TCPDIAG_SOCKET__LISTEN 0x00001000UL
#define NETLINK_TCPDIAG_SOCKET__ACCEPT 0x00002000UL
#define NETLINK_TCPDIAG_SOCKET__GETOPT 0x00004000UL
#define NETLINK_TCPDIAG_SOCKET__SETOPT 0x00008000UL
#define NETLINK_TCPDIAG_SOCKET__SHUTDOWN 0x00010000UL
#define NETLINK_TCPDIAG_SOCKET__RECVFROM 0x00020000UL
#define NETLINK_TCPDIAG_SOCKET__SENDTO 0x00040000UL
#define NETLINK_TCPDIAG_SOCKET__RECV_MSG 0x00080000UL
#define NETLINK_TCPDIAG_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_TCPDIAG_SOCKET__NAME_BIND 0x00200000UL
#define NETLINK_TCPDIAG_SOCKET__NLMSG_READ 0x00400000UL
#define NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE 0x00800000UL
#define NETLINK_NFLOG_SOCKET__IOCTL 0x00000001UL
#define NETLINK_NFLOG_SOCKET__READ 0x00000002UL
#define NETLINK_NFLOG_SOCKET__WRITE 0x00000004UL
#define NETLINK_NFLOG_SOCKET__CREATE 0x00000008UL
#define NETLINK_NFLOG_SOCKET__GETATTR 0x00000010UL
#define NETLINK_NFLOG_SOCKET__SETATTR 0x00000020UL
#define NETLINK_NFLOG_SOCKET__LOCK 0x00000040UL
#define NETLINK_NFLOG_SOCKET__RELABELFROM 0x00000080UL
#define NETLINK_NFLOG_SOCKET__RELABELTO 0x00000100UL
#define NETLINK_NFLOG_SOCKET__APPEND 0x00000200UL
#define NETLINK_NFLOG_SOCKET__BIND 0x00000400UL
#define NETLINK_NFLOG_SOCKET__CONNECT 0x00000800UL
#define NETLINK_NFLOG_SOCKET__LISTEN 0x00001000UL
#define NETLINK_NFLOG_SOCKET__ACCEPT 0x00002000UL
#define NETLINK_NFLOG_SOCKET__GETOPT 0x00004000UL
#define NETLINK_NFLOG_SOCKET__SETOPT 0x00008000UL
#define NETLINK_NFLOG_SOCKET__SHUTDOWN 0x00010000UL
#define NETLINK_NFLOG_SOCKET__RECVFROM 0x00020000UL
#define NETLINK_NFLOG_SOCKET__SENDTO 0x00040000UL
#define NETLINK_NFLOG_SOCKET__RECV_MSG 0x00080000UL
#define NETLINK_NFLOG_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_NFLOG_SOCKET__NAME_BIND 0x00200000UL
#define NETLINK_XFRM_SOCKET__IOCTL 0x00000001UL
#define NETLINK_XFRM_SOCKET__READ 0x00000002UL
#define NETLINK_XFRM_SOCKET__WRITE 0x00000004UL
#define NETLINK_XFRM_SOCKET__CREATE 0x00000008UL
#define NETLINK_XFRM_SOCKET__GETATTR 0x00000010UL
#define NETLINK_XFRM_SOCKET__SETATTR 0x00000020UL
#define NETLINK_XFRM_SOCKET__LOCK 0x00000040UL
#define NETLINK_XFRM_SOCKET__RELABELFROM 0x00000080UL
#define NETLINK_XFRM_SOCKET__RELABELTO 0x00000100UL
#define NETLINK_XFRM_SOCKET__APPEND 0x00000200UL
#define NETLINK_XFRM_SOCKET__BIND 0x00000400UL
#define NETLINK_XFRM_SOCKET__CONNECT 0x00000800UL
#define NETLINK_XFRM_SOCKET__LISTEN 0x00001000UL
#define NETLINK_XFRM_SOCKET__ACCEPT 0x00002000UL
#define NETLINK_XFRM_SOCKET__GETOPT 0x00004000UL
#define NETLINK_XFRM_SOCKET__SETOPT 0x00008000UL
#define NETLINK_XFRM_SOCKET__SHUTDOWN 0x00010000UL
#define NETLINK_XFRM_SOCKET__RECVFROM 0x00020000UL
#define NETLINK_XFRM_SOCKET__SENDTO 0x00040000UL
#define NETLINK_XFRM_SOCKET__RECV_MSG 0x00080000UL
#define NETLINK_XFRM_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_XFRM_SOCKET__NAME_BIND 0x00200000UL
#define NETLINK_XFRM_SOCKET__NLMSG_READ 0x00400000UL
#define NETLINK_XFRM_SOCKET__NLMSG_WRITE 0x00800000UL
#define NETLINK_SELINUX_SOCKET__IOCTL 0x00000001UL
#define NETLINK_SELINUX_SOCKET__READ 0x00000002UL
#define NETLINK_SELINUX_SOCKET__WRITE 0x00000004UL
#define NETLINK_SELINUX_SOCKET__CREATE 0x00000008UL
#define NETLINK_SELINUX_SOCKET__GETATTR 0x00000010UL
#define NETLINK_SELINUX_SOCKET__SETATTR 0x00000020UL
#define NETLINK_SELINUX_SOCKET__LOCK 0x00000040UL
#define NETLINK_SELINUX_SOCKET__RELABELFROM 0x00000080UL
#define NETLINK_SELINUX_SOCKET__RELABELTO 0x00000100UL
#define NETLINK_SELINUX_SOCKET__APPEND 0x00000200UL
#define NETLINK_SELINUX_SOCKET__BIND 0x00000400UL
#define NETLINK_SELINUX_SOCKET__CONNECT 0x00000800UL
#define NETLINK_SELINUX_SOCKET__LISTEN 0x00001000UL
#define NETLINK_SELINUX_SOCKET__ACCEPT 0x00002000UL
#define NETLINK_SELINUX_SOCKET__GETOPT 0x00004000UL
#define NETLINK_SELINUX_SOCKET__SETOPT 0x00008000UL
#define NETLINK_SELINUX_SOCKET__SHUTDOWN 0x00010000UL
#define NETLINK_SELINUX_SOCKET__RECVFROM 0x00020000UL
#define NETLINK_SELINUX_SOCKET__SENDTO 0x00040000UL
#define NETLINK_SELINUX_SOCKET__RECV_MSG 0x00080000UL
#define NETLINK_SELINUX_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_SELINUX_SOCKET__NAME_BIND 0x00200000UL
#define NETLINK_AUDIT_SOCKET__IOCTL 0x00000001UL
#define NETLINK_AUDIT_SOCKET__READ 0x00000002UL
#define NETLINK_AUDIT_SOCKET__WRITE 0x00000004UL
#define NETLINK_AUDIT_SOCKET__CREATE 0x00000008UL
#define NETLINK_AUDIT_SOCKET__GETATTR 0x00000010UL
#define NETLINK_AUDIT_SOCKET__SETATTR 0x00000020UL
#define NETLINK_AUDIT_SOCKET__LOCK 0x00000040UL
#define NETLINK_AUDIT_SOCKET__RELABELFROM 0x00000080UL
#define NETLINK_AUDIT_SOCKET__RELABELTO 0x00000100UL
#define NETLINK_AUDIT_SOCKET__APPEND 0x00000200UL
#define NETLINK_AUDIT_SOCKET__BIND 0x00000400UL
#define NETLINK_AUDIT_SOCKET__CONNECT 0x00000800UL
#define NETLINK_AUDIT_SOCKET__LISTEN 0x00001000UL
#define NETLINK_AUDIT_SOCKET__ACCEPT 0x00002000UL
#define NETLINK_AUDIT_SOCKET__GETOPT 0x00004000UL
#define NETLINK_AUDIT_SOCKET__SETOPT 0x00008000UL
#define NETLINK_AUDIT_SOCKET__SHUTDOWN 0x00010000UL
#define NETLINK_AUDIT_SOCKET__RECVFROM 0x00020000UL
#define NETLINK_AUDIT_SOCKET__SENDTO 0x00040000UL
#define NETLINK_AUDIT_SOCKET__RECV_MSG 0x00080000UL
#define NETLINK_AUDIT_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_AUDIT_SOCKET__NAME_BIND 0x00200000UL
#define NETLINK_AUDIT_SOCKET__NLMSG_READ 0x00400000UL
#define NETLINK_AUDIT_SOCKET__NLMSG_WRITE 0x00800000UL
#define NETLINK_IP6FW_SOCKET__IOCTL 0x00000001UL
#define NETLINK_IP6FW_SOCKET__READ 0x00000002UL
#define NETLINK_IP6FW_SOCKET__WRITE 0x00000004UL
#define NETLINK_IP6FW_SOCKET__CREATE 0x00000008UL
#define NETLINK_IP6FW_SOCKET__GETATTR 0x00000010UL
#define NETLINK_IP6FW_SOCKET__SETATTR 0x00000020UL
#define NETLINK_IP6FW_SOCKET__LOCK 0x00000040UL
#define NETLINK_IP6FW_SOCKET__RELABELFROM 0x00000080UL
#define NETLINK_IP6FW_SOCKET__RELABELTO 0x00000100UL
#define NETLINK_IP6FW_SOCKET__APPEND 0x00000200UL
#define NETLINK_IP6FW_SOCKET__BIND 0x00000400UL
#define NETLINK_IP6FW_SOCKET__CONNECT 0x00000800UL
#define NETLINK_IP6FW_SOCKET__LISTEN 0x00001000UL
#define NETLINK_IP6FW_SOCKET__ACCEPT 0x00002000UL
#define NETLINK_IP6FW_SOCKET__GETOPT 0x00004000UL
#define NETLINK_IP6FW_SOCKET__SETOPT 0x00008000UL
#define NETLINK_IP6FW_SOCKET__SHUTDOWN 0x00010000UL
#define NETLINK_IP6FW_SOCKET__RECVFROM 0x00020000UL
#define NETLINK_IP6FW_SOCKET__SENDTO 0x00040000UL
#define NETLINK_IP6FW_SOCKET__RECV_MSG 0x00080000UL
#define NETLINK_IP6FW_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_IP6FW_SOCKET__NAME_BIND 0x00200000UL
#define NETLINK_IP6FW_SOCKET__NLMSG_READ 0x00400000UL
#define NETLINK_IP6FW_SOCKET__NLMSG_WRITE 0x00800000UL
#define NETLINK_DNRT_SOCKET__IOCTL 0x00000001UL
#define NETLINK_DNRT_SOCKET__READ 0x00000002UL
#define NETLINK_DNRT_SOCKET__WRITE 0x00000004UL
#define NETLINK_DNRT_SOCKET__CREATE 0x00000008UL
#define NETLINK_DNRT_SOCKET__GETATTR 0x00000010UL
#define NETLINK_DNRT_SOCKET__SETATTR 0x00000020UL
#define NETLINK_DNRT_SOCKET__LOCK 0x00000040UL
#define NETLINK_DNRT_SOCKET__RELABELFROM 0x00000080UL
#define NETLINK_DNRT_SOCKET__RELABELTO 0x00000100UL
#define NETLINK_DNRT_SOCKET__APPEND 0x00000200UL
#define NETLINK_DNRT_SOCKET__BIND 0x00000400UL
#define NETLINK_DNRT_SOCKET__CONNECT 0x00000800UL
#define NETLINK_DNRT_SOCKET__LISTEN 0x00001000UL
#define NETLINK_DNRT_SOCKET__ACCEPT 0x00002000UL
#define NETLINK_DNRT_SOCKET__GETOPT 0x00004000UL
#define NETLINK_DNRT_SOCKET__SETOPT 0x00008000UL
#define NETLINK_DNRT_SOCKET__SHUTDOWN 0x00010000UL
#define NETLINK_DNRT_SOCKET__RECVFROM 0x00020000UL
#define NETLINK_DNRT_SOCKET__SENDTO 0x00040000UL
#define NETLINK_DNRT_SOCKET__RECV_MSG 0x00080000UL
#define NETLINK_DNRT_SOCKET__SEND_MSG 0x00100000UL
/* FLASK */

View File

@@ -0,0 +1,155 @@
/*
* Access vector cache interface for object managers.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SELINUX_AVC_H_
#define _SELINUX_AVC_H_
#include <linux/stddef.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/kdev_t.h>
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/in6.h>
#include <asm/system.h>
#include "flask.h"
#include "av_permissions.h"
#include "security.h"
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
extern int selinux_enforcing;
#else
#define selinux_enforcing 1
#endif
/*
* An entry in the AVC.
*/
struct avc_entry;
/*
* A reference to an AVC entry.
*/
struct avc_entry_ref {
struct avc_entry *ae;
};
/* Initialize an AVC entry reference before first use. */
static inline void avc_entry_ref_init(struct avc_entry_ref *h)
{
h->ae = NULL;
}
struct task_struct;
struct vfsmount;
struct dentry;
struct inode;
struct sock;
struct sk_buff;
/* Auxiliary data to use in generating the audit record. */
struct avc_audit_data {
char type;
#define AVC_AUDIT_DATA_FS 1
#define AVC_AUDIT_DATA_NET 2
#define AVC_AUDIT_DATA_CAP 3
#define AVC_AUDIT_DATA_IPC 4
struct task_struct *tsk;
union {
struct {
struct vfsmount *mnt;
struct dentry *dentry;
struct inode *inode;
} fs;
struct {
char *netif;
struct sock *sk;
u16 family;
u16 dport;
u16 sport;
union {
struct {
u32 daddr;
u32 saddr;
} v4;
struct {
struct in6_addr daddr;
struct in6_addr saddr;
} v6;
} fam;
} net;
int cap;
int ipc_id;
} u;
};
#define v4info fam.v4
#define v6info fam.v6
/* Initialize an AVC audit data structure. */
#define AVC_AUDIT_DATA_INIT(_d,_t) \
{ memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; }
/*
* AVC statistics
*/
#define AVC_ENTRY_LOOKUPS 0
#define AVC_ENTRY_HITS 1
#define AVC_ENTRY_MISSES 2
#define AVC_ENTRY_DISCARDS 3
#define AVC_CAV_LOOKUPS 4
#define AVC_CAV_HITS 5
#define AVC_CAV_PROBES 6
#define AVC_CAV_MISSES 7
#define AVC_NSTATS 8
/*
* AVC display support
*/
struct audit_buffer;
void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass);
/*
* AVC operations
*/
void __init avc_init(void);
int avc_lookup(u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct avc_entry_ref *aeref);
int avc_insert(u32 ssid, u32 tsid, u16 tclass,
struct avc_entry *ae, struct avc_entry_ref *out_aeref);
void avc_audit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd, int result, struct avc_audit_data *auditdata);
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct avc_entry_ref *aeref, struct av_decision *avd);
int avc_has_perm(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct avc_entry_ref *aeref, struct avc_audit_data *auditdata);
#define AVC_CALLBACK_GRANT 1
#define AVC_CALLBACK_TRY_REVOKE 2
#define AVC_CALLBACK_REVOKE 4
#define AVC_CALLBACK_RESET 8
#define AVC_CALLBACK_AUDITALLOW_ENABLE 16
#define AVC_CALLBACK_AUDITALLOW_DISABLE 32
#define AVC_CALLBACK_AUDITDENY_ENABLE 64
#define AVC_CALLBACK_AUDITDENY_DISABLE 128
int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
u16 tclass, u32 perms,
u32 *out_retained),
u32 events, u32 ssid, u32 tsid,
u16 tclass, u32 perms);
#endif /* _SELINUX_AVC_H_ */

View File

@@ -0,0 +1,27 @@
/*
* Access vector cache interface for the security server.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SELINUX_AVC_SS_H_
#define _SELINUX_AVC_SS_H_
#include "flask.h"
int avc_ss_grant(u32 ssid, u32 tsid, u16 tclass, u32 perms, u32 seqno);
int avc_ss_try_revoke(u32 ssid, u32 tsid, u16 tclass, u32 perms, u32 seqno,
u32 *out_retained);
int avc_ss_revoke(u32 ssid, u32 tsid, u16 tclass, u32 perms, u32 seqno);
int avc_ss_reset(u32 seqno);
int avc_ss_set_auditallow(u32 ssid, u32 tsid, u16 tclass, u32 perms,
u32 seqno, u32 enable);
int avc_ss_set_auditdeny(u32 ssid, u32 tsid, u16 tclass, u32 perms,
u32 seqno, u32 enable);
#endif /* _SELINUX_AVC_SS_H_ */

View File

@@ -0,0 +1,60 @@
/* This file is automatically generated. Do not edit. */
/*
* Security object class definitions
*/
static char *class_to_string[] =
{
"null",
"security",
"process",
"system",
"capability",
"filesystem",
"file",
"dir",
"fd",
"lnk_file",
"chr_file",
"blk_file",
"sock_file",
"fifo_file",
"socket",
"tcp_socket",
"udp_socket",
"rawip_socket",
"node",
"netif",
"netlink_socket",
"packet_socket",
"key_socket",
"unix_stream_socket",
"unix_dgram_socket",
"sem",
"msg",
"msgq",
"shm",
"ipc",
"passwd",
"drawable",
"window",
"gc",
"font",
"colormap",
"property",
"cursor",
"xclient",
"xinput",
"xserver",
"xextension",
"pax",
"netlink_route_socket",
"netlink_firewall_socket",
"netlink_tcpdiag_socket",
"netlink_nflog_socket",
"netlink_xfrm_socket",
"netlink_selinux_socket",
"netlink_audit_socket",
"netlink_ip6fw_socket",
"netlink_dnrt_socket",
};

View File

@@ -0,0 +1,65 @@
/* This file is automatically generated. Do not edit. */
/* FLASK */
static char *common_file_perm_to_string[] =
{
"ioctl",
"read",
"write",
"create",
"getattr",
"setattr",
"lock",
"relabelfrom",
"relabelto",
"append",
"unlink",
"link",
"rename",
"execute",
"swapon",
"quotaon",
"mounton",
};
static char *common_socket_perm_to_string[] =
{
"ioctl",
"read",
"write",
"create",
"getattr",
"setattr",
"lock",
"relabelfrom",
"relabelto",
"append",
"bind",
"connect",
"listen",
"accept",
"getopt",
"setopt",
"shutdown",
"recvfrom",
"sendto",
"recv_msg",
"send_msg",
"name_bind",
};
static char *common_ipc_perm_to_string[] =
{
"create",
"destroy",
"getattr",
"setattr",
"read",
"write",
"associate",
"unix_read",
"unix_write",
};
/* FLASK */

View File

@@ -0,0 +1,22 @@
/*
* Interface to booleans in the security server. This is exported
* for the selinuxfs.
*
* Author: Karl MacMillan <kmacmillan@tresys.com>
*
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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.
*/
#ifndef _SELINUX_CONDITIONAL_H_
#define _SELINUX_CONDITIONAL_H_
int security_get_bools(int *len, char ***names, int **values);
int security_set_bools(int len, int *values);
int security_get_bool_value(int bool);
#endif

View File

@@ -0,0 +1,93 @@
/* This file is automatically generated. Do not edit. */
#ifndef _SELINUX_FLASK_H_
#define _SELINUX_FLASK_H_
/*
* Security object class definitions
*/
#define SECCLASS_SECURITY 1
#define SECCLASS_PROCESS 2
#define SECCLASS_SYSTEM 3
#define SECCLASS_CAPABILITY 4
#define SECCLASS_FILESYSTEM 5
#define SECCLASS_FILE 6
#define SECCLASS_DIR 7
#define SECCLASS_FD 8
#define SECCLASS_LNK_FILE 9
#define SECCLASS_CHR_FILE 10
#define SECCLASS_BLK_FILE 11
#define SECCLASS_SOCK_FILE 12
#define SECCLASS_FIFO_FILE 13
#define SECCLASS_SOCKET 14
#define SECCLASS_TCP_SOCKET 15
#define SECCLASS_UDP_SOCKET 16
#define SECCLASS_RAWIP_SOCKET 17
#define SECCLASS_NODE 18
#define SECCLASS_NETIF 19
#define SECCLASS_NETLINK_SOCKET 20
#define SECCLASS_PACKET_SOCKET 21
#define SECCLASS_KEY_SOCKET 22
#define SECCLASS_UNIX_STREAM_SOCKET 23
#define SECCLASS_UNIX_DGRAM_SOCKET 24
#define SECCLASS_SEM 25
#define SECCLASS_MSG 26
#define SECCLASS_MSGQ 27
#define SECCLASS_SHM 28
#define SECCLASS_IPC 29
#define SECCLASS_PASSWD 30
#define SECCLASS_DRAWABLE 31
#define SECCLASS_WINDOW 32
#define SECCLASS_GC 33
#define SECCLASS_FONT 34
#define SECCLASS_COLORMAP 35
#define SECCLASS_PROPERTY 36
#define SECCLASS_CURSOR 37
#define SECCLASS_XCLIENT 38
#define SECCLASS_XINPUT 39
#define SECCLASS_XSERVER 40
#define SECCLASS_XEXTENSION 41
#define SECCLASS_PAX 42
#define SECCLASS_NETLINK_ROUTE_SOCKET 43
#define SECCLASS_NETLINK_FIREWALL_SOCKET 44
#define SECCLASS_NETLINK_TCPDIAG_SOCKET 45
#define SECCLASS_NETLINK_NFLOG_SOCKET 46
#define SECCLASS_NETLINK_XFRM_SOCKET 47
#define SECCLASS_NETLINK_SELINUX_SOCKET 48
#define SECCLASS_NETLINK_AUDIT_SOCKET 49
#define SECCLASS_NETLINK_IP6FW_SOCKET 50
#define SECCLASS_NETLINK_DNRT_SOCKET 51
/*
* Security identifier indices for initial entities
*/
#define SECINITSID_KERNEL 1
#define SECINITSID_SECURITY 2
#define SECINITSID_UNLABELED 3
#define SECINITSID_FS 4
#define SECINITSID_FILE 5
#define SECINITSID_FILE_LABELS 6
#define SECINITSID_INIT 7
#define SECINITSID_ANY_SOCKET 8
#define SECINITSID_PORT 9
#define SECINITSID_NETIF 10
#define SECINITSID_NETMSG 11
#define SECINITSID_NODE 12
#define SECINITSID_IGMP_PACKET 13
#define SECINITSID_ICMP_SOCKET 14
#define SECINITSID_TCP_SOCKET 15
#define SECINITSID_SYSCTL_MODPROBE 16
#define SECINITSID_SYSCTL 17
#define SECINITSID_SYSCTL_FS 18
#define SECINITSID_SYSCTL_KERNEL 19
#define SECINITSID_SYSCTL_NET 20
#define SECINITSID_SYSCTL_NET_UNIX 21
#define SECINITSID_SYSCTL_VM 22
#define SECINITSID_SYSCTL_DEV 23
#define SECINITSID_KMOD 24
#define SECINITSID_POLICY 25
#define SECINITSID_SCMP_PACKET 26
#define SECINITSID_DEVNULL 27
#define SECINITSID_NUM 27
#endif

View File

@@ -0,0 +1,33 @@
/* This file is automatically generated. Do not edit. */
static char *initial_sid_to_string[] =
{
"null",
"kernel",
"security",
"unlabeled",
"fs",
"file",
"file_labels",
"init",
"any_socket",
"port",
"netif",
"netmsg",
"node",
"igmp_packet",
"icmp_socket",
"tcp_socket",
"sysctl_modprobe",
"sysctl",
"sysctl_fs",
"sysctl_kernel",
"sysctl_net",
"sysctl_net_unix",
"sysctl_vm",
"sysctl_dev",
"kmod",
"policy",
"scmp_packet",
"devnull",
};

View File

@@ -0,0 +1,21 @@
/*
* Network interface table.
*
* Network interfaces (devices) do not have a security field, so we
* maintain a table associating each interface with a SID.
*
* Author: James Morris <jmorris@redhat.com>
*
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
#ifndef _SELINUX_NETIF_H_
#define _SELINUX_NETIF_H_
int sel_netif_sids(struct net_device *dev, u32 *if_sid, u32 *msg_sid);
#endif /* _SELINUX_NETIF_H_ */

View File

@@ -0,0 +1,112 @@
/*
* NSA Security-Enhanced Linux (SELinux) security module
*
* This file contains the SELinux security data structures for kernel objects.
*
* Author(s): Stephen Smalley, <sds@epoch.ncsc.mil>
* Chris Vance, <cvance@nai.com>
* Wayne Salamon, <wsalamon@nai.com>
* James Morris <jmorris@redhat.com>
*
* Copyright (C) 2001,2002 Networks Associates Technology, Inc.
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
#ifndef _SELINUX_OBJSEC_H_
#define _SELINUX_OBJSEC_H_
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/binfmts.h>
#include <linux/in.h>
#include "flask.h"
#include "avc.h"
struct task_security_struct {
unsigned long magic; /* magic number for this module */
struct task_struct *task; /* back pointer to task object */
u32 osid; /* SID prior to last execve */
u32 sid; /* current SID */
u32 exec_sid; /* exec SID */
u32 create_sid; /* fscreate SID */
struct avc_entry_ref avcr; /* reference to process permissions */
u32 ptrace_sid; /* SID of ptrace parent */
};
struct inode_security_struct {
unsigned long magic; /* magic number for this module */
struct inode *inode; /* back pointer to inode object */
struct list_head list; /* list of inode_security_struct */
u32 task_sid; /* SID of creating task */
u32 sid; /* SID of this object */
u16 sclass; /* security class of this object */
struct avc_entry_ref avcr; /* reference to object permissions */
unsigned char initialized; /* initialization flag */
struct semaphore sem;
unsigned char inherit; /* inherit SID from parent entry */
};
struct file_security_struct {
unsigned long magic; /* magic number for this module */
struct file *file; /* back pointer to file object */
u32 sid; /* SID of open file description */
u32 fown_sid; /* SID of file owner (for SIGIO) */
struct avc_entry_ref avcr; /* reference to fd permissions */
struct avc_entry_ref inode_avcr; /* reference to object permissions */
};
struct superblock_security_struct {
unsigned long magic; /* magic number for this module */
struct super_block *sb; /* back pointer to sb object */
struct list_head list; /* list of superblock_security_struct */
u32 sid; /* SID of file system */
u32 def_sid; /* default SID for labeling */
unsigned int behavior; /* labeling behavior */
unsigned char initialized; /* initialization flag */
unsigned char proc; /* proc fs */
struct semaphore sem;
struct list_head isec_head;
spinlock_t isec_lock;
};
struct msg_security_struct {
unsigned long magic; /* magic number for this module */
struct msg_msg *msg; /* back pointer */
u32 sid; /* SID of message */
struct avc_entry_ref avcr; /* reference to permissions */
};
struct ipc_security_struct {
unsigned long magic; /* magic number for this module */
struct kern_ipc_perm *ipc_perm; /* back pointer */
u16 sclass; /* security class of this object */
u32 sid; /* SID of IPC resource */
struct avc_entry_ref avcr; /* reference to permissions */
};
struct bprm_security_struct {
unsigned long magic; /* magic number for this module */
struct linux_binprm *bprm; /* back pointer to bprm object */
u32 sid; /* SID for transformed process */
unsigned char set;
};
struct netif_security_struct {
struct net_device *dev; /* back pointer */
u32 if_sid; /* SID for this interface */
u32 msg_sid; /* default SID for messages received on this interface */
};
struct sk_security_struct {
unsigned long magic; /* magic number for this module */
struct sock *sk; /* back pointer to sk object */
u32 peer_sid; /* SID of peer */
};
extern int inode_security_set_sid(struct inode *inode, u32 sid);
#endif /* _SELINUX_OBJSEC_H_ */

View File

@@ -0,0 +1,96 @@
/*
* Security server interface.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*
*/
#ifndef _SELINUX_SECURITY_H_
#define _SELINUX_SECURITY_H_
#include "flask.h"
#define SECSID_NULL 0x00000000 /* unspecified SID */
#define SECSID_WILD 0xffffffff /* wildcard SID */
#define SECCLASS_NULL 0x0000 /* no class */
#define SELINUX_MAGIC 0xf97cff8c
/* Identify specific policy version changes */
#define POLICYDB_VERSION_BASE 15
#define POLICYDB_VERSION_BOOL 16
#define POLICYDB_VERSION_IPV6 17
#define POLICYDB_VERSION_NLCLASS 18
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_NLCLASS
#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
extern int selinux_enabled;
#else
#define selinux_enabled 1
#endif
#ifdef CONFIG_SECURITY_SELINUX_MLS
#define selinux_mls_enabled 1
#else
#define selinux_mls_enabled 0
#endif
int security_load_policy(void * data, size_t len);
struct av_decision {
u32 allowed;
u32 decided;
u32 auditallow;
u32 auditdeny;
u32 seqno;
};
int security_compute_av(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd);
int security_transition_sid(u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid);
int security_member_sid(u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid);
int security_change_sid(u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid);
int security_sid_to_context(u32 sid, char **scontext,
u32 *scontext_len);
int security_context_to_sid(char *scontext, u32 scontext_len,
u32 *out_sid);
int security_get_user_sids(u32 callsid, char *username,
u32 **sids, u32 *nel);
int security_port_sid(u16 domain, u16 type, u8 protocol, u16 port,
u32 *out_sid);
int security_netif_sid(char *name, u32 *if_sid,
u32 *msg_sid);
int security_node_sid(u16 domain, void *addr, u32 addrlen,
u32 *out_sid);
#define SECURITY_FS_USE_XATTR 1 /* use xattr */
#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
#define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */
#define SECURITY_FS_USE_GENFS 4 /* use the genfs support */
#define SECURITY_FS_USE_NONE 5 /* no labeling support */
#define SECURITY_FS_USE_MNTPOINT 6 /* use mountpoint labeling */
int security_fs_use(const char *fstype, unsigned int *behavior,
u32 *sid);
int security_genfs_sid(const char *fstype, char *name, u16 sclass,
u32 *sid);
#endif /* _SELINUX_SECURITY_H_ */

View File

@@ -0,0 +1,270 @@
/*
* Network interface table.
*
* Network interfaces (devices) do not have a security field, so we
* maintain a table associating each interface with a SID.
*
* Author: James Morris <jmorris@redhat.com>
*
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/notifier.h>
#include <linux/netdevice.h>
#include <linux/rcupdate.h>
#include "security.h"
#include "objsec.h"
#include "netif.h"
#define SEL_NETIF_HASH_SIZE 64
#define SEL_NETIF_HASH_MAX 1024
#undef DEBUG
#ifdef DEBUG
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
struct sel_netif
{
struct list_head list;
struct netif_security_struct nsec;
struct rcu_head rcu_head;
};
static u32 sel_netif_total;
static LIST_HEAD(sel_netif_list);
static spinlock_t sel_netif_lock = SPIN_LOCK_UNLOCKED;
static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
static inline u32 sel_netif_hasfn(struct net_device *dev)
{
return (dev->ifindex & (SEL_NETIF_HASH_SIZE - 1));
}
/*
* All of the devices should normally fit in the hash, so we optimize
* for that case.
*/
static inline struct sel_netif *sel_netif_find(struct net_device *dev)
{
struct list_head *pos;
int idx = sel_netif_hasfn(dev);
__list_for_each_rcu(pos, &sel_netif_hash[idx]) {
struct sel_netif *netif = list_entry(pos,
struct sel_netif, list);
if (likely(netif->nsec.dev == dev))
return netif;
}
return NULL;
}
static int sel_netif_insert(struct sel_netif *netif)
{
int idx, ret = 0;
if (sel_netif_total >= SEL_NETIF_HASH_MAX) {
ret = -ENOSPC;
goto out;
}
idx = sel_netif_hasfn(netif->nsec.dev);
list_add_rcu(&netif->list, &sel_netif_hash[idx]);
sel_netif_total++;
out:
return ret;
}
static void sel_netif_free(struct rcu_head *p)
{
struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head);
DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name);
kfree(netif);
}
static void sel_netif_destroy(struct sel_netif *netif)
{
DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name);
list_del_rcu(&netif->list);
sel_netif_total--;
call_rcu(&netif->rcu_head, sel_netif_free);
}
static struct sel_netif *sel_netif_lookup(struct net_device *dev)
{
int ret;
struct sel_netif *netif, *new;
struct netif_security_struct *nsec;
netif = sel_netif_find(dev);
if (likely(netif != NULL))
goto out;
new = kmalloc(sizeof(*new), GFP_ATOMIC);
if (!new) {
netif = ERR_PTR(-ENOMEM);
goto out;
}
memset(new, 0, sizeof(*new));
nsec = &new->nsec;
ret = security_netif_sid(dev->name, &nsec->if_sid, &nsec->msg_sid);
if (ret < 0) {
kfree(new);
netif = ERR_PTR(ret);
goto out;
}
nsec->dev = dev;
spin_lock_bh(&sel_netif_lock);
netif = sel_netif_find(dev);
if (netif) {
spin_unlock_bh(&sel_netif_lock);
kfree(new);
goto out;
}
ret = sel_netif_insert(new);
spin_unlock_bh(&sel_netif_lock);
if (ret) {
kfree(new);
netif = ERR_PTR(ret);
goto out;
}
netif = new;
DEBUGP("new: ifindex=%u name=%s if_sid=%u msg_sid=%u\n", dev->ifindex, dev->name,
nsec->if_sid, nsec->msg_sid);
out:
return netif;
}
static void sel_netif_assign_sids(u32 if_sid_in, u32 msg_sid_in, u32 *if_sid_out, u32 *msg_sid_out)
{
if (if_sid_out)
*if_sid_out = if_sid_in;
if (msg_sid_out)
*msg_sid_out = msg_sid_in;
}
static int sel_netif_sids_slow(struct net_device *dev, u32 *if_sid, u32 *msg_sid)
{
int ret = 0;
u32 tmp_if_sid, tmp_msg_sid;
ret = security_netif_sid(dev->name, &tmp_if_sid, &tmp_msg_sid);
if (!ret)
sel_netif_assign_sids(tmp_if_sid, tmp_msg_sid, if_sid, msg_sid);
return ret;
}
int sel_netif_sids(struct net_device *dev, u32 *if_sid, u32 *msg_sid)
{
int ret = 0;
struct sel_netif *netif;
rcu_read_lock();
netif = sel_netif_lookup(dev);
if (IS_ERR(netif)) {
rcu_read_unlock();
ret = sel_netif_sids_slow(dev, if_sid, msg_sid);
goto out;
}
sel_netif_assign_sids(netif->nsec.if_sid, netif->nsec.msg_sid, if_sid, msg_sid);
rcu_read_unlock();
out:
return ret;
}
static void sel_netif_kill(struct net_device *dev)
{
struct sel_netif *netif;
spin_lock_bh(&sel_netif_lock);
netif = sel_netif_find(dev);
if (netif)
sel_netif_destroy(netif);
spin_unlock_bh(&sel_netif_lock);
}
static void sel_netif_flush(void)
{
int idx;
spin_lock_bh(&sel_netif_lock);
for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) {
struct sel_netif *netif;
list_for_each_entry(netif, &sel_netif_hash[idx], list)
sel_netif_destroy(netif);
}
spin_unlock_bh(&sel_netif_lock);
}
static int sel_netif_avc_callback(u32 event, u32 ssid, u32 tsid,
u16 class, u32 perms, u32 *retained)
{
if (event == AVC_CALLBACK_RESET) {
sel_netif_flush();
synchronize_net();
}
return 0;
}
static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
if (event == NETDEV_DOWN)
sel_netif_kill(dev);
return NOTIFY_DONE;
}
static struct notifier_block sel_netif_netdev_notifier = {
.notifier_call = sel_netif_netdev_notifier_handler,
};
static __init int sel_netif_init(void)
{
int i, err = 0;
if (!selinux_enabled)
goto out;
for (i = 0; i < SEL_NETIF_HASH_SIZE; i++)
INIT_LIST_HEAD(&sel_netif_hash[i]);
register_netdevice_notifier(&sel_netif_netdev_notifier);
err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET,
SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
if (err)
panic("avc_add_callback() failed, error %d\n", err);
out:
return err;
}
__initcall(sel_netif_init);

View File

@@ -0,0 +1,113 @@
/*
* Netlink event notifications for SELinux.
*
* Author: James Morris <jmorris@redhat.com>
*
* Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/selinux_netlink.h>
static struct sock *selnl;
static int selnl_msglen(int msgtype)
{
int ret = 0;
switch (msgtype) {
case SELNL_MSG_SETENFORCE:
ret = sizeof(struct selnl_msg_setenforce);
break;
case SELNL_MSG_POLICYLOAD:
ret = sizeof(struct selnl_msg_policyload);
break;
default:
BUG();
}
return ret;
}
static void selnl_add_payload(struct nlmsghdr *nlh, int len, int msgtype, void *data)
{
switch (msgtype) {
case SELNL_MSG_SETENFORCE: {
struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh);
memset(msg, 0, len);
msg->val = *((int *)data);
break;
}
case SELNL_MSG_POLICYLOAD: {
struct selnl_msg_policyload *msg = NLMSG_DATA(nlh);
memset(msg, 0, len);
msg->seqno = *((u32 *)data);
break;
}
default:
BUG();
}
}
static void selnl_notify(int msgtype, void *data)
{
int len;
unsigned char *tmp;
struct sk_buff *skb;
struct nlmsghdr *nlh;
len = selnl_msglen(msgtype);
skb = alloc_skb(NLMSG_SPACE(len), GFP_USER);
if (!skb)
goto oom;
tmp = skb->tail;
nlh = NLMSG_PUT(skb, 0, 0, msgtype, len);
selnl_add_payload(nlh, len, msgtype, data);
nlh->nlmsg_len = skb->tail - tmp;
netlink_broadcast(selnl, skb, 0, SELNL_GRP_AVC, GFP_USER);
out:
return;
nlmsg_failure:
kfree_skb(skb);
oom:
printk(KERN_ERR "SELinux: OOM in %s\n", __FUNCTION__);
goto out;
}
void selnl_notify_setenforce(int val)
{
selnl_notify(SELNL_MSG_SETENFORCE, &val);
}
void selnl_notify_policyload(u32 seqno)
{
selnl_notify(SELNL_MSG_POLICYLOAD, &seqno);
}
static int __init selnl_init(void)
{
selnl = netlink_kernel_create(NETLINK_SELINUX, NULL);
if (selnl == NULL)
panic("SELinux: Cannot create netlink socket.");
netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV);
return 0;
}
__initcall(selnl_init);

View File

@@ -0,0 +1,153 @@
/*
* Netlink message type permission tables, for user generated messages.
*
* Author: James Morris <jmorris@redhat.com>
*
* Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/netfilter_ipv4/ip_queue.h>
#include <linux/tcp_diag.h>
#include <linux/xfrm.h>
#include <linux/audit.h>
#include "flask.h"
#include "av_permissions.h"
struct nlmsg_perm
{
u16 nlmsg_type;
u32 perm;
};
static struct nlmsg_perm nlmsg_route_perms[] =
{
{ RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETLINK, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_SETLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_NEWADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETADDR, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETROUTE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETRULE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETQDISC, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
};
static struct nlmsg_perm nlmsg_firewall_perms[] =
{
{ IPQM_MODE, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
{ IPQM_VERDICT, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
};
static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
{
{ TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
};
static struct nlmsg_perm nlmsg_xfrm_perms[] =
{
{ XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_GETSA, NETLINK_XFRM_SOCKET__NLMSG_READ },
{ XFRM_MSG_NEWPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_DELPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_GETPOLICY, NETLINK_XFRM_SOCKET__NLMSG_READ },
{ XFRM_MSG_ALLOCSPI, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_UPDPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_UPDSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
};
static struct nlmsg_perm nlmsg_audit_perms[] =
{
{ AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
{ AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READ },
{ AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_LOGIN, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
};
static int nlmsg_perm(u16 nlmsg_type, u32 *perm, struct nlmsg_perm *tab, size_t tabsize)
{
int i, err = -EINVAL;
for (i = 0; i < tabsize/sizeof(struct nlmsg_perm); i++)
if (nlmsg_type == tab[i].nlmsg_type) {
*perm = tab[i].perm;
err = 0;
break;
}
return err;
}
int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
{
int err = 0;
switch (sclass) {
case SECCLASS_NETLINK_ROUTE_SOCKET:
err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
sizeof(nlmsg_route_perms));
break;
case SECCLASS_NETLINK_FIREWALL_SOCKET:
case NETLINK_IP6_FW:
err = nlmsg_perm(nlmsg_type, perm, nlmsg_firewall_perms,
sizeof(nlmsg_firewall_perms));
break;
case SECCLASS_NETLINK_TCPDIAG_SOCKET:
err = nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms,
sizeof(nlmsg_tcpdiag_perms));
break;
case SECCLASS_NETLINK_XFRM_SOCKET:
err = nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms,
sizeof(nlmsg_xfrm_perms));
break;
case SECCLASS_NETLINK_AUDIT_SOCKET:
err = nlmsg_perm(nlmsg_type, perm, nlmsg_audit_perms,
sizeof(nlmsg_audit_perms));
break;
/* No messaging from userspace, or class unknown/unhandled */
default:
err = -ENOENT;
break;
}
return err;
}

View File

@@ -0,0 +1,992 @@
/* Updated: Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/security.h>
#include <linux/major.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
/* selinuxfs pseudo filesystem for exporting the security policy API.
Based on the proc code and the fs/nfsd/nfsctl.c code. */
#include "flask.h"
#include "avc.h"
#include "avc_ss.h"
#include "security.h"
#include "objsec.h"
#include "conditional.h"
static DECLARE_MUTEX(sel_sem);
/* global data for booleans */
static struct dentry *bool_dir = NULL;
static int bool_num = 0;
static int *bool_pending_values = NULL;
extern void selnl_notify_setenforce(int val);
/* Check whether a task is allowed to use a security operation. */
int task_has_security(struct task_struct *tsk,
u32 perms)
{
struct task_security_struct *tsec;
tsec = tsk->security;
if (!tsec)
return -EACCES;
return avc_has_perm(tsec->sid, SECINITSID_SECURITY,
SECCLASS_SECURITY, perms, NULL, NULL);
}
enum sel_inos {
SEL_ROOT_INO = 2,
SEL_LOAD, /* load policy */
SEL_ENFORCE, /* get or set enforcing status */
SEL_CONTEXT, /* validate context */
SEL_ACCESS, /* compute access decision */
SEL_CREATE, /* compute create labeling decision */
SEL_RELABEL, /* compute relabeling decision */
SEL_USER, /* compute reachable user contexts */
SEL_POLICYVERS, /* return policy version for this kernel */
SEL_COMMIT_BOOLS, /* commit new boolean values */
SEL_MLS, /* return if MLS policy is enabled */
SEL_DISABLE /* disable SELinux until next reboot */
};
#define TMPBUFLEN 12
static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
char tmpbuf[TMPBUFLEN];
ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_enforcing);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
static ssize_t sel_write_enforce(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
char *page;
ssize_t length;
int new_value;
if (count < 0 || count >= PAGE_SIZE)
return -ENOMEM;
if (*ppos != 0) {
/* No partial writes. */
return -EINVAL;
}
page = (char*)get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
length = -EFAULT;
if (copy_from_user(page, buf, count))
goto out;
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
goto out;
if (new_value != selinux_enforcing) {
length = task_has_security(current, SECURITY__SETENFORCE);
if (length)
goto out;
selinux_enforcing = new_value;
if (selinux_enforcing)
avc_ss_reset(0);
selnl_notify_setenforce(selinux_enforcing);
}
length = count;
out:
free_page((unsigned long) page);
return length;
}
#else
#define sel_write_enforce NULL
#endif
static struct file_operations sel_enforce_ops = {
.read = sel_read_enforce,
.write = sel_write_enforce,
};
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
static ssize_t sel_write_disable(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
char *page;
ssize_t length;
int new_value;
extern int selinux_disable(void);
if (count < 0 || count >= PAGE_SIZE)
return -ENOMEM;
if (*ppos != 0) {
/* No partial writes. */
return -EINVAL;
}
page = (char*)get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
length = -EFAULT;
if (copy_from_user(page, buf, count))
goto out;
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
goto out;
if (new_value) {
length = selinux_disable();
if (length < 0)
goto out;
}
length = count;
out:
free_page((unsigned long) page);
return length;
}
#else
#define sel_write_disable NULL
#endif
static struct file_operations sel_disable_ops = {
.write = sel_write_disable,
};
static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
char tmpbuf[TMPBUFLEN];
ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%u", POLICYDB_VERSION_MAX);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
static struct file_operations sel_policyvers_ops = {
.read = sel_read_policyvers,
};
/* declaration for sel_write_load */
static int sel_make_bools(void);
static ssize_t sel_read_mls(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
char tmpbuf[TMPBUFLEN];
ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_mls_enabled);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
static struct file_operations sel_mls_ops = {
.read = sel_read_mls,
};
static ssize_t sel_write_load(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
int ret;
ssize_t length;
void *data = NULL;
down(&sel_sem);
length = task_has_security(current, SECURITY__LOAD_POLICY);
if (length)
goto out;
if (*ppos != 0) {
/* No partial writes. */
length = -EINVAL;
goto out;
}
if ((count < 0) || (count > 64 * 1024 * 1024)
|| (data = vmalloc(count)) == NULL) {
length = -ENOMEM;
goto out;
}
length = -EFAULT;
if (copy_from_user(data, buf, count) != 0)
goto out;
length = security_load_policy(data, count);
if (length)
goto out;
ret = sel_make_bools();
if (ret)
length = ret;
else
length = count;
out:
up(&sel_sem);
vfree(data);
return length;
}
static struct file_operations sel_load_ops = {
.write = sel_write_load,
};
static ssize_t sel_write_context(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
char *page;
u32 sid;
ssize_t length;
length = task_has_security(current, SECURITY__CHECK_CONTEXT);
if (length)
return length;
if (count < 0 || count >= PAGE_SIZE)
return -ENOMEM;
if (*ppos != 0) {
/* No partial writes. */
return -EINVAL;
}
page = (char*)get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
length = -EFAULT;
if (copy_from_user(page, buf, count))
goto out;
length = security_context_to_sid(page, count, &sid);
if (length < 0)
goto out;
length = count;
out:
free_page((unsigned long) page);
return length;
}
static struct file_operations sel_context_ops = {
.write = sel_write_context,
};
/*
* Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
*/
static ssize_t sel_write_access(struct file * file, char *buf, size_t size);
static ssize_t sel_write_create(struct file * file, char *buf, size_t size);
static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size);
static ssize_t sel_write_user(struct file * file, char *buf, size_t size);
static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[SEL_ACCESS] = sel_write_access,
[SEL_CREATE] = sel_write_create,
[SEL_RELABEL] = sel_write_relabel,
[SEL_USER] = sel_write_user,
};
static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
ino_t ino = file->f_dentry->d_inode->i_ino;
char *data;
ssize_t rv;
if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino])
return -EINVAL;
data = simple_transaction_get(file, buf, size);
if (IS_ERR(data))
return PTR_ERR(data);
rv = write_op[ino](file, data, size);
if (rv>0) {
simple_transaction_set(file, rv);
rv = size;
}
return rv;
}
static struct file_operations transaction_ops = {
.write = selinux_transaction_write,
.read = simple_transaction_read,
.release = simple_transaction_release,
};
/*
* payload - write methods
* If the method has a response, the response should be put in buf,
* and the length returned. Otherwise return 0 or and -error.
*/
static ssize_t sel_write_access(struct file * file, char *buf, size_t size)
{
char *scon, *tcon;
u32 ssid, tsid;
u16 tclass;
u32 req;
struct av_decision avd;
ssize_t length;
length = task_has_security(current, SECURITY__COMPUTE_AV);
if (length)
return length;
length = -ENOMEM;
scon = kmalloc(size+1, GFP_KERNEL);
if (!scon)
return length;
memset(scon, 0, size+1);
tcon = kmalloc(size+1, GFP_KERNEL);
if (!tcon)
goto out;
memset(tcon, 0, size+1);
length = -EINVAL;
if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4)
goto out2;
length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
if (length < 0)
goto out2;
length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
if (length < 0)
goto out2;
length = security_compute_av(ssid, tsid, tclass, req, &avd);
if (length < 0)
goto out2;
length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
"%x %x %x %x %u",
avd.allowed, avd.decided,
avd.auditallow, avd.auditdeny,
avd.seqno);
out2:
kfree(tcon);
out:
kfree(scon);
return length;
}
static ssize_t sel_write_create(struct file * file, char *buf, size_t size)
{
char *scon, *tcon;
u32 ssid, tsid, newsid;
u16 tclass;
ssize_t length;
char *newcon;
u32 len;
length = task_has_security(current, SECURITY__COMPUTE_CREATE);
if (length)
return length;
length = -ENOMEM;
scon = kmalloc(size+1, GFP_KERNEL);
if (!scon)
return length;
memset(scon, 0, size+1);
tcon = kmalloc(size+1, GFP_KERNEL);
if (!tcon)
goto out;
memset(tcon, 0, size+1);
length = -EINVAL;
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out2;
length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
if (length < 0)
goto out2;
length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
if (length < 0)
goto out2;
length = security_transition_sid(ssid, tsid, tclass, &newsid);
if (length < 0)
goto out2;
length = security_sid_to_context(newsid, &newcon, &len);
if (length < 0)
goto out2;
if (len > SIMPLE_TRANSACTION_LIMIT) {
printk(KERN_ERR "%s: context size (%u) exceeds payload "
"max\n", __FUNCTION__, len);
length = -ERANGE;
goto out3;
}
memcpy(buf, newcon, len);
length = len;
out3:
kfree(newcon);
out2:
kfree(tcon);
out:
kfree(scon);
return length;
}
static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size)
{
char *scon, *tcon;
u32 ssid, tsid, newsid;
u16 tclass;
ssize_t length;
char *newcon;
u32 len;
length = task_has_security(current, SECURITY__COMPUTE_RELABEL);
if (length)
return length;
length = -ENOMEM;
scon = kmalloc(size+1, GFP_KERNEL);
if (!scon)
return length;
memset(scon, 0, size+1);
tcon = kmalloc(size+1, GFP_KERNEL);
if (!tcon)
goto out;
memset(tcon, 0, size+1);
length = -EINVAL;
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out2;
length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
if (length < 0)
goto out2;
length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
if (length < 0)
goto out2;
length = security_change_sid(ssid, tsid, tclass, &newsid);
if (length < 0)
goto out2;
length = security_sid_to_context(newsid, &newcon, &len);
if (length < 0)
goto out2;
if (len > SIMPLE_TRANSACTION_LIMIT) {
length = -ERANGE;
goto out3;
}
memcpy(buf, newcon, len);
length = len;
out3:
kfree(newcon);
out2:
kfree(tcon);
out:
kfree(scon);
return length;
}
static ssize_t sel_write_user(struct file * file, char *buf, size_t size)
{
char *con, *user, *ptr;
u32 sid, *sids;
ssize_t length;
char *newcon;
int i, rc;
u32 len, nsids;
length = task_has_security(current, SECURITY__COMPUTE_USER);
if (length)
return length;
length = -ENOMEM;
con = kmalloc(size+1, GFP_KERNEL);
if (!con)
return length;
memset(con, 0, size+1);
user = kmalloc(size+1, GFP_KERNEL);
if (!user)
goto out;
memset(user, 0, size+1);
length = -EINVAL;
if (sscanf(buf, "%s %s", con, user) != 2)
goto out2;
length = security_context_to_sid(con, strlen(con)+1, &sid);
if (length < 0)
goto out2;
length = security_get_user_sids(sid, user, &sids, &nsids);
if (length < 0)
goto out2;
length = sprintf(buf, "%u", nsids) + 1;
ptr = buf + length;
for (i = 0; i < nsids; i++) {
rc = security_sid_to_context(sids[i], &newcon, &len);
if (rc) {
length = rc;
goto out3;
}
if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) {
kfree(newcon);
length = -ERANGE;
goto out3;
}
memcpy(ptr, newcon, len);
kfree(newcon);
ptr += len;
length += len;
}
out3:
kfree(sids);
out2:
kfree(user);
out:
kfree(con);
return length;
}
static struct inode *sel_make_inode(struct super_block *sb, int mode)
{
struct inode *ret = new_inode(sb);
if (ret) {
ret->i_mode = mode;
ret->i_uid = ret->i_gid = 0;
ret->i_blksize = PAGE_CACHE_SIZE;
ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
}
return ret;
}
#define BOOL_INO_OFFSET 30
static ssize_t sel_read_bool(struct file *filep, char __user *buf,
size_t count, loff_t *ppos)
{
char *page = NULL;
ssize_t length;
ssize_t end;
ssize_t ret;
int cur_enforcing;
struct inode *inode;
down(&sel_sem);
ret = -EFAULT;
/* check to see if this file has been deleted */
if (!filep->f_op)
goto out;
if (count < 0 || count > PAGE_SIZE) {
ret = -EINVAL;
goto out;
}
if (!(page = (char*)get_zeroed_page(GFP_KERNEL))) {
ret = -ENOMEM;
goto out;
}
inode = filep->f_dentry->d_inode;
cur_enforcing = security_get_bool_value(inode->i_ino - BOOL_INO_OFFSET);
if (cur_enforcing < 0) {
ret = cur_enforcing;
goto out;
}
length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]);
if (length < 0) {
ret = length;
goto out;
}
if (*ppos >= length) {
ret = 0;
goto out;
}
if (count + *ppos > length)
count = length - *ppos;
end = count + *ppos;
if (copy_to_user(buf, (char *) page + *ppos, count)) {
ret = -EFAULT;
goto out;
}
*ppos = end;
ret = count;
out:
up(&sel_sem);
if (page)
free_page((unsigned long)page);
return ret;
}
static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
size_t count, loff_t *ppos)
{
char *page = NULL;
ssize_t length = -EFAULT;
int new_value;
struct inode *inode;
down(&sel_sem);
length = task_has_security(current, SECURITY__SETBOOL);
if (length)
goto out;
/* check to see if this file has been deleted */
if (!filep->f_op)
goto out;
if (count < 0 || count >= PAGE_SIZE) {
length = -ENOMEM;
goto out;
}
if (*ppos != 0) {
/* No partial writes. */
goto out;
}
page = (char*)get_zeroed_page(GFP_KERNEL);
if (!page) {
length = -ENOMEM;
goto out;
}
if (copy_from_user(page, buf, count))
goto out;
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
goto out;
if (new_value)
new_value = 1;
inode = filep->f_dentry->d_inode;
bool_pending_values[inode->i_ino - BOOL_INO_OFFSET] = new_value;
length = count;
out:
up(&sel_sem);
if (page)
free_page((unsigned long) page);
return length;
}
static struct file_operations sel_bool_ops = {
.read = sel_read_bool,
.write = sel_write_bool,
};
static ssize_t sel_commit_bools_write(struct file *filep,
const char __user *buf,
size_t count, loff_t *ppos)
{
char *page = NULL;
ssize_t length = -EFAULT;
int new_value;
down(&sel_sem);
length = task_has_security(current, SECURITY__SETBOOL);
if (length)
goto out;
/* check to see if this file has been deleted */
if (!filep->f_op)
goto out;
if (count < 0 || count >= PAGE_SIZE) {
length = -ENOMEM;
goto out;
}
if (*ppos != 0) {
/* No partial writes. */
goto out;
}
page = (char*)get_zeroed_page(GFP_KERNEL);
if (!page) {
length = -ENOMEM;
goto out;
}
if (copy_from_user(page, buf, count))
goto out;
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
goto out;
if (new_value) {
security_set_bools(bool_num, bool_pending_values);
}
length = count;
out:
up(&sel_sem);
if (page)
free_page((unsigned long) page);
return length;
}
static struct file_operations sel_commit_bools_ops = {
.write = sel_commit_bools_write,
};
/* delete booleans - partial revoke() from
* fs/proc/generic.c proc_kill_inodes */
static void sel_remove_bools(struct dentry *de)
{
struct list_head *p, *node;
struct super_block *sb = de->d_sb;
spin_lock(&dcache_lock);
node = de->d_subdirs.next;
while (node != &de->d_subdirs) {
struct dentry *d = list_entry(node, struct dentry, d_child);
list_del_init(node);
if (d->d_inode) {
d = dget_locked(d);
spin_unlock(&dcache_lock);
d_delete(d);
simple_unlink(de->d_inode, d);
dput(d);
spin_lock(&dcache_lock);
}
node = de->d_subdirs.next;
}
spin_unlock(&dcache_lock);
file_list_lock();
list_for_each(p, &sb->s_files) {
struct file * filp = list_entry(p, struct file, f_list);
struct dentry * dentry = filp->f_dentry;
if (dentry->d_parent != de) {
continue;
}
filp->f_op = NULL;
}
file_list_unlock();
}
#define BOOL_DIR_NAME "booleans"
static int sel_make_bools(void)
{
int i, ret = 0;
ssize_t len;
struct dentry *dentry = NULL;
struct dentry *dir = bool_dir;
struct inode *inode = NULL;
struct inode_security_struct *isec;
char **names = NULL, *page;
int num;
int *values = NULL;
u32 sid;
/* remove any existing files */
if (bool_pending_values)
kfree(bool_pending_values);
sel_remove_bools(dir);
if (!(page = (char*)get_zeroed_page(GFP_KERNEL)))
return -ENOMEM;
ret = security_get_bools(&num, &names, &values);
if (ret != 0)
goto out;
for (i = 0; i < num; i++) {
dentry = d_alloc_name(dir, names[i]);
if (!dentry) {
ret = -ENOMEM;
goto err;
}
inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
if (!inode) {
ret = -ENOMEM;
goto err;
}
len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
if (len < 0) {
ret = -EINVAL;
goto err;
} else if (len >= PAGE_SIZE) {
ret = -ENAMETOOLONG;
goto err;
}
isec = (struct inode_security_struct*)inode->i_security;
if ((ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid)))
goto err;
isec->sid = sid;
isec->initialized = 1;
inode->i_fop = &sel_bool_ops;
inode->i_ino = i + BOOL_INO_OFFSET;
d_add(dentry, inode);
}
bool_num = num;
bool_pending_values = values;
out:
free_page((unsigned long)page);
if (names) {
for (i = 0; i < num; i++) {
if (names[i])
kfree(names[i]);
}
kfree(names);
}
return ret;
err:
d_genocide(dir);
ret = -ENOMEM;
goto out;
}
#define NULL_FILE_NAME "null"
struct dentry *selinux_null = NULL;
static int sel_fill_super(struct super_block * sb, void * data, int silent)
{
int ret;
struct dentry *dentry;
struct inode *inode;
struct inode_security_struct *isec;
static struct tree_descr selinux_files[] = {
[SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
[SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR},
[SEL_CONTEXT] = {"context", &sel_context_ops, S_IRUGO|S_IWUGO},
[SEL_ACCESS] = {"access", &transaction_ops, S_IRUGO|S_IWUGO},
[SEL_CREATE] = {"create", &transaction_ops, S_IRUGO|S_IWUGO},
[SEL_RELABEL] = {"relabel", &transaction_ops, S_IRUGO|S_IWUGO},
[SEL_USER] = {"user", &transaction_ops, S_IRUGO|S_IWUGO},
[SEL_POLICYVERS] = {"policyvers", &sel_policyvers_ops, S_IRUGO},
[SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR},
[SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO},
[SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
/* last one */ {""}
};
ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
if (ret)
return ret;
dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME);
if (!dentry)
return -ENOMEM;
inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
if (!inode)
goto out;
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
d_add(dentry, inode);
bool_dir = dentry;
ret = sel_make_bools();
if (ret)
goto out;
dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
if (!dentry)
return -ENOMEM;
inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
if (!inode)
goto out;
isec = (struct inode_security_struct*)inode->i_security;
isec->sid = SECINITSID_DEVNULL;
isec->sclass = SECCLASS_CHR_FILE;
isec->initialized = 1;
init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3));
d_add(dentry, inode);
selinux_null = dentry;
return 0;
out:
dput(dentry);
printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__);
return -ENOMEM;
}
static struct super_block *sel_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, sel_fill_super);
}
static struct file_system_type sel_fs_type = {
.name = "selinuxfs",
.get_sb = sel_get_sb,
.kill_sb = kill_litter_super,
};
struct vfsmount *selinuxfs_mount;
static int __init init_sel_fs(void)
{
int err;
if (!selinux_enabled)
return 0;
err = register_filesystem(&sel_fs_type);
if (!err) {
selinuxfs_mount = kern_mount(&sel_fs_type);
if (IS_ERR(selinuxfs_mount)) {
printk(KERN_ERR "selinuxfs: could not mount!\n");
err = PTR_ERR(selinuxfs_mount);
selinuxfs_mount = NULL;
}
}
return err;
}
__initcall(init_sel_fs);
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
void exit_sel_fs(void)
{
unregister_filesystem(&sel_fs_type);
}
#endif

View File

@@ -0,0 +1,11 @@
#
# Makefile for building the SELinux security server as part of the kernel tree.
#
EXTRA_CFLAGS += -Isecurity/selinux/include
obj-y := ss.o
ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o
ss-$(CONFIG_SECURITY_SELINUX_MLS) += mls.o

View File

@@ -0,0 +1,414 @@
/*
* Implementation of the access vector table type.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
* Copyright (C) 2003 Tresys Technology, LLC
* 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.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/errno.h>
#include "avtab.h"
#include "policydb.h"
#define AVTAB_HASH(keyp) \
((keyp->target_class + \
(keyp->target_type << 2) + \
(keyp->source_type << 9)) & \
AVTAB_HASH_MASK)
static kmem_cache_t *avtab_node_cachep;
static struct avtab_node*
avtab_insert_node(struct avtab *h, int hvalue, struct avtab_node * prev, struct avtab_node * cur,
struct avtab_key *key, struct avtab_datum *datum)
{
struct avtab_node * newnode;
newnode = kmem_cache_alloc(avtab_node_cachep, SLAB_KERNEL);
if (newnode == NULL)
return NULL;
memset(newnode, 0, sizeof(struct avtab_node));
newnode->key = *key;
newnode->datum = *datum;
if (prev) {
newnode->next = prev->next;
prev->next = newnode;
} else {
newnode->next = h->htable[hvalue];
h->htable[hvalue] = newnode;
}
h->nel++;
return newnode;
}
int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
{
int hvalue;
struct avtab_node *prev, *cur, *newnode;
if (!h)
return -EINVAL;
hvalue = AVTAB_HASH(key);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
(datum->specified & cur->datum.specified))
return -EEXIST;
if (key->source_type < cur->key.source_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type < cur->key.target_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class < cur->key.target_class)
break;
}
newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
if(!newnode)
return -ENOMEM;
return 0;
}
/* Unlike avtab_insert(), this function allow multiple insertions of the same
* key/specified mask into the table, as needed by the conditional avtab.
* It also returns a pointer to the node inserted.
*/
struct avtab_node *
avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_datum * datum)
{
int hvalue;
struct avtab_node *prev, *cur, *newnode;
if (!h)
return NULL;
hvalue = AVTAB_HASH(key);
for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
(datum->specified & cur->datum.specified))
break;
if (key->source_type < cur->key.source_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type < cur->key.target_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class < cur->key.target_class)
break;
}
newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
return newnode;
}
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified)
{
int hvalue;
struct avtab_node *cur;
if (!h)
return NULL;
hvalue = AVTAB_HASH(key);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
(specified & cur->datum.specified))
return &cur->datum;
if (key->source_type < cur->key.source_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type < cur->key.target_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class < cur->key.target_class)
break;
}
return NULL;
}
/* This search function returns a node pointer, and can be used in
* conjunction with avtab_search_next_node()
*/
struct avtab_node*
avtab_search_node(struct avtab *h, struct avtab_key *key, int specified)
{
int hvalue;
struct avtab_node *cur;
if (!h)
return NULL;
hvalue = AVTAB_HASH(key);
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
(specified & cur->datum.specified))
return cur;
if (key->source_type < cur->key.source_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type < cur->key.target_type)
break;
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class < cur->key.target_class)
break;
}
return NULL;
}
struct avtab_node*
avtab_search_node_next(struct avtab_node *node, int specified)
{
struct avtab_node *cur;
if (!node)
return NULL;
for (cur = node->next; cur; cur = cur->next) {
if (node->key.source_type == cur->key.source_type &&
node->key.target_type == cur->key.target_type &&
node->key.target_class == cur->key.target_class &&
(specified & cur->datum.specified))
return cur;
if (node->key.source_type < cur->key.source_type)
break;
if (node->key.source_type == cur->key.source_type &&
node->key.target_type < cur->key.target_type)
break;
if (node->key.source_type == cur->key.source_type &&
node->key.target_type == cur->key.target_type &&
node->key.target_class < cur->key.target_class)
break;
}
return NULL;
}
void avtab_destroy(struct avtab *h)
{
int i;
struct avtab_node *cur, *temp;
if (!h || !h->htable)
return;
for (i = 0; i < AVTAB_SIZE; i++) {
cur = h->htable[i];
while (cur != NULL) {
temp = cur;
cur = cur->next;
kmem_cache_free(avtab_node_cachep, temp);
}
h->htable[i] = NULL;
}
vfree(h->htable);
h->htable = NULL;
}
int avtab_map(struct avtab *h,
int (*apply) (struct avtab_key *k,
struct avtab_datum *d,
void *args),
void *args)
{
int i, ret;
struct avtab_node *cur;
if (!h)
return 0;
for (i = 0; i < AVTAB_SIZE; i++) {
cur = h->htable[i];
while (cur != NULL) {
ret = apply(&cur->key, &cur->datum, args);
if (ret)
return ret;
cur = cur->next;
}
}
return 0;
}
int avtab_init(struct avtab *h)
{
int i;
h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
if (!h->htable)
return -ENOMEM;
for (i = 0; i < AVTAB_SIZE; i++)
h->htable[i] = NULL;
h->nel = 0;
return 0;
}
void avtab_hash_eval(struct avtab *h, char *tag)
{
int i, chain_len, slots_used, max_chain_len;
struct avtab_node *cur;
slots_used = 0;
max_chain_len = 0;
for (i = 0; i < AVTAB_SIZE; i++) {
cur = h->htable[i];
if (cur) {
slots_used++;
chain_len = 0;
while (cur) {
chain_len++;
cur = cur->next;
}
if (chain_len > max_chain_len)
max_chain_len = chain_len;
}
}
printk(KERN_INFO "%s: %d entries and %d/%d buckets used, longest "
"chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
max_chain_len);
}
int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey)
{
__u32 *buf;
__u32 items, items2;
memset(avkey, 0, sizeof(struct avtab_key));
memset(avdatum, 0, sizeof(struct avtab_datum));
buf = next_entry(fp, sizeof(__u32));
if (!buf) {
printk(KERN_ERR "security: avtab: truncated entry\n");
goto bad;
}
items2 = le32_to_cpu(buf[0]);
buf = next_entry(fp, sizeof(__u32)*items2);
if (!buf) {
printk(KERN_ERR "security: avtab: truncated entry\n");
goto bad;
}
items = 0;
avkey->source_type = le32_to_cpu(buf[items++]);
avkey->target_type = le32_to_cpu(buf[items++]);
avkey->target_class = le32_to_cpu(buf[items++]);
avdatum->specified = le32_to_cpu(buf[items++]);
if (!(avdatum->specified & (AVTAB_AV | AVTAB_TYPE))) {
printk(KERN_ERR "security: avtab: null entry\n");
goto bad;
}
if ((avdatum->specified & AVTAB_AV) &&
(avdatum->specified & AVTAB_TYPE)) {
printk(KERN_ERR "security: avtab: entry has both access vectors and types\n");
goto bad;
}
if (avdatum->specified & AVTAB_AV) {
if (avdatum->specified & AVTAB_ALLOWED)
avtab_allowed(avdatum) = le32_to_cpu(buf[items++]);
if (avdatum->specified & AVTAB_AUDITDENY)
avtab_auditdeny(avdatum) = le32_to_cpu(buf[items++]);
if (avdatum->specified & AVTAB_AUDITALLOW)
avtab_auditallow(avdatum) = le32_to_cpu(buf[items++]);
} else {
if (avdatum->specified & AVTAB_TRANSITION)
avtab_transition(avdatum) = le32_to_cpu(buf[items++]);
if (avdatum->specified & AVTAB_CHANGE)
avtab_change(avdatum) = le32_to_cpu(buf[items++]);
if (avdatum->specified & AVTAB_MEMBER)
avtab_member(avdatum) = le32_to_cpu(buf[items++]);
}
if (items != items2) {
printk(KERN_ERR "security: avtab: entry only had %d items, expected %d\n",
items2, items);
goto bad;
}
return 0;
bad:
return -1;
}
int avtab_read(struct avtab *a, void *fp, u32 config)
{
int i, rc = -EINVAL;
struct avtab_key avkey;
struct avtab_datum avdatum;
u32 *buf;
u32 nel;
buf = next_entry(fp, sizeof(u32));
if (!buf) {
printk(KERN_ERR "security: avtab: truncated table\n");
goto bad;
}
nel = le32_to_cpu(buf[0]);
if (!nel) {
printk(KERN_ERR "security: avtab: table is empty\n");
goto bad;
}
for (i = 0; i < nel; i++) {
if (avtab_read_item(fp, &avdatum, &avkey))
goto bad;
rc = avtab_insert(a, &avkey, &avdatum);
if (rc) {
if (rc == -ENOMEM)
printk(KERN_ERR "security: avtab: out of memory\n");
if (rc == -EEXIST)
printk(KERN_ERR "security: avtab: duplicate entry\n");
goto bad;
}
}
rc = 0;
out:
return rc;
bad:
avtab_destroy(a);
goto out;
}
void avtab_cache_init(void)
{
avtab_node_cachep = kmem_cache_create("avtab_node",
sizeof(struct avtab_node),
0, SLAB_PANIC, NULL, NULL);
}
void avtab_cache_destroy(void)
{
kmem_cache_destroy (avtab_node_cachep);
}

View File

@@ -0,0 +1,91 @@
/*
* An access vector table (avtab) is a hash table
* of access vectors and transition types indexed
* by a type pair and a class. An access vector
* table is used to represent the type enforcement
* tables.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
* Copyright (C) 2003 Tresys Technology, LLC
* 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.
*/
#ifndef _SS_AVTAB_H_
#define _SS_AVTAB_H_
struct avtab_key {
u32 source_type; /* source type */
u32 target_type; /* target type */
u32 target_class; /* target object class */
};
struct avtab_datum {
#define AVTAB_ALLOWED 1
#define AVTAB_AUDITALLOW 2
#define AVTAB_AUDITDENY 4
#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
#define AVTAB_TRANSITION 16
#define AVTAB_MEMBER 32
#define AVTAB_CHANGE 64
#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
#define AVTAB_ENABLED 0x80000000 /* reserved for used in cond_avtab */
u32 specified; /* what fields are specified */
u32 data[3]; /* access vectors or types */
#define avtab_allowed(x) (x)->data[0]
#define avtab_auditdeny(x) (x)->data[1]
#define avtab_auditallow(x) (x)->data[2]
#define avtab_transition(x) (x)->data[0]
#define avtab_change(x) (x)->data[1]
#define avtab_member(x) (x)->data[2]
};
struct avtab_node {
struct avtab_key key;
struct avtab_datum datum;
struct avtab_node *next;
};
struct avtab {
struct avtab_node **htable;
u32 nel; /* number of elements */
};
int avtab_init(struct avtab *);
int avtab_insert(struct avtab *h, struct avtab_key *k, struct avtab_datum *d);
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k, int specified);
void avtab_destroy(struct avtab *h);
int avtab_map(struct avtab *h,
int (*apply) (struct avtab_key *k,
struct avtab_datum *d,
void *args),
void *args);
void avtab_hash_eval(struct avtab *h, char *tag);
int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey);
int avtab_read(struct avtab *a, void *fp, u32 config);
struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
struct avtab_datum *datum);
struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key, int specified);
struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified);
void avtab_cache_init(void);
void avtab_cache_destroy(void);
#define AVTAB_HASH_BITS 15
#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
#define AVTAB_SIZE AVTAB_HASH_BUCKETS
#endif /* _SS_AVTAB_H_ */

View File

@@ -0,0 +1,487 @@
/* Authors: Karl MacMillan <kmacmillan@tresys.com>
* Frank Mayer <mayerf@tresys.com>
*
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include <asm/semaphore.h>
#include <linux/slab.h>
#include "security.h"
#include "conditional.h"
/*
* cond_evaluate_expr evaluates a conditional expr
* in reverse polish notation. It returns true (1), false (0),
* or undefined (-1). Undefined occurs when the expression
* exceeds the stack depth of COND_EXPR_MAXDEPTH.
*/
static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
{
struct cond_expr *cur;
int s[COND_EXPR_MAXDEPTH];
int sp = -1;
for (cur = expr; cur != NULL; cur = cur->next) {
switch (cur->expr_type) {
case COND_BOOL:
if (sp == (COND_EXPR_MAXDEPTH - 1))
return -1;
sp++;
s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
break;
case COND_NOT:
if (sp < 0)
return -1;
s[sp] = !s[sp];
break;
case COND_OR:
if (sp < 1)
return -1;
sp--;
s[sp] |= s[sp + 1];
break;
case COND_AND:
if (sp < 1)
return -1;
sp--;
s[sp] &= s[sp + 1];
break;
case COND_XOR:
if (sp < 1)
return -1;
sp--;
s[sp] ^= s[sp + 1];
break;
case COND_EQ:
if (sp < 1)
return -1;
sp--;
s[sp] = (s[sp] == s[sp + 1]);
break;
case COND_NEQ:
if (sp < 1)
return -1;
sp--;
s[sp] = (s[sp] != s[sp + 1]);
break;
default:
return -1;
}
}
return s[0];
}
/*
* evaluate_cond_node evaluates the conditional stored in
* a struct cond_node and if the result is different than the
* current state of the node it sets the rules in the true/false
* list appropriately. If the result of the expression is undefined
* all of the rules are disabled for safety.
*/
int evaluate_cond_node(struct policydb *p, struct cond_node *node)
{
int new_state;
struct cond_av_list* cur;
new_state = cond_evaluate_expr(p, node->expr);
if (new_state != node->cur_state) {
node->cur_state = new_state;
if (new_state == -1)
printk(KERN_ERR "security: expression result was undefined - disabling all rules.\n");
/* turn the rules on or off */
for (cur = node->true_list; cur != NULL; cur = cur->next) {
if (new_state <= 0) {
cur->node->datum.specified &= ~AVTAB_ENABLED;
} else {
cur->node->datum.specified |= AVTAB_ENABLED;
}
}
for (cur = node->false_list; cur != NULL; cur = cur->next) {
/* -1 or 1 */
if (new_state) {
cur->node->datum.specified &= ~AVTAB_ENABLED;
} else {
cur->node->datum.specified |= AVTAB_ENABLED;
}
}
}
return 0;
}
int cond_policydb_init(struct policydb *p)
{
p->bool_val_to_struct = NULL;
p->cond_list = NULL;
if (avtab_init(&p->te_cond_avtab))
return -1;
return 0;
}
static void cond_av_list_destroy(struct cond_av_list *list)
{
struct cond_av_list *cur, *next;
for (cur = list; cur != NULL; cur = next) {
next = cur->next;
/* the avtab_ptr_t node is destroy by the avtab */
kfree(cur);
}
}
static void cond_node_destroy(struct cond_node *node)
{
struct cond_expr *cur_expr, *next_expr;
for (cur_expr = node->expr; cur_expr != NULL; cur_expr = next_expr) {
next_expr = cur_expr->next;
kfree(cur_expr);
}
cond_av_list_destroy(node->true_list);
cond_av_list_destroy(node->false_list);
kfree(node);
}
static void cond_list_destroy(struct cond_node *list)
{
struct cond_node *next, *cur;
if (list == NULL)
return;
for (cur = list; cur != NULL; cur = next) {
next = cur->next;
cond_node_destroy(cur);
}
}
void cond_policydb_destroy(struct policydb *p)
{
if (p->bool_val_to_struct != NULL)
kfree(p->bool_val_to_struct);
avtab_destroy(&p->te_cond_avtab);
cond_list_destroy(p->cond_list);
}
int cond_init_bool_indexes(struct policydb *p)
{
if (p->bool_val_to_struct)
kfree(p->bool_val_to_struct);
p->bool_val_to_struct = (struct cond_bool_datum**)
kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum*), GFP_KERNEL);
if (!p->bool_val_to_struct)
return -1;
return 0;
}
int cond_destroy_bool(void *key, void *datum, void *p)
{
if (key)
kfree(key);
kfree(datum);
return 0;
}
int cond_index_bool(void *key, void *datum, void *datap)
{
struct policydb *p;
struct cond_bool_datum *booldatum;
booldatum = datum;
p = datap;
if (!booldatum->value || booldatum->value > p->p_bools.nprim)
return -EINVAL;
p->p_bool_val_to_name[booldatum->value - 1] = key;
p->bool_val_to_struct[booldatum->value -1] = booldatum;
return 0;
}
int bool_isvalid(struct cond_bool_datum *b)
{
if (!(b->state == 0 || b->state == 1))
return 0;
return 1;
}
int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
{
char *key = NULL;
struct cond_bool_datum *booldatum;
__u32 *buf, len;
booldatum = kmalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
if (!booldatum)
return -1;
memset(booldatum, 0, sizeof(struct cond_bool_datum));
buf = next_entry(fp, sizeof(__u32) * 3);
if (!buf)
goto err;
booldatum->value = le32_to_cpu(buf[0]);
booldatum->state = le32_to_cpu(buf[1]);
if (!bool_isvalid(booldatum))
goto err;
len = le32_to_cpu(buf[2]);
buf = next_entry(fp, len);
if (!buf)
goto err;
key = kmalloc(len + 1, GFP_KERNEL);
if (!key)
goto err;
memcpy(key, buf, len);
key[len] = 0;
if (hashtab_insert(h, key, booldatum))
goto err;
return 0;
err:
cond_destroy_bool(key, booldatum, NULL);
return -1;
}
static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list,
struct cond_av_list *other)
{
struct cond_av_list *list, *last = NULL, *cur;
struct avtab_key key;
struct avtab_datum datum;
struct avtab_node *node_ptr;
int len, i;
__u32 *buf;
__u8 found;
*ret_list = NULL;
len = 0;
buf = next_entry(fp, sizeof(__u32));
if (!buf)
return -1;
len = le32_to_cpu(buf[0]);
if (len == 0) {
return 0;
}
for (i = 0; i < len; i++) {
if (avtab_read_item(fp, &datum, &key))
goto err;
/*
* For type rules we have to make certain there aren't any
* conflicting rules by searching the te_avtab and the
* cond_te_avtab.
*/
if (datum.specified & AVTAB_TYPE) {
if (avtab_search(&p->te_avtab, &key, AVTAB_TYPE)) {
printk("security: type rule already exists outside of a conditional.");
goto err;
}
/*
* If we are reading the false list other will be a pointer to
* the true list. We can have duplicate entries if there is only
* 1 other entry and it is in our true list.
*
* If we are reading the true list (other == NULL) there shouldn't
* be any other entries.
*/
if (other) {
node_ptr = avtab_search_node(&p->te_cond_avtab, &key, AVTAB_TYPE);
if (node_ptr) {
if (avtab_search_node_next(node_ptr, AVTAB_TYPE)) {
printk("security: too many conflicting type rules.");
goto err;
}
found = 0;
for (cur = other; cur != NULL; cur = cur->next) {
if (cur->node == node_ptr) {
found = 1;
break;
}
}
if (!found) {
printk("security: conflicting type rules.");
goto err;
}
}
} else {
if (avtab_search(&p->te_cond_avtab, &key, AVTAB_TYPE)) {
printk("security: conflicting type rules when adding type rule for true.");
goto err;
}
}
}
node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, &key, &datum);
if (!node_ptr) {
printk("security: could not insert rule.");
goto err;
}
list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL);
if (!list)
goto err;
memset(list, 0, sizeof(struct cond_av_list));
list->node = node_ptr;
if (i == 0)
*ret_list = list;
else
last->next = list;
last = list;
}
return 0;
err:
cond_av_list_destroy(*ret_list);
*ret_list = NULL;
return -1;
}
static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
{
if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
printk("security: conditional expressions uses unknown operator.\n");
return 0;
}
if (expr->bool > p->p_bools.nprim) {
printk("security: conditional expressions uses unknown bool.\n");
return 0;
}
return 1;
}
static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
{
__u32 *buf;
int len, i;
struct cond_expr *expr = NULL, *last = NULL;
buf = next_entry(fp, sizeof(__u32));
if (!buf)
return -1;
node->cur_state = le32_to_cpu(buf[0]);
len = 0;
buf = next_entry(fp, sizeof(__u32));
if (!buf)
return -1;
/* expr */
len = le32_to_cpu(buf[0]);
for (i = 0; i < len; i++ ) {
buf = next_entry(fp, sizeof(__u32) * 2);
if (!buf)
goto err;
expr = kmalloc(sizeof(struct cond_expr), GFP_KERNEL);
if (!expr) {
goto err;
}
memset(expr, 0, sizeof(struct cond_expr));
expr->expr_type = le32_to_cpu(buf[0]);
expr->bool = le32_to_cpu(buf[1]);
if (!expr_isvalid(p, expr))
goto err;
if (i == 0) {
node->expr = expr;
} else {
last->next = expr;
}
last = expr;
}
if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
goto err;
if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0)
goto err;
return 0;
err:
cond_node_destroy(node);
return -1;
}
int cond_read_list(struct policydb *p, void *fp)
{
struct cond_node *node, *last = NULL;
__u32 *buf;
int i, len;
buf = next_entry(fp, sizeof(__u32));
if (!buf)
return -1;
len = le32_to_cpu(buf[0]);
for (i = 0; i < len; i++) {
node = kmalloc(sizeof(struct cond_node), GFP_KERNEL);
if (!node)
goto err;
memset(node, 0, sizeof(struct cond_node));
if (cond_read_node(p, node, fp) != 0)
goto err;
if (i == 0) {
p->cond_list = node;
} else {
last->next = node;
}
last = node;
}
return 0;
err:
cond_list_destroy(p->cond_list);
return -1;
}
/* Determine whether additional permissions are granted by the conditional
* av table, and if so, add them to the result
*/
void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd)
{
struct avtab_node *node;
if(!ctab || !key || !avd)
return;
for(node = avtab_search_node(ctab, key, AVTAB_AV); node != NULL;
node = avtab_search_node_next(node, AVTAB_AV)) {
if ( (__u32) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
(node->datum.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
avd->allowed |= avtab_allowed(&node->datum);
if ( (__u32) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
(node->datum.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
/* Since a '0' in an auditdeny mask represents a
* permission we do NOT want to audit (dontaudit), we use
* the '&' operand to ensure that all '0's in the mask
* are retained (much unlike the allow and auditallow cases).
*/
avd->auditdeny &= avtab_auditdeny(&node->datum);
if ( (__u32) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
(node->datum.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
avd->auditallow |= avtab_auditallow(&node->datum);
}
return;
}

View File

@@ -0,0 +1,77 @@
/* Authors: Karl MacMillan <kmacmillan@tresys.com>
* Frank Mayer <mayerf@tresys.com>
*
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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.
*/
#ifndef _CONDITIONAL_H_
#define _CONDITIONAL_H_
#include "avtab.h"
#include "symtab.h"
#include "policydb.h"
#define COND_EXPR_MAXDEPTH 10
/*
* A conditional expression is a list of operators and operands
* in reverse polish notation.
*/
struct cond_expr {
#define COND_BOOL 1 /* plain bool */
#define COND_NOT 2 /* !bool */
#define COND_OR 3 /* bool || bool */
#define COND_AND 4 /* bool && bool */
#define COND_XOR 5 /* bool ^ bool */
#define COND_EQ 6 /* bool == bool */
#define COND_NEQ 7 /* bool != bool */
#define COND_LAST 8
__u32 expr_type;
__u32 bool;
struct cond_expr *next;
};
/*
* Each cond_node contains a list of rules to be enabled/disabled
* depending on the current value of the conditional expression. This
* struct is for that list.
*/
struct cond_av_list {
struct avtab_node *node;
struct cond_av_list *next;
};
/*
* A cond node represents a conditional block in a policy. It
* contains a conditional expression, the current state of the expression,
* two lists of rules to enable/disable depending on the value of the
* expression (the true list corresponds to if and the false list corresponds
* to else)..
*/
struct cond_node {
int cur_state;
struct cond_expr *expr;
struct cond_av_list *true_list;
struct cond_av_list *false_list;
struct cond_node *next;
};
int cond_policydb_init(struct policydb* p);
void cond_policydb_destroy(struct policydb* p);
int cond_init_bool_indexes(struct policydb* p);
int cond_destroy_bool(void *key, void *datum, void *p);
int cond_index_bool(void *key, void *datum, void *datap);
int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
int cond_read_list(struct policydb *p, void *fp);
void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
int evaluate_cond_node(struct policydb *p, struct cond_node *node);
#endif /* _CONDITIONAL_H_ */

View File

@@ -0,0 +1,54 @@
/*
* A constraint is a condition that must be satisfied in
* order for one or more permissions to be granted.
* Constraints are used to impose additional restrictions
* beyond the type-based rules in `te' or the role-based
* transition rules in `rbac'. Constraints are typically
* used to prevent a process from transitioning to a new user
* identity or role unless it is in a privileged type.
* Constraints are likewise typically used to prevent a
* process from labeling an object with a different user
* identity.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SS_CONSTRAINT_H_
#define _SS_CONSTRAINT_H_
#include "ebitmap.h"
#define CEXPR_MAXDEPTH 5
struct constraint_expr {
#define CEXPR_NOT 1 /* not expr */
#define CEXPR_AND 2 /* expr and expr */
#define CEXPR_OR 3 /* expr or expr */
#define CEXPR_ATTR 4 /* attr op attr */
#define CEXPR_NAMES 5 /* attr op names */
u32 expr_type; /* expression type */
#define CEXPR_USER 1 /* user */
#define CEXPR_ROLE 2 /* role */
#define CEXPR_TYPE 4 /* type */
#define CEXPR_TARGET 8 /* target if set, source otherwise */
u32 attr; /* attribute */
#define CEXPR_EQ 1 /* == or eq */
#define CEXPR_NEQ 2 /* != */
#define CEXPR_DOM 3 /* dom */
#define CEXPR_DOMBY 4 /* domby */
#define CEXPR_INCOMP 5 /* incomp */
u32 op; /* operator */
struct ebitmap names; /* names */
struct constraint_expr *next; /* next expression */
};
struct constraint_node {
u32 permissions; /* constrained permissions */
struct constraint_expr *expr; /* constraint on permissions */
struct constraint_node *next; /* next constraint */
};
#endif /* _SS_CONSTRAINT_H_ */

View File

@@ -0,0 +1,117 @@
/*
* A security context is a set of security attributes
* associated with each subject and object controlled
* by the security policy. Security contexts are
* externally represented as variable-length strings
* that can be interpreted by a user or application
* with an understanding of the security policy.
* Internally, the security server uses a simple
* structure. This structure is private to the
* security server and can be changed without affecting
* clients of the security server.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SS_CONTEXT_H_
#define _SS_CONTEXT_H_
#include "ebitmap.h"
#include "mls_types.h"
/*
* A security context consists of an authenticated user
* identity, a role, a type and a MLS range.
*/
struct context {
u32 user;
u32 role;
u32 type;
#ifdef CONFIG_SECURITY_SELINUX_MLS
struct mls_range range;
#endif
};
#ifdef CONFIG_SECURITY_SELINUX_MLS
static inline void mls_context_init(struct context *c)
{
memset(&c->range, 0, sizeof(c->range));
}
static inline int mls_context_cpy(struct context *dst, struct context *src)
{
int rc;
dst->range.level[0].sens = src->range.level[0].sens;
rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
if (rc)
goto out;
dst->range.level[1].sens = src->range.level[1].sens;
rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat);
if (rc)
ebitmap_destroy(&dst->range.level[0].cat);
out:
return rc;
}
static inline int mls_context_cmp(struct context *c1, struct context *c2)
{
return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
ebitmap_cmp(&c1->range.level[0].cat,&c2->range.level[0].cat) &&
(c1->range.level[1].sens == c2->range.level[1].sens) &&
ebitmap_cmp(&c1->range.level[1].cat,&c2->range.level[1].cat));
}
static inline void mls_context_destroy(struct context *c)
{
ebitmap_destroy(&c->range.level[0].cat);
ebitmap_destroy(&c->range.level[1].cat);
mls_context_init(c);
}
#else
static inline void mls_context_init(struct context *c)
{ }
static inline int mls_context_cpy(struct context *dst, struct context *src)
{ return 0; }
static inline int mls_context_cmp(struct context *c1, struct context *c2)
{ return 1; }
static inline void mls_context_destroy(struct context *c)
{ }
#endif
static inline void context_init(struct context *c)
{
memset(c, 0, sizeof(*c));
}
static inline int context_cpy(struct context *dst, struct context *src)
{
dst->user = src->user;
dst->role = src->role;
dst->type = src->type;
return mls_context_cpy(dst, src);
}
static inline void context_destroy(struct context *c)
{
c->user = c->role = c->type = 0;
mls_context_destroy(c);
}
static inline int context_cmp(struct context *c1, struct context *c2)
{
return ((c1->user == c2->user) &&
(c1->role == c2->role) &&
(c1->type == c2->type) &&
mls_context_cmp(c1, c2));
}
#endif /* _SS_CONTEXT_H_ */

View File

@@ -0,0 +1,335 @@
/*
* Implementation of the extensible bitmap type.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include "ebitmap.h"
#include "policydb.h"
int ebitmap_or(struct ebitmap *dst, struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2, *new, *prev;
ebitmap_init(dst);
n1 = e1->node;
n2 = e2->node;
prev = NULL;
while (n1 || n2) {
new = kmalloc(sizeof(*new), GFP_ATOMIC);
if (!new) {
ebitmap_destroy(dst);
return -ENOMEM;
}
memset(new, 0, sizeof(*new));
if (n1 && n2 && n1->startbit == n2->startbit) {
new->startbit = n1->startbit;
new->map = n1->map | n2->map;
n1 = n1->next;
n2 = n2->next;
} else if (!n2 || (n1 && n1->startbit < n2->startbit)) {
new->startbit = n1->startbit;
new->map = n1->map;
n1 = n1->next;
} else {
new->startbit = n2->startbit;
new->map = n2->map;
n2 = n2->next;
}
new->next = NULL;
if (prev)
prev->next = new;
else
dst->node = new;
prev = new;
}
dst->highbit = (e1->highbit > e2->highbit) ? e1->highbit : e2->highbit;
return 0;
}
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
if (e1->highbit != e2->highbit)
return 0;
n1 = e1->node;
n2 = e2->node;
while (n1 && n2 &&
(n1->startbit == n2->startbit) &&
(n1->map == n2->map)) {
n1 = n1->next;
n2 = n2->next;
}
if (n1 || n2)
return 0;
return 1;
}
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
{
struct ebitmap_node *n, *new, *prev;
ebitmap_init(dst);
n = src->node;
prev = NULL;
while (n) {
new = kmalloc(sizeof(*new), GFP_ATOMIC);
if (!new) {
ebitmap_destroy(dst);
return -ENOMEM;
}
memset(new, 0, sizeof(*new));
new->startbit = n->startbit;
new->map = n->map;
new->next = NULL;
if (prev)
prev->next = new;
else
dst->node = new;
prev = new;
n = n->next;
}
dst->highbit = src->highbit;
return 0;
}
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
if (e1->highbit < e2->highbit)
return 0;
n1 = e1->node;
n2 = e2->node;
while (n1 && n2 && (n1->startbit <= n2->startbit)) {
if (n1->startbit < n2->startbit) {
n1 = n1->next;
continue;
}
if ((n1->map & n2->map) != n2->map)
return 0;
n1 = n1->next;
n2 = n2->next;
}
if (n2)
return 0;
return 1;
}
int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
{
struct ebitmap_node *n;
if (e->highbit < bit)
return 0;
n = e->node;
while (n && (n->startbit <= bit)) {
if ((n->startbit + MAPSIZE) > bit) {
if (n->map & (MAPBIT << (bit - n->startbit)))
return 1;
else
return 0;
}
n = n->next;
}
return 0;
}
int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
{
struct ebitmap_node *n, *prev, *new;
prev = NULL;
n = e->node;
while (n && n->startbit <= bit) {
if ((n->startbit + MAPSIZE) > bit) {
if (value) {
n->map |= (MAPBIT << (bit - n->startbit));
} else {
n->map &= ~(MAPBIT << (bit - n->startbit));
if (!n->map) {
/* drop this node from the bitmap */
if (!n->next) {
/*
* this was the highest map
* within the bitmap
*/
if (prev)
e->highbit = prev->startbit + MAPSIZE;
else
e->highbit = 0;
}
if (prev)
prev->next = n->next;
else
e->node = n->next;
kfree(n);
}
}
return 0;
}
prev = n;
n = n->next;
}
if (!value)
return 0;
new = kmalloc(sizeof(*new), GFP_ATOMIC);
if (!new)
return -ENOMEM;
memset(new, 0, sizeof(*new));
new->startbit = bit & ~(MAPSIZE - 1);
new->map = (MAPBIT << (bit - new->startbit));
if (!n)
/* this node will be the highest map within the bitmap */
e->highbit = new->startbit + MAPSIZE;
if (prev) {
new->next = prev->next;
prev->next = new;
} else {
new->next = e->node;
e->node = new;
}
return 0;
}
void ebitmap_destroy(struct ebitmap *e)
{
struct ebitmap_node *n, *temp;
if (!e)
return;
n = e->node;
while (n) {
temp = n;
n = n->next;
kfree(temp);
}
e->highbit = 0;
e->node = NULL;
return;
}
int ebitmap_read(struct ebitmap *e, void *fp)
{
int rc = -EINVAL;
struct ebitmap_node *n, *l;
u32 *buf, mapsize, count, i;
u64 map;
ebitmap_init(e);
buf = next_entry(fp, sizeof(u32)*3);
if (!buf)
goto out;
mapsize = le32_to_cpu(buf[0]);
e->highbit = le32_to_cpu(buf[1]);
count = le32_to_cpu(buf[2]);
if (mapsize != MAPSIZE) {
printk(KERN_ERR "security: ebitmap: map size %u does not "
"match my size %Zd (high bit was %d)\n", mapsize,
MAPSIZE, e->highbit);
goto out;
}
if (!e->highbit) {
e->node = NULL;
goto ok;
}
if (e->highbit & (MAPSIZE - 1)) {
printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
"multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
goto bad;
}
l = NULL;
for (i = 0; i < count; i++) {
buf = next_entry(fp, sizeof(u32));
if (!buf) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
goto bad;
}
n = kmalloc(sizeof(*n), GFP_KERNEL);
if (!n) {
printk(KERN_ERR "security: ebitmap: out of memory\n");
rc = -ENOMEM;
goto bad;
}
memset(n, 0, sizeof(*n));
n->startbit = le32_to_cpu(buf[0]);
if (n->startbit & (MAPSIZE - 1)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
"not a multiple of the map size (%Zd)\n",
n->startbit, MAPSIZE);
goto bad_free;
}
if (n->startbit > (e->highbit - MAPSIZE)) {
printk(KERN_ERR "security: ebitmap start bit (%d) is "
"beyond the end of the bitmap (%Zd)\n",
n->startbit, (e->highbit - MAPSIZE));
goto bad_free;
}
buf = next_entry(fp, sizeof(u64));
if (!buf) {
printk(KERN_ERR "security: ebitmap: truncated map\n");
goto bad_free;
}
memcpy(&map, buf, sizeof(u64));
n->map = le64_to_cpu(map);
if (!n->map) {
printk(KERN_ERR "security: ebitmap: null map in "
"ebitmap (startbit %d)\n", n->startbit);
goto bad_free;
}
if (l) {
if (n->startbit <= l->startbit) {
printk(KERN_ERR "security: ebitmap: start "
"bit %d comes after start bit %d\n",
n->startbit, l->startbit);
goto bad_free;
}
l->next = n;
} else
e->node = n;
l = n;
}
ok:
rc = 0;
out:
return rc;
bad_free:
kfree(n);
bad:
ebitmap_destroy(e);
goto out;
}

View File

@@ -0,0 +1,49 @@
/*
* An extensible bitmap is a bitmap that supports an
* arbitrary number of bits. Extensible bitmaps are
* used to represent sets of values, such as types,
* roles, categories, and classes.
*
* Each extensible bitmap is implemented as a linked
* list of bitmap nodes, where each bitmap node has
* an explicitly specified starting bit position within
* the total bitmap.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SS_EBITMAP_H_
#define _SS_EBITMAP_H_
#define MAPTYPE u64 /* portion of bitmap in each node */
#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
#define MAPBIT 1ULL /* a bit in the node bitmap */
struct ebitmap_node {
u32 startbit; /* starting position in the total bitmap */
MAPTYPE map; /* this node's portion of the bitmap */
struct ebitmap_node *next;
};
struct ebitmap {
struct ebitmap_node *node; /* first node in the bitmap */
u32 highbit; /* highest position in the total bitmap */
};
#define ebitmap_length(e) ((e)->highbit)
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
static inline void ebitmap_init(struct ebitmap *e)
{
memset(e, 0, sizeof(*e));
}
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_or(struct ebitmap *dst, struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
void ebitmap_destroy(struct ebitmap *e);
int ebitmap_read(struct ebitmap *e, void *fp);
#endif /* _SS_EBITMAP_H_ */

View File

@@ -0,0 +1,280 @@
/*
* Implementation of the hash table type.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include "hashtab.h"
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
int (*keycmp)(struct hashtab *h, void *key1, void *key2),
u32 size)
{
struct hashtab *p;
u32 i;
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (p == NULL)
return p;
memset(p, 0, sizeof(*p));
p->size = size;
p->nel = 0;
p->hash_value = hash_value;
p->keycmp = keycmp;
p->htable = kmalloc(sizeof(*(p->htable)) * size, GFP_KERNEL);
if (p->htable == NULL) {
kfree(p);
return NULL;
}
for (i = 0; i < size; i++)
p->htable[i] = NULL;
return p;
}
int hashtab_insert(struct hashtab *h, void *key, void *datum)
{
u32 hvalue;
struct hashtab_node *prev, *cur, *newnode;
if (!h || h->nel == HASHTAB_MAX_NODES)
return -EINVAL;
hvalue = h->hash_value(h, key);
prev = NULL;
cur = h->htable[hvalue];
while (cur && h->keycmp(h, key, cur->key) > 0) {
prev = cur;
cur = cur->next;
}
if (cur && (h->keycmp(h, key, cur->key) == 0))
return -EEXIST;
newnode = kmalloc(sizeof(*newnode), GFP_KERNEL);
if (newnode == NULL)
return -ENOMEM;
memset(newnode, 0, sizeof(*newnode));
newnode->key = key;
newnode->datum = datum;
if (prev) {
newnode->next = prev->next;
prev->next = newnode;
} else {
newnode->next = h->htable[hvalue];
h->htable[hvalue] = newnode;
}
h->nel++;
return 0;
}
int hashtab_remove(struct hashtab *h, void *key,
void (*destroy)(void *k, void *d, void *args),
void *args)
{
u32 hvalue;
struct hashtab_node *cur, *last;
if (!h)
return -EINVAL;
hvalue = h->hash_value(h, key);
last = NULL;
cur = h->htable[hvalue];
while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
last = cur;
cur = cur->next;
}
if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
return -ENOENT;
if (last == NULL)
h->htable[hvalue] = cur->next;
else
last->next = cur->next;
if (destroy)
destroy(cur->key, cur->datum, args);
kfree(cur);
h->nel--;
return 0;
}
int hashtab_replace(struct hashtab *h, void *key, void *datum,
void (*destroy)(void *k, void *d, void *args),
void *args)
{
u32 hvalue;
struct hashtab_node *prev, *cur, *newnode;
if (!h)
return -EINVAL;
hvalue = h->hash_value(h, key);
prev = NULL;
cur = h->htable[hvalue];
while (cur != NULL && h->keycmp(h, key, cur->key) > 0) {
prev = cur;
cur = cur->next;
}
if (cur && (h->keycmp(h, key, cur->key) == 0)) {
if (destroy)
destroy(cur->key, cur->datum, args);
cur->key = key;
cur->datum = datum;
} else {
newnode = kmalloc(sizeof(*newnode), GFP_KERNEL);
if (newnode == NULL)
return -ENOMEM;
memset(newnode, 0, sizeof(*newnode));
newnode->key = key;
newnode->datum = datum;
if (prev) {
newnode->next = prev->next;
prev->next = newnode;
} else {
newnode->next = h->htable[hvalue];
h->htable[hvalue] = newnode;
}
}
return 0;
}
void *hashtab_search(struct hashtab *h, void *key)
{
u32 hvalue;
struct hashtab_node *cur;
if (!h)
return NULL;
hvalue = h->hash_value(h, key);
cur = h->htable[hvalue];
while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
cur = cur->next;
if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
return NULL;
return cur->datum;
}
void hashtab_destroy(struct hashtab *h)
{
u32 i;
struct hashtab_node *cur, *temp;
if (!h)
return;
for (i = 0; i < h->size; i++) {
cur = h->htable[i];
while (cur != NULL) {
temp = cur;
cur = cur->next;
kfree(temp);
}
h->htable[i] = NULL;
}
kfree(h->htable);
h->htable = NULL;
kfree(h);
}
int hashtab_map(struct hashtab *h,
int (*apply)(void *k, void *d, void *args),
void *args)
{
u32 i;
int ret;
struct hashtab_node *cur;
if (!h)
return 0;
for (i = 0; i < h->size; i++) {
cur = h->htable[i];
while (cur != NULL) {
ret = apply(cur->key, cur->datum, args);
if (ret)
return ret;
cur = cur->next;
}
}
return 0;
}
void hashtab_map_remove_on_error(struct hashtab *h,
int (*apply)(void *k, void *d, void *args),
void (*destroy)(void *k, void *d, void *args),
void *args)
{
u32 i;
int ret;
struct hashtab_node *last, *cur, *temp;
if (!h)
return;
for (i = 0; i < h->size; i++) {
last = NULL;
cur = h->htable[i];
while (cur != NULL) {
ret = apply(cur->key, cur->datum, args);
if (ret) {
if (last)
last->next = cur->next;
else
h->htable[i] = cur->next;
temp = cur;
cur = cur->next;
if (destroy)
destroy(temp->key, temp->datum, args);
kfree(temp);
h->nel--;
} else {
last = cur;
cur = cur->next;
}
}
}
return;
}
void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
{
u32 i, chain_len, slots_used, max_chain_len;
struct hashtab_node *cur;
slots_used = 0;
max_chain_len = 0;
for (slots_used = max_chain_len = i = 0; i < h->size; i++) {
cur = h->htable[i];
if (cur) {
slots_used++;
chain_len = 0;
while (cur) {
chain_len++;
cur = cur->next;
}
if (chain_len > max_chain_len)
max_chain_len = chain_len;
}
}
info->slots_used = slots_used;
info->max_chain_len = max_chain_len;
}

View File

@@ -0,0 +1,125 @@
/*
* A hash table (hashtab) maintains associations between
* key values and datum values. The type of the key values
* and the type of the datum values is arbitrary. The
* functions for hash computation and key comparison are
* provided by the creator of the table.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SS_HASHTAB_H_
#define _SS_HASHTAB_H_
#define HASHTAB_MAX_NODES 0xffffffff
struct hashtab_node {
void *key;
void *datum;
struct hashtab_node *next;
};
struct hashtab {
struct hashtab_node **htable; /* hash table */
u32 size; /* number of slots in hash table */
u32 nel; /* number of elements in hash table */
u32 (*hash_value)(struct hashtab *h, void *key);
/* hash function */
int (*keycmp)(struct hashtab *h, void *key1, void *key2);
/* key comparison function */
};
struct hashtab_info {
u32 slots_used;
u32 max_chain_len;
};
/*
* Creates a new hash table with the specified characteristics.
*
* Returns NULL if insufficent space is available or
* the new hash table otherwise.
*/
struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key),
int (*keycmp)(struct hashtab *h, void *key1, void *key2),
u32 size);
/*
* Inserts the specified (key, datum) pair into the specified hash table.
*
* Returns -ENOMEM on memory allocation error,
* -EEXIST if there is already an entry with the same key,
* -EINVAL for general errors or
* 0 otherwise.
*/
int hashtab_insert(struct hashtab *h, void *k, void *d);
/*
* Removes the entry with the specified key from the hash table.
* Applies the specified destroy function to (key,datum,args) for
* the entry.
*
* Returns -ENOENT if no entry has the specified key,
* -EINVAL for general errors or
*0 otherwise.
*/
int hashtab_remove(struct hashtab *h, void *k,
void (*destroy)(void *k, void *d, void *args),
void *args);
/*
* Insert or replace the specified (key, datum) pair in the specified
* hash table. If an entry for the specified key already exists,
* then the specified destroy function is applied to (key,datum,args)
* for the entry prior to replacing the entry's contents.
*
* Returns -ENOMEM if insufficient space is available,
* -EINVAL for general errors or
* 0 otherwise.
*/
int hashtab_replace(struct hashtab *h, void *k, void *d,
void (*destroy)(void *k, void *d, void *args),
void *args);
/*
* Searches for the entry with the specified key in the hash table.
*
* Returns NULL if no entry has the specified key or
* the datum of the entry otherwise.
*/
void *hashtab_search(struct hashtab *h, void *k);
/*
* Destroys the specified hash table.
*/
void hashtab_destroy(struct hashtab *h);
/*
* Applies the specified apply function to (key,datum,args)
* for each entry in the specified hash table.
*
* The order in which the function is applied to the entries
* is dependent upon the internal structure of the hash table.
*
* If apply returns a non-zero status, then hashtab_map will cease
* iterating through the hash table and will propagate the error
* return to its caller.
*/
int hashtab_map(struct hashtab *h,
int (*apply)(void *k, void *d, void *args),
void *args);
/*
* Same as hashtab_map, except that if apply returns a non-zero status,
* then the (key,datum) pair will be removed from the hashtab and the
* destroy function will be applied to (key,datum,args).
*/
void hashtab_map_remove_on_error(struct hashtab *h,
int (*apply)(void *k, void *d, void *args),
void (*destroy)(void *k, void *d, void *args),
void *args);
/* Fill info with some hash table statistics */
void hashtab_stat(struct hashtab *h, struct hashtab_info *info);
#endif /* _SS_HASHTAB_H */

View File

@@ -0,0 +1,754 @@
/*
* Implementation of the multi-level security (MLS) policy.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include "mls.h"
#include "policydb.h"
#include "services.h"
/*
* Remove any permissions from `allowed' that are
* denied by the MLS policy.
*/
void mls_compute_av(struct context *scontext,
struct context *tcontext,
struct class_datum *tclass,
u32 *allowed)
{
unsigned int rel[2];
int l;
for (l = 0; l < 2; l++)
rel[l] = mls_level_relation(scontext->range.level[l],
tcontext->range.level[l]);
if (rel[1] != MLS_RELATION_EQ) {
if (rel[1] != MLS_RELATION_DOM &&
!ebitmap_get_bit(&policydb.trustedreaders, scontext->type - 1) &&
!ebitmap_get_bit(&policydb.trustedobjects, tcontext->type - 1)) {
/* read(s,t) = (s.high >= t.high) = False */
*allowed = (*allowed) & ~(tclass->mlsperms.read);
}
if (rel[1] != MLS_RELATION_DOMBY &&
!ebitmap_get_bit(&policydb.trustedreaders, tcontext->type - 1) &&
!ebitmap_get_bit(&policydb.trustedobjects, scontext->type - 1)) {
/* readby(s,t) = read(t,s) = False */
*allowed = (*allowed) & ~(tclass->mlsperms.readby);
}
}
if (((rel[0] != MLS_RELATION_DOMBY && rel[0] != MLS_RELATION_EQ) ||
((!mls_level_eq(tcontext->range.level[0],
tcontext->range.level[1])) &&
(rel[1] != MLS_RELATION_DOM && rel[1] != MLS_RELATION_EQ))) &&
!ebitmap_get_bit(&policydb.trustedwriters, scontext->type - 1) &&
!ebitmap_get_bit(&policydb.trustedobjects, tcontext->type - 1)) {
/*
* write(s,t) = ((s.low <= t.low = t.high) or (s.low
* <= t.low <= t.high <= s.high)) = False
*/
*allowed = (*allowed) & ~(tclass->mlsperms.write);
}
if (((rel[0] != MLS_RELATION_DOM && rel[0] != MLS_RELATION_EQ) ||
((!mls_level_eq(scontext->range.level[0],
scontext->range.level[1])) &&
(rel[1] != MLS_RELATION_DOMBY && rel[1] != MLS_RELATION_EQ))) &&
!ebitmap_get_bit(&policydb.trustedwriters, tcontext->type - 1) &&
!ebitmap_get_bit(&policydb.trustedobjects, scontext->type - 1)) {
/* writeby(s,t) = write(t,s) = False */
*allowed = (*allowed) & ~(tclass->mlsperms.writeby);
}
}
/*
* Return the length in bytes for the MLS fields of the
* security context string representation of `context'.
*/
int mls_compute_context_len(struct context * context)
{
int i, l, len;
len = 0;
for (l = 0; l < 2; l++) {
len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]) + 1;
for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++)
if (ebitmap_get_bit(&context->range.level[l].cat, i - 1))
len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
if (mls_level_relation(context->range.level[0], context->range.level[1])
== MLS_RELATION_EQ)
break;
}
return len;
}
/*
* Write the security context string representation of
* the MLS fields of `context' into the string `*scontext'.
* Update `*scontext' to point to the end of the MLS fields.
*/
int mls_sid_to_context(struct context *context,
char **scontext)
{
char *scontextp;
int i, l;
scontextp = *scontext;
for (l = 0; l < 2; l++) {
strcpy(scontextp,
policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
*scontextp = ':';
scontextp++;
for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++)
if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
*scontextp = ',';
scontextp++;
}
if (mls_level_relation(context->range.level[0], context->range.level[1])
!= MLS_RELATION_EQ) {
scontextp--;
sprintf(scontextp, "-");
scontextp++;
} else {
break;
}
}
*scontext = scontextp;
return 0;
}
/*
* Return 1 if the MLS fields in the security context
* structure `c' are valid. Return 0 otherwise.
*/
int mls_context_isvalid(struct policydb *p, struct context *c)
{
unsigned int relation;
struct level_datum *levdatum;
struct user_datum *usrdatum;
struct mls_range_list *rnode;
int i, l;
/*
* MLS range validity checks: high must dominate low, low level must
* be valid (category set <-> sensitivity check), and high level must
* be valid (category set <-> sensitivity check)
*/
relation = mls_level_relation(c->range.level[1],
c->range.level[0]);
if (!(relation & (MLS_RELATION_DOM | MLS_RELATION_EQ)))
/* High does not dominate low. */
return 0;
for (l = 0; l < 2; l++) {
if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
return 0;
levdatum = hashtab_search(p->p_levels.table,
p->p_sens_val_to_name[c->range.level[l].sens - 1]);
if (!levdatum)
return 0;
for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
if (i > p->p_cats.nprim)
return 0;
if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
/*
* Category may not be associated with
* sensitivity in low level.
*/
return 0;
}
}
}
if (c->role == OBJECT_R_VAL)
return 1;
/*
* User must be authorized for the MLS range.
*/
if (!c->user || c->user > p->p_users.nprim)
return 0;
usrdatum = p->user_val_to_struct[c->user - 1];
for (rnode = usrdatum->ranges; rnode; rnode = rnode->next) {
if (mls_range_contains(rnode->range, c->range))
break;
}
if (!rnode)
/* user may not be associated with range */
return 0;
return 1;
}
/*
* Set the MLS fields in the security context structure
* `context' based on the string representation in
* the string `*scontext'. Update `*scontext' to
* point to the end of the string representation of
* the MLS fields.
*
* This function modifies the string in place, inserting
* NULL characters to terminate the MLS fields.
*/
int mls_context_to_sid(char oldc,
char **scontext,
struct context *context)
{
char delim;
char *scontextp, *p;
struct level_datum *levdatum;
struct cat_datum *catdatum;
int l, rc = -EINVAL;
if (!oldc) {
/* No MLS component to the security context. Try
to use a default 'unclassified' value. */
levdatum = hashtab_search(policydb.p_levels.table,
"unclassified");
if (!levdatum)
goto out;
context->range.level[0].sens = levdatum->level->sens;
context->range.level[1].sens = context->range.level[0].sens;
rc = 0;
goto out;
}
/* Extract low sensitivity. */
scontextp = p = *scontext;
while (*p && *p != ':' && *p != '-')
p++;
delim = *p;
if (delim != 0)
*p++ = 0;
for (l = 0; l < 2; l++) {
levdatum = hashtab_search(policydb.p_levels.table, scontextp);
if (!levdatum)
goto out;
context->range.level[l].sens = levdatum->level->sens;
if (delim == ':') {
/* Extract low category set. */
while (1) {
scontextp = p;
while (*p && *p != ',' && *p != '-')
p++;
delim = *p;
if (delim != 0)
*p++ = 0;
catdatum = hashtab_search(policydb.p_cats.table,
scontextp);
if (!catdatum)
goto out;
rc = ebitmap_set_bit(&context->range.level[l].cat,
catdatum->value - 1, 1);
if (rc)
goto out;
if (delim != ',')
break;
}
}
if (delim == '-') {
/* Extract high sensitivity. */
scontextp = p;
while (*p && *p != ':')
p++;
delim = *p;
if (delim != 0)
*p++ = 0;
} else
break;
}
if (l == 0) {
context->range.level[1].sens = context->range.level[0].sens;
rc = ebitmap_cpy(&context->range.level[1].cat,
&context->range.level[0].cat);
if (rc)
goto out;
}
*scontext = ++p;
rc = 0;
out:
return rc;
}
/*
* Copies the MLS range from `src' into `dst'.
*/
static inline int mls_copy_context(struct context *dst,
struct context *src)
{
int l, rc = 0;
/* Copy the MLS range from the source context */
for (l = 0; l < 2; l++) {
dst->range.level[l].sens = src->range.level[l].sens;
rc = ebitmap_cpy(&dst->range.level[l].cat,
&src->range.level[l].cat);
if (rc)
break;
}
return rc;
}
/*
* Convert the MLS fields in the security context
* structure `c' from the values specified in the
* policy `oldp' to the values specified in the policy `newp'.
*/
int mls_convert_context(struct policydb *oldp,
struct policydb *newp,
struct context *c)
{
struct level_datum *levdatum;
struct cat_datum *catdatum;
struct ebitmap bitmap;
int l, i;
for (l = 0; l < 2; l++) {
levdatum = hashtab_search(newp->p_levels.table,
oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
if (!levdatum)
return -EINVAL;
c->range.level[l].sens = levdatum->level->sens;
ebitmap_init(&bitmap);
for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
int rc;
catdatum = hashtab_search(newp->p_cats.table,
oldp->p_cat_val_to_name[i - 1]);
if (!catdatum)
return -EINVAL;
rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
if (rc)
return rc;
}
}
ebitmap_destroy(&c->range.level[l].cat);
c->range.level[l].cat = bitmap;
}
return 0;
}
int mls_compute_sid(struct context *scontext,
struct context *tcontext,
u16 tclass,
u32 specified,
struct context *newcontext)
{
switch (specified) {
case AVTAB_TRANSITION:
case AVTAB_CHANGE:
/* Use the process MLS attributes. */
return mls_copy_context(newcontext, scontext);
case AVTAB_MEMBER:
/* Only polyinstantiate the MLS attributes if
the type is being polyinstantiated */
if (newcontext->type != tcontext->type) {
/* Use the process MLS attributes. */
return mls_copy_context(newcontext, scontext);
} else {
/* Use the related object MLS attributes. */
return mls_copy_context(newcontext, tcontext);
}
default:
return -EINVAL;
}
return -EINVAL;
}
void mls_user_destroy(struct user_datum *usrdatum)
{
struct mls_range_list *rnode, *rtmp;
rnode = usrdatum->ranges;
while (rnode) {
rtmp = rnode;
rnode = rnode->next;
ebitmap_destroy(&rtmp->range.level[0].cat);
ebitmap_destroy(&rtmp->range.level[1].cat);
kfree(rtmp);
}
}
int mls_read_perm(struct perm_datum *perdatum, void *fp)
{
u32 *buf;
buf = next_entry(fp, sizeof(u32));
if (!buf)
return -EINVAL;
perdatum->base_perms = le32_to_cpu(buf[0]);
return 0;
}
/*
* Read a MLS level structure from a policydb binary
* representation file.
*/
struct mls_level *mls_read_level(void *fp)
{
struct mls_level *l;
u32 *buf;
l = kmalloc(sizeof(*l), GFP_ATOMIC);
if (!l) {
printk(KERN_ERR "security: mls: out of memory\n");
return NULL;
}
memset(l, 0, sizeof(*l));
buf = next_entry(fp, sizeof(u32));
if (!buf) {
printk(KERN_ERR "security: mls: truncated level\n");
goto bad;
}
l->sens = cpu_to_le32(buf[0]);
if (ebitmap_read(&l->cat, fp)) {
printk(KERN_ERR "security: mls: error reading level "
"categories\n");
goto bad;
}
return l;
bad:
kfree(l);
return NULL;
}
/*
* Read a MLS range structure from a policydb binary
* representation file.
*/
static int mls_read_range_helper(struct mls_range *r, void *fp)
{
u32 *buf;
int items, rc = -EINVAL;
buf = next_entry(fp, sizeof(u32));
if (!buf)
goto out;
items = le32_to_cpu(buf[0]);
buf = next_entry(fp, sizeof(u32) * items);
if (!buf) {
printk(KERN_ERR "security: mls: truncated range\n");
goto out;
}
r->level[0].sens = le32_to_cpu(buf[0]);
if (items > 1) {
r->level[1].sens = le32_to_cpu(buf[1]);
} else {
r->level[1].sens = r->level[0].sens;
}
rc = ebitmap_read(&r->level[0].cat, fp);
if (rc) {
printk(KERN_ERR "security: mls: error reading low "
"categories\n");
goto out;
}
if (items > 1) {
rc = ebitmap_read(&r->level[1].cat, fp);
if (rc) {
printk(KERN_ERR "security: mls: error reading high "
"categories\n");
goto bad_high;
}
} else {
rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
if (rc) {
printk(KERN_ERR "security: mls: out of memory\n");
goto bad_high;
}
}
rc = 0;
out:
return rc;
bad_high:
ebitmap_destroy(&r->level[0].cat);
goto out;
}
int mls_read_range(struct context *c, void *fp)
{
return mls_read_range_helper(&c->range, fp);
}
/*
* Read a MLS perms structure from a policydb binary
* representation file.
*/
int mls_read_class(struct class_datum *cladatum, void *fp)
{
struct mls_perms *p = &cladatum->mlsperms;
u32 *buf;
buf = next_entry(fp, sizeof(u32)*4);
if (!buf) {
printk(KERN_ERR "security: mls: truncated mls permissions\n");
return -EINVAL;
}
p->read = le32_to_cpu(buf[0]);
p->readby = le32_to_cpu(buf[1]);
p->write = le32_to_cpu(buf[2]);
p->writeby = le32_to_cpu(buf[3]);
return 0;
}
int mls_read_user(struct user_datum *usrdatum, void *fp)
{
struct mls_range_list *r, *l;
int rc = 0;
u32 nel, i;
u32 *buf;
buf = next_entry(fp, sizeof(u32));
if (!buf) {
rc = -EINVAL;
goto out;
}
nel = le32_to_cpu(buf[0]);
l = NULL;
for (i = 0; i < nel; i++) {
r = kmalloc(sizeof(*r), GFP_ATOMIC);
if (!r) {
rc = -ENOMEM;
goto out;
}
memset(r, 0, sizeof(*r));
rc = mls_read_range_helper(&r->range, fp);
if (rc) {
kfree(r);
goto out;
}
if (l)
l->next = r;
else
usrdatum->ranges = r;
l = r;
}
out:
return rc;
}
int mls_read_nlevels(struct policydb *p, void *fp)
{
u32 *buf;
buf = next_entry(fp, sizeof(u32));
if (!buf)
return -EINVAL;
p->nlevels = le32_to_cpu(buf[0]);
return 0;
}
int mls_read_trusted(struct policydb *p, void *fp)
{
int rc = 0;
rc = ebitmap_read(&p->trustedreaders, fp);
if (rc)
goto out;
rc = ebitmap_read(&p->trustedwriters, fp);
if (rc)
goto bad;
rc = ebitmap_read(&p->trustedobjects, fp);
if (rc)
goto bad2;
out:
return rc;
bad2:
ebitmap_destroy(&p->trustedwriters);
bad:
ebitmap_destroy(&p->trustedreaders);
goto out;
}
int sens_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct level_datum *levdatum;
levdatum = datum;
p = datap;
if (!levdatum->isalias)
p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
return 0;
}
int cat_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct cat_datum *catdatum;
catdatum = datum;
p = datap;
if (!catdatum->isalias)
p->p_cat_val_to_name[catdatum->value - 1] = key;
return 0;
}
int sens_destroy(void *key, void *datum, void *p)
{
struct level_datum *levdatum;
kfree(key);
levdatum = datum;
if (!levdatum->isalias) {
ebitmap_destroy(&levdatum->level->cat);
kfree(levdatum->level);
}
kfree(datum);
return 0;
}
int cat_destroy(void *key, void *datum, void *p)
{
kfree(key);
kfree(datum);
return 0;
}
int sens_read(struct policydb *p, struct hashtab *h, void *fp)
{
char *key = NULL;
struct level_datum *levdatum;
int rc;
u32 *buf, len;
levdatum = kmalloc(sizeof(*levdatum), GFP_ATOMIC);
if (!levdatum) {
rc = -ENOMEM;
goto out;
}
memset(levdatum, 0, sizeof(*levdatum));
buf = next_entry(fp, sizeof(u32)*2);
if (!buf) {
rc = -EINVAL;
goto bad;
}
len = le32_to_cpu(buf[0]);
levdatum->isalias = le32_to_cpu(buf[1]);
buf = next_entry(fp, len);
if (!buf) {
rc = -EINVAL;
goto bad;
}
key = kmalloc(len + 1,GFP_ATOMIC);
if (!key) {
rc = -ENOMEM;
goto bad;
}
memcpy(key, buf, len);
key[len] = 0;
levdatum->level = mls_read_level(fp);
if (!levdatum->level) {
rc = -EINVAL;
goto bad;
}
rc = hashtab_insert(h, key, levdatum);
if (rc)
goto bad;
out:
return rc;
bad:
sens_destroy(key, levdatum, NULL);
goto out;
}
int cat_read(struct policydb *p, struct hashtab *h, void *fp)
{
char *key = NULL;
struct cat_datum *catdatum;
int rc;
u32 *buf, len;
catdatum = kmalloc(sizeof(*catdatum), GFP_ATOMIC);
if (!catdatum) {
rc = -ENOMEM;
goto out;
}
memset(catdatum, 0, sizeof(*catdatum));
buf = next_entry(fp, sizeof(u32)*3);
if (!buf) {
rc = -EINVAL;
goto bad;
}
len = le32_to_cpu(buf[0]);
catdatum->value = le32_to_cpu(buf[1]);
catdatum->isalias = le32_to_cpu(buf[2]);
buf = next_entry(fp, len);
if (!buf) {
rc = -EINVAL;
goto bad;
}
key = kmalloc(len + 1,GFP_ATOMIC);
if (!key) {
rc = -ENOMEM;
goto bad;
}
memcpy(key, buf, len);
key[len] = 0;
rc = hashtab_insert(h, key, catdatum);
if (rc)
goto bad;
out:
return rc;
bad:
cat_destroy(key, catdatum, NULL);
goto out;
}

View File

@@ -0,0 +1,99 @@
/*
* Multi-level security (MLS) policy operations.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SS_MLS_H_
#define _SS_MLS_H_
#include "context.h"
#include "policydb.h"
#ifdef CONFIG_SECURITY_SELINUX_MLS
void mls_compute_av(struct context *scontext,
struct context *tcontext,
struct class_datum *tclass,
u32 *allowed);
int mls_compute_context_len(struct context *context);
int mls_sid_to_context(struct context *context, char **scontext);
int mls_context_isvalid(struct policydb *p, struct context *c);
int mls_context_to_sid(char oldc,
char **scontext,
struct context *context);
int mls_convert_context(struct policydb *oldp,
struct policydb *newp,
struct context *context);
int mls_compute_sid(struct context *scontext,
struct context *tcontext,
u16 tclass,
u32 specified,
struct context *newcontext);
int sens_index(void *key, void *datum, void *datap);
int cat_index(void *key, void *datum, void *datap);
int sens_destroy(void *key, void *datum, void *p);
int cat_destroy(void *key, void *datum, void *p);
int sens_read(struct policydb *p, struct hashtab *h, void *fp);
int cat_read(struct policydb *p, struct hashtab *h, void *fp);
#define mls_for_user_ranges(user, usercon) { \
struct mls_range_list *__ranges; \
for (__ranges = user->ranges; __ranges; __ranges = __ranges->next) { \
usercon.range = __ranges->range;
#define mls_end_user_ranges } }
#define mls_symtab_names "levels", "categories",
#define mls_symtab_sizes 16, 16,
#define mls_index_f sens_index, cat_index,
#define mls_destroy_f sens_destroy, cat_destroy,
#define mls_read_f sens_read, cat_read,
#define mls_write_f sens_write, cat_write,
#define mls_policydb_index_others(p) printk(", %d levels", p->nlevels);
#define mls_set_config(config) config |= POLICYDB_CONFIG_MLS
void mls_user_destroy(struct user_datum *usrdatum);
int mls_read_range(struct context *c, void *fp);
int mls_read_perm(struct perm_datum *perdatum, void *fp);
int mls_read_class(struct class_datum *cladatum, void *fp);
int mls_read_user(struct user_datum *usrdatum, void *fp);
int mls_read_nlevels(struct policydb *p, void *fp);
int mls_read_trusted(struct policydb *p, void *fp);
#else
#define mls_compute_av(scontext, tcontext, tclass_datum, allowed)
#define mls_compute_context_len(context) 0
#define mls_sid_to_context(context, scontextpp)
#define mls_context_isvalid(p, c) 1
#define mls_context_to_sid(oldc, context_str, context) 0
#define mls_convert_context(oldp, newp, c) 0
#define mls_compute_sid(scontext, tcontext, tclass, specified, newcontextp) 0
#define mls_for_user_ranges(user, usercon)
#define mls_end_user_ranges
#define mls_symtab_names
#define mls_symtab_sizes
#define mls_index_f
#define mls_destroy_f
#define mls_read_f
#define mls_write_f
#define mls_policydb_index_others(p)
#define mls_set_config(config)
#define mls_user_destroy(usrdatum)
#define mls_read_range(c, fp) 0
#define mls_read_perm(p, fp) 0
#define mls_read_class(c, fp) 0
#define mls_read_user(u, fp) 0
#define mls_read_nlevels(p, fp) 0
#define mls_read_trusted(p, fp) 0
#endif
#endif /* _SS_MLS_H */

View File

@@ -0,0 +1,58 @@
/*
* Type definitions for the multi-level security (MLS) policy.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SS_MLS_TYPES_H_
#define _SS_MLS_TYPES_H_
struct mls_level {
u32 sens; /* sensitivity */
struct ebitmap cat; /* category set */
};
struct mls_range {
struct mls_level level[2]; /* low == level[0], high == level[1] */
};
struct mls_range_list {
struct mls_range range;
struct mls_range_list *next;
};
#define MLS_RELATION_DOM 1 /* source dominates */
#define MLS_RELATION_DOMBY 2 /* target dominates */
#define MLS_RELATION_EQ 4 /* source and target are equivalent */
#define MLS_RELATION_INCOMP 8 /* source and target are incomparable */
#define mls_level_eq(l1,l2) \
(((l1).sens == (l2).sens) && ebitmap_cmp(&(l1).cat,&(l2).cat))
#define mls_level_relation(l1,l2) ( \
(((l1).sens == (l2).sens) && ebitmap_cmp(&(l1).cat,&(l2).cat)) ? \
MLS_RELATION_EQ : \
(((l1).sens >= (l2).sens) && ebitmap_contains(&(l1).cat, &(l2).cat)) ? \
MLS_RELATION_DOM : \
(((l2).sens >= (l1).sens) && ebitmap_contains(&(l2).cat, &(l1).cat)) ? \
MLS_RELATION_DOMBY : \
MLS_RELATION_INCOMP )
#define mls_range_contains(r1,r2) \
((mls_level_relation((r1).level[0], (r2).level[0]) & \
(MLS_RELATION_EQ | MLS_RELATION_DOMBY)) && \
(mls_level_relation((r1).level[1], (r2).level[1]) & \
(MLS_RELATION_EQ | MLS_RELATION_DOM)))
/*
* Every access vector permission is mapped to a set of MLS base
* permissions, based on the flow properties of the corresponding
* operation.
*/
struct mls_perms {
u32 read; /* permissions that map to `read' */
u32 readby; /* permissions that map to `readby' */
u32 write; /* permissions that map to `write' */
u32 writeby; /* permissions that map to `writeby' */
};
#endif /* _SS_MLS_TYPES_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,288 @@
/*
* A policy database (policydb) specifies the
* configuration data for the security policy.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
* Added conditional policy language extensions
*
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* 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.
*/
#ifndef _SS_POLICYDB_H_
#define _SS_POLICYDB_H_
#include "symtab.h"
#include "avtab.h"
#include "sidtab.h"
#include "context.h"
#include "constraint.h"
/*
* A datum type is defined for each kind of symbol
* in the configuration data: individual permissions,
* common prefixes for access vectors, classes,
* users, roles, types, sensitivities, categories, etc.
*/
/* Permission attributes */
struct perm_datum {
u32 value; /* permission bit + 1 */
#ifdef CONFIG_SECURITY_SELINUX_MLS
#define MLS_BASE_READ 1 /* MLS base permission `read' */
#define MLS_BASE_WRITE 2 /* MLS base permission `write' */
#define MLS_BASE_READBY 4 /* MLS base permission `readby' */
#define MLS_BASE_WRITEBY 8 /* MLS base permission `writeby' */
u32 base_perms; /* MLS base permission mask */
#endif
};
/* Attributes of a common prefix for access vectors */
struct common_datum {
u32 value; /* internal common value */
struct symtab permissions; /* common permissions */
};
/* Class attributes */
struct class_datum {
u32 value; /* class value */
char *comkey; /* common name */
struct common_datum *comdatum; /* common datum */
struct symtab permissions; /* class-specific permission symbol table */
struct constraint_node *constraints; /* constraints on class permissions */
#ifdef CONFIG_SECURITY_SELINUX_MLS
struct mls_perms mlsperms; /* MLS base permission masks */
#endif
};
/* Role attributes */
struct role_datum {
u32 value; /* internal role value */
struct ebitmap dominates; /* set of roles dominated by this role */
struct ebitmap types; /* set of authorized types for role */
};
struct role_trans {
u32 role; /* current role */
u32 type; /* program executable type */
u32 new_role; /* new role */
struct role_trans *next;
};
struct role_allow {
u32 role; /* current role */
u32 new_role; /* new role */
struct role_allow *next;
};
/* Type attributes */
struct type_datum {
u32 value; /* internal type value */
unsigned char primary; /* primary name? */
};
/* User attributes */
struct user_datum {
u32 value; /* internal user value */
struct ebitmap roles; /* set of authorized roles for user */
#ifdef CONFIG_SECURITY_SELINUX_MLS
struct mls_range_list *ranges; /* list of authorized MLS ranges for user */
#endif
};
#ifdef CONFIG_SECURITY_SELINUX_MLS
/* Sensitivity attributes */
struct level_datum {
struct mls_level *level; /* sensitivity and associated categories */
unsigned char isalias; /* is this sensitivity an alias for another? */
};
/* Category attributes */
struct cat_datum {
u32 value; /* internal category bit + 1 */
unsigned char isalias; /* is this category an alias for another? */
};
#endif
/* Boolean data type */
struct cond_bool_datum {
__u32 value; /* internal type value */
int state;
};
struct cond_node;
/*
* The configuration data includes security contexts for
* initial SIDs, unlabeled file systems, TCP and UDP port numbers,
* network interfaces, and nodes. This structure stores the
* relevant data for one such entry. Entries of the same kind
* (e.g. all initial SIDs) are linked together into a list.
*/
struct ocontext {
union {
char *name; /* name of initial SID, fs, netif, fstype, path */
struct {
u8 protocol;
u16 low_port;
u16 high_port;
} port; /* TCP or UDP port information */
struct {
u32 addr;
u32 mask;
} node; /* node information */
struct {
u32 addr[4];
u32 mask[4];
} node6; /* IPv6 node information */
} u;
union {
u32 sclass; /* security class for genfs */
u32 behavior; /* labeling behavior for fs_use */
} v;
struct context context[2]; /* security context(s) */
u32 sid[2]; /* SID(s) */
struct ocontext *next;
};
struct genfs {
char *fstype;
struct ocontext *head;
struct genfs *next;
};
/* symbol table array indices */
#define SYM_COMMONS 0
#define SYM_CLASSES 1
#define SYM_ROLES 2
#define SYM_TYPES 3
#define SYM_USERS 4
#ifdef CONFIG_SECURITY_SELINUX_MLS
#define SYM_LEVELS 5
#define SYM_CATS 6
#define SYM_BOOLS 7
#define SYM_NUM 8
#else
#define SYM_BOOLS 5
#define SYM_NUM 6
#endif
/* object context array indices */
#define OCON_ISID 0 /* initial SIDs */
#define OCON_FS 1 /* unlabeled file systems */
#define OCON_PORT 2 /* TCP and UDP port numbers */
#define OCON_NETIF 3 /* network interfaces */
#define OCON_NODE 4 /* nodes */
#define OCON_FSUSE 5 /* fs_use */
#define OCON_NODE6 6 /* IPv6 nodes */
#define OCON_NUM 7
/* The policy database */
struct policydb {
/* symbol tables */
struct symtab symtab[SYM_NUM];
#define p_commons symtab[SYM_COMMONS]
#define p_classes symtab[SYM_CLASSES]
#define p_roles symtab[SYM_ROLES]
#define p_types symtab[SYM_TYPES]
#define p_users symtab[SYM_USERS]
#define p_levels symtab[SYM_LEVELS]
#define p_cats symtab[SYM_CATS]
#define p_bools symtab[SYM_BOOLS]
/* symbol names indexed by (value - 1) */
char **sym_val_to_name[SYM_NUM];
#define p_common_val_to_name sym_val_to_name[SYM_COMMONS]
#define p_class_val_to_name sym_val_to_name[SYM_CLASSES]
#define p_role_val_to_name sym_val_to_name[SYM_ROLES]
#define p_type_val_to_name sym_val_to_name[SYM_TYPES]
#define p_user_val_to_name sym_val_to_name[SYM_USERS]
#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
#define p_cat_val_to_name sym_val_to_name[SYM_CATS]
#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
/* class, role, and user attributes indexed by (value - 1) */
struct class_datum **class_val_to_struct;
struct role_datum **role_val_to_struct;
struct user_datum **user_val_to_struct;
/* type enforcement access vectors and transitions */
struct avtab te_avtab;
/* role transitions */
struct role_trans *role_tr;
/* bools indexed by (value - 1) */
struct cond_bool_datum **bool_val_to_struct;
/* type enforcement conditional access vectors and transitions */
struct avtab te_cond_avtab;
/* linked list indexing te_cond_avtab by conditional */
struct cond_node* cond_list;
/* role allows */
struct role_allow *role_allow;
/* security contexts of initial SIDs, unlabeled file systems,
TCP or UDP port numbers, network interfaces and nodes */
struct ocontext *ocontexts[OCON_NUM];
/* security contexts for files in filesystems that cannot support
a persistent label mapping or use another
fixed labeling behavior. */
struct genfs *genfs;
#ifdef CONFIG_SECURITY_SELINUX_MLS
/* number of legitimate MLS levels */
u32 nlevels;
struct ebitmap trustedreaders;
struct ebitmap trustedwriters;
struct ebitmap trustedobjects;
#endif
};
extern int policydb_init(struct policydb *p);
extern int policydb_index_classes(struct policydb *p);
extern int policydb_index_others(struct policydb *p);
extern void policydb_destroy(struct policydb *p);
extern int policydb_load_isids(struct policydb *p, struct sidtab *s);
extern int policydb_context_isvalid(struct policydb *p, struct context *c);
extern int policydb_read(struct policydb *p, void *fp);
#define PERM_SYMTAB_SIZE 32
#define POLICYDB_CONFIG_MLS 1
#define OBJECT_R "object_r"
#define OBJECT_R_VAL 1
#define POLICYDB_MAGIC SELINUX_MAGIC
#define POLICYDB_STRING "SE Linux"
struct policy_file {
char *data;
size_t len;
};
static inline void *next_entry(struct policy_file *fp, size_t bytes)
{
void *buf;
if (bytes > fp->len)
return NULL;
buf = fp->data;
fp->data += bytes;
fp->len -= bytes;
return buf;
}
#endif /* _SS_POLICYDB_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
/*
* Implementation of the security services.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SS_SERVICES_H_
#define _SS_SERVICES_H_
#include "policydb.h"
#include "sidtab.h"
/*
* The security server uses two global data structures
* when providing its services: the SID table (sidtab)
* and the policy database (policydb).
*/
extern struct sidtab sidtab;
extern struct policydb policydb;
#endif /* _SS_SERVICES_H_ */

View File

@@ -0,0 +1,341 @@
/*
* Implementation of the SID table type.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include "flask.h"
#include "security.h"
#include "sidtab.h"
#define SIDTAB_HASH(sid) \
(sid & SIDTAB_HASH_MASK)
#define INIT_SIDTAB_LOCK(s) spin_lock_init(&s->lock)
#define SIDTAB_LOCK(s, x) spin_lock_irqsave(&s->lock, x)
#define SIDTAB_UNLOCK(s, x) spin_unlock_irqrestore(&s->lock, x)
int sidtab_init(struct sidtab *s)
{
int i;
s->htable = kmalloc(sizeof(*(s->htable)) * SIDTAB_SIZE, GFP_ATOMIC);
if (!s->htable)
return -ENOMEM;
for (i = 0; i < SIDTAB_SIZE; i++)
s->htable[i] = NULL;
s->nel = 0;
s->next_sid = 1;
s->shutdown = 0;
INIT_SIDTAB_LOCK(s);
return 0;
}
int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
{
int hvalue, rc = 0;
struct sidtab_node *prev, *cur, *newnode;
if (!s) {
rc = -ENOMEM;
goto out;
}
hvalue = SIDTAB_HASH(sid);
prev = NULL;
cur = s->htable[hvalue];
while (cur != NULL && sid > cur->sid) {
prev = cur;
cur = cur->next;
}
if (cur && sid == cur->sid) {
rc = -EEXIST;
goto out;
}
newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC);
if (newnode == NULL) {
rc = -ENOMEM;
goto out;
}
newnode->sid = sid;
if (context_cpy(&newnode->context, context)) {
kfree(newnode);
rc = -ENOMEM;
goto out;
}
if (prev) {
newnode->next = prev->next;
wmb();
prev->next = newnode;
} else {
newnode->next = s->htable[hvalue];
wmb();
s->htable[hvalue] = newnode;
}
s->nel++;
if (sid >= s->next_sid)
s->next_sid = sid + 1;
out:
return rc;
}
int sidtab_remove(struct sidtab *s, u32 sid)
{
int hvalue, rc = 0;
struct sidtab_node *cur, *last;
if (!s) {
rc = -ENOENT;
goto out;
}
hvalue = SIDTAB_HASH(sid);
last = NULL;
cur = s->htable[hvalue];
while (cur != NULL && sid > cur->sid) {
last = cur;
cur = cur->next;
}
if (cur == NULL || sid != cur->sid) {
rc = -ENOENT;
goto out;
}
if (last == NULL)
s->htable[hvalue] = cur->next;
else
last->next = cur->next;
context_destroy(&cur->context);
kfree(cur);
s->nel--;
out:
return rc;
}
struct context *sidtab_search(struct sidtab *s, u32 sid)
{
int hvalue;
struct sidtab_node *cur;
if (!s)
return NULL;
hvalue = SIDTAB_HASH(sid);
cur = s->htable[hvalue];
while (cur != NULL && sid > cur->sid)
cur = cur->next;
if (cur == NULL || sid != cur->sid) {
/* Remap invalid SIDs to the unlabeled SID. */
sid = SECINITSID_UNLABELED;
hvalue = SIDTAB_HASH(sid);
cur = s->htable[hvalue];
while (cur != NULL && sid > cur->sid)
cur = cur->next;
if (!cur || sid != cur->sid)
return NULL;
}
return &cur->context;
}
int sidtab_map(struct sidtab *s,
int (*apply) (u32 sid,
struct context *context,
void *args),
void *args)
{
int i, rc = 0;
struct sidtab_node *cur;
if (!s)
goto out;
for (i = 0; i < SIDTAB_SIZE; i++) {
cur = s->htable[i];
while (cur != NULL) {
rc = apply(cur->sid, &cur->context, args);
if (rc)
goto out;
cur = cur->next;
}
}
out:
return rc;
}
void sidtab_map_remove_on_error(struct sidtab *s,
int (*apply) (u32 sid,
struct context *context,
void *args),
void *args)
{
int i, ret;
struct sidtab_node *last, *cur, *temp;
if (!s)
return;
for (i = 0; i < SIDTAB_SIZE; i++) {
last = NULL;
cur = s->htable[i];
while (cur != NULL) {
ret = apply(cur->sid, &cur->context, args);
if (ret) {
if (last) {
last->next = cur->next;
} else {
s->htable[i] = cur->next;
}
temp = cur;
cur = cur->next;
context_destroy(&temp->context);
kfree(temp);
s->nel--;
} else {
last = cur;
cur = cur->next;
}
}
}
return;
}
static inline u32 sidtab_search_context(struct sidtab *s,
struct context *context)
{
int i;
struct sidtab_node *cur;
for (i = 0; i < SIDTAB_SIZE; i++) {
cur = s->htable[i];
while (cur != NULL) {
if (context_cmp(&cur->context, context))
return cur->sid;
cur = cur->next;
}
}
return 0;
}
int sidtab_context_to_sid(struct sidtab *s,
struct context *context,
u32 *out_sid)
{
u32 sid;
int ret = 0;
unsigned long flags;
*out_sid = SECSID_NULL;
sid = sidtab_search_context(s, context);
if (!sid) {
SIDTAB_LOCK(s, flags);
/* Rescan now that we hold the lock. */
sid = sidtab_search_context(s, context);
if (sid)
goto unlock_out;
/* No SID exists for the context. Allocate a new one. */
if (s->next_sid == UINT_MAX || s->shutdown) {
ret = -ENOMEM;
goto unlock_out;
}
sid = s->next_sid++;
ret = sidtab_insert(s, sid, context);
if (ret)
s->next_sid--;
unlock_out:
SIDTAB_UNLOCK(s, flags);
}
if (ret)
return ret;
*out_sid = sid;
return 0;
}
void sidtab_hash_eval(struct sidtab *h, char *tag)
{
int i, chain_len, slots_used, max_chain_len;
struct sidtab_node *cur;
slots_used = 0;
max_chain_len = 0;
for (i = 0; i < SIDTAB_SIZE; i++) {
cur = h->htable[i];
if (cur) {
slots_used++;
chain_len = 0;
while (cur) {
chain_len++;
cur = cur->next;
}
if (chain_len > max_chain_len)
max_chain_len = chain_len;
}
}
printk(KERN_INFO "%s: %d entries and %d/%d buckets used, longest "
"chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE,
max_chain_len);
}
void sidtab_destroy(struct sidtab *s)
{
int i;
struct sidtab_node *cur, *temp;
if (!s)
return;
for (i = 0; i < SIDTAB_SIZE; i++) {
cur = s->htable[i];
while (cur != NULL) {
temp = cur;
cur = cur->next;
context_destroy(&temp->context);
kfree(temp);
}
s->htable[i] = NULL;
}
kfree(s->htable);
s->htable = NULL;
s->nel = 0;
s->next_sid = 1;
}
void sidtab_set(struct sidtab *dst, struct sidtab *src)
{
unsigned long flags;
SIDTAB_LOCK(src, flags);
dst->htable = src->htable;
dst->nel = src->nel;
dst->next_sid = src->next_sid;
dst->shutdown = 0;
SIDTAB_UNLOCK(src, flags);
}
void sidtab_shutdown(struct sidtab *s)
{
unsigned long flags;
SIDTAB_LOCK(s, flags);
s->shutdown = 1;
SIDTAB_UNLOCK(s, flags);
}

View File

@@ -0,0 +1,59 @@
/*
* A security identifier table (sidtab) is a hash table
* of security context structures indexed by SID value.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SS_SIDTAB_H_
#define _SS_SIDTAB_H_
#include "context.h"
struct sidtab_node {
u32 sid; /* security identifier */
struct context context; /* security context structure */
struct sidtab_node *next;
};
#define SIDTAB_HASH_BITS 7
#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1)
#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS
struct sidtab {
struct sidtab_node **htable;
unsigned int nel; /* number of elements */
unsigned int next_sid; /* next SID to allocate */
unsigned char shutdown;
spinlock_t lock;
};
int sidtab_init(struct sidtab *s);
int sidtab_insert(struct sidtab *s, u32 sid, struct context *context);
struct context *sidtab_search(struct sidtab *s, u32 sid);
int sidtab_map(struct sidtab *s,
int (*apply) (u32 sid,
struct context *context,
void *args),
void *args);
void sidtab_map_remove_on_error(struct sidtab *s,
int (*apply) (u32 sid,
struct context *context,
void *args),
void *args);
int sidtab_context_to_sid(struct sidtab *s,
struct context *context,
u32 *sid);
void sidtab_hash_eval(struct sidtab *h, char *tag);
void sidtab_destroy(struct sidtab *s);
void sidtab_set(struct sidtab *dst, struct sidtab *src);
void sidtab_shutdown(struct sidtab *s);
#endif /* _SS_SIDTAB_H_ */

View File

@@ -0,0 +1,44 @@
/*
* Implementation of the symbol table type.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include "symtab.h"
static unsigned int symhash(struct hashtab *h, void *key)
{
char *p, *keyp;
unsigned int size;
unsigned int val;
val = 0;
keyp = key;
size = strlen(keyp);
for (p = keyp; (p - keyp) < size; p++)
val = (val << 4 | (val >> (8*sizeof(unsigned int)-4))) ^ (*p);
return val & (h->size - 1);
}
static int symcmp(struct hashtab *h, void *key1, void *key2)
{
char *keyp1, *keyp2;
keyp1 = key1;
keyp2 = key2;
return strcmp(keyp1, keyp2);
}
int symtab_init(struct symtab *s, unsigned int size)
{
s->table = hashtab_create(symhash, symcmp, size);
if (!s->table)
return -1;
s->nprim = 0;
return 0;
}

View File

@@ -0,0 +1,23 @@
/*
* A symbol table (symtab) maintains associations between symbol
* strings and datum values. The type of the datum values
* is arbitrary. The symbol table type is implemented
* using the hash table type (hashtab).
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _SS_SYMTAB_H_
#define _SS_SYMTAB_H_
#include "hashtab.h"
struct symtab {
struct hashtab *table; /* hash table (keyed on a string) */
u32 nprim; /* number of primary names in table */
};
int symtab_init(struct symtab *s, unsigned int size);
#endif /* _SS_SYMTAB_H_ */