📄 hooks.c
字号:
/* * NSA Security-Enhanced Linux (SELinux) security module * * This file contains the SELinux hook function implementations. * * Authors: 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. */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/security.h>#include <linux/xattr.h>#include <linux/capability.h>#include <linux/unistd.h>#include <linux/mm.h>#include <linux/mman.h>#include <linux/slab.h>#include <linux/pagemap.h>#include <linux/swap.h>#include <linux/smp_lock.h>#include <linux/spinlock.h>#include <linux/syscalls.h>#include <linux/file.h>#include <linux/namei.h>#include <linux/mount.h>#include <linux/ext2_fs.h>#include <linux/proc_fs.h>#include <linux/kd.h>#include <linux/netfilter_ipv4.h>#include <linux/netfilter_ipv6.h>#include <linux/tty.h>#include <net/icmp.h>#include <net/ip.h> /* for sysctl_local_port_range[] */#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */#include <asm/uaccess.h>#include <asm/semaphore.h>#include <asm/ioctls.h>#include <linux/bitops.h>#include <linux/interrupt.h>#include <linux/netdevice.h> /* for network interface checks */#include <linux/netlink.h>#include <linux/tcp.h>#include <linux/udp.h>#include <linux/quota.h>#include <linux/un.h> /* for Unix socket types */#include <net/af_unix.h> /* for Unix socket types */#include <linux/parser.h>#include <linux/nfs_mount.h>#include <net/ipv6.h>#include <linux/hugetlb.h>#include <linux/personality.h>#include "avc.h"#include "objsec.h"#include "netif.h"#define XATTR_SELINUX_SUFFIX "selinux"#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIXextern int policydb_loaded_version;extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);#ifdef CONFIG_SECURITY_SELINUX_DEVELOPint selinux_enforcing = 0;static int __init enforcing_setup(char *str){ selinux_enforcing = simple_strtol(str,NULL,0); return 1;}__setup("enforcing=", enforcing_setup);#endif#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAMint selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;static int __init selinux_enabled_setup(char *str){ selinux_enabled = simple_strtol(str, NULL, 0); return 1;}__setup("selinux=", selinux_enabled_setup);#endif/* Original (dummy) security module. */static struct security_operations *original_ops = NULL;/* Minimal support for a secondary security module, just to allow the use of the dummy or capability modules. The owlsm module can alternatively be used as a secondary module as long as CONFIG_OWLSM_FD is not enabled. */static struct security_operations *secondary_ops = NULL;/* Lists of inode and superblock security structures initialized before the policy was loaded. */static LIST_HEAD(superblock_security_head);static spinlock_t sb_security_lock = SPIN_LOCK_UNLOCKED;/* Allocate and free functions for each kind of security blob. */static int task_alloc_security(struct task_struct *task){ struct task_security_struct *tsec; tsec = kmalloc(sizeof(struct task_security_struct), GFP_KERNEL); if (!tsec) return -ENOMEM; memset(tsec, 0, sizeof(struct task_security_struct)); tsec->magic = SELINUX_MAGIC; tsec->task = task; tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED; task->security = tsec; return 0;}static void task_free_security(struct task_struct *task){ struct task_security_struct *tsec = task->security; if (!tsec || tsec->magic != SELINUX_MAGIC) return; task->security = NULL; kfree(tsec);}static int inode_alloc_security(struct inode *inode){ struct task_security_struct *tsec = current->security; struct inode_security_struct *isec; isec = kmalloc(sizeof(struct inode_security_struct), GFP_KERNEL); if (!isec) return -ENOMEM; memset(isec, 0, sizeof(struct inode_security_struct)); init_MUTEX(&isec->sem); INIT_LIST_HEAD(&isec->list); isec->magic = SELINUX_MAGIC; isec->inode = inode; isec->sid = SECINITSID_UNLABELED; isec->sclass = SECCLASS_FILE; if (tsec && tsec->magic == SELINUX_MAGIC) isec->task_sid = tsec->sid; else isec->task_sid = SECINITSID_UNLABELED; inode->i_security = isec; return 0;}static void inode_free_security(struct inode *inode){ struct inode_security_struct *isec = inode->i_security; struct superblock_security_struct *sbsec = inode->i_sb->s_security; if (!isec || isec->magic != SELINUX_MAGIC) return; spin_lock(&sbsec->isec_lock); if (!list_empty(&isec->list)) list_del_init(&isec->list); spin_unlock(&sbsec->isec_lock); inode->i_security = NULL; kfree(isec);}static int file_alloc_security(struct file *file){ struct task_security_struct *tsec = current->security; struct file_security_struct *fsec; fsec = kmalloc(sizeof(struct file_security_struct), GFP_ATOMIC); if (!fsec) return -ENOMEM; memset(fsec, 0, sizeof(struct file_security_struct)); fsec->magic = SELINUX_MAGIC; fsec->file = file; if (tsec && tsec->magic == SELINUX_MAGIC) { fsec->sid = tsec->sid; fsec->fown_sid = tsec->sid; } else { fsec->sid = SECINITSID_UNLABELED; fsec->fown_sid = SECINITSID_UNLABELED; } file->f_security = fsec; return 0;}static void file_free_security(struct file *file){ struct file_security_struct *fsec = file->f_security; if (!fsec || fsec->magic != SELINUX_MAGIC) return; file->f_security = NULL; kfree(fsec);}static int superblock_alloc_security(struct super_block *sb){ struct superblock_security_struct *sbsec; sbsec = kmalloc(sizeof(struct superblock_security_struct), GFP_KERNEL); if (!sbsec) return -ENOMEM; memset(sbsec, 0, sizeof(struct superblock_security_struct)); init_MUTEX(&sbsec->sem); INIT_LIST_HEAD(&sbsec->list); INIT_LIST_HEAD(&sbsec->isec_head); spin_lock_init(&sbsec->isec_lock); sbsec->magic = SELINUX_MAGIC; sbsec->sb = sb; sbsec->sid = SECINITSID_UNLABELED; sbsec->def_sid = SECINITSID_FILE; sb->s_security = sbsec; return 0;}static void superblock_free_security(struct super_block *sb){ struct superblock_security_struct *sbsec = sb->s_security; if (!sbsec || sbsec->magic != SELINUX_MAGIC) return; spin_lock(&sb_security_lock); if (!list_empty(&sbsec->list)) list_del_init(&sbsec->list); spin_unlock(&sb_security_lock); sb->s_security = NULL; kfree(sbsec);}#ifdef CONFIG_SECURITY_NETWORKstatic int sk_alloc_security(struct sock *sk, int family, int priority){ struct sk_security_struct *ssec; if (family != PF_UNIX) return 0; ssec = kmalloc(sizeof(*ssec), priority); if (!ssec) return -ENOMEM; memset(ssec, 0, sizeof(*ssec)); ssec->magic = SELINUX_MAGIC; ssec->sk = sk; ssec->peer_sid = SECINITSID_UNLABELED; sk->sk_security = ssec; return 0;}static void sk_free_security(struct sock *sk){ struct sk_security_struct *ssec = sk->sk_security; if (sk->sk_family != PF_UNIX || ssec->magic != SELINUX_MAGIC) return; sk->sk_security = NULL; kfree(ssec);}#endif /* CONFIG_SECURITY_NETWORK *//* The security server must be initialized before any labeling or access decisions can be provided. */extern int ss_initialized;/* The file system's label must be initialized prior to use. */static char *labeling_behaviors[6] = { "uses xattr", "uses transition SIDs", "uses task SIDs", "uses genfs_contexts", "not configured for labeling", "uses mountpoint labeling",};static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);static inline int inode_doinit(struct inode *inode){ return inode_doinit_with_dentry(inode, NULL);}enum { Opt_context = 1, Opt_fscontext = 2, Opt_defcontext = 4,};static match_table_t tokens = { {Opt_context, "context=%s"}, {Opt_fscontext, "fscontext=%s"}, {Opt_defcontext, "defcontext=%s"},};#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n"static int try_context_mount(struct super_block *sb, void *data){ char *context = NULL, *defcontext = NULL; const char *name; u32 sid; int alloc = 0, rc = 0, seen = 0; struct task_security_struct *tsec = current->security; struct superblock_security_struct *sbsec = sb->s_security; if (!data) goto out; name = sb->s_type->name; if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) { /* NFS we understand. */ if (!strcmp(name, "nfs")) { struct nfs_mount_data *d = data; if (d->version < NFS_MOUNT_VERSION) goto out; if (d->context[0]) { context = d->context; seen |= Opt_context; } } else goto out; } else { /* Standard string-based options. */ char *p, *options = data; while ((p = strsep(&options, ",")) != NULL) { int token; substring_t args[MAX_OPT_ARGS]; if (!*p) continue; token = match_token(p, tokens, args); switch (token) { case Opt_context: if (seen) { rc = -EINVAL; printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); goto out_free; } context = match_strdup(&args[0]); if (!context) { rc = -ENOMEM; goto out_free; } if (!alloc) alloc = 1; seen |= Opt_context; break; case Opt_fscontext: if (sbsec->behavior != SECURITY_FS_USE_XATTR) { rc = -EINVAL; printk(KERN_WARNING "SELinux: " "fscontext option is invalid for" " this filesystem type\n"); goto out_free; } if (seen & (Opt_context|Opt_fscontext)) { rc = -EINVAL; printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); goto out_free; } context = match_strdup(&args[0]); if (!context) { rc = -ENOMEM; goto out_free; } if (!alloc) alloc = 1; seen |= Opt_fscontext; break; case Opt_defcontext: if (sbsec->behavior != SECURITY_FS_USE_XATTR) { rc = -EINVAL; printk(KERN_WARNING "SELinux: " "defcontext option is invalid " "for this filesystem type\n"); goto out_free; } if (seen & (Opt_context|Opt_defcontext)) { rc = -EINVAL; printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); goto out_free; } defcontext = match_strdup(&args[0]); if (!defcontext) { rc = -ENOMEM; goto out_free; } if (!alloc) alloc = 1; seen |= Opt_defcontext; break; default: rc = -EINVAL; printk(KERN_WARNING "SELinux: unknown mount " "option\n"); goto out_free; } } } if (!seen) goto out; if (context) { rc = security_context_to_sid(context, strlen(context), &sid); if (rc) { printk(KERN_WARNING "SELinux: security_context_to_sid" "(%s) failed for (dev %s, type %s) errno=%d\n", context, sb->s_id, name, rc); goto out_free; } rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__RELABELFROM, NULL, NULL); if (rc) goto out_free; rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, FILESYSTEM__RELABELTO, NULL, NULL); if (rc) goto out_free; sbsec->sid = sid; if (seen & Opt_context) sbsec->behavior = SECURITY_FS_USE_MNTPOINT; } if (defcontext) { rc = security_context_to_sid(defcontext, strlen(defcontext), &sid); if (rc) { printk(KERN_WARNING "SELinux: security_context_to_sid" "(%s) failed for (dev %s, type %s) errno=%d\n", defcontext, sb->s_id, name, rc); goto out_free; } if (sid == sbsec->def_sid) goto out_free; rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__RELABELFROM, NULL, NULL); if (rc) goto out_free; rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE, NULL, NULL); if (rc) goto out_free; sbsec->def_sid = sid; }out_free: if (alloc) { kfree(context); kfree(defcontext); }out: return rc;}static int superblock_doinit(struct super_block *sb, void *data){ struct superblock_security_struct *sbsec = sb->s_security; struct dentry *root = sb->s_root; struct inode *inode = root->d_inode; int rc = 0; down(&sbsec->sem); if (sbsec->initialized) goto out; if (!ss_initialized) { /* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security server is ready to handle calls. */ spin_lock(&sb_security_lock); if (list_empty(&sbsec->list)) list_add(&sbsec->list, &superblock_security_head); spin_unlock(&sb_security_lock); goto out; } /* Determine the labeling behavior to use for this filesystem type. */ rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid); if (rc) { printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", __FUNCTION__, sb->s_type->name, rc); goto out; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -