]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - security/selinux/hooks.c
binder: use cred instead of task for selinux checks
[mirror_ubuntu-jammy-kernel.git] / security / selinux / hooks.c
index e7ebd45ca34573e16ade281ef5349a953238e3a9..834ec59ed5d44cbe7ee2ecddabcaa8683ba1c5b3 100644 (file)
@@ -255,29 +255,6 @@ static inline u32 task_sid_obj(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);
 
 /*
@@ -2066,18 +2043,19 @@ static inline u32 open_file_to_av(struct file *file)
 
 /* Hook functions begin here. */
 
-static int selinux_binder_set_context_mgr(struct task_struct *mgr)
+static int selinux_binder_set_context_mgr(const struct cred *mgr)
 {
        return avc_has_perm(&selinux_state,
-                           current_sid(), task_sid_binder(mgr), SECCLASS_BINDER,
+                           current_sid(), cred_sid(mgr), SECCLASS_BINDER,
                            BINDER__SET_CONTEXT_MGR, NULL);
 }
 
-static int selinux_binder_transaction(struct task_struct *from,
-                                     struct task_struct *to)
+static int selinux_binder_transaction(const struct cred *from,
+                                     const struct cred *to)
 {
        u32 mysid = current_sid();
-       u32 fromsid = task_sid_binder(from);
+       u32 fromsid = cred_sid(from);
+       u32 tosid = cred_sid(to);
        int rc;
 
        if (mysid != fromsid) {
@@ -2088,24 +2066,24 @@ static int selinux_binder_transaction(struct task_struct *from,
                        return rc;
        }
 
-       return avc_has_perm(&selinux_state, fromsid, task_sid_binder(to),
+       return avc_has_perm(&selinux_state, fromsid, tosid,
                            SECCLASS_BINDER, BINDER__CALL, NULL);
 }
 
-static int selinux_binder_transfer_binder(struct task_struct *from,
-                                         struct task_struct *to)
+static int selinux_binder_transfer_binder(const struct cred *from,
+                                         const struct cred *to)
 {
        return avc_has_perm(&selinux_state,
-                           task_sid_binder(from), task_sid_binder(to),
+                           cred_sid(from), cred_sid(to),
                            SECCLASS_BINDER, BINDER__TRANSFER,
                            NULL);
 }
 
-static int selinux_binder_transfer_file(struct task_struct *from,
-                                       struct task_struct *to,
+static int selinux_binder_transfer_file(const struct cred *from,
+                                       const struct cred *to,
                                        struct file *file)
 {
-       u32 sid = task_sid_binder(to);
+       u32 sid = cred_sid(to);
        struct file_security_struct *fsec = selinux_file(file);
        struct dentry *dentry = file->f_path.dentry;
        struct inode_security_struct *isec;
@@ -4646,7 +4624,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
 
 static int sock_has_perm(struct sock *sk, u32 perms)
 {
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
 
@@ -4703,7 +4681,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
        isec->initialized = LABEL_INITIALIZED;
 
        if (sock->sk) {
-               sksec = sock->sk->sk_security;
+               sksec = selinux_sock(sock->sk);
                sksec->sclass = sclass;
                sksec->sid = sid;
                /* Allows detection of the first association on this socket */
@@ -4719,8 +4697,8 @@ static int selinux_socket_post_create(struct socket *sock, int family,
 static int selinux_socket_socketpair(struct socket *socka,
                                     struct socket *sockb)
 {
-       struct sk_security_struct *sksec_a = socka->sk->sk_security;
-       struct sk_security_struct *sksec_b = sockb->sk->sk_security;
+       struct sk_security_struct *sksec_a = selinux_sock(socka->sk);
+       struct sk_security_struct *sksec_b = selinux_sock(sockb->sk);
 
        sksec_a->peer_sid = sksec_b->sid;
        sksec_b->peer_sid = sksec_a->sid;
@@ -4735,7 +4713,7 @@ static int selinux_socket_socketpair(struct socket *socka,
 static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
 {
        struct sock *sk = sock->sk;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        u16 family;
        int err;
 
@@ -4870,7 +4848,7 @@ static int selinux_socket_connect_helper(struct socket *sock,
                                         struct sockaddr *address, int addrlen)
 {
        struct sock *sk = sock->sk;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        int err;
 
        err = sock_has_perm(sk, SOCKET__CONNECT);
@@ -5049,9 +5027,9 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
                                              struct sock *other,
                                              struct sock *newsk)
 {
-       struct sk_security_struct *sksec_sock = sock->sk_security;
-       struct sk_security_struct *sksec_other = other->sk_security;
-       struct sk_security_struct *sksec_new = newsk->sk_security;
+       struct sk_security_struct *sksec_sock = selinux_sock(sock);
+       struct sk_security_struct *sksec_other = selinux_sock(other);
+       struct sk_security_struct *sksec_new = selinux_sock(newsk);
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
        int err;
@@ -5083,8 +5061,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
 static int selinux_socket_unix_may_send(struct socket *sock,
                                        struct socket *other)
 {
-       struct sk_security_struct *ssec = sock->sk->sk_security;
-       struct sk_security_struct *osec = other->sk->sk_security;
+       struct sk_security_struct *ssec = selinux_sock(sock->sk);
+       struct sk_security_struct *osec = selinux_sock(other->sk);
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
 
@@ -5126,7 +5104,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
                                       u16 family)
 {
        int err = 0;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
@@ -5159,7 +5137,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
 static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        int err;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        u16 family = sk->sk_family;
        u32 sk_sid = sksec->sid;
        struct common_audit_data ad;
@@ -5227,13 +5205,15 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        return err;
 }
 
-static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
-                                           int __user *optlen, unsigned len)
+static int selinux_socket_getpeersec_stream(struct socket *sock,
+                                           char __user *optval,
+                                           int __user *optlen,
+                                           unsigned int len)
 {
        int err = 0;
        char *scontext;
        u32 scontext_len;
-       struct sk_security_struct *sksec = sock->sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sock->sk);
        u32 peer_sid = SECSID_NULL;
 
        if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
@@ -5293,34 +5273,27 @@ out:
 
 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
-       struct sk_security_struct *sksec;
-
-       sksec = kzalloc(sizeof(*sksec), priority);
-       if (!sksec)
-               return -ENOMEM;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
        sksec->peer_sid = SECINITSID_UNLABELED;
        sksec->sid = SECINITSID_UNLABELED;
        sksec->sclass = SECCLASS_SOCKET;
        selinux_netlbl_sk_security_reset(sksec);
-       sk->sk_security = sksec;
 
        return 0;
 }
 
 static void selinux_sk_free_security(struct sock *sk)
 {
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
-       sk->sk_security = NULL;
        selinux_netlbl_sk_security_free(sksec);
-       kfree(sksec);
 }
 
 static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
 {
-       struct sk_security_struct *sksec = sk->sk_security;
-       struct sk_security_struct *newsksec = newsk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
+       struct sk_security_struct *newsksec = selinux_sock(newsk);
 
        newsksec->sid = sksec->sid;
        newsksec->peer_sid = sksec->peer_sid;
@@ -5334,7 +5307,7 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
        if (!sk)
                *secid = SECINITSID_ANY_SOCKET;
        else {
-               struct sk_security_struct *sksec = sk->sk_security;
+               struct sk_security_struct *sksec = selinux_sock(sk);
 
                *secid = sksec->sid;
        }
@@ -5344,7 +5317,7 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
 {
        struct inode_security_struct *isec =
                inode_security_novalidate(SOCK_INODE(parent));
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
        if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
            sk->sk_family == PF_UNIX)
@@ -5359,7 +5332,7 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
 static int selinux_sctp_assoc_request(struct sctp_endpoint *ep,
                                      struct sk_buff *skb)
 {
-       struct sk_security_struct *sksec = ep->base.sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(ep->base.sk);
        struct common_audit_data ad;
        struct lsm_network_audit net = {0,};
        u8 peerlbl_active;
@@ -5510,8 +5483,8 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
 static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
                                  struct sock *newsk)
 {
-       struct sk_security_struct *sksec = sk->sk_security;
-       struct sk_security_struct *newsksec = newsk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
+       struct sk_security_struct *newsksec = selinux_sock(newsk);
 
        /* If policy does not support SECCLASS_SCTP_SOCKET then call
         * the non-sctp clone version.
@@ -5528,7 +5501,7 @@ static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
 static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
                                     struct request_sock *req)
 {
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        int err;
        u16 family = req->rsk_ops->family;
        u32 connsid;
@@ -5549,7 +5522,7 @@ static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
 static void selinux_inet_csk_clone(struct sock *newsk,
                                   const struct request_sock *req)
 {
-       struct sk_security_struct *newsksec = newsk->sk_security;
+       struct sk_security_struct *newsksec = selinux_sock(newsk);
 
        newsksec->sid = req->secid;
        newsksec->peer_sid = req->peer_secid;
@@ -5566,7 +5539,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
 static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
 {
        u16 family = sk->sk_family;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
        /* handle mapped IPv4 packets arriving via IPv6 sockets */
        if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
@@ -5650,7 +5623,7 @@ static int selinux_tun_dev_attach_queue(void *security)
 static int selinux_tun_dev_attach(struct sock *sk, void *security)
 {
        struct tun_security_struct *tunsec = security;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
 
        /* we don't currently perform any NetLabel based labeling here and it
         * isn't clear that we would want to do so anyway; while we could apply
@@ -5794,7 +5767,7 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
                        return NF_ACCEPT;
 
                /* standard practice, label using the parent socket */
-               sksec = sk->sk_security;
+               sksec = selinux_sock(sk);
                sid = sksec->sid;
        } else
                sid = SECINITSID_KERNEL;
@@ -5833,7 +5806,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
 
        if (sk == NULL)
                return NF_ACCEPT;
-       sksec = sk->sk_security;
+       sksec = selinux_sock(sk);
 
        ad.type = LSM_AUDIT_DATA_NET;
        ad.u.net = &net;
@@ -5925,7 +5898,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
                u32 skb_sid;
                struct sk_security_struct *sksec;
 
-               sksec = sk->sk_security;
+               sksec = selinux_sock(sk);
                if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
                        return NF_DROP;
                /* At this point, if the returned skb peerlbl is SECSID_NULL
@@ -5954,7 +5927,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
        } else {
                /* Locally generated packet, fetch the security label from the
                 * associated socket. */
-               struct sk_security_struct *sksec = sk->sk_security;
+               struct sk_security_struct *sksec = selinux_sock(sk);
                peer_sid = sksec->sid;
                secmark_perm = PACKET__SEND;
        }
@@ -6019,7 +5992,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
        unsigned int data_len = skb->len;
        unsigned char *data = skb->data;
        struct nlmsghdr *nlh;
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct sk_security_struct *sksec = selinux_sock(sk);
        u16 sclass = sksec->sclass;
        u32 perm;
 
@@ -6467,7 +6440,7 @@ static int selinux_getprocattr(struct task_struct *p,
                        goto bad;
        }
 
-       if (!strcmp(name, "current"))
+       if (!strcmp(name, "current") || !strcmp(name, "context"))
                sid = __tsec->sid;
        else if (!strcmp(name, "prev"))
                sid = __tsec->osid;
@@ -6509,6 +6482,17 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
        /*
         * Basic control over ability to set these attributes at all.
         */
+
+       /*
+        * For setting display, we only perform a permission check;
+        * the actual update to the display value is handled by the
+        * LSM framework.
+        */
+       if (!strcmp(name, "display"))
+               return avc_has_perm(&selinux_state,
+                                   mysid, mysid, SECCLASS_PROCESS2,
+                                   PROCESS2__SETDISPLAY, NULL);
+
        if (!strcmp(name, "exec"))
                error = avc_has_perm(&selinux_state,
                                     mysid, mysid, SECCLASS_PROCESS,
@@ -7048,6 +7032,7 @@ struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
        .lbs_ipc = sizeof(struct ipc_security_struct),
        .lbs_msg_msg = sizeof(struct msg_security_struct),
        .lbs_superblock = sizeof(struct superblock_security_struct),
+       .lbs_sock = sizeof(struct sk_security_struct),
 };
 
 #ifdef CONFIG_PERF_EVENTS
@@ -7111,6 +7096,11 @@ static int selinux_perf_event_write(struct perf_event *event)
 }
 #endif
 
+struct lsm_id selinux_lsmid __lsm_ro_after_init = {
+       .lsm  = "selinux",
+       .slot = LSMBLOB_NEEDED
+};
+
 /*
  * 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,
@@ -7424,7 +7414,8 @@ static __init int selinux_init(void)
 
        hashtab_cache_init();
 
-       security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
+       security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks),
+                          &selinux_lsmid);
 
        if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
                panic("SELinux: Unable to register AVC netcache callback\n");