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
  ...
This commit is contained in:
Linus Torvalds 2008-07-14 13:36:55 -07:00
commit 847106ff62
31 changed files with 1592 additions and 1827 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
*/

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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,13 +94,7 @@ 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);

View File

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

View File

@ -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);
@ -594,7 +597,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
*/
if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
&& (num_opts == 0))
goto out;
goto out;
/*
* parse the mount options, check if they are valid sids.
@ -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;
@ -2690,7 +2768,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
}
static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size,
const void *value, size_t size,
int flags)
{
struct inode *inode = dentry->d_inode;
@ -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,12 +2823,33 @@ 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;
error = security_sid_to_context(isec->sid, &context, &size);
/*
* 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;
error = size;
@ -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;
u32 av = 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;
if (_IOC_DIR(cmd) & _IOC_WRITE)
av |= FILE__WRITE;
if (_IOC_DIR(cmd) & _IOC_READ)
av |= FILE__READ;
if (!av)
av = FILE__IOCTL;
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;
case KDSKBENT:
case KDSKBSENT:
error = task_has_capability(current, CAP_SYS_TTY_CONFIG);
break;
/* 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,
@ -5378,7 +5432,7 @@ static struct security_operations selinux_ops = {
.inode_listsecurity = selinux_inode_listsecurity,
.inode_need_killpriv = selinux_inode_need_killpriv,
.inode_killpriv = selinux_inode_killpriv,
.inode_getsecid = selinux_inode_getsecid,
.inode_getsecid = selinux_inode_getsecid,
.file_permission = selinux_file_permission,
.file_alloc_security = selinux_file_alloc_security,
@ -5419,7 +5473,7 @@ static struct security_operations selinux_ops = {
.task_to_inode = selinux_task_to_inode,
.ipc_permission = selinux_ipc_permission,
.ipc_getsecid = selinux_ipc_getsecid,
.ipc_getsecid = selinux_ipc_getsecid,
.msg_msg_alloc_security = selinux_msg_msg_alloc_security,
.msg_msg_free_security = selinux_msg_msg_free_security,
@ -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))

View File

@ -1,7 +1,7 @@
/*
* SELinux support for the Audit LSM hooks
*
* Most of below header was moved from include/linux/selinux.h which
* Most of below header was moved from include/linux/selinux.h which
* is released under below copyrights:
*
* Author: James Morris <jmorris@redhat.com>
@ -52,7 +52,7 @@ void selinux_audit_rule_free(void *rule);
* -errno on failure.
*/
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule,
struct audit_context *actx);
struct audit_context *actx);
/**
* selinux_audit_rule_known - check to see if rule contains selinux fields.

View File

@ -75,13 +75,12 @@ struct avc_audit_data {
/* Initialize an AVC audit data structure. */
#define AVC_AUDIT_DATA_INIT(_d,_t) \
{ memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; }
{ memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; }
/*
* AVC statistics
*/
struct avc_cache_stats
{
struct avc_cache_stats {
unsigned int lookups;
unsigned int hits;
unsigned int misses;
@ -97,8 +96,8 @@ struct avc_cache_stats
void __init avc_init(void);
void avc_audit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd, int result, struct avc_audit_data *auditdata);
u16 tclass, u32 requested,
struct av_decision *avd, int result, struct avc_audit_data *auditdata);
#define AVC_STRICT 1 /* Ignore permissive mode. */
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
@ -107,8 +106,8 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
struct av_decision *avd);
int avc_has_perm(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct avc_audit_data *auditdata);
u16 tclass, u32 requested,
struct avc_audit_data *auditdata);
u32 avc_policy_seqno(void);
@ -122,7 +121,7 @@ u32 avc_policy_seqno(void);
#define AVC_CALLBACK_AUDITDENY_DISABLE 128
int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
u16 tclass, u32 perms,
u16 tclass, u32 perms,
u32 *out_retained),
u32 events, u32 ssid, u32 tsid,
u16 tclass, u32 perms);

View File

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

View File

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

View File

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

View File

@ -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"
@ -272,7 +271,7 @@ static __init int sel_netport_init(void)
}
ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET,
SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
if (ret != 0)
panic("avc_add_callback() failed, error %d\n", ret);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
return -EINVAL;
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,8 +693,11 @@ int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
rc = -EINVAL;
goto out;
}
POLICY_RDLOCK;
context = sidtab_search(&sidtab, sid);
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",
__func__, sid);
@ -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,36 +793,90 @@ 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 = sidtab_context_to_sid(&sidtab, &context, sid);
out_unlock:
POLICY_RDUNLOCK;
context_destroy(&context);
kfree(scontext2);
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);
if (rc)
context_destroy(&context);
out:
read_unlock(&policy_rwlock);
kfree(scontext2);
kfree(str);
return rc;
}
/**
* security_context_to_sid - Obtain a SID for a given security context.
* @scontext: security context
@ -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,9 +1314,12 @@ 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);
kfree(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,18 +1960,27 @@ int security_fs_use(
goto out;
}
*sid = c->sid[0];
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;
rc = 0;
} else {
rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
if (rc) {
*behavior = SECURITY_FS_USE_NONE;
rc = 0;
} else {
*behavior = SECURITY_FS_USE_GENFS;
}
*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);
@ -2420,7 +2540,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
}
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
struct audit_context *actx)
struct audit_context *actx)
{
struct context *ctxt;
struct mls_level *level;
@ -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,14 +2647,14 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
}
out:
POLICY_RDUNLOCK;
read_unlock(&policy_rwlock);
return match;
}
static int (*aurule_callback)(void) = audit_update_lsm_rules;
static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid,
u16 class, u32 perms, u32 *retained)
u16 class, u32 perms, u32 *retained)
{
int err = 0;
@ -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 */

View File

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

View File

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

View File

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