Commit f1c921fb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'selinux-pr-20210426' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

Pull selinux updates from Paul Moore:

 - Add support for measuring the SELinux state and policy capabilities
   using IMA.

 - A handful of SELinux/NFS patches to compare the SELinux state of one
   mount with a set of mount options. Olga goes into more detail in the
   patch descriptions, but this is important as it allows more
   flexibility when using NFS and SELinux context mounts.

 - Properly differentiate between the subjective and objective LSM
   credentials; including support for the SELinux and Smack. My clumsy
   attempt at a proper fix for AppArmor didn't quite pass muster so John
   is working on a proper AppArmor patch, in the meantime this set of
   patches shouldn't change the behavior of AppArmor in any way. This
   change explains the bulk of the diffstat beyond security/.

 - Fix a problem where we were not properly terminating the permission
   list for two SELinux object classes.

* tag 'selinux-pr-20210426' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: add proper NULL termination to the secclass_map permissions
  smack: differentiate between subjective and objective task credentials
  selinux: clarify task subjective and objective credentials
  lsm: separate security_task_getsecid() into subjective and objective variants
  nfs: account for selinux security context when deciding to share superblock
  nfs: remove unneeded null check in nfs_fill_super()
  lsm,selinux: add new hook to compare new mount to an existing mount
  selinux: fix misspellings using codespell tool
  selinux: fix misspellings using codespell tool
  selinux: measure state and policy capabilities
  selinux: Allow context mounts for unpriviliged overlayfs
