|
|
|
@ -259,7 +259,7 @@ static int __inode_security_revalidate(struct inode *inode,
|
|
|
|
|
|
|
|
|
|
might_sleep_if(may_sleep);
|
|
|
|
|
|
|
|
|
|
if (isec->initialized == LABEL_INVALID) {
|
|
|
|
|
if (ss_initialized && isec->initialized != LABEL_INITIALIZED) {
|
|
|
|
|
if (!may_sleep)
|
|
|
|
|
return -ECHILD;
|
|
|
|
|
|
|
|
|
@ -297,6 +297,13 @@ static struct inode_security_struct *inode_security(struct inode *inode)
|
|
|
|
|
return inode->i_security;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry)
|
|
|
|
|
{
|
|
|
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
|
|
|
|
|
|
|
|
return inode->i_security;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get the security label of a dentry's backing inode.
|
|
|
|
|
*/
|
|
|
|
@ -686,7 +693,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
|
|
|
|
struct superblock_security_struct *sbsec = sb->s_security;
|
|
|
|
|
const char *name = sb->s_type->name;
|
|
|
|
|
struct dentry *root = sbsec->sb->s_root;
|
|
|
|
|
struct inode_security_struct *root_isec = backing_inode_security(root);
|
|
|
|
|
struct inode_security_struct *root_isec;
|
|
|
|
|
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
|
|
|
|
|
u32 defcontext_sid = 0;
|
|
|
|
|
char **mount_options = opts->mnt_opts;
|
|
|
|
@ -729,6 +736,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
|
|
|
|
&& (num_opts == 0))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
root_isec = backing_inode_security_novalidate(root);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* parse the mount options, check if they are valid sids.
|
|
|
|
|
* also check if someone is trying to mount the same sb more
|
|
|
|
@ -1622,7 +1631,7 @@ static int current_has_perm(const struct task_struct *tsk,
|
|
|
|
|
|
|
|
|
|
/* Check whether a task is allowed to use a capability. */
|
|
|
|
|
static int cred_has_capability(const struct cred *cred,
|
|
|
|
|
int cap, int audit)
|
|
|
|
|
int cap, int audit, bool initns)
|
|
|
|
|
{
|
|
|
|
|
struct common_audit_data ad;
|
|
|
|
|
struct av_decision avd;
|
|
|
|
@ -1636,10 +1645,10 @@ static int cred_has_capability(const struct cred *cred,
|
|
|
|
|
|
|
|
|
|
switch (CAP_TO_INDEX(cap)) {
|
|
|
|
|
case 0:
|
|
|
|
|
sclass = SECCLASS_CAPABILITY;
|
|
|
|
|
sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sclass = SECCLASS_CAPABILITY2;
|
|
|
|
|
sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
printk(KERN_ERR
|
|
|
|
@ -1781,7 +1790,6 @@ static int selinux_determine_inode_label(struct inode *dir,
|
|
|
|
|
u32 *_new_isid)
|
|
|
|
|
{
|
|
|
|
|
const struct superblock_security_struct *sbsec = dir->i_sb->s_security;
|
|
|
|
|
const struct inode_security_struct *dsec = inode_security(dir);
|
|
|
|
|
const struct task_security_struct *tsec = current_security();
|
|
|
|
|
|
|
|
|
|
if ((sbsec->flags & SE_SBINITIALIZED) &&
|
|
|
|
@ -1791,6 +1799,7 @@ static int selinux_determine_inode_label(struct inode *dir,
|
|
|
|
|
tsec->create_sid) {
|
|
|
|
|
*_new_isid = tsec->create_sid;
|
|
|
|
|
} else {
|
|
|
|
|
const struct inode_security_struct *dsec = inode_security(dir);
|
|
|
|
|
return security_transition_sid(tsec->sid, dsec->sid, tclass,
|
|
|
|
|
name, _new_isid);
|
|
|
|
|
}
|
|
|
|
@ -2075,7 +2084,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
|
|
|
|
|
u32 sid = task_sid(to);
|
|
|
|
|
struct file_security_struct *fsec = file->f_security;
|
|
|
|
|
struct dentry *dentry = file->f_path.dentry;
|
|
|
|
|
struct inode_security_struct *isec = backing_inode_security(dentry);
|
|
|
|
|
struct inode_security_struct *isec;
|
|
|
|
|
struct common_audit_data ad;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
@ -2094,6 +2103,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
|
|
|
|
|
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
isec = backing_inode_security(dentry);
|
|
|
|
|
return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
|
|
|
|
|
&ad);
|
|
|
|
|
}
|
|
|
|
@ -2142,7 +2152,7 @@ static int selinux_capset(struct cred *new, const struct cred *old,
|
|
|
|
|
static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
|
|
|
|
|
int cap, int audit)
|
|
|
|
|
{
|
|
|
|
|
return cred_has_capability(cred, cap, audit);
|
|
|
|
|
return cred_has_capability(cred, cap, audit, ns == &init_user_ns);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
|
|
|
|
@ -2220,7 +2230,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
|
|
|
|
|
int rc, cap_sys_admin = 0;
|
|
|
|
|
|
|
|
|
|
rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
|
|
|
|
|
SECURITY_CAP_NOAUDIT);
|
|
|
|
|
SECURITY_CAP_NOAUDIT, true);
|
|
|
|
|
if (rc == 0)
|
|
|
|
|
cap_sys_admin = 1;
|
|
|
|
|
|
|
|
|
@ -2229,6 +2239,20 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
|
|
|
|
|
|
|
|
|
|
/* binprm security operations */
|
|
|
|
|
|
|
|
|
|
static u32 ptrace_parent_sid(struct task_struct *task)
|
|
|
|
|
{
|
|
|
|
|
u32 sid = 0;
|
|
|
|
|
struct task_struct *tracer;
|
|
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
tracer = ptrace_parent(task);
|
|
|
|
|
if (tracer)
|
|
|
|
|
sid = task_sid(tracer);
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
|
|
return sid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int check_nnp_nosuid(const struct linux_binprm *bprm,
|
|
|
|
|
const struct task_security_struct *old_tsec,
|
|
|
|
|
const struct task_security_struct *new_tsec)
|
|
|
|
@ -2350,18 +2374,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
|
|
|
|
|
* changes its SID has the appropriate permit */
|
|
|
|
|
if (bprm->unsafe &
|
|
|
|
|
(LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
|
|
|
|
|
struct task_struct *tracer;
|
|
|
|
|
struct task_security_struct *sec;
|
|
|
|
|
u32 ptsid = 0;
|
|
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
tracer = ptrace_parent(current);
|
|
|
|
|
if (likely(tracer != NULL)) {
|
|
|
|
|
sec = __task_cred(tracer)->security;
|
|
|
|
|
ptsid = sec->sid;
|
|
|
|
|
}
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
|
|
u32 ptsid = ptrace_parent_sid(current);
|
|
|
|
|
if (ptsid != 0) {
|
|
|
|
|
rc = avc_has_perm(ptsid, new_tsec->sid,
|
|
|
|
|
SECCLASS_PROCESS,
|
|
|
|
@ -3045,7 +3058,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
|
|
|
|
|
const void *value, size_t size, int flags)
|
|
|
|
|
{
|
|
|
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
|
|
|
struct inode_security_struct *isec = backing_inode_security(dentry);
|
|
|
|
|
struct inode_security_struct *isec;
|
|
|
|
|
struct superblock_security_struct *sbsec;
|
|
|
|
|
struct common_audit_data ad;
|
|
|
|
|
u32 newsid, sid = current_sid();
|
|
|
|
@ -3064,6 +3077,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
|
|
|
|
|
ad.type = LSM_AUDIT_DATA_DENTRY;
|
|
|
|
|
ad.u.dentry = dentry;
|
|
|
|
|
|
|
|
|
|
isec = backing_inode_security(dentry);
|
|
|
|
|
rc = avc_has_perm(sid, isec->sid, isec->sclass,
|
|
|
|
|
FILE__RELABELFROM, &ad);
|
|
|
|
|
if (rc)
|
|
|
|
@ -3122,7 +3136,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
|
|
|
|
|
int flags)
|
|
|
|
|
{
|
|
|
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
|
|
|
struct inode_security_struct *isec = backing_inode_security(dentry);
|
|
|
|
|
struct inode_security_struct *isec;
|
|
|
|
|
u32 newsid;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
@ -3139,6 +3153,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isec = backing_inode_security(dentry);
|
|
|
|
|
isec->sclass = inode_mode_to_security_class(inode->i_mode);
|
|
|
|
|
isec->sid = newsid;
|
|
|
|
|
isec->initialized = LABEL_INITIALIZED;
|
|
|
|
@ -3180,7 +3195,7 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
|
|
|
|
|
u32 size;
|
|
|
|
|
int error;
|
|
|
|
|
char *context = NULL;
|
|
|
|
|
struct inode_security_struct *isec = inode_security(inode);
|
|
|
|
|
struct inode_security_struct *isec;
|
|
|
|
|
|
|
|
|
|
if (strcmp(name, XATTR_SELINUX_SUFFIX))
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
@ -3198,7 +3213,8 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
|
|
|
|
|
SECURITY_CAP_NOAUDIT);
|
|
|
|
|
if (!error)
|
|
|
|
|
error = cred_has_capability(current_cred(), CAP_MAC_ADMIN,
|
|
|
|
|
SECURITY_CAP_NOAUDIT);
|
|
|
|
|
SECURITY_CAP_NOAUDIT, true);
|
|
|
|
|
isec = inode_security(inode);
|
|
|
|
|
if (!error)
|
|
|
|
|
error = security_sid_to_context_force(isec->sid, &context,
|
|
|
|
|
&size);
|
|
|
|
@ -3219,7 +3235,7 @@ out_nofree:
|
|
|
|
|
static int selinux_inode_setsecurity(struct inode *inode, const char *name,
|
|
|
|
|
const void *value, size_t size, int flags)
|
|
|
|
|
{
|
|
|
|
|
struct inode_security_struct *isec = inode_security(inode);
|
|
|
|
|
struct inode_security_struct *isec = inode_security_novalidate(inode);
|
|
|
|
|
u32 newsid;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
@ -3308,7 +3324,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
|
|
|
|
|
struct common_audit_data ad;
|
|
|
|
|
struct file_security_struct *fsec = file->f_security;
|
|
|
|
|
struct inode *inode = file_inode(file);
|
|
|
|
|
struct inode_security_struct *isec = inode_security(inode);
|
|
|
|
|
struct inode_security_struct *isec;
|
|
|
|
|
struct lsm_ioctlop_audit ioctl;
|
|
|
|
|
u32 ssid = cred_sid(cred);
|
|
|
|
|
int rc;
|
|
|
|
@ -3332,6 +3348,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
|
|
|
|
|
if (unlikely(IS_PRIVATE(inode)))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
isec = inode_security(inode);
|
|
|
|
|
rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,
|
|
|
|
|
requested, driver, xperm, &ad);
|
|
|
|
|
out:
|
|
|
|
@ -3373,7 +3390,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
|
|
|
|
|
case KDSKBENT:
|
|
|
|
|
case KDSKBSENT:
|
|
|
|
|
error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
|
|
|
|
|
SECURITY_CAP_AUDIT);
|
|
|
|
|
SECURITY_CAP_AUDIT, true);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* default case assumes that the command will go
|
|
|
|
@ -3462,8 +3479,9 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
|
|
|
|
|
vma->vm_end <= vma->vm_mm->brk) {
|
|
|
|
|
rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
|
|
|
|
|
} else if (!vma->vm_file &&
|
|
|
|
|
vma->vm_start <= vma->vm_mm->start_stack &&
|
|
|
|
|
vma->vm_end >= vma->vm_mm->start_stack) {
|
|
|
|
|
((vma->vm_start <= vma->vm_mm->start_stack &&
|
|
|
|
|
vma->vm_end >= vma->vm_mm->start_stack) ||
|
|
|
|
|
vma_is_stack_for_task(vma, current))) {
|
|
|
|
|
rc = current_has_perm(current, PROCESS__EXECSTACK);
|
|
|
|
|
} else if (vma->vm_file && vma->anon_vma) {
|
|
|
|
|
/*
|
|
|
|
@ -3719,6 +3737,52 @@ static int selinux_kernel_module_request(char *kmod_name)
|
|
|
|
|
SYSTEM__MODULE_REQUEST, &ad);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int selinux_kernel_module_from_file(struct file *file)
|
|
|
|
|
{
|
|
|
|
|
struct common_audit_data ad;
|
|
|
|
|
struct inode_security_struct *isec;
|
|
|
|
|
struct file_security_struct *fsec;
|
|
|
|
|
u32 sid = current_sid();
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
/* init_module */
|
|
|
|
|
if (file == NULL)
|
|
|
|
|
return avc_has_perm(sid, sid, SECCLASS_SYSTEM,
|
|
|
|
|
SYSTEM__MODULE_LOAD, NULL);
|
|
|
|
|
|
|
|
|
|
/* finit_module */
|
|
|
|
|
|
|
|
|
|
ad.type = LSM_AUDIT_DATA_PATH;
|
|
|
|
|
ad.u.path = file->f_path;
|
|
|
|
|
|
|
|
|
|
fsec = file->f_security;
|
|
|
|
|
if (sid != fsec->sid) {
|
|
|
|
|
rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isec = inode_security(file_inode(file));
|
|
|
|
|
return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM,
|
|
|
|
|
SYSTEM__MODULE_LOAD, &ad);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int selinux_kernel_read_file(struct file *file,
|
|
|
|
|
enum kernel_read_file_id id)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
|
|
switch (id) {
|
|
|
|
|
case READING_MODULE:
|
|
|
|
|
rc = selinux_kernel_module_from_file(file);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
|
|
|
|
|
{
|
|
|
|
|
return current_has_perm(p, PROCESS__SETPGID);
|
|
|
|
@ -4598,6 +4662,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
|
|
|
|
|
{
|
|
|
|
|
u32 peer_secid = SECSID_NULL;
|
|
|
|
|
u16 family;
|
|
|
|
|
struct inode_security_struct *isec;
|
|
|
|
|
|
|
|
|
|
if (skb && skb->protocol == htons(ETH_P_IP))
|
|
|
|
|
family = PF_INET;
|
|
|
|
@ -4608,9 +4673,10 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
|
|
|
|
|
else
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
if (sock && family == PF_UNIX)
|
|
|
|
|
selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid);
|
|
|
|
|
else if (skb)
|
|
|
|
|
if (sock && family == PF_UNIX) {
|
|
|
|
|
isec = inode_security_novalidate(SOCK_INODE(sock));
|
|
|
|
|
peer_secid = isec->sid;
|
|
|
|
|
} else if (skb)
|
|
|
|
|
selinux_skb_peerlbl_sid(skb, family, &peer_secid);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
@ -5675,7 +5741,6 @@ static int selinux_setprocattr(struct task_struct *p,
|
|
|
|
|
char *name, void *value, size_t size)
|
|
|
|
|
{
|
|
|
|
|
struct task_security_struct *tsec;
|
|
|
|
|
struct task_struct *tracer;
|
|
|
|
|
struct cred *new;
|
|
|
|
|
u32 sid = 0, ptsid;
|
|
|
|
|
int error;
|
|
|
|
@ -5782,14 +5847,8 @@ static int selinux_setprocattr(struct task_struct *p,
|
|
|
|
|
|
|
|
|
|
/* Check for ptracing, and update the task SID if ok.
|
|
|
|
|
Otherwise, leave SID unchanged and fail. */
|
|
|
|
|
ptsid = 0;
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
tracer = ptrace_parent(p);
|
|
|
|
|
if (tracer)
|
|
|
|
|
ptsid = task_sid(tracer);
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
|
|
if (tracer) {
|
|
|
|
|
ptsid = ptrace_parent_sid(p);
|
|
|
|
|
if (ptsid != 0) {
|
|
|
|
|
error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
|
|
|
|
|
PROCESS__PTRACE, NULL);
|
|
|
|
|
if (error)
|
|
|
|
@ -6020,6 +6079,7 @@ static struct security_hook_list selinux_hooks[] = {
|
|
|
|
|
LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
|
|
|
|
|
LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
|
|
|
|
|
LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
|
|
|
|
|
LSM_HOOK_INIT(kernel_read_file, selinux_kernel_read_file),
|
|
|
|
|
LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
|
|
|
|
|
LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
|
|
|
|
|
LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
|
|
|
|
|