1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */ 21da177e4SLinus Torvalds #ifndef __LINUX_NET_SCM_H 31da177e4SLinus Torvalds #define __LINUX_NET_SCM_H 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds #include <linux/limits.h> 61da177e4SLinus Torvalds #include <linux/net.h> 75b825c3aSIngo Molnar #include <linux/cred.h> 8dc49c1f9SCatherine Zhang #include <linux/security.h> 9b488893aSPavel Emelyanov #include <linux/pid.h> 10b488893aSPavel Emelyanov #include <linux/nsproxy.h> 117a36094dSEric W. Biederman #include <linux/sched/signal.h> 12*718e6b51SKuniyuki Iwashima #include <net/compat.h> 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds /* Well, we should have at least one descriptor open 151da177e4SLinus Torvalds * to accept passed FDs 8) 161da177e4SLinus Torvalds */ 17bba14de9SEric Dumazet #define SCM_MAX_FD 253 181da177e4SLinus Torvalds 19dbe9a417SEric W. Biederman struct scm_creds { 20dbe9a417SEric W. Biederman u32 pid; 21dbe9a417SEric W. Biederman kuid_t uid; 22dbe9a417SEric W. Biederman kgid_t gid; 23dbe9a417SEric W. Biederman }; 24dbe9a417SEric W. Biederman 25fd2c3ef7SEric Dumazet struct scm_fp_list { 26bba14de9SEric Dumazet short count; 27bba14de9SEric Dumazet short max; 28415e3d3eSHannes Frederic Sowa struct user_struct *user; 291da177e4SLinus Torvalds struct file *fp[SCM_MAX_FD]; 301da177e4SLinus Torvalds }; 311da177e4SLinus Torvalds 32fd2c3ef7SEric Dumazet struct scm_cookie { 33257b5358SEric W. Biederman struct pid *pid; /* Skb credentials */ 341da177e4SLinus Torvalds struct scm_fp_list *fp; /* Passed files */ 35dbe9a417SEric W. Biederman struct scm_creds creds; /* Skb credentials */ 36877ce7c1SCatherine Zhang #ifdef CONFIG_SECURITY_NETWORK 37dc49c1f9SCatherine Zhang u32 secid; /* Passed security ID */ 38877ce7c1SCatherine Zhang #endif 391da177e4SLinus Torvalds }; 401da177e4SLinus Torvalds 418153ff5cSJoe Perches void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm); 428153ff5cSJoe Perches void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm); 438153ff5cSJoe Perches int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm); 448153ff5cSJoe Perches void __scm_destroy(struct scm_cookie *scm); 458153ff5cSJoe Perches struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl); 461da177e4SLinus Torvalds 47dc49c1f9SCatherine Zhang #ifdef CONFIG_SECURITY_NETWORK 48dc49c1f9SCatherine Zhang static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) 49dc49c1f9SCatherine Zhang { 50dc49c1f9SCatherine Zhang security_socket_getpeersec_dgram(sock, NULL, &scm->secid); 51dc49c1f9SCatherine Zhang } 52dc49c1f9SCatherine Zhang #else 53dc49c1f9SCatherine Zhang static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) 54dc49c1f9SCatherine Zhang { } 55dc49c1f9SCatherine Zhang #endif /* CONFIG_SECURITY_NETWORK */ 56dc49c1f9SCatherine Zhang 57257b5358SEric W. Biederman static __inline__ void scm_set_cred(struct scm_cookie *scm, 586b0ee8c0SEric W. Biederman struct pid *pid, kuid_t uid, kgid_t gid) 59257b5358SEric W. Biederman { 60257b5358SEric W. Biederman scm->pid = get_pid(pid); 61dbe9a417SEric W. Biederman scm->creds.pid = pid_vnr(pid); 626b0ee8c0SEric W. Biederman scm->creds.uid = uid; 636b0ee8c0SEric W. Biederman scm->creds.gid = gid; 64257b5358SEric W. Biederman } 65257b5358SEric W. Biederman 66257b5358SEric W. Biederman static __inline__ void scm_destroy_cred(struct scm_cookie *scm) 67257b5358SEric W. Biederman { 68257b5358SEric W. Biederman put_pid(scm->pid); 69257b5358SEric W. Biederman scm->pid = NULL; 70257b5358SEric W. Biederman } 71257b5358SEric W. Biederman 721da177e4SLinus Torvalds static __inline__ void scm_destroy(struct scm_cookie *scm) 731da177e4SLinus Torvalds { 74257b5358SEric W. Biederman scm_destroy_cred(scm); 752a6c8c79SDavid S. Miller if (scm->fp) 761da177e4SLinus Torvalds __scm_destroy(scm); 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, 80e0e3cea4SEric Dumazet struct scm_cookie *scm, bool forcecreds) 811da177e4SLinus Torvalds { 8216e57262SEric Dumazet memset(scm, 0, sizeof(*scm)); 836b0ee8c0SEric W. Biederman scm->creds.uid = INVALID_UID; 846b0ee8c0SEric W. Biederman scm->creds.gid = INVALID_GID; 85e0e3cea4SEric Dumazet if (forcecreds) 866e0895c2SDavid S. Miller scm_set_cred(scm, task_tgid(current), current_uid(), current_gid()); 87dc49c1f9SCatherine Zhang unix_get_peersec_dgram(sock, scm); 881da177e4SLinus Torvalds if (msg->msg_controllen <= 0) 891da177e4SLinus Torvalds return 0; 901da177e4SLinus Torvalds return __scm_send(sock, msg, scm); 911da177e4SLinus Torvalds } 921da177e4SLinus Torvalds 93877ce7c1SCatherine Zhang #ifdef CONFIG_SECURITY_NETWORK 94877ce7c1SCatherine Zhang static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) 95877ce7c1SCatherine Zhang { 96dc49c1f9SCatherine Zhang char *secdata; 97dc49c1f9SCatherine Zhang u32 seclen; 98dc49c1f9SCatherine Zhang int err; 99dc49c1f9SCatherine Zhang 100dc49c1f9SCatherine Zhang if (test_bit(SOCK_PASSSEC, &sock->flags)) { 101dc49c1f9SCatherine Zhang err = security_secid_to_secctx(scm->secid, &secdata, &seclen); 102dc49c1f9SCatherine Zhang 103dc49c1f9SCatherine Zhang if (!err) { 104dc49c1f9SCatherine Zhang put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata); 105dc49c1f9SCatherine Zhang security_release_secctx(secdata, seclen); 106dc49c1f9SCatherine Zhang } 107dc49c1f9SCatherine Zhang } 108877ce7c1SCatherine Zhang } 109a02d83f9SAlexander Mikhalitsyn 110a02d83f9SAlexander Mikhalitsyn static inline bool scm_has_secdata(struct socket *sock) 111a02d83f9SAlexander Mikhalitsyn { 112a02d83f9SAlexander Mikhalitsyn return test_bit(SOCK_PASSSEC, &sock->flags); 113a02d83f9SAlexander Mikhalitsyn } 114877ce7c1SCatherine Zhang #else 115877ce7c1SCatherine Zhang static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) 116877ce7c1SCatherine Zhang { } 117a02d83f9SAlexander Mikhalitsyn 118a02d83f9SAlexander Mikhalitsyn static inline bool scm_has_secdata(struct socket *sock) 119a02d83f9SAlexander Mikhalitsyn { 120a02d83f9SAlexander Mikhalitsyn return false; 121a02d83f9SAlexander Mikhalitsyn } 122877ce7c1SCatherine Zhang #endif /* CONFIG_SECURITY_NETWORK */ 123877ce7c1SCatherine Zhang 1245e2ff670SAlexander Mikhalitsyn static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm) 1255e2ff670SAlexander Mikhalitsyn { 1265e2ff670SAlexander Mikhalitsyn struct file *pidfd_file = NULL; 127*718e6b51SKuniyuki Iwashima int len, pidfd; 1285e2ff670SAlexander Mikhalitsyn 129*718e6b51SKuniyuki Iwashima /* put_cmsg() doesn't return an error if CMSG is truncated, 1305e2ff670SAlexander Mikhalitsyn * that's why we need to opencode these checks here. 1315e2ff670SAlexander Mikhalitsyn */ 132*718e6b51SKuniyuki Iwashima if (msg->msg_flags & MSG_CMSG_COMPAT) 133*718e6b51SKuniyuki Iwashima len = sizeof(struct compat_cmsghdr) + sizeof(int); 134*718e6b51SKuniyuki Iwashima else 135*718e6b51SKuniyuki Iwashima len = sizeof(struct cmsghdr) + sizeof(int); 136*718e6b51SKuniyuki Iwashima 137*718e6b51SKuniyuki Iwashima if (msg->msg_controllen < len) { 1385e2ff670SAlexander Mikhalitsyn msg->msg_flags |= MSG_CTRUNC; 1395e2ff670SAlexander Mikhalitsyn return; 1405e2ff670SAlexander Mikhalitsyn } 1415e2ff670SAlexander Mikhalitsyn 142603fc57aSKuniyuki Iwashima if (!scm->pid) 143603fc57aSKuniyuki Iwashima return; 144603fc57aSKuniyuki Iwashima 1455e2ff670SAlexander Mikhalitsyn pidfd = pidfd_prepare(scm->pid, 0, &pidfd_file); 1465e2ff670SAlexander Mikhalitsyn 1475e2ff670SAlexander Mikhalitsyn if (put_cmsg(msg, SOL_SOCKET, SCM_PIDFD, sizeof(int), &pidfd)) { 1485e2ff670SAlexander Mikhalitsyn if (pidfd_file) { 1495e2ff670SAlexander Mikhalitsyn put_unused_fd(pidfd); 1505e2ff670SAlexander Mikhalitsyn fput(pidfd_file); 1515e2ff670SAlexander Mikhalitsyn } 1525e2ff670SAlexander Mikhalitsyn 1535e2ff670SAlexander Mikhalitsyn return; 1545e2ff670SAlexander Mikhalitsyn } 1555e2ff670SAlexander Mikhalitsyn 1565e2ff670SAlexander Mikhalitsyn if (pidfd_file) 1575e2ff670SAlexander Mikhalitsyn fd_install(pidfd, pidfd_file); 1585e2ff670SAlexander Mikhalitsyn } 1595e2ff670SAlexander Mikhalitsyn 160a9c49cc2SAlexander Mikhalitsyn static inline bool __scm_recv_common(struct socket *sock, struct msghdr *msg, 1611da177e4SLinus Torvalds struct scm_cookie *scm, int flags) 1621da177e4SLinus Torvalds { 163fd2c3ef7SEric Dumazet if (!msg->msg_control) { 1645e2ff670SAlexander Mikhalitsyn if (test_bit(SOCK_PASSCRED, &sock->flags) || 1655e2ff670SAlexander Mikhalitsyn test_bit(SOCK_PASSPIDFD, &sock->flags) || 1665e2ff670SAlexander Mikhalitsyn scm->fp || scm_has_secdata(sock)) 1671da177e4SLinus Torvalds msg->msg_flags |= MSG_CTRUNC; 168f78a5fdaSDavid S. Miller scm_destroy(scm); 169a9c49cc2SAlexander Mikhalitsyn return false; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 172dbe9a417SEric W. Biederman if (test_bit(SOCK_PASSCRED, &sock->flags)) { 173dbe9a417SEric W. Biederman struct user_namespace *current_ns = current_user_ns(); 174dbe9a417SEric W. Biederman struct ucred ucreds = { 175dbe9a417SEric W. Biederman .pid = scm->creds.pid, 176dbe9a417SEric W. Biederman .uid = from_kuid_munged(current_ns, scm->creds.uid), 177dbe9a417SEric W. Biederman .gid = from_kgid_munged(current_ns, scm->creds.gid), 178dbe9a417SEric W. Biederman }; 179dbe9a417SEric W. Biederman put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds); 180dbe9a417SEric W. Biederman } 1811da177e4SLinus Torvalds 182a9c49cc2SAlexander Mikhalitsyn scm_passec(sock, msg, scm); 183a9c49cc2SAlexander Mikhalitsyn 184a9c49cc2SAlexander Mikhalitsyn if (scm->fp) 185a9c49cc2SAlexander Mikhalitsyn scm_detach_fds(msg, scm); 186a9c49cc2SAlexander Mikhalitsyn 187a9c49cc2SAlexander Mikhalitsyn return true; 188a9c49cc2SAlexander Mikhalitsyn } 189a9c49cc2SAlexander Mikhalitsyn 190a9c49cc2SAlexander Mikhalitsyn static inline void scm_recv(struct socket *sock, struct msghdr *msg, 191a9c49cc2SAlexander Mikhalitsyn struct scm_cookie *scm, int flags) 192a9c49cc2SAlexander Mikhalitsyn { 193a9c49cc2SAlexander Mikhalitsyn if (!__scm_recv_common(sock, msg, scm, flags)) 194a9c49cc2SAlexander Mikhalitsyn return; 195a9c49cc2SAlexander Mikhalitsyn 196a9c49cc2SAlexander Mikhalitsyn scm_destroy_cred(scm); 197a9c49cc2SAlexander Mikhalitsyn } 198a9c49cc2SAlexander Mikhalitsyn 199a9c49cc2SAlexander Mikhalitsyn static inline void scm_recv_unix(struct socket *sock, struct msghdr *msg, 200a9c49cc2SAlexander Mikhalitsyn struct scm_cookie *scm, int flags) 201a9c49cc2SAlexander Mikhalitsyn { 202a9c49cc2SAlexander Mikhalitsyn if (!__scm_recv_common(sock, msg, scm, flags)) 203a9c49cc2SAlexander Mikhalitsyn return; 204a9c49cc2SAlexander Mikhalitsyn 2055e2ff670SAlexander Mikhalitsyn if (test_bit(SOCK_PASSPIDFD, &sock->flags)) 2065e2ff670SAlexander Mikhalitsyn scm_pidfd_recv(msg, scm); 2075e2ff670SAlexander Mikhalitsyn 208f78a5fdaSDavid S. Miller scm_destroy_cred(scm); 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds #endif /* __LINUX_NET_SCM_H */ 2121da177e4SLinus Torvalds 213