parents fafe1e39 e4c82eaf
......@@ -2713,7 +2713,16 @@ static void binder_transaction(struct binder_proc *proc,
u32 secid;
size_t added_size;
security_task_getsecid(proc->tsk, &secid);
/*
* Arguably this should be the task's subjective LSM secid but
* we can't reliably access the subjective creds of a task
* other than our own so we must use the objective creds, which
* are safe to access. The downside is that if a task is
* temporarily overriding it's creds it will not be reflected
* here; however, it isn't clear that binder would handle that
* case well anyway.
*/
security_task_getsecid_obj(proc->tsk, &secid);
ret = security_secid_to_secctx(secid, &secctx, &secctx_sz);
if (ret) {
return_error = BR_FAILED_REPLY;
......
......@@ -463,6 +463,9 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
if (opt < 0)
return ctx->sloppy ? 1 : opt;
if (fc->security)
ctx->has_sec_mnt_opts = 1;
switch (opt) {
case Opt_source:
if (fc->source)
......
......@@ -96,6 +96,7 @@ struct nfs_fs_context {
char *fscache_uniq;
unsigned short protofamily;
unsigned short mountfamily;
bool has_sec_mnt_opts;
struct {
union {
......
......@@ -1045,7 +1045,7 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx)
sb->s_blocksize = 0;
sb->s_xattr = server->nfs_client->cl_nfs_mod->xattr;
sb->s_op = server->nfs_client->cl_nfs_mod->sops;
if (ctx && ctx->bsize)
if (ctx->bsize)
sb->s_blocksize = nfs_block_size(ctx->bsize, &sb->s_blocksize_bits);
if (server->nfs_client->rpc_ops->version != 2) {
......@@ -1077,6 +1077,7 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx)
&sb->s_blocksize_bits);
nfs_super_set_maxbytes(sb, server->maxfilesize);
server->has_sec_mnt_opts = ctx->has_sec_mnt_opts;
}
static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b,
......@@ -1193,6 +1194,9 @@ static int nfs_compare_super(struct super_block *sb, struct fs_context *fc)
return 0;
if (!nfs_compare_userns(old, server))
return 0;
if ((old->has_sec_mnt_opts || fc->security) &&
security_sb_mnt_opts_compat(sb, fc->security))
return 0;
return nfs_compare_mount_options(sb, server, fc);
}
......
......@@ -140,7 +140,7 @@ struct cred {
struct key *request_key_auth; /* assumed request_key authority */
#endif
#ifdef CONFIG_SECURITY
void *security; /* subjective LSM security */
void *security; /* LSM security */
#endif
struct user_struct *user; /* real user ID subscription */
struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
......
......@@ -62,6 +62,7 @@ LSM_HOOK(int, 0, sb_alloc_security, struct super_block *sb)
LSM_HOOK(void, LSM_RET_VOID, sb_free_security, struct super_block *sb)
LSM_HOOK(void, LSM_RET_VOID, sb_free_mnt_opts, void *mnt_opts)
LSM_HOOK(int, 0, sb_eat_lsm_opts, char *orig, void **mnt_opts)
LSM_HOOK(int, 0, sb_mnt_opts_compat, struct super_block *sb, void *mnt_opts)
LSM_HOOK(int, 0, sb_remount, struct super_block *sb, void *mnt_opts)
LSM_HOOK(int, 0, sb_kern_mount, struct super_block *sb)
LSM_HOOK(int, 0, sb_show_options, struct seq_file *m, struct super_block *sb)
......@@ -203,7 +204,10 @@ LSM_HOOK(int, 0, task_fix_setgid, struct cred *new, const struct cred * old,
LSM_HOOK(int, 0, task_setpgid, struct task_struct *p, pid_t pgid)
LSM_HOOK(int, 0, task_getpgid, struct task_struct *p)
LSM_HOOK(int, 0, task_getsid, struct task_struct *p)
LSM_HOOK(void, LSM_RET_VOID, task_getsecid, struct task_struct *p, u32 *secid)
LSM_HOOK(void, LSM_RET_VOID, task_getsecid_subj,
struct task_struct *p, u32 *secid)
LSM_HOOK(void, LSM_RET_VOID, task_getsecid_obj,
struct task_struct *p, u32 *secid)
LSM_HOOK(int, 0, task_setnice, struct task_struct *p, int nice)
LSM_HOOK(int, 0, task_setioprio, struct task_struct *p, int ioprio)
LSM_HOOK(int, 0, task_getioprio, struct task_struct *p)
......
......@@ -142,6 +142,12 @@
* @orig the original mount data copied from userspace.
* @copy copied data which will be passed to the security module.
* Returns 0 if the copy was successful.
* @sb_mnt_opts_compat:
* Determine if the new mount options in @mnt_opts are allowed given
* the existing mounted filesystem at @sb.
* @sb superblock being compared
* @mnt_opts new mount options
* Return 0 if options are compatible.
* @sb_remount:
* Extracts security system specific mount options and verifies no changes
* are being made to those options.
......@@ -707,9 +713,15 @@
* @p.
* @p contains the task_struct for the process.
* Return 0 if permission is granted.
* @task_getsecid:
* Retrieve the security identifier of the process @p.
* @p contains the task_struct for the process and place is into @secid.
* @task_getsecid_subj:
* Retrieve the subjective security identifier of the task_struct in @p
* and return it in @secid. Special care must be taken to ensure that @p
* is the either the "current" task, or the caller has exclusive access
* to @p.
* In case of failure, @secid will be set to zero.
* @task_getsecid_obj:
* Retrieve the objective security identifier of the task_struct in @p
* and return it in @secid.
* In case of failure, @secid will be set to zero.
*
* @task_setnice:
......
......@@ -256,6 +256,7 @@ struct nfs_server {
/* User namespace info */
const struct cred *cred;
bool has_sec_mnt_opts;
};
/* Server capabilities */
......
......@@ -294,6 +294,7 @@ int security_sb_alloc(struct super_block *sb);
void security_sb_free(struct super_block *sb);
void security_free_mnt_opts(void **mnt_opts);
int security_sb_eat_lsm_opts(char *options, void **mnt_opts);
int security_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts);
int security_sb_remount(struct super_block *sb, void *mnt_opts);
int security_sb_kern_mount(struct super_block *sb);
int security_sb_show_options(struct seq_file *m, struct super_block *sb);
......@@ -414,7 +415,8 @@ int security_task_fix_setgid(struct cred *new, const struct cred *old,
int security_task_setpgid(struct task_struct *p, pid_t pgid);
int security_task_getpgid(struct task_struct *p);
int security_task_getsid(struct task_struct *p);
void security_task_getsecid(struct task_struct *p, u32 *secid);
void security_task_getsecid_subj(struct task_struct *p, u32 *secid);
void security_task_getsecid_obj(struct task_struct *p, u32 *secid);
int security_task_setnice(struct task_struct *p, int nice);
int security_task_setioprio(struct task_struct *p, int ioprio);
int security_task_getioprio(struct task_struct *p);
......@@ -646,6 +648,13 @@ static inline int security_sb_remount(struct super_block *sb,
return 0;
}
static inline int security_sb_mnt_opts_compat(struct super_block *sb,
void *mnt_opts)
{
return 0;
}
static inline int security_sb_kern_mount(struct super_block *sb)
{
return 0;
......@@ -1098,7 +1107,12 @@ static inline int security_task_getsid(struct task_struct *p)
return 0;
}
static inline void security_task_getsecid(struct task_struct *p, u32 *secid)
static inline void security_task_getsecid_subj(struct task_struct *p, u32 *secid)
{
*secid = 0;
}
static inline void security_task_getsecid_obj(struct task_struct *p, u32 *secid)
{
*secid = 0;
}
......
......@@ -2132,7 +2132,7 @@ int audit_log_task_context(struct audit_buffer *ab)
int error;
u32 sid;
security_task_getsecid(current, &sid);
security_task_getsecid_subj(current, &sid);
if (!sid)
return 0;
......@@ -2353,7 +2353,7 @@ int audit_signal_info(int sig, struct task_struct *t)
audit_sig_uid = auid;
else
audit_sig_uid = uid;
security_task_getsecid(current, &audit_sig_sid);
security_task_getsecid_subj(current, &audit_sig_sid);
}
return audit_signal_info_syscall(t);
......
......@@ -1359,7 +1359,8 @@ int audit_filter(int msgtype, unsigned int listtype)
case AUDIT_SUBJ_SEN:
case AUDIT_SUBJ_CLR:
if (f->lsm_rule) {
security_task_getsecid(current, &sid);
security_task_getsecid_subj(current,
&sid);
result = security_audit_rule_match(sid,
f->type, f->op, f->lsm_rule);
}
......
......@@ -667,7 +667,7 @@ static int audit_filter_rules(struct task_struct *tsk,
logged upon error */
if (f->lsm_rule) {
if (need_sid) {
security_task_getsecid(tsk, &sid);
security_task_getsecid_subj(tsk, &sid);
need_sid = 0;
}
result = security_audit_rule_match(sid, f->type,
......@@ -2400,7 +2400,7 @@ void __audit_ptrace(struct task_struct *t)
context->target_auid = audit_get_loginuid(t);
context->target_uid = task_uid(t);
context->target_sessionid = audit_get_sessionid(t);
security_task_getsecid(t, &context->target_sid);
security_task_getsecid_obj(t, &context->target_sid);
memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
}
......@@ -2427,7 +2427,7 @@ int audit_signal_info_syscall(struct task_struct *t)
ctx->target_auid = audit_get_loginuid(t);
ctx->target_uid = t_uid;
ctx->target_sessionid = audit_get_sessionid(t);
security_task_getsecid(t, &ctx->target_sid);
security_task_getsecid_obj(t, &ctx->target_sid);
memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
return 0;
}
......@@ -2448,7 +2448,7 @@ int audit_signal_info_syscall(struct task_struct *t)
axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
axp->target_uid[axp->pid_count] = t_uid;
axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
security_task_getsecid_obj(t, &axp->target_sid[axp->pid_count]);
memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
axp->pid_count++;
......
......@@ -209,7 +209,8 @@ BTF_ID(func, bpf_lsm_socket_socketpair)
BTF_ID(func, bpf_lsm_syslog)
BTF_ID(func, bpf_lsm_task_alloc)
BTF_ID(func, bpf_lsm_task_getsecid)
BTF_ID(func, bpf_lsm_task_getsecid_subj)
BTF_ID(func, bpf_lsm_task_getsecid_obj)
BTF_ID(func, bpf_lsm_task_prctl)
BTF_ID(func, bpf_lsm_task_setscheduler)
BTF_ID(func, bpf_lsm_task_to_inode)
......
......@@ -1539,7 +1539,7 @@ int __init netlbl_unlabel_defconf(void)
/* Only the kernel is allowed to call this function and the only time
* it is called is at bootup before the audit subsystem is reporting
* messages so don't worry to much about these values. */
security_task_getsecid(current, &audit_info.secid);
security_task_getsecid_subj(current, &audit_info.secid);
audit_info.loginuid = GLOBAL_ROOT_UID;
audit_info.sessionid = 0;
......
......@@ -34,7 +34,7 @@
static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
struct netlbl_audit *audit_info)
{
security_task_getsecid(current, &audit_info->secid);
security_task_getsecid_subj(current, &audit_info->secid);
audit_info->loginuid = audit_get_loginuid(current);
audit_info->sessionid = audit_get_sessionid(current);
}
......
......@@ -1252,7 +1252,8 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(task_free, apparmor_task_free),
LSM_HOOK_INIT(task_alloc, apparmor_task_alloc),
LSM_HOOK_INIT(task_getsecid, apparmor_task_getsecid),
LSM_HOOK_INIT(task_getsecid_subj, apparmor_task_getsecid),
LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid),
LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
LSM_HOOK_INIT(task_kill, apparmor_task_kill),
......
......@@ -76,7 +76,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
if (!ima_appraise)
return 0;
security_task_getsecid(current, &secid);
security_task_getsecid_subj(current, &secid);
return ima_match_policy(mnt_userns, inode, current_cred(), secid, func,
mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL);
}
......
......@@ -391,7 +391,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
u32 secid;
if (file && (prot & PROT_EXEC)) {
security_task_getsecid(current, &secid);
security_task_getsecid_subj(current, &secid);
return process_measurement(file, current_cred(), secid, NULL,
0, MAY_EXEC, MMAP_CHECK);
}
......@@ -429,7 +429,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
!(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC))
return 0;
security_task_getsecid(current, &secid);
security_task_getsecid_subj(current, &secid);
inode = file_inode(vma->vm_file);
action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode,
current_cred(), secid, MAY_EXEC, MMAP_CHECK,
......@@ -470,7 +470,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
int ret;
u32 secid;
security_task_getsecid(current, &secid);
security_task_getsecid_subj(current, &secid);
ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0,
MAY_EXEC, BPRM_CHECK);
if (ret)
......@@ -495,7 +495,7 @@ int ima_file_check(struct file *file, int mask)
{
u32 secid;
security_task_getsecid(current, &secid);
security_task_getsecid_subj(current, &secid);
return process_measurement(file, current_cred(), secid, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
MAY_APPEND), FILE_CHECK);
......@@ -686,7 +686,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
/* Read entire file for all partial reads. */
func = read_idmap[read_id] ?: FILE_CHECK;
security_task_getsecid(current, &secid);
security_task_getsecid_subj(current, &secid);
return process_measurement(file, current_cred(), secid, NULL,
0, MAY_READ, func);
}
......@@ -729,7 +729,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
}
func = read_idmap[read_id] ?: FILE_CHECK;
security_task_getsecid(current, &secid);
security_task_getsecid_subj(current, &secid);
return process_measurement(file, current_cred(), secid, buf, size,
MAY_READ, func);
}
......@@ -872,7 +872,7 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
* buffer measurements.
*/
if (func) {
security_task_getsecid(current, &secid);
security_task_getsecid_subj(current, &secid);
action = ima_get_action(mnt_userns, inode, current_cred(),
secid, 0, func, &pcr, &template,
func_data);
......
......@@ -890,6 +890,13 @@ int security_sb_eat_lsm_opts(char *options, void **mnt_opts)
}
EXPORT_SYMBOL(security_sb_eat_lsm_opts);
int security_sb_mnt_opts_compat(struct super_block *sb,
void *mnt_opts)
{
return call_int_hook(sb_mnt_opts_compat, 0, sb, mnt_opts);
}
EXPORT_SYMBOL(security_sb_mnt_opts_compat);
int security_sb_remount(struct super_block *sb,
void *mnt_opts)
{
......@@ -1762,12 +1769,19 @@ int security_task_getsid(struct task_struct *p)
return call_int_hook(task_getsid, 0, p);
}
void security_task_getsecid(struct task_struct *p, u32 *secid)
void security_task_getsecid_subj(struct task_struct *p, u32 *secid)
{
*secid = 0;
call_void_hook(task_getsecid_subj, p, secid);
}
EXPORT_SYMBOL(security_task_getsecid_subj);
void security_task_getsecid_obj(struct task_struct *p, u32 *secid)
{
*secid = 0;
call_void_hook(task_getsecid, p, secid);
call_void_hook(task_getsecid_obj, p, secid);
}
EXPORT_SYMBOL(security_task_getsecid);
EXPORT_SYMBOL(security_task_getsecid_obj);
int security_task_setnice(struct task_struct *p, int nice)
{
......
......@@ -229,10 +229,23 @@ static inline u32 cred_sid(const struct cred *cred)
return tsec->sid;
}
/*
* get the subjective security ID of a task
*/
static inline u32 task_sid_subj(const struct task_struct *task)
{
u32 sid;
rcu_read_lock();
sid = cred_sid(rcu_dereference(task->cred));
rcu_read_unlock();
return sid;
}
/*
* get the objective security ID of a task
*/
static inline u32 task_sid(const struct task_struct *task)
static inline u32 task_sid_obj(const struct task_struct *task)
{
u32 sid;
......@@ -242,6 +255,29 @@ static inline u32 task_sid(const struct task_struct *task)
return sid;
}
/*
* get the security ID of a task for use with binder
*/
static inline u32 task_sid_binder(const struct task_struct *task)
{
/*
* In many case where this function is used we should be using the
* task's subjective SID, but we can't reliably access the subjective
* creds of a task other than our own so we must use the objective
* creds/SID, which are safe to access. The downside is that if a task
* is temporarily overriding it's creds it will not be reflected here;
* however, it isn't clear that binder would handle that case well
* anyway.
*
* If this ever changes and we can safely reference the subjective
* creds/SID of another task, this function will make it easier to
* identify the various places where we make use of the task SIDs in
* the binder code. It is also likely that we will need to adjust
* the main drivers/android binder code as well.
*/
return task_sid_obj(task);
}
static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
/*
......@@ -760,7 +796,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
if (sb->s_user_ns != &init_user_ns &&
strcmp(sb->s_type->name, "tmpfs") &&
strcmp(sb->s_type->name, "ramfs") &&
strcmp(sb->s_type->name, "devpts")) {
strcmp(sb->s_type->name, "devpts") &&
strcmp(sb->s_type->name, "overlay")) {
if (context_sid || fscontext_sid || rootcontext_sid ||
defcontext_sid) {
rc = -EACCES;
......@@ -2034,11 +2071,8 @@ static inline u32 open_file_to_av(struct file *file)
static int selinux_binder_set_context_mgr(struct task_struct *mgr)
{
u32 mysid = current_sid();
u32 mgrsid = task_sid(mgr);
return avc_has_perm(&selinux_state,
mysid, mgrsid, SECCLASS_BINDER,
current_sid(), task_sid_binder(mgr), SECCLASS_BINDER,
BINDER__SET_CONTEXT_MGR, NULL);
}
......@@ -2046,8 +2080,7 @@ static int selinux_binder_transaction(struct task_struct *from,
struct task_struct *to)
{
u32 mysid = current_sid();
u32 fromsid = task_sid(from);
u32 tosid = task_sid(to);
u32 fromsid = task_sid_binder(from);
int rc;
if (mysid != fromsid) {
......@@ -2058,19 +2091,16 @@ static int selinux_binder_transaction(struct task_struct *from,
return rc;
}
return avc_has_perm(&selinux_state,
fromsid, tosid, SECCLASS_BINDER, BINDER__CALL,
NULL);
return avc_has_perm(&selinux_state, fromsid, task_sid_binder(to),
SECCLASS_BINDER, BINDER__CALL, NULL);
}
static int selinux_binder_transfer_binder(struct task_struct *from,
struct task_struct *to)
{
u32 fromsid = task_sid(from);
u32 tosid = task_sid(to);
return avc_has_perm(&selinux_state,
fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER,
task_sid_binder(from), task_sid_binder(to),
SECCLASS_BINDER, BINDER__TRANSFER,
NULL);
}
......@@ -2078,7 +2108,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
struct task_struct *to,
struct file *file)
{
u32 sid = task_sid(to);
u32 sid = task_sid_binder(to);
struct file_security_struct *fsec = selinux_file(file);
struct dentry *dentry = file->f_path.dentry;
struct inode_security_struct *isec;
......@@ -2117,7 +2147,7 @@ static int selinux_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
u32 sid = current_sid();
u32 csid = task_sid(child);
u32 csid = task_sid_obj(child);
if (mode & PTRACE_MODE_READ)
return avc_has_perm(&selinux_state,
......@@ -2130,15 +2160,15 @@ static int selinux_ptrace_access_check(struct task_struct *child,
static int selinux_ptrace_traceme(struct task_struct *parent)
{
return avc_has_perm(&selinux_state,
task_sid(parent), current_sid(), SECCLASS_PROCESS,
PROCESS__PTRACE, NULL);
task_sid_subj(parent), task_sid_obj(current),
SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
}
static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
return avc_has_perm(&selinux_state,
current_sid(), task_sid(target), SECCLASS_PROCESS,
current_sid(), task_sid_obj(target), SECCLASS_PROCESS,
PROCESS__GETCAP, NULL);
}
......@@ -2263,7 +2293,7 @@ static u32 ptrace_parent_sid(void)
rcu_read_lock();
tracer = ptrace_parent(current);
if (tracer)
sid = task_sid(tracer);
sid = task_sid_obj(tracer);
rcu_read_unlock();
return sid;
......@@ -2684,6 +2714,61 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
return rc;
}
static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
{
struct selinux_mnt_opts *opts = mnt_opts;
struct superblock_security_struct *sbsec = sb->s_security;
u32 sid;
int rc;
/*
* Superblock not initialized (i.e. no options) - reject if any
* options specified, otherwise accept.
*/
if (!(sbsec->flags & SE_SBINITIALIZED))
return opts ? 1 : 0;
/*
* Superblock initialized and no options specified - reject if
* superblock has any options set, otherwise accept.
*/
if (!opts)
return (sbsec->flags & SE_MNTMASK) ? 1 : 0;
if (opts->fscontext) {
rc = parse_sid(sb, opts->fscontext, &sid);
if (rc)
return 1;
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
return 1;
}
if (opts->context) {
rc = parse_sid(sb, opts->context, &sid);
if (rc)
return 1;
if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
return 1;
}
if (opts->rootcontext) {
struct inode_security_struct *root_isec;
root_isec = backing_inode_security(sb->s_root);
rc = parse_sid(sb, opts->rootcontext, &sid);
if (rc)
return 1;
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
return 1;
}
if (opts->defcontext) {
rc = parse_sid(sb, opts->defcontext, &sid);
if (rc)
return 1;
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
return 1;
}
return 0;
}
static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
{
struct selinux_mnt_opts *opts = mnt_opts;
......@@ -3920,7 +4005,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum)
{
struct file *file;
u32 sid = task_sid(tsk);
u32 sid = task_sid_obj(tsk);
u32 perm;
struct file_security_struct *fsec;
......@@ -4139,47 +4224,52 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{
return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETPGID, NULL);
}
static int selinux_task_getpgid(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETPGID, NULL);
}
static int selinux_task_getsid(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSESSION, NULL);
}
static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
static void selinux_task_getsecid_subj(struct task_struct *p, u32 *secid)
{
*secid = task_sid_subj(p);
}
static void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid)
{
*secid = task_sid(p);
*secid = task_sid_obj(p);
}
static int selinux_task_setnice(struct task_struct *p, int nice)
{
return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_setioprio(struct task_struct *p, int ioprio)
{
return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_getioprio(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL);
}
......@@ -4210,7 +4300,7 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
return avc_has_perm(&selinux_state,
current_sid(), task_sid(p),
current_sid(), task_sid_obj(p),
SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
return 0;
......@@ -4219,21 +4309,21 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
static int selinux_task_setscheduler(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_getscheduler(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL);
}
static int selinux_task_movememory(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
......@@ -4252,14 +4342,14 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
else
secid = cred_sid(cred);
return avc_has_perm(&selinux_state,
secid, task_sid(p), SECCLASS_PROCESS, perm, NULL);
secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL);
}
static void selinux_task_to_inode(struct task_struct *p,
struct inode *inode)
{
struct inode_security_struct *isec = selinux_inode(inode);
u32 sid = task_sid(p);
u32 sid = task_sid_obj(p);
spin_lock(&isec->lock);
isec->sclass = inode_mode_to_security_class(inode->i_mode);
......@@ -6152,7 +6242,7 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
struct ipc_security_struct *isec;
struct msg_security_struct *msec;
struct common_audit_data ad;
u32 sid = task_sid(target);
u32 sid = task_sid_subj(target);
int rc;
isec = selinux_ipc(msq);
......@@ -7077,6 +7167,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
LSM_HOOK_INIT(sb_mnt_opts_compat, selinux_sb_mnt_opts_compat),
LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
......@@ -7148,7 +7239,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
LSM_HOOK_INIT(task_getsecid, selinux_task_getsecid),
LSM_HOOK_INIT(task_getsecid_subj, selinux_task_getsecid_subj),
LSM_HOOK_INIT(task_getsecid_obj, selinux_task_getsecid_obj),
LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
......
......@@ -13,18 +13,83 @@
#include "ima.h"
/*
* selinux_ima_measure_state - Measure hash of the SELinux policy
* selinux_ima_collect_state - Read selinux configuration settings
*
* @state: selinux state struct
* @state: selinux_state
*
* NOTE: This function must be called with policy_mutex held.
* On success returns the configuration settings string.
* On error, returns NULL.
*/
void selinux_ima_measure_state(struct selinux_state *state)
static char *selinux_ima_collect_state(struct selinux_state *state)
{
const char *on = "=1;", *off = "=0;";
char *buf;
int buf_len, len, i, rc;
buf_len = strlen("initialized=0;enforcing=0;checkreqprot=0;") + 1;
len = strlen(on);
for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++)
buf_len += strlen(selinux_policycap_names[i]) + len;
buf = kzalloc(buf_len, GFP_KERNEL);
if (!buf)
return NULL;
rc = strscpy(buf, "initialized", buf_len);
WARN_ON(rc < 0);
rc = strlcat(buf, selinux_initialized(state) ? on : off, buf_len);
WARN_ON(rc >= buf_len);
rc = strlcat(buf, "enforcing", buf_len);
WARN_ON(rc >= buf_len);
rc = strlcat(buf, enforcing_enabled(state) ? on : off, buf_len);
WARN_ON(rc >= buf_len);
rc = strlcat(buf, "checkreqprot", buf_len);
WARN_ON(rc >= buf_len);
rc = strlcat(buf, checkreqprot_get(state) ? on : off, buf_len);
WARN_ON(rc >= buf_len);
for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++) {
rc = strlcat(buf, selinux_policycap_names[i], buf_len);
WARN_ON(rc >= buf_len);
rc = strlcat(buf, state->policycap[i] ? on : off, buf_len);
WARN_ON(rc >= buf_len);
}
return buf;
}
/*
* selinux_ima_measure_state_locked - Measure SELinux state and hash of policy
*
* @state: selinux state struct
*/
void selinux_ima_measure_state_locked(struct selinux_state *state)
{
char *state_str = NULL;
void *policy = NULL;
size_t policy_len;
int rc = 0;
WARN_ON(!mutex_is_locked(&state->policy_mutex));
state_str = selinux_ima_collect_state(state);
if (!state_str) {
pr_err("SELinux: %s: failed to read state.\n", __func__);
return;
}
ima_measure_critical_data("selinux", "selinux-state",
state_str, strlen(state_str), false);
kfree(state_str);
/*
* Measure SELinux policy only after initialization is completed.
*/
......@@ -42,3 +107,17 @@ void selinux_ima_measure_state(struct selinux_state *state)
vfree(policy);
}
/*
* selinux_ima_measure_state - Measure SELinux state and hash of policy
*
* @state: selinux state struct
*/
void selinux_ima_measure_state(struct selinux_state *state)
{
WARN_ON(mutex_is_locked(&state->policy_mutex));
mutex_lock(&state->policy_mutex);
selinux_ima_measure_state_locked(state);
mutex_unlock(&state->policy_mutex);
}
......@@ -242,11 +242,12 @@ struct security_class_mapping secclass_map[] = {
{ "infiniband_endport",
{ "manage_subnet", NULL } },
{ "bpf",
{"map_create", "map_read", "map_write", "prog_load", "prog_run"} },
{ "map_create", "map_read", "map_write", "prog_load", "prog_run",
NULL } },
{ "xdp_socket",
{ COMMON_SOCK_PERMS, NULL } },
{ "perf_event",
{"open", "cpu", "kernel", "tracepoint", "read", "write"} },
{ "open", "cpu", "kernel", "tracepoint", "read", "write", NULL } },
{ "lockdown",
{ "integrity", "confidentiality", NULL } },
{ "anon_inode",
......
......@@ -15,10 +15,16 @@
#ifdef CONFIG_IMA
extern void selinux_ima_measure_state(struct selinux_state *selinux_state);
extern void selinux_ima_measure_state_locked(
struct selinux_state *selinux_state);
#else
static inline void selinux_ima_measure_state(struct selinux_state *selinux_state)
{
}
static inline void selinux_ima_measure_state_locked(
struct selinux_state *selinux_state)
{
}
#endif
#endif /* _SELINUX_IMA_H_ */
......@@ -426,7 +426,7 @@ extern struct page *selinux_kernel_status_page(struct selinux_state *state);
#define SELINUX_KERNEL_STATUS_VERSION 1
struct selinux_kernel_status {
u32 version; /* version number of thie structure */
u32 version; /* version number of the structure */
u32 sequence; /* sequence number of seqlock logic */
u32 enforcing; /* current setting of enforcing mode */
u32 policyload; /* times of policy reloaded */
......
......@@ -41,6 +41,7 @@
#include "security.h"
#include "objsec.h"
#include "conditional.h"
#include "ima.h"
enum sel_inos {
SEL_ROOT_INO = 2,
......@@ -182,6 +183,8 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
selinux_status_update_setenforce(state, new_value);
if (!new_value)
call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL);
selinux_ima_measure_state(state);
}
length = count;
out:
......@@ -758,6 +761,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
checkreqprot_set(fsi->state, (new_value ? 1 : 0));
length = count;
selinux_ima_measure_state(fsi->state);
out:
kfree(page);
return length;
......
......@@ -13,7 +13,7 @@ static struct kmem_cache *hashtab_node_cachep __ro_after_init;
/*
* Here we simply round the number of elements up to the nearest power of two.
* I tried also other options like rouding down or rounding to the closest
* I tried also other options like rounding down or rounding to the closest
* power of two (up or down based on which is closer), but I was unable to
* find any significant difference in lookup/insert performance that would
* justify switching to a different (less intuitive) formula. It could be that
......
......@@ -2202,7 +2202,7 @@ static void selinux_notify_policy_change(struct selinux_state *state,
selinux_status_update_policyload(state, seqno);
selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload();
selinux_ima_measure_state(state);
selinux_ima_measure_state_locked(state);
}
void selinux_policy_commit(struct selinux_state *state,
......
......@@ -383,7 +383,23 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
return tsp->smk_task;
}
static inline struct smack_known *smk_of_task_struct(
static inline struct smack_known *smk_of_task_struct_subj(
const struct task_struct *t)
{
struct smack_known *skp;
const struct cred *cred;
rcu_read_lock();
cred = rcu_dereference(t->cred);
skp = smk_of_task(smack_cred(cred));
rcu_read_unlock();
return skp;
}
static inline struct smack_known *smk_of_task_struct_obj(
const struct task_struct *t)
{
struct smack_known *skp;
......
......@@ -159,7 +159,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp,
static int smk_bu_task(struct task_struct *otp, int mode, int rc)
{
struct task_smack *tsp = smack_cred(current_cred());
struct smack_known *smk_task = smk_of_task_struct(otp);
struct smack_known *smk_task = smk_of_task_struct_obj(otp);
char acc[SMK_NUM_ACCESS_TYPE + 1];
if (rc <= 0)
......@@ -479,7 +479,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{
struct smack_known *skp;
skp = smk_of_task_struct(ctp);
skp = smk_of_task_struct_obj(ctp);
return smk_ptrace_rule_check(current, skp, mode, __func__);
}
......@@ -2033,7 +2033,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
const char *caller)
{
struct smk_audit_info ad;
struct smack_known *skp = smk_of_task_struct(p);
struct smack_known *skp = smk_of_task_struct_subj(p);
int rc;
smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
......@@ -2078,15 +2078,29 @@ static int smack_task_getsid(struct task_struct *p)
}
/**
* smack_task_getsecid - get the secid of the task
* @p: the object task
* smack_task_getsecid_subj - get the subjective secid of the task
* @p: the task
* @secid: where to put the result
*
* Sets the secid to contain a u32 version of the smack label.
* Sets the secid to contain a u32 version of the task's subjective smack label.
*/
static void smack_task_getsecid_subj(struct task_struct *p, u32 *secid)
{
struct smack_known *skp = smk_of_task_struct_subj(p);
*secid = skp->smk_secid;
}
/**
* smack_task_getsecid_obj - get the objective secid of the task
* @p: the task
* @secid: where to put the result
*
* Sets the secid to contain a u32 version of the task's objective smack label.
*/
static void smack_task_getsecid(struct task_struct *p, u32 *secid)
static void smack_task_getsecid_obj(struct task_struct *p, u32 *secid)
{
struct smack_known *skp = smk_of_task_struct(p);
struct smack_known *skp = smk_of_task_struct_obj(p);
*secid = skp->smk_secid;
}
......@@ -2174,7 +2188,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info,
{
struct smk_audit_info ad;
struct smack_known *skp;
struct smack_known *tkp = smk_of_task_struct(p);
struct smack_known *tkp = smk_of_task_struct_obj(p);
int rc;
if (!sig)
......@@ -2212,7 +2226,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info,
static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
{
struct inode_smack *isp = smack_inode(inode);
struct smack_known *skp = smk_of_task_struct(p);
struct smack_known *skp = smk_of_task_struct_obj(p);
isp->smk_inode = skp;
isp->smk_flags |= SMK_INODE_INSTANT;
......@@ -3483,7 +3497,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
static int smack_getprocattr(struct task_struct *p, char *name, char **value)
{
struct smack_known *skp = smk_of_task_struct(p);
struct smack_known *skp = smk_of_task_struct_subj(p);
char *cp;
int slen;
......@@ -4759,7 +4773,8 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(task_setpgid, smack_task_setpgid),
LSM_HOOK_INIT(task_getpgid, smack_task_getpgid),
LSM_HOOK_INIT(task_getsid, smack_task_getsid),
LSM_HOOK_INIT(task_getsecid, smack_task_getsecid),
LSM_HOOK_INIT(task_getsecid_subj, smack_task_getsecid_subj),
LSM_HOOK_INIT(task_getsecid_obj, smack_task_getsecid_obj),
LSM_HOOK_INIT(task_setnice, smack_task_setnice),
LSM_HOOK_INIT(task_setioprio, smack_task_setioprio),
LSM_HOOK_INIT(task_getioprio, smack_task_getioprio),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment