Merge tag 'lsm-pr-20240105' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm
[sfrench/cifs-2.6.git] / security / selinux / hooks.c
index 17954044111533adaf20773ebfb8f1a68d6f077f..5e5fd5be6d93aa118d8a6eda3b5a78d3efa0d705 100644 (file)
@@ -1661,8 +1661,6 @@ static int inode_has_perm(const struct cred *cred,
        struct inode_security_struct *isec;
        u32 sid;
 
-       validate_creds(cred);
-
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
@@ -2316,6 +2314,19 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
        new_tsec->keycreate_sid = 0;
        new_tsec->sockcreate_sid = 0;
 
+       /*
+        * Before policy is loaded, label any task outside kernel space
+        * as SECINITSID_INIT, so that any userspace tasks surviving from
+        * early boot end up with a label different from SECINITSID_KERNEL
+        * (if the policy chooses to set SECINITSID_INIT != SECINITSID_KERNEL).
+        */
+       if (!selinux_initialized()) {
+               new_tsec->sid = SECINITSID_INIT;
+               /* also clear the exec_sid just in case */
+               new_tsec->exec_sid = 0;
+               return 0;
+       }
+
        if (old_tsec->exec_sid) {
                new_tsec->sid = old_tsec->exec_sid;
                /* Reset exec SID on execve. */
@@ -3057,8 +3068,6 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
        struct inode_security_struct *isec;
        u32 sid;
 
-       validate_creds(cred);
-
        ad.type = LSM_AUDIT_DATA_DENTRY;
        ad.u.dentry = dentry;
        sid = cred_sid(cred);
@@ -3102,8 +3111,6 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        if (!mask)
                return 0;
 
-       validate_creds(cred);
-
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
@@ -4581,6 +4588,21 @@ static int sock_has_perm(struct sock *sk, u32 perms)
        if (sksec->sid == SECINITSID_KERNEL)
                return 0;
 
+       /*
+        * Before POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT, sockets that
+        * inherited the kernel context from early boot used to be skipped
+        * here, so preserve that behavior unless the capability is set.
+        *
+        * By setting the capability the policy signals that it is ready
+        * for this quirk to be fixed. Note that sockets created by a kernel
+        * thread or a usermode helper executed without a transition will
+        * still be skipped in this check regardless of the policycap
+        * setting.
+        */
+       if (!selinux_policycap_userspace_initial_context() &&
+           sksec->sid == SECINITSID_INIT)
+               return 0;
+
        ad_net_init_from_sk(&ad, &net, sk);
 
        return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms,
@@ -4695,6 +4717,13 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                return -EINVAL;
                        addr4 = (struct sockaddr_in *)address;
                        if (family_sa == AF_UNSPEC) {
+                               if (family == PF_INET6) {
+                                       /* Length check from inet6_bind_sk() */
+                                       if (addrlen < SIN6_LEN_RFC2133)
+                                               return -EINVAL;
+                                       /* Family check from __inet6_bind() */
+                                       goto err_af;
+                               }
                                /* see __inet_bind(), we only want to allow
                                 * AF_UNSPEC if the address is INADDR_ANY
                                 */
@@ -6476,7 +6505,6 @@ static int selinux_lsm_setattr(u64 attr, void *value, size_t size)
                if (sid == 0)
                        goto abort_change;
 
-               /* Only allow single threaded processes to change context */
                if (!current_is_single_threaded()) {
                        error = security_bounded_transition(tsec->sid, sid);
                        if (error)