mirror of https://gitee.com/openkylin/linux.git
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:
commit
847106ff62
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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) &&
|
||||
|
|
1251
security/dummy.c
1251
security/dummy.c
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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))
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue