Merge tag 'livepatching-for-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / security / selinux / hooks.c
index ddd0977..92f909a 100644 (file)
@@ -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;
@@ -2114,10 +2144,10 @@ static int selinux_binder_transfer_file(struct task_struct *from,
 }
 
 static int selinux_ptrace_access_check(struct task_struct *child,
-                                    unsigned int mode)
+                                      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 @@ free_opt:
        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),