Commit 847106ff authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of...

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (25 commits)
  security: remove register_security hook
  security: remove dummy module fix
  security: remove dummy module
  security: remove unused sb_get_mnt_opts hook
  LSM/SELinux: show LSM mount options in /proc/mounts
  SELinux: allow fstype unknown to policy to use xattrs if present
  security: fix return of void-valued expressions
  SELinux: use do_each_thread as a proper do/while block
  SELinux: remove unused and shadowed addrlen variable
  SELinux: more user friendly unknown handling printk
  selinux: change handling of invalid classes (Was: Re: 2.6.26-rc5-mm1 selinux whine)
  SELinux: drop load_mutex in security_load_policy
  SELinux: fix off by 1 reference of class_to_string in context_struct_compute_av
  SELinux: open code sidtab lock
  SELinux: open code load_mutex
  SELinux: open code policy_rwlock
  selinux: fix endianness bug in network node address handling
  selinux: simplify ioctl checking
  SELinux: enable processes with mac_admin to get the raw inode contexts
  Security: split proc ptrace checking into read vs. attach
  ...
parents c142bda4 6f0f0fd4
......@@ -750,7 +750,7 @@ struct proc_fs_info {
const char *str;
};
static void show_sb_opts(struct seq_file *m, struct super_block *sb)
static int show_sb_opts(struct seq_file *m, struct super_block *sb)
{
static const struct proc_fs_info fs_info[] = {
{ MS_SYNCHRONOUS, ",sync" },
......@@ -764,6 +764,8 @@ static void show_sb_opts(struct seq_file *m, struct super_block *sb)
if (sb->s_flags & fs_infop->flag)
seq_puts(m, fs_infop->str);
}
return security_sb_show_options(m, sb);
}
static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
......@@ -806,11 +808,14 @@ static int show_vfsmnt(struct seq_file *m, void *v)
seq_putc(m, ' ');
show_type(m, mnt->mnt_sb);
seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
show_sb_opts(m, mnt->mnt_sb);
err = show_sb_opts(m, mnt->mnt_sb);
if (err)
goto out;
show_mnt_opts(m, mnt);
if (mnt->mnt_sb->s_op->show_options)
err = mnt->mnt_sb->s_op->show_options(m, mnt);
seq_puts(m, " 0 0\n");
out:
return err;
}
......@@ -865,10 +870,13 @@ static int show_mountinfo(struct seq_file *m, void *v)
seq_putc(m, ' ');
mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
show_sb_opts(m, sb);
err = show_sb_opts(m, sb);
if (err)
goto out;
if (sb->s_op->show_options)
err = sb->s_op->show_options(m, mnt);
seq_putc(m, '\n');
out:
return err;
}
......
......@@ -233,7 +233,7 @@ static int check_mem_permission(struct task_struct *task)
*/
if (task->parent == current && (task->ptrace & PT_PTRACED) &&
task_is_stopped_or_traced(task) &&
ptrace_may_attach(task))
ptrace_may_access(task, PTRACE_MODE_ATTACH))
return 0;
/*
......@@ -251,7 +251,8 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
task_lock(task);
if (task->mm != mm)
goto out;
if (task->mm != current->mm && __ptrace_may_attach(task) < 0)
if (task->mm != current->mm &&
__ptrace_may_access(task, PTRACE_MODE_READ) < 0)
goto out;
task_unlock(task);
return mm;
......@@ -518,7 +519,7 @@ static int proc_fd_access_allowed(struct inode *inode)
*/
task = get_proc_task(inode);
if (task) {
allowed = ptrace_may_attach(task);
allowed = ptrace_may_access(task, PTRACE_MODE_READ);
put_task_struct(task);
}
return allowed;
......@@ -904,7 +905,7 @@ static ssize_t environ_read(struct file *file, char __user *buf,
if (!task)
goto out_no_task;
if (!ptrace_may_attach(task))
if (!ptrace_may_access(task, PTRACE_MODE_READ))
goto out;
ret = -ENOMEM;
......
......@@ -210,7 +210,7 @@ static int show_map(struct seq_file *m, void *v)
dev_t dev = 0;
int len;
if (maps_protect && !ptrace_may_attach(task))
if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
return -EACCES;
if (file) {
......@@ -646,7 +646,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
goto out;
ret = -EACCES;
if (!ptrace_may_attach(task))
if (!ptrace_may_access(task, PTRACE_MODE_READ))
goto out_task;
ret = -EINVAL;
......@@ -747,7 +747,7 @@ static int show_numa_map_checked(struct seq_file *m, void *v)
struct proc_maps_private *priv = m->private;
struct task_struct *task = priv->task;
if (maps_protect && !ptrace_may_attach(task))
if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
return -EACCES;
return show_numa_map(m, v);
......
......@@ -113,7 +113,7 @@ static int show_map(struct seq_file *m, void *_vml)
struct proc_maps_private *priv = m->private;
struct task_struct *task = priv->task;
if (maps_protect && !ptrace_may_attach(task))
if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ))
return -EACCES;
return nommu_vma_show(m, vml->vma);
......
......@@ -95,8 +95,12 @@ extern void __ptrace_link(struct task_struct *child,
struct task_struct *new_parent);
extern void __ptrace_unlink(struct task_struct *child);
extern void ptrace_untrace(struct task_struct *child);
extern int ptrace_may_attach(struct task_struct *task);
extern int __ptrace_may_attach(struct task_struct *task);
#define PTRACE_MODE_READ 1
#define PTRACE_MODE_ATTACH 2
/* Returns 0 on success, -errno on denial. */
extern int __ptrace_may_access(struct task_struct *task, unsigned int mode);
/* Returns true on success, false on denial. */
extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);
static inline int ptrace_reparented(struct task_struct *child)
{
......
......@@ -46,7 +46,8 @@ struct audit_krule;
*/
extern int cap_capable(struct task_struct *tsk, int cap);
extern int cap_settime(struct timespec *ts, struct timezone *tz);
extern int cap_ptrace(struct task_struct *parent, struct task_struct *child);
extern int cap_ptrace(struct task_struct *parent, struct task_struct *child,
unsigned int mode);
extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern int cap_capset_check(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern void cap_capset_set(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
......@@ -79,6 +80,7 @@ struct xfrm_selector;
struct xfrm_policy;
struct xfrm_state;
struct xfrm_user_sec_ctx;
struct seq_file;
extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
extern int cap_netlink_recv(struct sk_buff *skb, int cap);
......@@ -289,10 +291,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Update module state after a successful pivot.
* @old_path contains the path for the old root.
* @new_path contains the path for the new root.
* @sb_get_mnt_opts:
* Get the security relevant mount options used for a superblock
* @sb the superblock to get security mount options from
* @opts binary data structure containing all lsm mount data
* @sb_set_mnt_opts:
* Set the security relevant mount options used for a superblock
* @sb the superblock to set security mount options for
......@@ -1170,6 +1168,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* attributes would be changed by the execve.
* @parent contains the task_struct structure for parent process.
* @child contains the task_struct structure for child process.
* @mode contains the PTRACE_MODE flags indicating the form of access.
* Return 0 if permission is granted.
* @capget:
* Get the @effective, @inheritable, and @permitted capability sets for
......@@ -1240,11 +1239,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @pages contains the number of pages.
* Return 0 if permission is granted.
*
* @register_security:
* allow module stacking.
* @name contains the name of the security module being stacked.
* @ops contains a pointer to the struct security_operations of the module to stack.
*
* @secid_to_secctx:
* Convert secid to security context.
* @secid contains the security ID.
......@@ -1295,7 +1289,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
struct security_operations {
char name[SECURITY_NAME_MAX + 1];
int (*ptrace) (struct task_struct *parent, struct task_struct *child);
int (*ptrace) (struct task_struct *parent, struct task_struct *child,
unsigned int mode);
int (*capget) (struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted);
......@@ -1328,6 +1323,7 @@ struct security_operations {
void (*sb_free_security) (struct super_block *sb);
int (*sb_copy_data) (char *orig, char *copy);
int (*sb_kern_mount) (struct super_block *sb, void *data);
int (*sb_show_options) (struct seq_file *m, struct super_block *sb);
int (*sb_statfs) (struct dentry *dentry);
int (*sb_mount) (char *dev_name, struct path *path,
char *type, unsigned long flags, void *data);
......@@ -1343,8 +1339,6 @@ struct security_operations {
struct path *new_path);
void (*sb_post_pivotroot) (struct path *old_path,
struct path *new_path);
int (*sb_get_mnt_opts) (const struct super_block *sb,
struct security_mnt_opts *opts);
int (*sb_set_mnt_opts) (struct super_block *sb,
struct security_mnt_opts *opts);
void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
......@@ -1472,10 +1466,6 @@ struct security_operations {
int (*netlink_send) (struct sock *sk, struct sk_buff *skb);
int (*netlink_recv) (struct sk_buff *skb, int cap);
/* allow module stacking */
int (*register_security) (const char *name,
struct security_operations *ops);
void (*d_instantiate) (struct dentry *dentry, struct inode *inode);
int (*getprocattr) (struct task_struct *p, char *name, char **value);
......@@ -1565,7 +1555,6 @@ struct security_operations {
extern int security_init(void);
extern int security_module_enable(struct security_operations *ops);
extern int register_security(struct security_operations *ops);
extern int mod_reg_security(const char *name, struct security_operations *ops);
extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops);
......@@ -1573,7 +1562,8 @@ extern struct dentry *securityfs_create_dir(const char *name, struct dentry *par
extern void securityfs_remove(struct dentry *dentry);
/* Security operations */
int security_ptrace(struct task_struct *parent, struct task_struct *child);
int security_ptrace(struct task_struct *parent, struct task_struct *child,
unsigned int mode);
int security_capget(struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
......@@ -1606,6 +1596,7 @@ int security_sb_alloc(struct super_block *sb);
void security_sb_free(struct super_block *sb);
int security_sb_copy_data(char *orig, char *copy);
int security_sb_kern_mount(struct super_block *sb, void *data);
int security_sb_show_options(struct seq_file *m, struct super_block *sb);
int security_sb_statfs(struct dentry *dentry);
int security_sb_mount(char *dev_name, struct path *path,
char *type, unsigned long flags, void *data);
......@@ -1617,8 +1608,6 @@ void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *d
void security_sb_post_addmount(struct vfsmount *mnt, struct path *mountpoint);
int security_sb_pivotroot(struct path *old_path, struct path *new_path);
void security_sb_post_pivotroot(struct path *old_path, struct path *new_path);
int security_sb_get_mnt_opts(const struct super_block *sb,
struct security_mnt_opts *opts);
int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts);
void security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb);
......@@ -1755,9 +1744,11 @@ static inline int security_init(void)
return 0;
}
static inline int security_ptrace(struct task_struct *parent, struct task_struct *child)
static inline int security_ptrace(struct task_struct *parent,
struct task_struct *child,
unsigned int mode)
{
return cap_ptrace(parent, child);
return cap_ptrace(parent, child, mode);
}
static inline int security_capget(struct task_struct *target,
......@@ -1881,6 +1872,12 @@ static inline int security_sb_kern_mount(struct super_block *sb, void *data)
return 0;
}
static inline int security_sb_show_options(struct seq_file *m,
struct super_block *sb)
{
return 0;
}
static inline int security_sb_statfs(struct dentry *dentry)
{
return 0;
......@@ -1927,12 +1924,6 @@ static inline int security_sb_pivotroot(struct path *old_path,
static inline void security_sb_post_pivotroot(struct path *old_path,
struct path *new_path)
{ }
static inline int security_sb_get_mnt_opts(const struct super_block *sb,
struct security_mnt_opts *opts)
{
security_init_mnt_opts(opts);
return 0;
}
static inline int security_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts)
......
......@@ -121,7 +121,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)
return ret;
}
int __ptrace_may_attach(struct task_struct *task)
int __ptrace_may_access(struct task_struct *task, unsigned int mode)
{
/* May we inspect the given task?
* This check is used both for attaching with ptrace
......@@ -148,16 +148,16 @@ int __ptrace_may_attach(struct task_struct *task)
if (!dumpable && !capable(CAP_SYS_PTRACE))
return -EPERM;
return security_ptrace(current, task);
return security_ptrace(current, task, mode);
}
int ptrace_may_attach(struct task_struct *task)
bool ptrace_may_access(struct task_struct *task, unsigned int mode)
{
int err;
task_lock(task);
err = __ptrace_may_attach(task);
err = __ptrace_may_access(task, mode);
task_unlock(task);
return !err;
return (!err ? true : false);
}
int ptrace_attach(struct task_struct *task)
......@@ -195,7 +195,7 @@ int ptrace_attach(struct task_struct *task)
/* the same process cannot be attached many times */
if (task->ptrace & PT_PTRACED)
goto bad;
retval = __ptrace_may_attach(task);
retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH);
if (retval)
goto bad;
......@@ -494,7 +494,8 @@ int ptrace_traceme(void)
*/
task_lock(current);
if (!(current->ptrace & PT_PTRACED)) {
ret = security_ptrace(current->parent, current);
ret = security_ptrace(current->parent, current,
PTRACE_MODE_ATTACH);
/*
* Set the ptrace bit in the process ptrace flags.
*/
......
......@@ -73,17 +73,9 @@ config SECURITY_NETWORK_XFRM
IPSec.
If you are unsure how to answer this question, answer N.
config SECURITY_CAPABILITIES
bool "Default Linux Capabilities"
depends on SECURITY
default y
help
This enables the "default" Linux capabilities functionality.
If you are unsure how to answer this question, answer Y.
config SECURITY_FILE_CAPABILITIES
bool "File POSIX Capabilities (EXPERIMENTAL)"
depends on (SECURITY=n || SECURITY_CAPABILITIES!=n) && EXPERIMENTAL
depends on EXPERIMENTAL
default n
help
This enables filesystem capabilities, allowing you to give
......
......@@ -6,16 +6,13 @@ obj-$(CONFIG_KEYS) += keys/
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_SECURITY_SMACK) += smack
# if we don't select a security model, use the default capabilities
ifneq ($(CONFIG_SECURITY),y)
# always enable default capabilities
obj-y += commoncap.o
endif
# Object file lists
obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
obj-$(CONFIG_SECURITY) += security.o capability.o inode.o
# Must precede capability.o in order to stack properly.
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
/*
* Capabilities Linux Security Module
*
* This is the default security module in case no other module is loaded.
*
* 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
......@@ -8,75 +10,988 @@
*
*/
#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/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,
.inode_need_killpriv = cap_inode_need_killpriv,
.inode_killpriv = cap_inode_killpriv,
.task_setscheduler = cap_task_setscheduler,
.task_setioprio = cap_task_setioprio,
.task_setnice = cap_task_setnice,
.task_post_setuid = cap_task_post_setuid,
.task_prctl = cap_task_prctl,
.task_reparent_to_init = cap_task_reparent_to_init,
.syslog = cap_syslog,
.vm_enough_memory = cap_vm_enough_memory,
};
/* flag to keep track of how we were registered */
static int secondary;
static int cap_acct(struct file *file)
{
return 0;
}
static int cap_sysctl(ctl_table *table, int op)
{
return 0;
}
static int capability_disable;
module_param_named(disable, capability_disable, int, 0);
static int cap_quotactl(int cmds, int type, int id, struct super_block *sb)
{
return 0;
}
static int __init capability_init (void)
static int cap_quota_on(struct dentry *dentry)
{
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 (KBUILD_MODNAME, &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" : "");
}
static int cap_bprm_alloc_security(struct linux_binprm *bprm)
{
return 0;
}
static void cap_bprm_free_security(struct linux_binprm *bprm)
{
}
static void cap_bprm_post_apply_creds(struct linux_binprm *bprm)
{
}
static int cap_bprm_check_security(struct linux_binprm *bprm)
{
return 0;
}
static int cap_sb_alloc_security(struct super_block *sb)
{
return 0;
}
static void cap_sb_free_security(struct super_block *sb)
{
}
static int cap_sb_copy_data(char *orig, char *copy)
{
return 0;
}
static int cap_sb_kern_mount(struct super_block *sb, void *data)
{
return 0;
}
static int cap_sb_show_options(struct seq_file *m, struct super_block *sb)
{
return 0;
}
static int cap_sb_statfs(struct dentry *dentry)
{
return 0;
}
static int cap_sb_mount(char *dev_name, struct path *path, char *type,
unsigned long flags, void *data)
{
return 0;
}
static int cap_sb_check_sb(struct vfsmount *mnt, struct path *path)
{
return 0;
}
static int cap_sb_umount(struct vfsmount *mnt, int flags)
{
return 0;
}
static void cap_sb_umount_close(struct vfsmount *mnt)
{
}
static void cap_sb_umount_busy(struct vfsmount *mnt)
{
}
static void cap_sb_post_remount(struct vfsmount *mnt, unsigned long flags,
void *data)
{
}
static void cap_sb_post_addmount(struct vfsmount *mnt, struct path *path)
{
}
static int cap_sb_pivotroot(struct path *old_path, struct path *new_path)
{
return 0;
}
static void cap_sb_post_pivotroot(struct path *old_path, struct path *new_path)
{
}
static int cap_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts)
{
if (unlikely(opts->num_mnt_opts))
return -EOPNOTSUPP;
return 0;
}
static void cap_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb)
{
}
static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
{
return 0;
}
static int cap_inode_alloc_security(struct inode *inode)
{
return 0;
}
static void cap_inode_free_security(struct inode *inode)
{
}
static int cap_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len)
{
return -EOPNOTSUPP;
}
static int cap_inode_create(struct inode *inode, struct dentry *dentry,
int mask)
{
return 0;
}
static int cap_inode_link(struct dentry *old_dentry, struct inode *inode,
struct dentry *new_dentry)
{
return 0;
}
static int cap_inode_unlink(struct inode *inode, struct dentry *dentry)
{
return 0;
}
static int cap_inode_symlink(struct inode *inode, struct dentry *dentry,
const char *name)
{
return 0;
}
static int cap_inode_mkdir(struct inode *inode, struct dentry *dentry,
int mask)
{
return 0;
}
static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry)
{
return 0;
}
static int cap_inode_mknod(struct inode *inode, struct dentry *dentry,
int mode, dev_t dev)
{
return 0;
}
static int cap_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
struct inode *new_inode, struct dentry *new_dentry)
{
return 0;
}
static int cap_inode_readlink(struct dentry *dentry)
{
return 0;
}
static int cap_inode_follow_link(struct dentry *dentry,
struct nameidata *nameidata)
{
return 0;
}
static int cap_inode_permission(struct inode *inode, int mask,
struct nameidata *nd)
{
return 0;
}
static int cap_inode_setattr(struct dentry *dentry, struct iattr *iattr)
{
return 0;
}
static int cap_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
{
return 0;
}
static void cap_inode_delete(struct inode *ino)
{
}
static void cap_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
}
static int cap_inode_getxattr(struct dentry *dentry, const char *name)
{
return 0;
}
static int cap_inode_listxattr(struct dentry *dentry)
{
return 0;
}
static int cap_inode_getsecurity(const struct inode *inode, const char *name,
void **buffer, bool alloc)
{
return -EOPNOTSUPP;
}
static int cap_inode_setsecurity(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
return -EOPNOTSUPP;
}
static int cap_inode_listsecurity(struct inode *inode, char *buffer,
size_t buffer_size)
{
return 0;
}
static void cap_inode_getsecid(const struct inode *inode, u32 *secid)
{
*secid = 0;
}
static int cap_file_permission(struct file *file, int mask)
{
return 0;
}
static int cap_file_alloc_security(struct file *file)
{
return 0;
}
static void cap_file_free_security(struct file *file)
{
}
static int cap_file_ioctl(struct file *file, unsigned int command,
unsigned long arg)
{
return 0;
}
static int cap_file_mmap(struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags,
unsigned long addr, unsigned long addr_only)
{
if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
return -EACCES;
return 0;
}
static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
unsigned long prot)
{
return 0;
}
static int cap_file_lock(struct file *file, unsigned int cmd)
{
return 0;
}
static int cap_file_fcntl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return 0;
}
static int cap_file_set_fowner(struct file *file)
{
return 0;
}
static int cap_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int sig)
{
return 0;
}
static int cap_file_receive(struct file *file)
{
return 0;
}
static int cap_dentry_open(struct file *file)
{
return 0;
}
static int cap_task_create(unsigned long clone_flags)
{
return 0;
}
static int cap_task_alloc_security(struct task_struct *p)
{
return 0;
}
static void cap_task_free_security(struct task_struct *p)
{
}
static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
{
return 0;
}
static int cap_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
{
return 0;
}
static int cap_task_setpgid(struct task_struct *p, pid_t pgid)
{
return 0;
}
static int cap_task_getpgid(struct task_struct *p)
{
return 0;
}
security_initcall (capability_init);
static int cap_task_getsid(struct task_struct *p)
{
return 0;
}
static void cap_task_getsecid(struct task_struct *p, u32 *secid)
{
*secid = 0;
}
static int cap_task_setgroups(struct group_info *group_info)
{
return 0;
}
static int cap_task_getioprio(struct task_struct *p)
{
return 0;
}
static int cap_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
{
return 0;
}
static int cap_task_getscheduler(struct task_struct *p)
{
return 0;
}
static int cap_task_movememory(struct task_struct *p)
{
return 0;
}
static int cap_task_wait(struct task_struct *p)
{
return 0;
}
static int cap_task_kill(struct task_struct *p, struct siginfo *info,
int sig, u32 secid)
{
return 0;
}
static void cap_task_to_inode(struct task_struct *p, struct inode *inode)
{
}
static int cap_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
{
return 0;
}
static void cap_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
{
*secid = 0;
}
static int cap_msg_msg_alloc_security(struct msg_msg *msg)
{
return 0;
}
static void cap_msg_msg_free_security(struct msg_msg *msg)
{
}
static int cap_msg_queue_alloc_security(struct msg_queue *msq)
{
return 0;
}
static void cap_msg_queue_free_security(struct msg_queue *msq)
{
}
static int cap_msg_queue_associate(struct msg_queue *msq, int msqflg)
{
return 0;
}
static int cap_msg_queue_msgctl(struct msg_queue *msq, int cmd)
{
return 0;
}
static int cap_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
int msgflg)
{
return 0;
}
static int cap_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
struct task_struct *target, long type, int mode)
{
return 0;
}
static int cap_shm_alloc_security(struct shmid_kernel *shp)
{
return 0;
}
static void cap_shm_free_security(struct shmid_kernel *shp)
{
}
static int cap_shm_associate(struct shmid_kernel *shp, int shmflg)
{
return 0;
}
static int cap_shm_shmctl(struct shmid_kernel *shp, int cmd)
{
return 0;
}
static int cap_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
int shmflg)
{
return 0;
}
static int cap_sem_alloc_security(struct sem_array *sma)
{
return 0;
}
static void cap_sem_free_security(struct sem_array *sma)
{
}
static int cap_sem_associate(struct sem_array *sma, int semflg)
{
return 0;
}
static int cap_sem_semctl(struct sem_array *sma, int cmd)
{
return 0;
}
static int cap_sem_semop(struct sem_array *sma, struct sembuf *sops,
unsigned nsops, int alter)
{
return 0;
}
#ifdef CONFIG_SECURITY_NETWORK
static int cap_unix_stream_connect(struct socket *sock, struct socket *other,
struct sock *newsk)
{
return 0;
}
static int cap_unix_may_send(struct socket *sock, struct socket *other)
{
return 0;
}
static int cap_socket_create(int family, int type, int protocol, int kern)
{
return 0;
}
static int cap_socket_post_create(struct socket *sock, int family, int type,
int protocol, int kern)
{
return 0;
}
static int cap_socket_bind(struct socket *sock, struct sockaddr *address,
int addrlen)
{
return 0;
}
static int cap_socket_connect(struct socket *sock, struct sockaddr *address,
int addrlen)
{
return 0;
}
static int cap_socket_listen(struct socket *sock, int backlog)
{
return 0;
}
static int cap_socket_accept(struct socket *sock, struct socket *newsock)
{
return 0;
}
static void cap_socket_post_accept(struct socket *sock, struct socket *newsock)
{
}
static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
{
return 0;
}
static int cap_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags)
{
return 0;
}
static int cap_socket_getsockname(struct socket *sock)
{
return 0;
}
static int cap_socket_getpeername(struct socket *sock)
{
return 0;
}
static int cap_socket_setsockopt(struct socket *sock, int level, int optname)
{
return 0;
}
static int cap_socket_getsockopt(struct socket *sock, int level, int optname)
{
return 0;
}
static int cap_socket_shutdown(struct socket *sock, int how)
{
return 0;
}
static int cap_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
return 0;
}
static int cap_socket_getpeersec_stream(struct socket *sock,
char __user *optval,
int __user *optlen, unsigned len)
{
return -ENOPROTOOPT;
}
static int cap_socket_getpeersec_dgram(struct socket *sock,
struct sk_buff *skb, u32 *secid)
{
return -ENOPROTOOPT;
}
static int cap_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
{
return 0;
}
static void cap_sk_free_security(struct sock *sk)
{
}
static void cap_sk_clone_security(const struct sock *sk, struct sock *newsk)
{
}
static void cap_sk_getsecid(struct sock *sk, u32 *secid)
{
}
static void cap_sock_graft(struct sock *sk, struct socket *parent)
{
}
static int cap_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct request_sock *req)
{
return 0;
}
static void cap_inet_csk_clone(struct sock *newsk,
const struct request_sock *req)
{
}
static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb)
{
}
static void cap_req_classify_flow(const struct request_sock *req,
struct flowi *fl)
{
}
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
static int cap_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *sec_ctx)
{
return 0;
}
static int cap_xfrm_policy_clone_security(struct xfrm_sec_ctx *old_ctx,
struct xfrm_sec_ctx **new_ctxp)
{
return 0;
}
static void cap_xfrm_policy_free_security(struct xfrm_sec_ctx *ctx)
{
}
static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx)
{
return 0;
}
static int cap_xfrm_state_alloc_security(struct xfrm_state *x,
struct xfrm_user_sec_ctx *sec_ctx,
u32 secid)
{
return 0;
}
static void cap_xfrm_state_free_security(struct xfrm_state *x)
{
}
static int cap_xfrm_state_delete_security(struct xfrm_state *x)
{
return 0;
}
static int cap_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 sk_sid, u8 dir)
{
return 0;
}
static int cap_xfrm_state_pol_flow_match(struct xfrm_state *x,
struct xfrm_policy *xp,
struct flowi *fl)
{
return 1;
}
static int cap_xfrm_decode_session(struct sk_buff *skb, u32 *fl, int ckall)
{
return 0;
}
#endif /* CONFIG_SECURITY_NETWORK_XFRM */
static void cap_d_instantiate(struct dentry *dentry, struct inode *inode)
{
}
static int cap_getprocattr(struct task_struct *p, char *name, char **value)
{
return -EINVAL;
}
static int cap_setprocattr(struct task_struct *p, char *name, void *value,
size_t size)
{
return -EINVAL;
}
static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
return -EOPNOTSUPP;
}
static int cap_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
return -EOPNOTSUPP;
}
static void cap_release_secctx(char *secdata, u32 seclen)
{
}
#ifdef CONFIG_KEYS
static int cap_key_alloc(struct key *key, struct task_struct *ctx,
unsigned long flags)
{
return 0;
}
static void cap_key_free(struct key *key)
{
}
static int cap_key_permission(key_ref_t key_ref, struct task_struct *context,
key_perm_t perm)
{
return 0;
}
static int cap_key_getsecurity(struct key *key, char **_buffer)
{
*_buffer = NULL;
return 0;
}
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
static int cap_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
{
return 0;
}
static int cap_audit_rule_known(struct audit_krule *krule)
{
return 0;
}
static int cap_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
struct audit_context *actx)
{
return 0;
}
static void cap_audit_rule_free(void *lsmrule)
{
}
#endif /* CONFIG_AUDIT */
struct security_operations default_security_ops = {
.name = "default",
};
#define set_to_cap_if_null(ops, function) \
do { \
if (!ops->function) { \
ops->function = cap_##function; \
pr_debug("Had to override the " #function \
" security operation with the default.\n");\
} \
} while (0)
void security_fixup_ops(struct security_operations *ops)
{
set_to_cap_if_null(ops, ptrace);
set_to_cap_if_null(ops, capget);
set_to_cap_if_null(ops, capset_check);
set_to_cap_if_null(ops, capset_set);
set_to_cap_if_null(ops, acct);
set_to_cap_if_null(ops, capable);
set_to_cap_if_null(ops, quotactl);
set_to_cap_if_null(ops, quota_on);
set_to_cap_if_null(ops, sysctl);
set_to_cap_if_null(ops, syslog);
set_to_cap_if_null(ops, settime);
set_to_cap_if_null(ops, vm_enough_memory);
set_to_cap_if_null(ops, bprm_alloc_security);
set_to_cap_if_null(ops, bprm_free_security);
set_to_cap_if_null(ops, bprm_apply_creds);
set_to_cap_if_null(ops, bprm_post_apply_creds);
set_to_cap_if_null(ops, bprm_set_security);
set_to_cap_if_null(ops, bprm_check_security);
set_to_cap_if_null(ops, bprm_secureexec);
set_to_cap_if_null(ops, sb_alloc_security);
set_to_cap_if_null(ops, sb_free_security);
set_to_cap_if_null(ops, sb_copy_data);
set_to_cap_if_null(ops, sb_kern_mount);
set_to_cap_if_null(ops, sb_show_options);
set_to_cap_if_null(ops, sb_statfs);
set_to_cap_if_null(ops, sb_mount);
set_to_cap_if_null(ops, sb_check_sb);
set_to_cap_if_null(ops, sb_umount);
set_to_cap_if_null(ops, sb_umount_close);
set_to_cap_if_null(ops, sb_umount_busy);
set_to_cap_if_null(ops, sb_post_remount);
set_to_cap_if_null(ops, sb_post_addmount);
set_to_cap_if_null(ops, sb_pivotroot);
set_to_cap_if_null(ops, sb_post_pivotroot);
set_to_cap_if_null(ops, sb_set_mnt_opts);
set_to_cap_if_null(ops, sb_clone_mnt_opts);
set_to_cap_if_null(ops, sb_parse_opts_str);
set_to_cap_if_null(ops, inode_alloc_security);
set_to_cap_if_null(ops, inode_free_security);
set_to_cap_if_null(ops, inode_init_security);
set_to_cap_if_null(ops, inode_create);
set_to_cap_if_null(ops, inode_link);
set_to_cap_if_null(ops, inode_unlink);
set_to_cap_if_null(ops, inode_symlink);
set_to_cap_if_null(ops, inode_mkdir);
set_to_cap_if_null(ops, inode_rmdir);
set_to_cap_if_null(ops, inode_mknod);
set_to_cap_if_null(ops, inode_rename);
set_to_cap_if_null(ops, inode_readlink);
set_to_cap_if_null(ops, inode_follow_link);
set_to_cap_if_null(ops, inode_permission);
set_to_cap_if_null(ops, inode_setattr);
set_to_cap_if_null(ops, inode_getattr);
set_to_cap_if_null(ops, inode_delete);
set_to_cap_if_null(ops, inode_setxattr);
set_to_cap_if_null(ops, inode_post_setxattr);
set_to_cap_if_null(ops, inode_getxattr);
set_to_cap_if_null(ops, inode_listxattr);
set_to_cap_if_null(ops, inode_removexattr);
set_to_cap_if_null(ops, inode_need_killpriv);
set_to_cap_if_null(ops, inode_killpriv);
set_to_cap_if_null(ops, inode_getsecurity);
set_to_cap_if_null(ops, inode_setsecurity);
set_to_cap_if_null(ops, inode_listsecurity);
set_to_cap_if_null(ops, inode_getsecid);
set_to_cap_if_null(ops, file_permission);
set_to_cap_if_null(ops, file_alloc_security);
set_to_cap_if_null(ops, file_free_security);
set_to_cap_if_null(ops, file_ioctl);
set_to_cap_if_null(ops, file_mmap);
set_to_cap_if_null(ops, file_mprotect);
set_to_cap_if_null(ops, file_lock);
set_to_cap_if_null(ops, file_fcntl);
set_to_cap_if_null(ops, file_set_fowner);
set_to_cap_if_null(ops, file_send_sigiotask);
set_to_cap_if_null(ops, file_receive);
set_to_cap_if_null(ops, dentry_open);
set_to_cap_if_null(ops, task_create);
set_to_cap_if_null(ops, task_alloc_security);
set_to_cap_if_null(ops, task_free_security);
set_to_cap_if_null(ops, task_setuid);
set_to_cap_if_null(ops, task_post_setuid);
set_to_cap_if_null(ops, task_setgid);
set_to_cap_if_null(ops, task_setpgid);
set_to_cap_if_null(ops, task_getpgid);
set_to_cap_if_null(ops, task_getsid);
set_to_cap_if_null(ops, task_getsecid);
set_to_cap_if_null(ops, task_setgroups);
set_to_cap_if_null(ops, task_setnice);
set_to_cap_if_null(ops, task_setioprio);
set_to_cap_if_null(ops, task_getioprio);
set_to_cap_if_null(ops, task_setrlimit);
set_to_cap_if_null(ops, task_setscheduler);
set_to_cap_if_null(ops, task_getscheduler);
set_to_cap_if_null(ops, task_movememory);
set_to_cap_if_null(ops, task_wait);
set_to_cap_if_null(ops, task_kill);
set_to_cap_if_null(ops, task_prctl);
set_to_cap_if_null(ops, task_reparent_to_init);
set_to_cap_if_null(ops, task_to_inode);
set_to_cap_if_null(ops, ipc_permission);
set_to_cap_if_null(ops, ipc_getsecid);
set_to_cap_if_null(ops, msg_msg_alloc_security);
set_to_cap_if_null(ops, msg_msg_free_security);
set_to_cap_if_null(ops, msg_queue_alloc_security);
set_to_cap_if_null(ops, msg_queue_free_security);
set_to_cap_if_null(ops, msg_queue_associate);
set_to_cap_if_null(ops, msg_queue_msgctl);
set_to_cap_if_null(ops, msg_queue_msgsnd);
set_to_cap_if_null(ops, msg_queue_msgrcv);
set_to_cap_if_null(ops, shm_alloc_security);
set_to_cap_if_null(ops, shm_free_security);
set_to_cap_if_null(ops, shm_associate);
set_to_cap_if_null(ops, shm_shmctl);
set_to_cap_if_null(ops, shm_shmat);
set_to_cap_if_null(ops, sem_alloc_security);
set_to_cap_if_null(ops, sem_free_security);
set_to_cap_if_null(ops, sem_associate);
set_to_cap_if_null(ops, sem_semctl);
set_to_cap_if_null(ops, sem_semop);
set_to_cap_if_null(ops, netlink_send);
set_to_cap_if_null(ops, netlink_recv);
set_to_cap_if_null(ops, d_instantiate);
set_to_cap_if_null(ops, getprocattr);
set_to_cap_if_null(ops, setprocattr);
set_to_cap_if_null(ops, secid_to_secctx);
set_to_cap_if_null(ops, secctx_to_secid);
set_to_cap_if_null(ops, release_secctx);
#ifdef CONFIG_SECURITY_NETWORK
set_to_cap_if_null(ops, unix_stream_connect);
set_to_cap_if_null(ops, unix_may_send);
set_to_cap_if_null(ops, socket_create);
set_to_cap_if_null(ops, socket_post_create);
set_to_cap_if_null(ops, socket_bind);
set_to_cap_if_null(ops, socket_connect);
set_to_cap_if_null(ops, socket_listen);
set_to_cap_if_null(ops, socket_accept);
set_to_cap_if_null(ops, socket_post_accept);
set_to_cap_if_null(ops, socket_sendmsg);
set_to_cap_if_null(ops, socket_recvmsg);
set_to_cap_if_null(ops, socket_getsockname);
set_to_cap_if_null(ops, socket_getpeername);
set_to_cap_if_null(ops, socket_setsockopt);
set_to_cap_if_null(ops, socket_getsockopt);
set_to_cap_if_null(ops, socket_shutdown);
set_to_cap_if_null(ops, socket_sock_rcv_skb);
set_to_cap_if_null(ops, socket_getpeersec_stream);
set_to_cap_if_null(ops, socket_getpeersec_dgram);
set_to_cap_if_null(ops, sk_alloc_security);
set_to_cap_if_null(ops, sk_free_security);
set_to_cap_if_null(ops, sk_clone_security);
set_to_cap_if_null(ops, sk_getsecid);
set_to_cap_if_null(ops, sock_graft);
set_to_cap_if_null(ops, inet_conn_request);
set_to_cap_if_null(ops, inet_csk_clone);
set_to_cap_if_null(ops, inet_conn_established);
set_to_cap_if_null(ops, req_classify_flow);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
set_to_cap_if_null(ops, xfrm_policy_alloc_security);
set_to_cap_if_null(ops, xfrm_policy_clone_security);
set_to_cap_if_null(ops, xfrm_policy_free_security);
set_to_cap_if_null(ops, xfrm_policy_delete_security);
set_to_cap_if_null(ops, xfrm_state_alloc_security);
set_to_cap_if_null(ops, xfrm_state_free_security);
set_to_cap_if_null(ops, xfrm_state_delete_security);
set_to_cap_if_null(ops, xfrm_policy_lookup);
set_to_cap_if_null(ops, xfrm_state_pol_flow_match);
set_to_cap_if_null(ops, xfrm_decode_session);
#endif /* CONFIG_SECURITY_NETWORK_XFRM */
#ifdef CONFIG_KEYS
set_to_cap_if_null(ops, key_alloc);
set_to_cap_if_null(ops, key_free);
set_to_cap_if_null(ops, key_permission);
set_to_cap_if_null(ops, key_getsecurity);
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
set_to_cap_if_null(ops, audit_rule_init);
set_to_cap_if_null(ops, audit_rule_known);
set_to_cap_if_null(ops, audit_rule_match);
set_to_cap_if_null(ops, audit_rule_free);
#endif
}
......@@ -63,7 +63,8 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
return 0;
}
int cap_ptrace (struct task_struct *parent, struct task_struct *child)
int cap_ptrace (struct task_struct *parent, struct task_struct *child,
unsigned int mode)
{
/* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
if (!cap_issubset(child->cap_permitted, parent->cap_permitted) &&
......
/*
* Stub functions for the default security function pointers in case no
* security model is loaded.
*
* Copyright (C) 2001 WireX Communications, Inc <chris@wirex.com>
* Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#undef DEBUG
#include <linux/capability.h>
#include <linux/kernel.h>
#include <linux/mman.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
#include <linux/security.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <net/sock.h>
#include <linux/xattr.h>
#include <linux/hugetlb.h>
#include <linux/ptrace.h>
#include <linux/file.h>
#include <linux/prctl.h>
#include <linux/securebits.h>
static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
{
return 0;
}
static int dummy_capget (struct task_struct *target, kernel_cap_t * effective,
kernel_cap_t * inheritable, kernel_cap_t * permitted)
{
if (target->euid == 0) {
cap_set_full(*permitted);
cap_set_init_eff(*effective);
} else {
cap_clear(*permitted);
cap_clear(*effective);
}
cap_clear(*inheritable);
if (target->fsuid != 0) {
*permitted = cap_drop_fs_set(*permitted);
*effective = cap_drop_fs_set(*effective);
}
return 0;
}
static int dummy_capset_check (struct task_struct *target,
kernel_cap_t * effective,
kernel_cap_t * inheritable,
kernel_cap_t * permitted)
{
return -EPERM;
}
static void dummy_capset_set (struct task_struct *target,
kernel_cap_t * effective,
kernel_cap_t * inheritable,
kernel_cap_t * permitted)
{
return;
}
static int dummy_acct (struct file *file)
{
return 0;
}
static int dummy_capable (struct task_struct *tsk, int cap)
{
if (cap_raised (tsk->cap_effective, cap))
return 0;
return -EPERM;
}
static int dummy_sysctl (ctl_table * table, int op)
{
return 0;
}
static int dummy_quotactl (int cmds, int type, int id, struct super_block *sb)
{
return 0;
}
static int dummy_quota_on (struct dentry *dentry)
{
return 0;
}
static int dummy_syslog (int type)
{
if ((type != 3 && type != 10) && current->euid)
return -EPERM;
return 0;
}
static int dummy_settime(struct timespec *ts, struct timezone *tz)
{
if (!capable(CAP_SYS_TIME))
return -EPERM;
return 0;
}
static int dummy_vm_enough_memory(struct mm_struct *mm, long pages)
{
int cap_sys_admin = 0;
if (dummy_capable(current, CAP_SYS_ADMIN) == 0)
cap_sys_admin = 1;
return __vm_enough_memory(mm, pages, cap_sys_admin);
}
static int dummy_bprm_alloc_security (struct linux_binprm *bprm)
{
return 0;
}
static void dummy_bprm_free_security (struct linux_binprm *bprm)
{
return;
}
static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
set_dumpable(current->mm, suid_dumpable);
if ((unsafe & ~LSM_UNSAFE_PTRACE_CAP) && !capable(CAP_SETUID)) {
bprm->e_uid = current->uid;
bprm->e_gid = current->gid;
}
}
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;
dummy_capget(current, &current->cap_effective, &current->cap_inheritable, &current->cap_permitted);
}
static void dummy_bprm_post_apply_creds (struct linux_binprm *bprm)
{
return;
}
static int dummy_bprm_set_security (struct linux_binprm *bprm)
{
return 0;
}
static int dummy_bprm_check_security (struct linux_binprm *bprm)
{
return 0;
}
static int dummy_bprm_secureexec (struct linux_binprm *bprm)
{
/* The new userland will simply use the value provided
in the AT_SECURE field to decide whether secure mode
is required. Hence, this logic is required to preserve
the legacy decision algorithm used by the old userland. */
return (current->euid != current->uid ||
current->egid != current->gid);
}
static int dummy_sb_alloc_security (struct super_block *sb)
{
return 0;
}
static void dummy_sb_free_security (struct super_block *sb)
{
return;
}
static int dummy_sb_copy_data (char *orig, char *copy)
{
return 0;
}
static int dummy_sb_kern_mount (struct super_block *sb, void *data)
{
return 0;
}
static int dummy_sb_statfs (struct dentry *dentry)
{
return 0;
}
static int dummy_sb_mount (char *dev_name, struct path *path, char *type,
unsigned long flags, void *data)
{
return 0;
}
static int dummy_sb_check_sb (struct vfsmount *mnt, struct path *path)
{
return 0;
}
static int dummy_sb_umount (struct vfsmount *mnt, int flags)
{
return 0;
}
static void dummy_sb_umount_close (struct vfsmount *mnt)
{
return;
}
static void dummy_sb_umount_busy (struct vfsmount *mnt)
{
return;
}
static void dummy_sb_post_remount (struct vfsmount *mnt, unsigned long flags,
void *data)
{
return;
}
static void dummy_sb_post_addmount (struct vfsmount *mnt, struct path *path)
{
return;
}
static int dummy_sb_pivotroot (struct path *old_path, struct path *new_path)
{
return 0;
}
static void dummy_sb_post_pivotroot (struct path *old_path, struct path *new_path)
{
return;
}
static int dummy_sb_get_mnt_opts(const struct super_block *sb,
struct security_mnt_opts *opts)
{
security_init_mnt_opts(opts);
return 0;
}
static int dummy_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts)
{
if (unlikely(opts->num_mnt_opts))
return -EOPNOTSUPP;
return 0;
}
static void dummy_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb)
{
return;
}
static int dummy_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
{
return 0;
}
static int dummy_inode_alloc_security (struct inode *inode)
{
return 0;
}
static void dummy_inode_free_security (struct inode *inode)
{
return;
}
static int dummy_inode_init_security (struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len)
{
return -EOPNOTSUPP;
}
static int dummy_inode_create (struct inode *inode, struct dentry *dentry,
int mask)
{
return 0;
}
static int dummy_inode_link (struct dentry *old_dentry, struct inode *inode,
struct dentry *new_dentry)
{
return 0;
}
static int dummy_inode_unlink (struct inode *inode, struct dentry *dentry)
{
return 0;
}
static int dummy_inode_symlink (struct inode *inode, struct dentry *dentry,
const char *name)
{
return 0;
}
static int dummy_inode_mkdir (struct inode *inode, struct dentry *dentry,
int mask)
{
return 0;
}
static int dummy_inode_rmdir (struct inode *inode, struct dentry *dentry)
{
return 0;
}
static int dummy_inode_mknod (struct inode *inode, struct dentry *dentry,
int mode, dev_t dev)
{
return 0;
}
static int dummy_inode_rename (struct inode *old_inode,
struct dentry *old_dentry,
struct inode *new_inode,
struct dentry *new_dentry)
{
return 0;
}
static int dummy_inode_readlink (struct dentry *dentry)
{
return 0;
}
static int dummy_inode_follow_link (struct dentry *dentry,
struct nameidata *nameidata)
{
return 0;
}
static int dummy_inode_permission (struct inode *inode, int mask, struct nameidata *nd)
{
return 0;
}
static int dummy_inode_setattr (struct dentry *dentry, struct iattr *iattr)
{
return 0;
}
static int dummy_inode_getattr (struct vfsmount *mnt, struct dentry *dentry)
{
return 0;
}
static void dummy_inode_delete (struct inode *ino)
{
return;
}
static int dummy_inode_setxattr (struct dentry *dentry, const char *name,
const 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;
}
static void dummy_inode_post_setxattr (struct dentry *dentry, const char *name,
const void *value, size_t size,
int flags)
{
}
static int dummy_inode_getxattr (struct dentry *dentry, const char *name)
{
return 0;
}
static int dummy_inode_listxattr (struct dentry *dentry)
{
return 0;
}
static int dummy_inode_removexattr (struct dentry *dentry, const char *name)
{
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
!capable(CAP_SYS_ADMIN))
return -EPERM;
return 0;
}
static int dummy_inode_need_killpriv(struct dentry *dentry)
{
return 0;
}
static int dummy_inode_killpriv(struct dentry *dentry)
{
return 0;
}
static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
return -EOPNOTSUPP;
}
static int dummy_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
{
return -EOPNOTSUPP;
}
static int dummy_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
{
return 0;
}
static void dummy_inode_getsecid(const struct inode *inode, u32 *secid)
{
*secid = 0;
}
static int dummy_file_permission (struct file *file, int mask)
{
return 0;
}
static int dummy_file_alloc_security (struct file *file)
{
return 0;
}
static void dummy_file_free_security (struct file *file)
{
return;
}
static int dummy_file_ioctl (struct file *file, unsigned int command,
unsigned long arg)
{
return 0;
}
static int dummy_file_mmap (struct file *file, unsigned long reqprot,
unsigned long prot,
unsigned long flags,
unsigned long addr,
unsigned long addr_only)
{
if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
return -EACCES;
return 0;
}
static int dummy_file_mprotect (struct vm_area_struct *vma,
unsigned long reqprot,
unsigned long prot)
{
return 0;
}
static int dummy_file_lock (struct file *file, unsigned int cmd)
{
return 0;
}
static int dummy_file_fcntl (struct file *file, unsigned int cmd,
unsigned long arg)
{
return 0;
}
static int dummy_file_set_fowner (struct file *file)
{
return 0;
}
static int dummy_file_send_sigiotask (struct task_struct *tsk,
struct fown_struct *fown, int sig)
{
return 0;
}
static int dummy_file_receive (struct file *file)
{
return 0;
}
static int dummy_dentry_open (struct file *file)
{
return 0;
}
static int dummy_task_create (unsigned long clone_flags)
{
return 0;
}
static int dummy_task_alloc_security (struct task_struct *p)
{
return 0;
}
static void dummy_task_free_security (struct task_struct *p)
{
return;
}
static int dummy_task_setuid (uid_t id0, uid_t id1, uid_t id2, int flags)
{
return 0;
}
static int dummy_task_post_setuid (uid_t id0, uid_t id1, uid_t id2, int flags)
{
dummy_capget(current, &current->cap_effective, &current->cap_inheritable, &current->cap_permitted);
return 0;
}
static int dummy_task_setgid (gid_t id0, gid_t id1, gid_t id2, int flags)
{
return 0;
}
static int dummy_task_setpgid (struct task_struct *p, pid_t pgid)
{
return 0;
}
static int dummy_task_getpgid (struct task_struct *p)
{
return 0;
}
static int dummy_task_getsid (struct task_struct *p)
{
return 0;
}
static void dummy_task_getsecid (struct task_struct *p, u32 *secid)
{
*secid = 0;
}
static int dummy_task_setgroups (struct group_info *group_info)
{
return 0;
}
static int dummy_task_setnice (struct task_struct *p, int nice)
{
return 0;
}
static int dummy_task_setioprio (struct task_struct *p, int ioprio)
{
return 0;
}
static int dummy_task_getioprio (struct task_struct *p)
{
return 0;
}
static int dummy_task_setrlimit (unsigned int resource, struct rlimit *new_rlim)
{
return 0;
}
static int dummy_task_setscheduler (struct task_struct *p, int policy,
struct sched_param *lp)
{
return 0;
}
static int dummy_task_getscheduler (struct task_struct *p)
{
return 0;
}
static int dummy_task_movememory (struct task_struct *p)
{
return 0;
}
static int dummy_task_wait (struct task_struct *p)
{
return 0;
}
static int dummy_task_kill (struct task_struct *p, struct siginfo *info,
int sig, u32 secid)
{
return 0;
}
static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5, long *rc_p)
{
switch (option) {
case PR_CAPBSET_READ:
*rc_p = (cap_valid(arg2) ? 1 : -EINVAL);
break;
case PR_GET_KEEPCAPS:
*rc_p = issecure(SECURE_KEEP_CAPS);
break;
case PR_SET_KEEPCAPS:
if (arg2 > 1)
*rc_p = -EINVAL;
else if (arg2)
current->securebits |= issecure_mask(SECURE_KEEP_CAPS);
else
current->securebits &=
~issecure_mask(SECURE_KEEP_CAPS);
break;
default:
return 0;
}
return 1;
}
static void dummy_task_reparent_to_init (struct task_struct *p)
{
p->euid = p->fsuid = 0;
return;
}
static void dummy_task_to_inode(struct task_struct *p, struct inode *inode)
{ }
static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
{
return 0;
}
static void dummy_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
{
*secid = 0;
}
static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
{
return 0;
}
static void dummy_msg_msg_free_security (struct msg_msg *msg)
{
return;
}
static int dummy_msg_queue_alloc_security (struct msg_queue *msq)
{
return 0;
}
static void dummy_msg_queue_free_security (struct msg_queue *msq)
{
return;
}
static int dummy_msg_queue_associate (struct msg_queue *msq,
int msqflg)
{
return 0;
}
static int dummy_msg_queue_msgctl (struct msg_queue *msq, int cmd)
{
return 0;
}
static int dummy_msg_queue_msgsnd (struct msg_queue *msq, struct msg_msg *msg,
int msgflg)
{
return 0;
}
static int dummy_msg_queue_msgrcv (struct msg_queue *msq, struct msg_msg *msg,
struct task_struct *target, long type,
int mode)
{
return 0;
}
static int dummy_shm_alloc_security (struct shmid_kernel *shp)
{
return 0;
}
static void dummy_shm_free_security (struct shmid_kernel *shp)
{
return;
}
static int dummy_shm_associate (struct shmid_kernel *shp, int shmflg)
{
return 0;
}
static int dummy_shm_shmctl (struct shmid_kernel *shp, int cmd)
{
return 0;
}
static int dummy_shm_shmat (struct shmid_kernel *shp, char __user *shmaddr,
int shmflg)
{
return 0;
}
static int dummy_sem_alloc_security (struct sem_array *sma)
{
return 0;
}
static void dummy_sem_free_security (struct sem_array *sma)
{
return;
}
static int dummy_sem_associate (struct sem_array *sma, int semflg)
{
return 0;
}
static int dummy_sem_semctl (struct sem_array *sma, int cmd)
{
return 0;
}
static int dummy_sem_semop (struct sem_array *sma,
struct sembuf *sops, unsigned nsops, int alter)
{
return 0;
}
static int dummy_netlink_send (struct sock *sk, struct sk_buff *skb)
{
NETLINK_CB(skb).eff_cap = current->cap_effective;
return 0;
}
static int dummy_netlink_recv (struct sk_buff *skb, int cap)
{
if (!cap_raised (NETLINK_CB (skb).eff_cap, cap))
return -EPERM;
return 0;
}
#ifdef CONFIG_SECURITY_NETWORK
static int dummy_unix_stream_connect (struct socket *sock,
struct socket *other,
struct sock *newsk)
{
return 0;
}
static int dummy_unix_may_send (struct socket *sock,
struct socket *other)
{
return 0;
}
static int dummy_socket_create (int family, int type,
int protocol, int kern)
{
return 0;
}
static int dummy_socket_post_create (struct socket *sock, int family, int type,
int protocol, int kern)
{
return 0;
}
static int dummy_socket_bind (struct socket *sock, struct sockaddr *address,
int addrlen)
{
return 0;
}
static int dummy_socket_connect (struct socket *sock, struct sockaddr *address,
int addrlen)
{
return 0;
}
static int dummy_socket_listen (struct socket *sock, int backlog)
{
return 0;
}
static int dummy_socket_accept (struct socket *sock, struct socket *newsock)
{
return 0;
}
static void dummy_socket_post_accept (struct socket *sock,
struct socket *newsock)
{
return;
}
static int dummy_socket_sendmsg (struct socket *sock, struct msghdr *msg,
int size)
{
return 0;
}
static int dummy_socket_recvmsg (struct socket *sock, struct msghdr *msg,
int size, int flags)
{
return 0;
}
static int dummy_socket_getsockname (struct socket *sock)
{
return 0;
}
static int dummy_socket_getpeername (struct socket *sock)
{
return 0;
}
static int dummy_socket_setsockopt (struct socket *sock, int level, int optname)
{
return 0;
}
static int dummy_socket_getsockopt (struct socket *sock, int level, int optname)
{
return 0;
}
static int dummy_socket_shutdown (struct socket *sock, int how)
{
return 0;
}
static int dummy_socket_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
{
return 0;
}
static int dummy_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
{
return -ENOPROTOOPT;
}
static int dummy_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
{
return -ENOPROTOOPT;
}
static inline int dummy_sk_alloc_security (struct sock *sk, int family, gfp_t priority)
{
return 0;
}
static inline void dummy_sk_free_security (struct sock *sk)
{
}
static inline void dummy_sk_clone_security (const struct sock *sk, struct sock *newsk)
{
}
static inline void dummy_sk_getsecid(struct sock *sk, u32 *secid)
{
}
static inline void dummy_sock_graft(struct sock* sk, struct socket *parent)
{
}
static inline int dummy_inet_conn_request(struct sock *sk,
struct sk_buff *skb, struct request_sock *req)
{
return 0;
}
static inline void dummy_inet_csk_clone(struct sock *newsk,
const struct request_sock *req)
{
}
static inline void dummy_inet_conn_established(struct sock *sk,
struct sk_buff *skb)
{
}
static inline void dummy_req_classify_flow(const struct request_sock *req,
struct flowi *fl)
{
}
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
static int dummy_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *sec_ctx)
{
return 0;
}
static inline int dummy_xfrm_policy_clone_security(struct xfrm_sec_ctx *old_ctx,
struct xfrm_sec_ctx **new_ctxp)
{
return 0;
}
static void dummy_xfrm_policy_free_security(struct xfrm_sec_ctx *ctx)
{
}
static int dummy_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx)
{
return 0;
}
static int dummy_xfrm_state_alloc_security(struct xfrm_state *x,
struct xfrm_user_sec_ctx *sec_ctx, u32 secid)
{
return 0;
}
static void dummy_xfrm_state_free_security(struct xfrm_state *x)
{
}
static int dummy_xfrm_state_delete_security(struct xfrm_state *x)
{
return 0;
}
static int dummy_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx,
u32 sk_sid, u8 dir)
{
return 0;
}
static int dummy_xfrm_state_pol_flow_match(struct xfrm_state *x,
struct xfrm_policy *xp, struct flowi *fl)
{
return 1;
}
static int dummy_xfrm_decode_session(struct sk_buff *skb, u32 *fl, int ckall)
{
return 0;
}
#endif /* CONFIG_SECURITY_NETWORK_XFRM */
static int dummy_register_security (const char *name, struct security_operations *ops)
{
return -EINVAL;
}
static void dummy_d_instantiate (struct dentry *dentry, struct inode *inode)
{
return;
}
static int dummy_getprocattr(struct task_struct *p, char *name, char **value)
{
return -EINVAL;
}
static int dummy_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
{
return -EINVAL;
}
static int dummy_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
return -EOPNOTSUPP;
}
static int dummy_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
return -EOPNOTSUPP;
}
static void dummy_release_secctx(char *secdata, u32 seclen)
{
}
#ifdef CONFIG_KEYS
static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx,
unsigned long flags)
{
return 0;
}
static inline void dummy_key_free(struct key *key)
{
}
static inline int dummy_key_permission(key_ref_t key_ref,
struct task_struct *context,
key_perm_t perm)
{
return 0;
}
static int dummy_key_getsecurity(struct key *key, char **_buffer)
{
*_buffer = NULL;
return 0;
}
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
static inline int dummy_audit_rule_init(u32 field, u32 op, char *rulestr,
void **lsmrule)
{
return 0;
}
static inline int dummy_audit_rule_known(struct audit_krule *krule)
{
return 0;
}
static inline int dummy_audit_rule_match(u32 secid, u32 field, u32 op,
void *lsmrule,
struct audit_context *actx)
{
return 0;
}
static inline void dummy_audit_rule_free(void *lsmrule)
{ }
#endif /* CONFIG_AUDIT */
struct security_operations dummy_security_ops = {
.name = "dummy",
};
#define set_to_dummy_if_null(ops, function) \
do { \
if (!ops->function) { \
ops->function = dummy_##function; \
pr_debug("Had to override the " #function \
" security operation with the dummy one.\n");\
} \
} while (0)
void security_fixup_ops (struct security_operations *ops)
{
set_to_dummy_if_null(ops, ptrace);
set_to_dummy_if_null(ops, capget);
set_to_dummy_if_null(ops, capset_check);
set_to_dummy_if_null(ops, capset_set);
set_to_dummy_if_null(ops, acct);
set_to_dummy_if_null(ops, capable);
set_to_dummy_if_null(ops, quotactl);
set_to_dummy_if_null(ops, quota_on);
set_to_dummy_if_null(ops, sysctl);
set_to_dummy_if_null(ops, syslog);
set_to_dummy_if_null(ops, settime);
set_to_dummy_if_null(ops, vm_enough_memory);
set_to_dummy_if_null(ops, bprm_alloc_security);
set_to_dummy_if_null(ops, bprm_free_security);
set_to_dummy_if_null(ops, bprm_apply_creds);
set_to_dummy_if_null(ops, bprm_post_apply_creds);
set_to_dummy_if_null(ops, bprm_set_security);
set_to_dummy_if_null(ops, bprm_check_security);
set_to_dummy_if_null(ops, bprm_secureexec);
set_to_dummy_if_null(ops, sb_alloc_security);
set_to_dummy_if_null(ops, sb_free_security);
set_to_dummy_if_null(ops, sb_copy_data);
set_to_dummy_if_null(ops, sb_kern_mount);
set_to_dummy_if_null(ops, sb_statfs);
set_to_dummy_if_null(ops, sb_mount);
set_to_dummy_if_null(ops, sb_check_sb);
set_to_dummy_if_null(ops, sb_umount);
set_to_dummy_if_null(ops, sb_umount_close);
set_to_dummy_if_null(ops, sb_umount_busy);
set_to_dummy_if_null(ops, sb_post_remount);
set_to_dummy_if_null(ops, sb_post_addmount);
set_to_dummy_if_null(ops, sb_pivotroot);
set_to_dummy_if_null(ops, sb_post_pivotroot);
set_to_dummy_if_null(ops, sb_get_mnt_opts);
set_to_dummy_if_null(ops, sb_set_mnt_opts);
set_to_dummy_if_null(ops, sb_clone_mnt_opts);
set_to_dummy_if_null(ops, sb_parse_opts_str);
set_to_dummy_if_null(ops, inode_alloc_security);
set_to_dummy_if_null(ops, inode_free_security);
set_to_dummy_if_null(ops, inode_init_security);
set_to_dummy_if_null(ops, inode_create);
set_to_dummy_if_null(ops, inode_link);
set_to_dummy_if_null(ops, inode_unlink);
set_to_dummy_if_null(ops, inode_symlink);
set_to_dummy_if_null(ops, inode_mkdir);
set_to_dummy_if_null(ops, inode_rmdir);
set_to_dummy_if_null(ops, inode_mknod);
set_to_dummy_if_null(ops, inode_rename);
set_to_dummy_if_null(ops, inode_readlink);
set_to_dummy_if_null(ops, inode_follow_link);
set_to_dummy_if_null(ops, inode_permission);
set_to_dummy_if_null(ops, inode_setattr);
set_to_dummy_if_null(ops, inode_getattr);
set_to_dummy_if_null(ops, inode_delete);
set_to_dummy_if_null(ops, inode_setxattr);
set_to_dummy_if_null(ops, inode_post_setxattr);
set_to_dummy_if_null(ops, inode_getxattr);
set_to_dummy_if_null(ops, inode_listxattr);
set_to_dummy_if_null(ops, inode_removexattr);
set_to_dummy_if_null(ops, inode_need_killpriv);
set_to_dummy_if_null(ops, inode_killpriv);
set_to_dummy_if_null(ops, inode_getsecurity);
set_to_dummy_if_null(ops, inode_setsecurity);
set_to_dummy_if_null(ops, inode_listsecurity);
set_to_dummy_if_null(ops, inode_getsecid);
set_to_dummy_if_null(ops, file_permission);
set_to_dummy_if_null(ops, file_alloc_security);
set_to_dummy_if_null(ops, file_free_security);
set_to_dummy_if_null(ops, file_ioctl);
set_to_dummy_if_null(ops, file_mmap);
set_to_dummy_if_null(ops, file_mprotect);
set_to_dummy_if_null(ops, file_lock);
set_to_dummy_if_null(ops, file_fcntl);
set_to_dummy_if_null(ops, file_set_fowner);
set_to_dummy_if_null(ops, file_send_sigiotask);
set_to_dummy_if_null(ops, file_receive);
set_to_dummy_if_null(ops, dentry_open);
set_to_dummy_if_null(ops, task_create);
set_to_dummy_if_null(ops, task_alloc_security);
set_to_dummy_if_null(ops, task_free_security);
set_to_dummy_if_null(ops, task_setuid);
set_to_dummy_if_null(ops, task_post_setuid);
set_to_dummy_if_null(ops, task_setgid);
set_to_dummy_if_null(ops, task_setpgid);
set_to_dummy_if_null(ops, task_getpgid);
set_to_dummy_if_null(ops, task_getsid);
set_to_dummy_if_null(ops, task_getsecid);
set_to_dummy_if_null(ops, task_setgroups);
set_to_dummy_if_null(ops, task_setnice);
set_to_dummy_if_null(ops, task_setioprio);
set_to_dummy_if_null(ops, task_getioprio);
set_to_dummy_if_null(ops, task_setrlimit);
set_to_dummy_if_null(ops, task_setscheduler);
set_to_dummy_if_null(ops, task_getscheduler);
set_to_dummy_if_null(ops, task_movememory);
set_to_dummy_if_null(ops, task_wait);
set_to_dummy_if_null(ops, task_kill);
set_to_dummy_if_null(ops, task_prctl);
set_to_dummy_if_null(ops, task_reparent_to_init);
set_to_dummy_if_null(ops, task_to_inode);
set_to_dummy_if_null(ops, ipc_permission);
set_to_dummy_if_null(ops, ipc_getsecid);
set_to_dummy_if_null(ops, msg_msg_alloc_security);
set_to_dummy_if_null(ops, msg_msg_free_security);
set_to_dummy_if_null(ops, msg_queue_alloc_security);
set_to_dummy_if_null(ops, msg_queue_free_security);
set_to_dummy_if_null(ops, msg_queue_associate);
set_to_dummy_if_null(ops, msg_queue_msgctl);
set_to_dummy_if_null(ops, msg_queue_msgsnd);
set_to_dummy_if_null(ops, msg_queue_msgrcv);
set_to_dummy_if_null(ops, shm_alloc_security);
set_to_dummy_if_null(ops, shm_free_security);
set_to_dummy_if_null(ops, shm_associate);
set_to_dummy_if_null(ops, shm_shmctl);
set_to_dummy_if_null(ops, shm_shmat);
set_to_dummy_if_null(ops, sem_alloc_security);
set_to_dummy_if_null(ops, sem_free_security);
set_to_dummy_if_null(ops, sem_associate);
set_to_dummy_if_null(ops, sem_semctl);
set_to_dummy_if_null(ops, sem_semop);
set_to_dummy_if_null(ops, netlink_send);
set_to_dummy_if_null(ops, netlink_recv);
set_to_dummy_if_null(ops, register_security);
set_to_dummy_if_null(ops, d_instantiate);
set_to_dummy_if_null(ops, getprocattr);
set_to_dummy_if_null(ops, setprocattr);
set_to_dummy_if_null(ops, secid_to_secctx);
set_to_dummy_if_null(ops, secctx_to_secid);
set_to_dummy_if_null(ops, release_secctx);
#ifdef CONFIG_SECURITY_NETWORK
set_to_dummy_if_null(ops, unix_stream_connect);
set_to_dummy_if_null(ops, unix_may_send);
set_to_dummy_if_null(ops, socket_create);
set_to_dummy_if_null(ops, socket_post_create);
set_to_dummy_if_null(ops, socket_bind);
set_to_dummy_if_null(ops, socket_connect);
set_to_dummy_if_null(ops, socket_listen);
set_to_dummy_if_null(ops, socket_accept);
set_to_dummy_if_null(ops, socket_post_accept);
set_to_dummy_if_null(ops, socket_sendmsg);
set_to_dummy_if_null(ops, socket_recvmsg);
set_to_dummy_if_null(ops, socket_getsockname);
set_to_dummy_if_null(ops, socket_getpeername);
set_to_dummy_if_null(ops, socket_setsockopt);
set_to_dummy_if_null(ops, socket_getsockopt);
set_to_dummy_if_null(ops, socket_shutdown);
set_to_dummy_if_null(ops, socket_sock_rcv_skb);
set_to_dummy_if_null(ops, socket_getpeersec_stream);
set_to_dummy_if_null(ops, socket_getpeersec_dgram);
set_to_dummy_if_null(ops, sk_alloc_security);
set_to_dummy_if_null(ops, sk_free_security);
set_to_dummy_if_null(ops, sk_clone_security);
set_to_dummy_if_null(ops, sk_getsecid);
set_to_dummy_if_null(ops, sock_graft);
set_to_dummy_if_null(ops, inet_conn_request);
set_to_dummy_if_null(ops, inet_csk_clone);
set_to_dummy_if_null(ops, inet_conn_established);
set_to_dummy_if_null(ops, req_classify_flow);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
set_to_dummy_if_null(ops, xfrm_policy_alloc_security);
set_to_dummy_if_null(ops, xfrm_policy_clone_security);
set_to_dummy_if_null(ops, xfrm_policy_free_security);
set_to_dummy_if_null(ops, xfrm_policy_delete_security);
set_to_dummy_if_null(ops, xfrm_state_alloc_security);
set_to_dummy_if_null(ops, xfrm_state_free_security);
set_to_dummy_if_null(ops, xfrm_state_delete_security);
set_to_dummy_if_null(ops, xfrm_policy_lookup);
set_to_dummy_if_null(ops, xfrm_state_pol_flow_match);
set_to_dummy_if_null(ops, xfrm_decode_session);
#endif /* CONFIG_SECURITY_NETWORK_XFRM */
#ifdef CONFIG_KEYS
set_to_dummy_if_null(ops, key_alloc);
set_to_dummy_if_null(ops, key_free);
set_to_dummy_if_null(ops, key_permission);
set_to_dummy_if_null(ops, key_getsecurity);
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
set_to_dummy_if_null(ops, audit_rule_init);
set_to_dummy_if_null(ops, audit_rule_known);
set_to_dummy_if_null(ops, audit_rule_match);
set_to_dummy_if_null(ops, audit_rule_free);
#endif
}
......@@ -28,9 +28,6 @@
#include <linux/usb.h>
#include <linux/moduleparam.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;
......@@ -97,14 +94,8 @@ static int __init rootplug_init (void)
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;
......
......@@ -20,8 +20,8 @@
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
/* things that live in dummy.c */
extern struct security_operations dummy_security_ops;
/* things that live in capability.c */
extern struct security_operations default_security_ops;
extern void security_fixup_ops(struct security_operations *ops);
struct security_operations *security_ops; /* Initialized to NULL */
......@@ -57,13 +57,8 @@ int __init security_init(void)
{
printk(KERN_INFO "Security Framework initialized\n");
if (verify(&dummy_security_ops)) {
printk(KERN_ERR "%s could not verify "
"dummy_security_ops structure.\n", __func__);
return -EIO;
}
security_ops = &dummy_security_ops;
security_fixup_ops(&default_security_ops);
security_ops = &default_security_ops;
do_security_initcalls();
return 0;
......@@ -122,7 +117,7 @@ int register_security(struct security_operations *ops)
return -EINVAL;
}
if (security_ops != &dummy_security_ops)
if (security_ops != &default_security_ops)
return -EAGAIN;
security_ops = ops;
......@@ -130,40 +125,12 @@ int register_security(struct security_operations *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", __func__);
return -EINVAL;
}
if (ops == security_ops) {
printk(KERN_INFO "%s security operations "
"already registered.\n", __func__);
return -EINVAL;
}
return security_ops->register_security(name, ops);
}
/* Security operations */
int security_ptrace(struct task_struct *parent, struct task_struct *child)
int security_ptrace(struct task_struct *parent, struct task_struct *child,
unsigned int mode)
{
return security_ops->ptrace(parent, child);
return security_ops->ptrace(parent, child, mode);
}
int security_capget(struct task_struct *target,
......@@ -291,6 +258,11 @@ int security_sb_kern_mount(struct super_block *sb, void *data)
return security_ops->sb_kern_mount(sb, data);
}
int security_sb_show_options(struct seq_file *m, struct super_block *sb)
{
return security_ops->sb_show_options(m, sb);
}
int security_sb_statfs(struct dentry *dentry)
{
return security_ops->sb_statfs(dentry);
......@@ -342,12 +314,6 @@ void security_sb_post_pivotroot(struct path *old_path, struct path *new_path)
security_ops->sb_post_pivotroot(old_path, new_path);
}
int security_sb_get_mnt_opts(const struct super_block *sb,
struct security_mnt_opts *opts)
{
return security_ops->sb_get_mnt_opts(sb, opts);
}
int security_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts)
{
......@@ -894,7 +860,7 @@ EXPORT_SYMBOL(security_secctx_to_secid);
void security_release_secctx(char *secdata, u32 seclen)
{
return security_ops->release_secctx(secdata, seclen);
security_ops->release_secctx(secdata, seclen);
}
EXPORT_SYMBOL(security_release_secctx);
......@@ -1011,12 +977,12 @@ int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
void security_sk_free(struct sock *sk)
{
return security_ops->sk_free_security(sk);
security_ops->sk_free_security(sk);
}
void security_sk_clone(const struct sock *sk, struct sock *newsk)
{
return security_ops->sk_clone_security(sk, newsk);
security_ops->sk_clone_security(sk, newsk);
}
void security_sk_classify_flow(struct sock *sk, struct flowi *fl)
......
......@@ -9,7 +9,8 @@
* James Morris <jmorris@redhat.com>
*
* Copyright (C) 2001,2002 Networks Associates Technology, Inc.
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
* Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
* Eric Paris <eparis@redhat.com>
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
* <dgoeddel@trustedcs.com>
* Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
......@@ -42,9 +43,7 @@
#include <linux/fdtable.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>
......@@ -53,7 +52,7 @@
#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
#include <net/net_namespace.h>
#include <net/netlabel.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <asm/ioctls.h>
#include <asm/atomic.h>
#include <linux/bitops.h>
......@@ -104,7 +103,9 @@ int selinux_enforcing;
static int __init enforcing_setup(char *str)
{
selinux_enforcing = simple_strtol(str, NULL, 0);
unsigned long enforcing;
if (!strict_strtoul(str, 0, &enforcing))
selinux_enforcing = enforcing ? 1 : 0;
return 1;
}
__setup("enforcing=", enforcing_setup);
......@@ -115,7 +116,9 @@ int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
static int __init selinux_enabled_setup(char *str)
{
selinux_enabled = simple_strtol(str, NULL, 0);
unsigned long enabled;
if (!strict_strtoul(str, 0, &enabled))
selinux_enabled = enabled ? 1 : 0;
return 1;
}
__setup("selinux=", selinux_enabled_setup);
......@@ -123,13 +126,11 @@ __setup("selinux=", selinux_enabled_setup);
int selinux_enabled = 1;
#endif
/* Original (dummy) security module. */
static struct security_operations *original_ops;
/* 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. */
/*
* Minimal support for a secondary security module,
* just to allow the use of the capability module.
*/
static struct security_operations *secondary_ops;
/* Lists of inode and superblock security structures initialized
......@@ -554,13 +555,15 @@ static int selinux_set_mnt_opts(struct super_block *sb,
struct task_security_struct *tsec = current->security;
struct superblock_security_struct *sbsec = sb->s_security;
const char *name = sb->s_type->name;
struct inode *inode = sbsec->sb->s_root->d_inode;
struct inode_security_struct *root_isec = inode->i_security;
struct dentry *root = sb->s_root;
struct inode *root_inode = root->d_inode;
struct inode_security_struct *root_isec = root_inode->i_security;
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
u32 defcontext_sid = 0;
char **mount_options = opts->mnt_opts;
int *flags = opts->mnt_opts_flags;
int num_opts = opts->num_mnt_opts;
bool can_xattr = false;
mutex_lock(&sbsec->lock);
......@@ -664,14 +667,24 @@ static int selinux_set_mnt_opts(struct super_block *sb,
goto out;
}
if (strcmp(sb->s_type->name, "proc") == 0)
if (strcmp(name, "proc") == 0)
sbsec->proc = 1;
/*
* test if the fs supports xattrs, fs_use might make use of this if the
* fs has no definition in policy.
*/
if (root_inode->i_op->getxattr) {
rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
if (rc >= 0 || rc == -ENODATA)
can_xattr = true;
}
/* Determine the labeling behavior to use for this filesystem type. */
rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
rc = security_fs_use(name, &sbsec->behavior, &sbsec->sid, can_xattr);
if (rc) {
printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
__func__, sb->s_type->name, rc);
__func__, name, rc);
goto out;
}
......@@ -956,6 +969,57 @@ static int superblock_doinit(struct super_block *sb, void *data)
return rc;
}
void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts)
{
int i;
char *prefix;
for (i = 0; i < opts->num_mnt_opts; i++) {
char *has_comma = strchr(opts->mnt_opts[i], ',');
switch (opts->mnt_opts_flags[i]) {
case CONTEXT_MNT:
prefix = CONTEXT_STR;
break;
case FSCONTEXT_MNT:
prefix = FSCONTEXT_STR;
break;
case ROOTCONTEXT_MNT:
prefix = ROOTCONTEXT_STR;
break;
case DEFCONTEXT_MNT:
prefix = DEFCONTEXT_STR;
break;
default:
BUG();
};
/* we need a comma before each option */
seq_putc(m, ',');
seq_puts(m, prefix);
if (has_comma)
seq_putc(m, '\"');
seq_puts(m, opts->mnt_opts[i]);
if (has_comma)
seq_putc(m, '\"');
}
}
static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
{
struct security_mnt_opts opts;
int rc;
rc = selinux_get_mnt_opts(sb, &opts);
if (rc)
return rc;
selinux_write_opts(m, &opts);
security_free_mnt_opts(&opts);
return rc;
}
static inline u16 inode_mode_to_security_class(umode_t mode)
{
switch (mode & S_IFMT) {
......@@ -1682,14 +1746,23 @@ static inline u32 file_to_av(struct file *file)
/* Hook functions begin here. */
static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
static int selinux_ptrace(struct task_struct *parent,
struct task_struct *child,
unsigned int mode)
{
int rc;
rc = secondary_ops->ptrace(parent, child);
rc = secondary_ops->ptrace(parent, child, mode);
if (rc)
return rc;
if (mode == PTRACE_MODE_READ) {
struct task_security_struct *tsec = parent->security;
struct task_security_struct *csec = child->security;
return avc_has_perm(tsec->sid, csec->sid,
SECCLASS_FILE, FILE__READ, NULL);
}
return task_has_perm(parent, child, PROCESS__PTRACE);
}
......@@ -2495,7 +2568,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
}
if (value && len) {
rc = security_sid_to_context(newsid, &context, &clen);
rc = security_sid_to_context_force(newsid, &context, &clen);
if (rc) {
kfree(namep);
return rc;
......@@ -2669,6 +2742,11 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
return rc;
rc = security_context_to_sid(value, size, &newsid);
if (rc == -EINVAL) {
if (!capable(CAP_MAC_ADMIN))
return rc;
rc = security_context_to_sid_force(value, size, &newsid);
}
if (rc)
return rc;
......@@ -2703,10 +2781,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}
rc = security_context_to_sid(value, size, &newsid);
rc = security_context_to_sid_force(value, size, &newsid);
if (rc) {
printk(KERN_WARNING "%s: unable to obtain SID for context "
"%s, rc=%d\n", __func__, (char *)value, -rc);
printk(KERN_ERR "SELinux: unable to map context to SID"
"for (%s, %lu), rc=%d\n",
inode->i_sb->s_id, inode->i_ino, -rc);
return;
}
......@@ -2735,9 +2814,7 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
}
/*
* Copy the in-core inode security context value to the user. If the
* getxattr() prior to this succeeded, check to see if we need to
* canonicalize the value to be finally returned to the user.
* Copy the inode security context value to the user.
*
* Permission check is handled by selinux_inode_getxattr hook.
*/
......@@ -2746,11 +2823,32 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
u32 size;
int error;
char *context = NULL;
struct task_security_struct *tsec = current->security;
struct inode_security_struct *isec = inode->i_security;
if (strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP;
/*
* If the caller has CAP_MAC_ADMIN, then get the raw context
* value even if it is not defined by current policy; otherwise,
* use the in-core value under current policy.
* Use the non-auditing forms of the permission checks since
* getxattr may be called by unprivileged processes commonly
* and lack of permission just means that we fall back to the
* in-core context value, not a denial.
*/
error = secondary_ops->capable(current, CAP_MAC_ADMIN);
if (!error)
error = avc_has_perm_noaudit(tsec->sid, tsec->sid,
SECCLASS_CAPABILITY2,
CAPABILITY2__MAC_ADMIN,
0,
NULL);
if (!error)
error = security_sid_to_context_force(isec->sid, &context,
&size);
else
error = security_sid_to_context(isec->sid, &context, &size);
if (error)
return error;
......@@ -2865,46 +2963,16 @@ static void selinux_file_free_security(struct file *file)
static int selinux_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int error = 0;
switch (cmd) {
case FIONREAD:
/* fall through */
case FIBMAP:
/* fall through */
case FIGETBSZ:
/* fall through */
case EXT2_IOC_GETFLAGS:
/* fall through */
case EXT2_IOC_GETVERSION:
error = file_has_perm(current, file, FILE__GETATTR);
break;
case EXT2_IOC_SETFLAGS:
/* fall through */
case EXT2_IOC_SETVERSION:
error = file_has_perm(current, file, FILE__SETATTR);
break;
/* sys_ioctl() checks */
case FIONBIO:
/* fall through */
case FIOASYNC:
error = file_has_perm(current, file, 0);
break;
u32 av = 0;
case KDSKBENT:
case KDSKBSENT:
error = task_has_capability(current, CAP_SYS_TTY_CONFIG);
break;
if (_IOC_DIR(cmd) & _IOC_WRITE)
av |= FILE__WRITE;
if (_IOC_DIR(cmd) & _IOC_READ)
av |= FILE__READ;
if (!av)
av = FILE__IOCTL;
/* default case assumes that the command will go
* to the file's ioctl() function.
*/
default:
error = file_has_perm(current, file, FILE__IOCTL);
}
return error;
return file_has_perm(current, file, av);
}
static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
......@@ -3663,7 +3731,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
struct sockaddr_in6 *addr6 = NULL;
unsigned short snum;
struct sock *sk = sock->sk;
u32 sid, node_perm, addrlen;
u32 sid, node_perm;
tsec = current->security;
isec = SOCK_INODE(sock)->i_security;
......@@ -3671,12 +3739,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
if (family == PF_INET) {
addr4 = (struct sockaddr_in *)address;
snum = ntohs(addr4->sin_port);
addrlen = sizeof(addr4->sin_addr.s_addr);
addrp = (char *)&addr4->sin_addr.s_addr;
} else {
addr6 = (struct sockaddr_in6 *)address;
snum = ntohs(addr6->sin6_port);
addrlen = sizeof(addr6->sin6_addr.s6_addr);
addrp = (char *)&addr6->sin6_addr.s6_addr;
}
......@@ -5047,24 +5113,6 @@ static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
*secid = isec->sid;
}
/* module stacking operations */
static int selinux_register_security(const char *name, struct security_operations *ops)
{
if (secondary_ops != original_ops) {
printk(KERN_ERR "%s: There is already a secondary security "
"module registered.\n", __func__);
return -EINVAL;
}
secondary_ops = ops;
printk(KERN_INFO "%s: Registering secondary module %s\n",
__func__,
name);
return 0;
}
static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
{
if (inode)
......@@ -5153,6 +5201,12 @@ static int selinux_setprocattr(struct task_struct *p,
size--;
}
error = security_context_to_sid(value, size, &sid);
if (error == -EINVAL && !strcmp(name, "fscreate")) {
if (!capable(CAP_MAC_ADMIN))
return error;
error = security_context_to_sid_force(value, size,
&sid);
}
if (error)
return error;
}
......@@ -5186,12 +5240,12 @@ static int selinux_setprocattr(struct task_struct *p,
struct task_struct *g, *t;
struct mm_struct *mm = p->mm;
read_lock(&tasklist_lock);
do_each_thread(g, t)
do_each_thread(g, t) {
if (t->mm == mm && t != p) {
read_unlock(&tasklist_lock);
return -EPERM;
}
while_each_thread(g, t);
} while_each_thread(g, t);
read_unlock(&tasklist_lock);
}
......@@ -5343,10 +5397,10 @@ static struct security_operations selinux_ops = {
.sb_free_security = selinux_sb_free_security,
.sb_copy_data = selinux_sb_copy_data,
.sb_kern_mount = selinux_sb_kern_mount,
.sb_show_options = selinux_sb_show_options,
.sb_statfs = selinux_sb_statfs,
.sb_mount = selinux_mount,
.sb_umount = selinux_umount,
.sb_get_mnt_opts = selinux_get_mnt_opts,
.sb_set_mnt_opts = selinux_set_mnt_opts,
.sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
.sb_parse_opts_str = selinux_parse_opts_str,
......@@ -5443,8 +5497,6 @@ static struct security_operations selinux_ops = {
.sem_semctl = selinux_sem_semctl,
.sem_semop = selinux_sem_semop,
.register_security = selinux_register_security,
.d_instantiate = selinux_d_instantiate,
.getprocattr = selinux_getprocattr,
......@@ -5538,7 +5590,7 @@ static __init int selinux_init(void)
0, SLAB_PANIC, NULL);
avc_init();
original_ops = secondary_ops = security_ops;
secondary_ops = security_ops;
if (!secondary_ops)
panic("SELinux: No initial security operations\n");
if (register_security(&selinux_ops))
......
......@@ -80,8 +80,7 @@ struct avc_audit_data {
/*
* AVC statistics
*/
struct avc_cache_stats
{
struct avc_cache_stats {
unsigned int lookups;
unsigned int hits;
unsigned int misses;
......
......@@ -44,7 +44,6 @@ struct inode_security_struct {
u16 sclass; /* security class of this object */
unsigned char initialized; /* initialization flag */
struct mutex lock;
unsigned char inherit; /* inherit SID from parent entry */
};
struct file_security_struct {
......
......@@ -93,12 +93,17 @@ int security_change_sid(u32 ssid, u32 tsid,
int security_sid_to_context(u32 sid, char **scontext,
u32 *scontext_len);
int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
int security_context_to_sid(const char *scontext, u32 scontext_len,
u32 *out_sid);
int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
int security_context_to_sid_force(const char *scontext, u32 scontext_len,
u32 *sid);
int security_get_user_sids(u32 callsid, char *username,
u32 **sids, u32 *nel);
......@@ -131,7 +136,7 @@ int security_get_allow_unknown(void);
#define SECURITY_FS_USE_MNTPOINT 6 /* use mountpoint labeling */
int security_fs_use(const char *fstype, unsigned int *behavior,
u32 *sid);
u32 *sid, bool can_xattr);
int security_genfs_sid(const char *fstype, char *name, u16 sclass,
u32 *sid);
......
......@@ -38,7 +38,6 @@
#include <linux/ipv6.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <asm/bug.h>
#include "netnode.h"
#include "objsec.h"
......
......@@ -37,7 +37,6 @@
#include <linux/ipv6.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <asm/bug.h>
#include "netport.h"
#include "objsec.h"
......
......@@ -27,7 +27,7 @@
#include <linux/seq_file.h>
#include <linux/percpu.h>
#include <linux/audit.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
/* selinuxfs pseudo filesystem for exporting the security policy API.
Based on the proc code and the fs/nfsd/nfsctl.c code. */
......@@ -57,14 +57,18 @@ int selinux_compat_net = SELINUX_COMPAT_NET_VALUE;
static int __init checkreqprot_setup(char *str)
{
selinux_checkreqprot = simple_strtoul(str, NULL, 0) ? 1 : 0;
unsigned long checkreqprot;
if (!strict_strtoul(str, 0, &checkreqprot))
selinux_checkreqprot = checkreqprot ? 1 : 0;
return 1;
}
__setup("checkreqprot=", checkreqprot_setup);
static int __init selinux_compat_net_setup(char *str)
{
selinux_compat_net = simple_strtoul(str, NULL, 0) ? 1 : 0;
unsigned long compat_net;
if (!strict_strtoul(str, 0, &compat_net))
selinux_compat_net = compat_net ? 1 : 0;
return 1;
}
__setup("selinux_compat_net=", selinux_compat_net_setup);
......@@ -352,11 +356,6 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
length = count;
out1:
printk(KERN_INFO "SELinux: policy loaded with handle_unknown=%s\n",
(security_get_reject_unknown() ? "reject" :
(security_get_allow_unknown() ? "allow" : "deny")));
audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
"policy loaded auid=%u ses=%u",
audit_get_loginuid(current),
......
......@@ -311,7 +311,7 @@ void avtab_hash_eval(struct avtab *h, char *tag)
}
printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, "
"longest chain length %d sum of chain length^2 %Lu\n",
"longest chain length %d sum of chain length^2 %llu\n",
tag, h->nel, slots_used, h->nslot, max_chain_len,
chain2_len_sum);
}
......
......@@ -28,6 +28,8 @@ struct context {
u32 role;
u32 type;
struct mls_range range;
char *str; /* string representation if context cannot be mapped. */
u32 len; /* length of string in bytes */
};
static inline void mls_context_init(struct context *c)
......@@ -106,20 +108,43 @@ static inline void context_init(struct context *c)
static inline int context_cpy(struct context *dst, struct context *src)
{
int rc;
dst->user = src->user;
dst->role = src->role;
dst->type = src->type;
return mls_context_cpy(dst, src);
if (src->str) {
dst->str = kstrdup(src->str, GFP_ATOMIC);
if (!dst->str)
return -ENOMEM;
dst->len = src->len;
} else {
dst->str = NULL;
dst->len = 0;
}
rc = mls_context_cpy(dst, src);
if (rc) {
kfree(dst->str);
return rc;
}
return 0;
}
static inline void context_destroy(struct context *c)
{
c->user = c->role = c->type = 0;
kfree(c->str);
c->str = NULL;
c->len = 0;
mls_context_destroy(c);
}
static inline int context_cmp(struct context *c1, struct context *c2)
{
if (c1->len && c2->len)
return (c1->len == c2->len && !strcmp(c1->str, c2->str));
if (c1->len || c2->len)
return 0;
return ((c1->user == c2->user) &&
(c1->role == c2->role) &&
(c1->type == c2->type) &&
......
......@@ -239,7 +239,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
* Policy read-lock must be held for sidtab lookup.
*
*/
int mls_context_to_sid(char oldc,
int mls_context_to_sid(struct policydb *pol,
char oldc,
char **scontext,
struct context *context,
struct sidtab *s,
......@@ -286,7 +287,7 @@ int mls_context_to_sid(char oldc,
*p++ = 0;
for (l = 0; l < 2; l++) {
levdatum = hashtab_search(policydb.p_levels.table, scontextp);
levdatum = hashtab_search(pol->p_levels.table, scontextp);
if (!levdatum) {
rc = -EINVAL;
goto out;
......@@ -311,7 +312,7 @@ int mls_context_to_sid(char oldc,
*rngptr++ = 0;
}
catdatum = hashtab_search(policydb.p_cats.table,
catdatum = hashtab_search(pol->p_cats.table,
scontextp);
if (!catdatum) {
rc = -EINVAL;
......@@ -327,7 +328,7 @@ int mls_context_to_sid(char oldc,
if (rngptr) {
int i;
rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
rngdatum = hashtab_search(pol->p_cats.table, rngptr);
if (!rngdatum) {
rc = -EINVAL;
goto out;
......@@ -395,7 +396,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
if (!tmpstr) {
rc = -ENOMEM;
} else {
rc = mls_context_to_sid(':', &tmpstr, context,
rc = mls_context_to_sid(&policydb, ':', &tmpstr, context,
NULL, SECSID_NULL);
kfree(freestr);
}
......@@ -436,13 +437,13 @@ int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
struct mls_level *usercon_clr = &(usercon->range.level[1]);
/* Honor the user's default level if we can */
if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
*usercon_sen = *user_def;
} else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
else if (mls_level_between(fromcon_sen, user_def, user_clr))
*usercon_sen = *fromcon_sen;
} else if (mls_level_between(fromcon_clr, user_low, user_def)) {
else if (mls_level_between(fromcon_clr, user_low, user_def))
*usercon_sen = *user_low;
} else
else
return -EINVAL;
/* Lower the clearance of available contexts
......
......@@ -30,7 +30,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c);
int mls_range_isvalid(struct policydb *p, struct mls_range *r);
int mls_level_isvalid(struct policydb *p, struct mls_level *l);
int mls_context_to_sid(char oldc,
int mls_context_to_sid(struct policydb *p,
char oldc,
char **scontext,
struct context *context,
struct sidtab *s,
......
......@@ -1478,7 +1478,8 @@ int policydb_read(struct policydb *p, void *fp)
struct ocontext *l, *c, *newc;
struct genfs *genfs_p, *genfs, *newgenfs;
int i, j, rc;
__le32 buf[8];
__le32 buf[4];
u32 nodebuf[8];
u32 len, len2, config, nprim, nel, nel2;
char *policydb_str;
struct policydb_compat_info *info;
......@@ -1749,11 +1750,11 @@ int policydb_read(struct policydb *p, void *fp)
goto bad;
break;
case OCON_NODE:
rc = next_entry(buf, fp, sizeof(u32) * 2);
rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
if (rc < 0)
goto bad;
c->u.node.addr = le32_to_cpu(buf[0]);
c->u.node.mask = le32_to_cpu(buf[1]);
c->u.node.addr = nodebuf[0]; /* network order */
c->u.node.mask = nodebuf[1]; /* network order */
rc = context_read_and_validate(&c->context[0], p, fp);
if (rc)
goto bad;
......@@ -1782,13 +1783,13 @@ int policydb_read(struct policydb *p, void *fp)
case OCON_NODE6: {
int k;
rc = next_entry(buf, fp, sizeof(u32) * 8);
rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
if (rc < 0)
goto bad;
for (k = 0; k < 4; k++)
c->u.node6.addr[k] = le32_to_cpu(buf[k]);
c->u.node6.addr[k] = nodebuf[k];
for (k = 0; k < 4; k++)
c->u.node6.mask[k] = le32_to_cpu(buf[k+4]);
c->u.node6.mask[k] = nodebuf[k+4];
if (context_read_and_validate(&c->context[0], p, fp))
goto bad;
break;
......
......@@ -71,14 +71,6 @@ int selinux_policycap_openperm;
extern const struct selinux_class_perm selinux_class_perm;
static DEFINE_RWLOCK(policy_rwlock);
#define POLICY_RDLOCK read_lock(&policy_rwlock)
#define POLICY_WRLOCK write_lock_irq(&policy_rwlock)
#define POLICY_RDUNLOCK read_unlock(&policy_rwlock)
#define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock)
static DEFINE_MUTEX(load_mutex);
#define LOAD_LOCK mutex_lock(&load_mutex)
#define LOAD_UNLOCK mutex_unlock(&load_mutex)
static struct sidtab sidtab;
struct policydb policydb;
......@@ -332,7 +324,7 @@ static int context_struct_compute_av(struct context *scontext,
goto inval_class;
if (unlikely(tclass > policydb.p_classes.nprim))
if (tclass > kdefs->cts_len ||
!kdefs->class_to_string[tclass - 1] ||
!kdefs->class_to_string[tclass] ||
!policydb.allow_unknown)
goto inval_class;
......@@ -415,9 +407,19 @@ static int context_struct_compute_av(struct context *scontext,
return 0;
inval_class:
printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", __func__,
tclass);
if (!tclass || tclass > kdefs->cts_len ||
!kdefs->class_to_string[tclass]) {
if (printk_ratelimit())
printk(KERN_ERR "SELinux: %s: unrecognized class %d\n",
__func__, tclass);
return -EINVAL;
}
/*
* Known to the kernel, but not to the policy.
* Handle as a denial (allowed is 0).
*/
return 0;
}
/*
......@@ -429,7 +431,7 @@ int security_permissive_sid(u32 sid)
u32 type;
int rc;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
context = sidtab_search(&sidtab, sid);
BUG_ON(!context);
......@@ -441,7 +443,7 @@ int security_permissive_sid(u32 sid)
*/
rc = ebitmap_get_bit(&policydb.permissive_map, type);
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -486,7 +488,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
if (!ss_initialized)
return 0;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
/*
* Remap extended Netlink classes for old policy versions.
......@@ -543,7 +545,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
}
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -578,7 +580,7 @@ int security_compute_av(u32 ssid,
return 0;
}
POLICY_RDLOCK;
read_lock(&policy_rwlock);
scontext = sidtab_search(&sidtab, ssid);
if (!scontext) {
......@@ -598,7 +600,7 @@ int security_compute_av(u32 ssid,
rc = context_struct_compute_av(scontext, tcontext, tclass,
requested, avd);
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -616,6 +618,14 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
*scontext = NULL;
*scontext_len = 0;
if (context->len) {
*scontext_len = context->len;
*scontext = kstrdup(context->str, GFP_ATOMIC);
if (!(*scontext))
return -ENOMEM;
return 0;
}
/* Compute the size of the context. */
*scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1;
*scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1;
......@@ -655,17 +665,8 @@ const char *security_get_initial_sid_context(u32 sid)
return initial_sid_to_string[sid];
}
/**
* security_sid_to_context - Obtain a context for a given SID.
* @sid: security identifier, SID
* @scontext: security context
* @scontext_len: length in bytes
*
* Write the string representation of the context associated with @sid
* into a dynamically allocated string of the correct size. Set @scontext
* to point to this string and set @scontext_len to the length of the string.
*/
int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
static int security_sid_to_context_core(u32 sid, char **scontext,
u32 *scontext_len, int force)
{
struct context *context;
int rc = 0;
......@@ -692,7 +693,10 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
rc = -EINVAL;
goto out;
}
POLICY_RDLOCK;
read_lock(&policy_rwlock);
if (force)
context = sidtab_search_force(&sidtab, sid);
else
context = sidtab_search(&sidtab, sid);
if (!context) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
......@@ -702,59 +706,54 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
}
rc = context_struct_to_string(context, scontext, scontext_len);
out_unlock:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
out:
return rc;
}
static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags)
/**
* security_sid_to_context - Obtain a context for a given SID.
* @sid: security identifier, SID
* @scontext: security context
* @scontext_len: length in bytes
*
* Write the string representation of the context associated with @sid
* into a dynamically allocated string of the correct size. Set @scontext
* to point to this string and set @scontext_len to the length of the string.
*/
int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(sid, scontext, scontext_len, 0);
}
int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(sid, scontext, scontext_len, 1);
}
/*
* Caveat: Mutates scontext.
*/
static int string_to_context_struct(struct policydb *pol,
struct sidtab *sidtabp,
char *scontext,
u32 scontext_len,
struct context *ctx,
u32 def_sid)
{
char *scontext2;
struct context context;
struct role_datum *role;
struct type_datum *typdatum;
struct user_datum *usrdatum;
char *scontextp, *p, oldc;
int rc = 0;
if (!ss_initialized) {
int i;
for (i = 1; i < SECINITSID_NUM; i++) {
if (!strcmp(initial_sid_to_string[i], scontext)) {
*sid = i;
goto out;
}
}
*sid = SECINITSID_KERNEL;
goto out;
}
*sid = SECSID_NULL;
/* Copy the string so that we can modify the copy as we parse it.
The string should already by null terminated, but we append a
null suffix to the copy to avoid problems with the existing
attr package, which doesn't view the null terminator as part
of the attribute value. */
scontext2 = kmalloc(scontext_len+1, gfp_flags);
if (!scontext2) {
rc = -ENOMEM;
goto out;
}
memcpy(scontext2, scontext, scontext_len);
scontext2[scontext_len] = 0;
context_init(&context);
*sid = SECSID_NULL;
POLICY_RDLOCK;
context_init(ctx);
/* Parse the security context. */
rc = -EINVAL;
scontextp = (char *) scontext2;
scontextp = (char *) scontext;
/* Extract the user. */
p = scontextp;
......@@ -762,15 +761,15 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
p++;
if (*p == 0)
goto out_unlock;
goto out;
*p++ = 0;
usrdatum = hashtab_search(policydb.p_users.table, scontextp);
usrdatum = hashtab_search(pol->p_users.table, scontextp);
if (!usrdatum)
goto out_unlock;
goto out;
context.user = usrdatum->value;
ctx->user = usrdatum->value;
/* Extract role. */
scontextp = p;
......@@ -778,14 +777,14 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
p++;
if (*p == 0)
goto out_unlock;
goto out;
*p++ = 0;
role = hashtab_search(policydb.p_roles.table, scontextp);
role = hashtab_search(pol->p_roles.table, scontextp);
if (!role)
goto out_unlock;
context.role = role->value;
goto out;
ctx->role = role->value;
/* Extract type. */
scontextp = p;
......@@ -794,33 +793,87 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
oldc = *p;
*p++ = 0;
typdatum = hashtab_search(policydb.p_types.table, scontextp);
typdatum = hashtab_search(pol->p_types.table, scontextp);
if (!typdatum)
goto out_unlock;
goto out;
context.type = typdatum->value;
ctx->type = typdatum->value;
rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
if (rc)
goto out_unlock;
goto out;
if ((p - scontext2) < scontext_len) {
if ((p - scontext) < scontext_len) {
rc = -EINVAL;
goto out_unlock;
goto out;
}
/* Check the validity of the new context. */
if (!policydb_context_isvalid(&policydb, &context)) {
if (!policydb_context_isvalid(pol, ctx)) {
rc = -EINVAL;
goto out_unlock;
context_destroy(ctx);
goto out;
}
/* Obtain the new sid. */
rc = 0;
out:
return rc;
}
static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags,
int force)
{
char *scontext2, *str = NULL;
struct context context;
int rc = 0;
if (!ss_initialized) {
int i;
for (i = 1; i < SECINITSID_NUM; i++) {
if (!strcmp(initial_sid_to_string[i], scontext)) {
*sid = i;
return 0;
}
}
*sid = SECINITSID_KERNEL;
return 0;
}
*sid = SECSID_NULL;
/* Copy the string so that we can modify the copy as we parse it. */
scontext2 = kmalloc(scontext_len+1, gfp_flags);
if (!scontext2)
return -ENOMEM;
memcpy(scontext2, scontext, scontext_len);
scontext2[scontext_len] = 0;
if (force) {
/* Save another copy for storing in uninterpreted form */
str = kstrdup(scontext2, gfp_flags);
if (!str) {
kfree(scontext2);
return -ENOMEM;
}
}
read_lock(&policy_rwlock);
rc = string_to_context_struct(&policydb, &sidtab,
scontext2, scontext_len,
&context, def_sid);
if (rc == -EINVAL && force) {
context.str = str;
context.len = scontext_len;
str = NULL;
} else if (rc)
goto out;
rc = sidtab_context_to_sid(&sidtab, &context, sid);
out_unlock:
POLICY_RDUNLOCK;
if (rc)
context_destroy(&context);
kfree(scontext2);
out:
read_unlock(&policy_rwlock);
kfree(scontext2);
kfree(str);
return rc;
}
......@@ -838,7 +891,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
{
return security_context_to_sid_core(scontext, scontext_len,
sid, SECSID_NULL, GFP_KERNEL);
sid, SECSID_NULL, GFP_KERNEL, 0);
}
/**
......@@ -855,6 +908,7 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
* The default SID is passed to the MLS layer to be used to allow
* kernel labeling of the MLS field if the MLS field is not present
* (for upgrading to MLS without full relabel).
* Implicitly forces adding of the context even if it cannot be mapped yet.
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
......@@ -862,7 +916,14 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags)
{
return security_context_to_sid_core(scontext, scontext_len,
sid, def_sid, gfp_flags);
sid, def_sid, gfp_flags, 1);
}
int security_context_to_sid_force(const char *scontext, u32 scontext_len,
u32 *sid)
{
return security_context_to_sid_core(scontext, scontext_len,
sid, SECSID_NULL, GFP_KERNEL, 1);
}
static int compute_sid_handle_invalid_context(
......@@ -922,7 +983,7 @@ static int security_compute_sid(u32 ssid,
context_init(&newcontext);
POLICY_RDLOCK;
read_lock(&policy_rwlock);
scontext = sidtab_search(&sidtab, ssid);
if (!scontext) {
......@@ -1027,7 +1088,7 @@ static int security_compute_sid(u32 ssid,
/* Obtain the sid for the context. */
rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
out_unlock:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
context_destroy(&newcontext);
out:
return rc;
......@@ -1110,6 +1171,7 @@ static int validate_classes(struct policydb *p)
const struct selinux_class_perm *kdefs = &selinux_class_perm;
const char *def_class, *def_perm, *pol_class;
struct symtab *perms;
bool print_unknown_handle = 0;
if (p->allow_unknown) {
u32 num_classes = kdefs->cts_len;
......@@ -1130,6 +1192,7 @@ static int validate_classes(struct policydb *p)
return -EINVAL;
if (p->allow_unknown)
p->undefined_perms[i-1] = ~0U;
print_unknown_handle = 1;
continue;
}
pol_class = p->p_class_val_to_name[i-1];
......@@ -1159,6 +1222,7 @@ static int validate_classes(struct policydb *p)
return -EINVAL;
if (p->allow_unknown)
p->undefined_perms[class_val-1] |= perm_val;
print_unknown_handle = 1;
continue;
}
perdatum = hashtab_search(perms->table, def_perm);
......@@ -1206,6 +1270,7 @@ static int validate_classes(struct policydb *p)
return -EINVAL;
if (p->allow_unknown)
p->undefined_perms[class_val-1] |= (1 << j);
print_unknown_handle = 1;
continue;
}
perdatum = hashtab_search(perms->table, def_perm);
......@@ -1223,6 +1288,9 @@ static int validate_classes(struct policydb *p)
}
}
}
if (print_unknown_handle)
printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
(security_get_allow_unknown() ? "allowed" : "denied"));
return 0;
}
......@@ -1246,10 +1314,13 @@ static inline int convert_context_handle_invalid_context(struct context *context
char *s;
u32 len;
context_struct_to_string(context, &s, &len);
printk(KERN_ERR "SELinux: context %s is invalid\n", s);
if (!context_struct_to_string(context, &s, &len)) {
printk(KERN_WARNING
"SELinux: Context %s would be invalid if enforcing\n",
s);
kfree(s);
}
}
return rc;
}
......@@ -1280,6 +1351,37 @@ static int convert_context(u32 key,
args = p;
if (c->str) {
struct context ctx;
s = kstrdup(c->str, GFP_KERNEL);
if (!s) {
rc = -ENOMEM;
goto out;
}
rc = string_to_context_struct(args->newp, NULL, s,
c->len, &ctx, SECSID_NULL);
kfree(s);
if (!rc) {
printk(KERN_INFO
"SELinux: Context %s became valid (mapped).\n",
c->str);
/* Replace string with mapped representation. */
kfree(c->str);
memcpy(c, &ctx, sizeof(*c));
goto out;
} else if (rc == -EINVAL) {
/* Retain string representation for later mapping. */
rc = 0;
goto out;
} else {
/* Other error condition, e.g. ENOMEM. */
printk(KERN_ERR
"SELinux: Unable to map context %s, rc = %d.\n",
c->str, -rc);
goto out;
}
}
rc = context_cpy(&oldc, c);
if (rc)
goto out;
......@@ -1319,13 +1421,21 @@ static int convert_context(u32 key,
}
context_destroy(&oldc);
rc = 0;
out:
return rc;
bad:
context_struct_to_string(&oldc, &s, &len);
/* Map old representation to string and save it. */
if (context_struct_to_string(&oldc, &s, &len))
return -ENOMEM;
context_destroy(&oldc);
printk(KERN_ERR "SELinux: invalidating context %s\n", s);
kfree(s);
context_destroy(c);
c->str = s;
c->len = len;
printk(KERN_INFO
"SELinux: Context %s became invalid (unmapped).\n",
c->str);
rc = 0;
goto out;
}
......@@ -1359,17 +1469,13 @@ int security_load_policy(void *data, size_t len)
int rc = 0;
struct policy_file file = { data, len }, *fp = &file;
LOAD_LOCK;
if (!ss_initialized) {
avtab_cache_init();
if (policydb_read(&policydb, fp)) {
LOAD_UNLOCK;
avtab_cache_destroy();
return -EINVAL;
}
if (policydb_load_isids(&policydb, &sidtab)) {
LOAD_UNLOCK;
policydb_destroy(&policydb);
avtab_cache_destroy();
return -EINVAL;
......@@ -1378,7 +1484,6 @@ int security_load_policy(void *data, size_t len)
if (validate_classes(&policydb)) {
printk(KERN_ERR
"SELinux: the definition of a class is incorrect\n");
LOAD_UNLOCK;
sidtab_destroy(&sidtab);
policydb_destroy(&policydb);
avtab_cache_destroy();
......@@ -1388,7 +1493,6 @@ int security_load_policy(void *data, size_t len)
policydb_loaded_version = policydb.policyvers;
ss_initialized = 1;
seqno = ++latest_granting;
LOAD_UNLOCK;
selinux_complete_init();
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
......@@ -1401,12 +1505,13 @@ int security_load_policy(void *data, size_t len)
sidtab_hash_eval(&sidtab, "sids");
#endif
if (policydb_read(&newpolicydb, fp)) {
LOAD_UNLOCK;
if (policydb_read(&newpolicydb, fp))
return -EINVAL;
}
sidtab_init(&newsidtab);
if (sidtab_init(&newsidtab)) {
policydb_destroy(&newpolicydb);
return -ENOMEM;
}
/* Verify that the kernel defined classes are correct. */
if (validate_classes(&newpolicydb)) {
......@@ -1429,25 +1534,28 @@ int security_load_policy(void *data, size_t len)
goto err;
}
/* Convert the internal representations of contexts
in the new SID table and remove invalid SIDs. */
/*
* Convert the internal representations of contexts
* in the new SID table.
*/
args.oldp = &policydb;
args.newp = &newpolicydb;
sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
rc = sidtab_map(&newsidtab, convert_context, &args);
if (rc)
goto err;
/* Save the old policydb and SID table to free later. */
memcpy(&oldpolicydb, &policydb, sizeof policydb);
sidtab_set(&oldsidtab, &sidtab);
/* Install the new policydb and SID table. */
POLICY_WRLOCK;
write_lock_irq(&policy_rwlock);
memcpy(&policydb, &newpolicydb, sizeof policydb);
sidtab_set(&sidtab, &newsidtab);
security_load_policycaps();
seqno = ++latest_granting;
policydb_loaded_version = policydb.policyvers;
POLICY_WRUNLOCK;
LOAD_UNLOCK;
write_unlock_irq(&policy_rwlock);
/* Free the old policydb and SID table. */
policydb_destroy(&oldpolicydb);
......@@ -1461,7 +1569,6 @@ int security_load_policy(void *data, size_t len)
return 0;
err:
LOAD_UNLOCK;
sidtab_destroy(&newsidtab);
policydb_destroy(&newpolicydb);
return rc;
......@@ -1479,7 +1586,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
struct ocontext *c;
int rc = 0;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
c = policydb.ocontexts[OCON_PORT];
while (c) {
......@@ -1504,7 +1611,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
}
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -1518,7 +1625,7 @@ int security_netif_sid(char *name, u32 *if_sid)
int rc = 0;
struct ocontext *c;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
c = policydb.ocontexts[OCON_NETIF];
while (c) {
......@@ -1545,7 +1652,7 @@ int security_netif_sid(char *name, u32 *if_sid)
*if_sid = SECINITSID_NETIF;
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -1577,7 +1684,7 @@ int security_node_sid(u16 domain,
int rc = 0;
struct ocontext *c;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
switch (domain) {
case AF_INET: {
......@@ -1632,7 +1739,7 @@ int security_node_sid(u16 domain,
}
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -1671,7 +1778,9 @@ int security_get_user_sids(u32 fromsid,
if (!ss_initialized)
goto out;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
context_init(&usercon);
fromcon = sidtab_search(&sidtab, fromsid);
if (!fromcon) {
......@@ -1722,7 +1831,7 @@ int security_get_user_sids(u32 fromsid,
}
out_unlock:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
if (rc || !mynel) {
kfree(mysids);
goto out;
......@@ -1775,7 +1884,7 @@ int security_genfs_sid(const char *fstype,
while (path[0] == '/' && path[1] == '/')
path++;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
cmp = strcmp(fstype, genfs->fstype);
......@@ -1812,7 +1921,7 @@ int security_genfs_sid(const char *fstype,
*sid = c->sid[0];
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -1825,12 +1934,13 @@ int security_genfs_sid(const char *fstype,
int security_fs_use(
const char *fstype,
unsigned int *behavior,
u32 *sid)
u32 *sid,
bool can_xattr)
{
int rc = 0;
struct ocontext *c;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
c = policydb.ocontexts[OCON_FSUSE];
while (c) {
......@@ -1839,6 +1949,7 @@ int security_fs_use(
c = c->next;
}
/* look for labeling behavior defined in policy */
if (c) {
*behavior = c->v.behavior;
if (!c->sid[0]) {
......@@ -1849,7 +1960,17 @@ int security_fs_use(
goto out;
}
*sid = c->sid[0];
} else {
goto out;
}
/* labeling behavior not in policy, use xattrs if possible */
if (can_xattr) {
*behavior = SECURITY_FS_USE_XATTR;
*sid = SECINITSID_FS;
goto out;
}
/* no behavior in policy and can't use xattrs, try GENFS */
rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
if (rc) {
*behavior = SECURITY_FS_USE_NONE;
......@@ -1857,10 +1978,9 @@ int security_fs_use(
} else {
*behavior = SECURITY_FS_USE_GENFS;
}
}
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -1868,7 +1988,7 @@ int security_get_bools(int *len, char ***names, int **values)
{
int i, rc = -ENOMEM;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
*names = NULL;
*values = NULL;
......@@ -1898,7 +2018,7 @@ int security_get_bools(int *len, char ***names, int **values)
}
rc = 0;
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
err:
if (*names) {
......@@ -1916,7 +2036,7 @@ int security_set_bools(int len, int *values)
int lenp, seqno = 0;
struct cond_node *cur;
POLICY_WRLOCK;
write_lock_irq(&policy_rwlock);
lenp = policydb.p_bools.nprim;
if (len != lenp) {
......@@ -1950,7 +2070,7 @@ int security_set_bools(int len, int *values)
seqno = ++latest_granting;
out:
POLICY_WRUNLOCK;
write_unlock_irq(&policy_rwlock);
if (!rc) {
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
......@@ -1964,7 +2084,7 @@ int security_get_bool_value(int bool)
int rc = 0;
int len;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
len = policydb.p_bools.nprim;
if (bool >= len) {
......@@ -1974,7 +2094,7 @@ int security_get_bool_value(int bool)
rc = policydb.bool_val_to_struct[bool]->state;
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -2029,7 +2149,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
context_init(&newcon);
POLICY_RDLOCK;
read_lock(&policy_rwlock);
context1 = sidtab_search(&sidtab, sid);
if (!context1) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
......@@ -2071,7 +2191,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
}
out_unlock:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
context_destroy(&newcon);
out:
return rc;
......@@ -2128,7 +2248,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
return 0;
}
POLICY_RDLOCK;
read_lock(&policy_rwlock);
nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
if (!nlbl_ctx) {
......@@ -2147,7 +2267,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
out_slowpath:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
if (rc == 0)
/* at present NetLabel SIDs/labels really only carry MLS
* information so if the MLS portion of the NetLabel SID
......@@ -2177,7 +2297,7 @@ int security_get_classes(char ***classes, int *nclasses)
{
int rc = -ENOMEM;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
*nclasses = policydb.p_classes.nprim;
*classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC);
......@@ -2194,7 +2314,7 @@ int security_get_classes(char ***classes, int *nclasses)
}
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -2216,7 +2336,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms)
int rc = -ENOMEM, i;
struct class_datum *match;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
match = hashtab_search(policydb.p_classes.table, class);
if (!match) {
......@@ -2244,11 +2364,11 @@ int security_get_permissions(char *class, char ***perms, int *nperms)
goto err;
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
err:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
for (i = 0; i < *nperms; i++)
kfree((*perms)[i]);
kfree(*perms);
......@@ -2279,9 +2399,9 @@ int security_policycap_supported(unsigned int req_cap)
{
int rc;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
......@@ -2345,7 +2465,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
context_init(&tmprule->au_ctxt);
POLICY_RDLOCK;
read_lock(&policy_rwlock);
tmprule->au_seqno = latest_granting;
......@@ -2382,7 +2502,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
break;
}
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
if (rc) {
selinux_audit_rule_free(tmprule);
......@@ -2433,7 +2553,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
return -ENOENT;
}
POLICY_RDLOCK;
read_lock(&policy_rwlock);
if (rule->au_seqno < latest_granting) {
audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
......@@ -2527,7 +2647,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
}
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return match;
}
......@@ -2615,7 +2735,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
return 0;
}
POLICY_RDLOCK;
read_lock(&policy_rwlock);
if (secattr->flags & NETLBL_SECATTR_CACHE) {
*sid = *(u32 *)secattr->cache->data;
......@@ -2660,7 +2780,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
}
netlbl_secattr_to_sid_return:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
netlbl_secattr_to_sid_return_cleanup:
ebitmap_destroy(&ctx_new.range.level[0].cat);
......@@ -2685,7 +2805,7 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
if (!ss_initialized)
return 0;
POLICY_RDLOCK;
read_lock(&policy_rwlock);
ctx = sidtab_search(&sidtab, sid);
if (ctx == NULL)
goto netlbl_sid_to_secattr_failure;
......@@ -2696,12 +2816,12 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
rc = mls_export_netlbl_cat(ctx, secattr);
if (rc != 0)
goto netlbl_sid_to_secattr_failure;
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return 0;
netlbl_sid_to_secattr_failure:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return rc;
}
#endif /* CONFIG_NETLABEL */
......@@ -14,10 +14,6 @@
#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;
......@@ -30,7 +26,7 @@ int sidtab_init(struct sidtab *s)
s->nel = 0;
s->next_sid = 1;
s->shutdown = 0;
INIT_SIDTAB_LOCK(s);
spin_lock_init(&s->lock);
return 0;
}
......@@ -86,7 +82,7 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
return rc;
}
struct context *sidtab_search(struct sidtab *s, u32 sid)
static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
{
int hvalue;
struct sidtab_node *cur;
......@@ -99,7 +95,10 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
while (cur != NULL && sid > cur->sid)
cur = cur->next;
if (cur == NULL || sid != cur->sid) {
if (force && cur && sid == cur->sid && cur->context.len)
return &cur->context;
if (cur == NULL || sid != cur->sid || cur->context.len) {
/* Remap invalid SIDs to the unlabeled SID. */
sid = SECINITSID_UNLABELED;
hvalue = SIDTAB_HASH(sid);
......@@ -113,6 +112,16 @@ struct context *sidtab_search(struct sidtab *s, u32 sid)
return &cur->context;
}
struct context *sidtab_search(struct sidtab *s, u32 sid)
{
return sidtab_search_core(s, sid, 0);
}
struct context *sidtab_search_force(struct sidtab *s, u32 sid)
{
return sidtab_search_core(s, sid, 1);
}
int sidtab_map(struct sidtab *s,
int (*apply) (u32 sid,
struct context *context,
......@@ -138,43 +147,6 @@ int sidtab_map(struct sidtab *s,
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)
{
......@@ -204,7 +176,7 @@ int sidtab_context_to_sid(struct sidtab *s,
sid = sidtab_search_context(s, context);
if (!sid) {
SIDTAB_LOCK(s, flags);
spin_lock_irqsave(&s->lock, flags);
/* Rescan now that we hold the lock. */
sid = sidtab_search_context(s, context);
if (sid)
......@@ -215,11 +187,15 @@ int sidtab_context_to_sid(struct sidtab *s,
goto unlock_out;
}
sid = s->next_sid++;
if (context->len)
printk(KERN_INFO
"SELinux: Context %s is not valid (left unmapped).\n",
context->str);
ret = sidtab_insert(s, sid, context);
if (ret)
s->next_sid--;
unlock_out:
SIDTAB_UNLOCK(s, flags);
spin_unlock_irqrestore(&s->lock, flags);
}
if (ret)
......@@ -284,19 +260,19 @@ void sidtab_set(struct sidtab *dst, struct sidtab *src)
{
unsigned long flags;
SIDTAB_LOCK(src, flags);
spin_lock_irqsave(&src->lock, flags);
dst->htable = src->htable;
dst->nel = src->nel;
dst->next_sid = src->next_sid;
dst->shutdown = 0;
SIDTAB_UNLOCK(src, flags);
spin_unlock_irqrestore(&src->lock, flags);
}
void sidtab_shutdown(struct sidtab *s)
{
unsigned long flags;
SIDTAB_LOCK(s, flags);
spin_lock_irqsave(&s->lock, flags);
s->shutdown = 1;
SIDTAB_UNLOCK(s, flags);
spin_unlock_irqrestore(&s->lock, flags);
}
......@@ -32,6 +32,7 @@ struct sidtab {
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);
struct context *sidtab_search_force(struct sidtab *s, u32 sid);
int sidtab_map(struct sidtab *s,
int (*apply) (u32 sid,
......@@ -39,12 +40,6 @@ int sidtab_map(struct sidtab *s,
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);
......
......@@ -95,11 +95,12 @@ struct inode_smack *new_inode_smack(char *smack)
*
* Do the capability checks, and require read and write.
*/
static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp)
static int smack_ptrace(struct task_struct *ptp, struct task_struct *ctp,
unsigned int mode)
{
int rc;
rc = cap_ptrace(ptp, ctp);
rc = cap_ptrace(ptp, ctp, mode);
if (rc != 0)
return rc;
......@@ -1821,27 +1822,6 @@ static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
*secid = smack_to_secid(smack);
}
/* module stacking operations */
/**
* smack_register_security - stack capability module
* @name: module name
* @ops: module operations - ignored
*
* Allow the capability module to register.
*/
static int smack_register_security(const char *name,
struct security_operations *ops)
{
if (strcmp(name, "capability") != 0)
return -EINVAL;
printk(KERN_INFO "%s: Registering secondary module %s\n",
__func__, name);
return 0;
}
/**
* smack_d_instantiate - Make sure the blob is correct on an inode
* @opt_dentry: unused
......@@ -2672,8 +2652,6 @@ struct security_operations smack_ops = {
.netlink_send = cap_netlink_send,
.netlink_recv = cap_netlink_recv,
.register_security = smack_register_security,
.d_instantiate = smack_d_instantiate,
.getprocattr = smack_getprocattr,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment