|
|
|
|
@@ -737,6 +737,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sbsec->creator_sid = current_sid();
|
|
|
|
|
|
|
|
|
|
if (strcmp(sb->s_type->name, "proc") == 0)
|
|
|
|
|
sbsec->flags |= SE_SBPROC | SE_SBGENFS;
|
|
|
|
|
|
|
|
|
|
@@ -908,6 +910,8 @@ static int selinux_cmp_sb_context(const struct super_block *oldsb,
|
|
|
|
|
if (oldroot->sid != newroot->sid)
|
|
|
|
|
goto mismatch;
|
|
|
|
|
}
|
|
|
|
|
if (old->creator_sid != new->creator_sid)
|
|
|
|
|
goto mismatch;
|
|
|
|
|
return 0;
|
|
|
|
|
mismatch:
|
|
|
|
|
pr_warn("SELinux: mount invalid. Same superblock, "
|
|
|
|
|
@@ -967,6 +971,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
|
|
|
|
|
newsbsec->sid = oldsbsec->sid;
|
|
|
|
|
newsbsec->def_sid = oldsbsec->def_sid;
|
|
|
|
|
newsbsec->behavior = oldsbsec->behavior;
|
|
|
|
|
newsbsec->creator_sid = oldsbsec->creator_sid;
|
|
|
|
|
|
|
|
|
|
if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
|
|
|
|
|
!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
|
|
|
|
|
@@ -1654,7 +1659,6 @@ static int cred_has_capability(const struct cred *cred,
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
pr_err("SELinux: out of range capability %d\n", cap);
|
|
|
|
|
BUG();
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2586,6 +2590,7 @@ static int selinux_sb_alloc_security(struct super_block *sb)
|
|
|
|
|
sbsec->sid = SECINITSID_UNLABELED;
|
|
|
|
|
sbsec->def_sid = SECINITSID_FILE;
|
|
|
|
|
sbsec->mntpoint_sid = SECINITSID_UNLABELED;
|
|
|
|
|
sbsec->creator_sid = SECINITSID_UNLABELED;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@@ -7043,6 +7048,9 @@ static int selinux_bpf(int cmd, union bpf_attr *attr,
|
|
|
|
|
u32 sid = current_sid();
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (selinux_policycap_bpf_token_perms())
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case BPF_MAP_CREATE:
|
|
|
|
|
ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
|
|
|
|
|
@@ -7124,60 +7132,144 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
|
|
|
|
|
BPF__PROG_RUN, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static u32 selinux_bpffs_creator_sid(u32 fd)
|
|
|
|
|
{
|
|
|
|
|
struct path path;
|
|
|
|
|
struct super_block *sb;
|
|
|
|
|
struct superblock_security_struct *sbsec;
|
|
|
|
|
|
|
|
|
|
CLASS(fd, f)(fd);
|
|
|
|
|
|
|
|
|
|
if (fd_empty(f))
|
|
|
|
|
return SECSID_NULL;
|
|
|
|
|
|
|
|
|
|
path = fd_file(f)->f_path;
|
|
|
|
|
sb = path.dentry->d_sb;
|
|
|
|
|
sbsec = selinux_superblock(sb);
|
|
|
|
|
|
|
|
|
|
return sbsec->creator_sid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
|
|
|
|
|
struct bpf_token *token, bool kernel)
|
|
|
|
|
{
|
|
|
|
|
struct bpf_security_struct *bpfsec;
|
|
|
|
|
u32 ssid;
|
|
|
|
|
|
|
|
|
|
bpfsec = selinux_bpf_map_security(map);
|
|
|
|
|
bpfsec->sid = current_sid();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
if (!token)
|
|
|
|
|
ssid = bpfsec->sid;
|
|
|
|
|
else
|
|
|
|
|
ssid = selinux_bpffs_creator_sid(attr->map_token_fd);
|
|
|
|
|
|
|
|
|
|
return avc_has_perm(ssid, bpfsec->sid, SECCLASS_BPF, BPF__MAP_CREATE,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
|
|
|
|
|
struct bpf_token *token, bool kernel)
|
|
|
|
|
{
|
|
|
|
|
struct bpf_security_struct *bpfsec;
|
|
|
|
|
u32 ssid;
|
|
|
|
|
|
|
|
|
|
bpfsec = selinux_bpf_prog_security(prog);
|
|
|
|
|
bpfsec->sid = current_sid();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
if (!token)
|
|
|
|
|
ssid = bpfsec->sid;
|
|
|
|
|
else
|
|
|
|
|
ssid = selinux_bpffs_creator_sid(attr->prog_token_fd);
|
|
|
|
|
|
|
|
|
|
return avc_has_perm(ssid, bpfsec->sid, SECCLASS_BPF, BPF__PROG_LOAD,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr,
|
|
|
|
|
#define bpf_token_cmd(T, C) \
|
|
|
|
|
((T)->allowed_cmds & (1ULL << (C)))
|
|
|
|
|
|
|
|
|
|
static int selinux_bpf_token_create(struct bpf_token *token,
|
|
|
|
|
union bpf_attr *attr,
|
|
|
|
|
const struct path *path)
|
|
|
|
|
{
|
|
|
|
|
struct bpf_security_struct *bpfsec;
|
|
|
|
|
u32 sid = selinux_bpffs_creator_sid(attr->token_create.bpffs_fd);
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
bpfsec = selinux_bpf_token_security(token);
|
|
|
|
|
bpfsec->sid = current_sid();
|
|
|
|
|
bpfsec->grantor_sid = sid;
|
|
|
|
|
|
|
|
|
|
bpfsec->perms = 0;
|
|
|
|
|
/**
|
|
|
|
|
* 'token->allowed_cmds' is a bit mask of allowed commands
|
|
|
|
|
* Convert the BPF command enum to a bitmask representing its position
|
|
|
|
|
* in the allowed_cmds bitmap.
|
|
|
|
|
*/
|
|
|
|
|
if (bpf_token_cmd(token, BPF_MAP_CREATE)) {
|
|
|
|
|
err = avc_has_perm(bpfsec->sid, sid, SECCLASS_BPF,
|
|
|
|
|
BPF__MAP_CREATE_AS, NULL);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
bpfsec->perms |= BPF__MAP_CREATE;
|
|
|
|
|
}
|
|
|
|
|
if (bpf_token_cmd(token, BPF_PROG_LOAD)) {
|
|
|
|
|
err = avc_has_perm(bpfsec->sid, sid, SECCLASS_BPF,
|
|
|
|
|
BPF__PROG_LOAD_AS, NULL);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
bpfsec->perms |= BPF__PROG_LOAD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
|
|
|
|
|
.lbs_cred = sizeof(struct cred_security_struct),
|
|
|
|
|
.lbs_task = sizeof(struct task_security_struct),
|
|
|
|
|
.lbs_file = sizeof(struct file_security_struct),
|
|
|
|
|
.lbs_inode = sizeof(struct inode_security_struct),
|
|
|
|
|
.lbs_ipc = sizeof(struct ipc_security_struct),
|
|
|
|
|
.lbs_key = sizeof(struct key_security_struct),
|
|
|
|
|
.lbs_msg_msg = sizeof(struct msg_security_struct),
|
|
|
|
|
#ifdef CONFIG_PERF_EVENTS
|
|
|
|
|
.lbs_perf_event = sizeof(struct perf_event_security_struct),
|
|
|
|
|
static int selinux_bpf_token_cmd(const struct bpf_token *token,
|
|
|
|
|
enum bpf_cmd cmd)
|
|
|
|
|
{
|
|
|
|
|
struct bpf_security_struct *bpfsec;
|
|
|
|
|
|
|
|
|
|
bpfsec = token->security;
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case BPF_MAP_CREATE:
|
|
|
|
|
if (!(bpfsec->perms & BPF__MAP_CREATE))
|
|
|
|
|
return -EACCES;
|
|
|
|
|
break;
|
|
|
|
|
case BPF_PROG_LOAD:
|
|
|
|
|
if (!(bpfsec->perms & BPF__PROG_LOAD))
|
|
|
|
|
return -EACCES;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int selinux_bpf_token_capable(const struct bpf_token *token, int cap)
|
|
|
|
|
{
|
|
|
|
|
u16 sclass;
|
|
|
|
|
struct bpf_security_struct *bpfsec = token->security;
|
|
|
|
|
bool initns = (token->userns == &init_user_ns);
|
|
|
|
|
u32 av = CAP_TO_MASK(cap);
|
|
|
|
|
|
|
|
|
|
switch (CAP_TO_INDEX(cap)) {
|
|
|
|
|
case 0:
|
|
|
|
|
sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
pr_err("SELinux: out of range capability %d\n", cap);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return avc_has_perm(current_sid(), bpfsec->grantor_sid, sclass, av,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
.lbs_sock = sizeof(struct sk_security_struct),
|
|
|
|
|
.lbs_superblock = sizeof(struct superblock_security_struct),
|
|
|
|
|
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
|
|
|
|
|
.lbs_tun_dev = sizeof(struct tun_security_struct),
|
|
|
|
|
.lbs_ib = sizeof(struct ib_security_struct),
|
|
|
|
|
.lbs_bpf_map = sizeof(struct bpf_security_struct),
|
|
|
|
|
.lbs_bpf_prog = sizeof(struct bpf_security_struct),
|
|
|
|
|
.lbs_bpf_token = sizeof(struct bpf_security_struct),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_PERF_EVENTS
|
|
|
|
|
static int selinux_perf_event_open(int type)
|
|
|
|
|
@@ -7297,6 +7389,27 @@ static const struct lsm_id selinux_lsmid = {
|
|
|
|
|
.id = LSM_ID_SELINUX,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
|
|
|
|
|
.lbs_cred = sizeof(struct cred_security_struct),
|
|
|
|
|
.lbs_task = sizeof(struct task_security_struct),
|
|
|
|
|
.lbs_file = sizeof(struct file_security_struct),
|
|
|
|
|
.lbs_inode = sizeof(struct inode_security_struct),
|
|
|
|
|
.lbs_ipc = sizeof(struct ipc_security_struct),
|
|
|
|
|
.lbs_key = sizeof(struct key_security_struct),
|
|
|
|
|
.lbs_msg_msg = sizeof(struct msg_security_struct),
|
|
|
|
|
#ifdef CONFIG_PERF_EVENTS
|
|
|
|
|
.lbs_perf_event = sizeof(struct perf_event_security_struct),
|
|
|
|
|
#endif
|
|
|
|
|
.lbs_sock = sizeof(struct sk_security_struct),
|
|
|
|
|
.lbs_superblock = sizeof(struct superblock_security_struct),
|
|
|
|
|
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
|
|
|
|
|
.lbs_tun_dev = sizeof(struct tun_security_struct),
|
|
|
|
|
.lbs_ib = sizeof(struct ib_security_struct),
|
|
|
|
|
.lbs_bpf_map = sizeof(struct bpf_security_struct),
|
|
|
|
|
.lbs_bpf_prog = sizeof(struct bpf_security_struct),
|
|
|
|
|
.lbs_bpf_token = sizeof(struct bpf_security_struct),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* IMPORTANT NOTE: When adding new hooks, please be careful to keep this order:
|
|
|
|
|
* 1. any hooks that don't belong to (2.) or (3.) below,
|
|
|
|
|
@@ -7590,6 +7703,8 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
|
|
|
|
|
LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create),
|
|
|
|
|
LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load),
|
|
|
|
|
LSM_HOOK_INIT(bpf_token_create, selinux_bpf_token_create),
|
|
|
|
|
LSM_HOOK_INIT(bpf_token_cmd, selinux_bpf_token_cmd),
|
|
|
|
|
LSM_HOOK_INIT(bpf_token_capable, selinux_bpf_token_capable),
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef CONFIG_PERF_EVENTS
|
|
|
|
|
LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc),
|
|
|
|
|
|