1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __LINUX_NET_SCM_H 3 #define __LINUX_NET_SCM_H 4 5 #include <linux/limits.h> 6 #include <linux/net.h> 7 #include <linux/cred.h> 8 #include <linux/file.h> 9 #include <linux/security.h> 10 #include <linux/pid.h> 11 #include <linux/nsproxy.h> 12 #include <linux/sched/signal.h> 13 #include <net/compat.h> 14 15 /* Well, we should have at least one descriptor open 16 * to accept passed FDs 8) 17 */ 18 #define SCM_MAX_FD 253 19 20 struct scm_creds { 21 u32 pid; 22 kuid_t uid; 23 kgid_t gid; 24 }; 25 26 struct scm_fp_list { 27 short count; 28 short max; 29 struct user_struct *user; 30 struct file *fp[SCM_MAX_FD]; 31 }; 32 33 struct scm_cookie { 34 struct pid *pid; /* Skb credentials */ 35 struct scm_fp_list *fp; /* Passed files */ 36 struct scm_creds creds; /* Skb credentials */ 37 #ifdef CONFIG_SECURITY_NETWORK 38 u32 secid; /* Passed security ID */ 39 #endif 40 }; 41 42 void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm); 43 void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm); 44 int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm); 45 void __scm_destroy(struct scm_cookie *scm); 46 struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl); 47 48 #ifdef CONFIG_SECURITY_NETWORK 49 static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) 50 { 51 security_socket_getpeersec_dgram(sock, NULL, &scm->secid); 52 } 53 #else 54 static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) 55 { } 56 #endif /* CONFIG_SECURITY_NETWORK */ 57 58 static __inline__ void scm_set_cred(struct scm_cookie *scm, 59 struct pid *pid, kuid_t uid, kgid_t gid) 60 { 61 scm->pid = get_pid(pid); 62 scm->creds.pid = pid_vnr(pid); 63 scm->creds.uid = uid; 64 scm->creds.gid = gid; 65 } 66 67 static __inline__ void scm_destroy_cred(struct scm_cookie *scm) 68 { 69 put_pid(scm->pid); 70 scm->pid = NULL; 71 } 72 73 static __inline__ void scm_destroy(struct scm_cookie *scm) 74 { 75 scm_destroy_cred(scm); 76 if (scm->fp) 77 __scm_destroy(scm); 78 } 79 80 static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, 81 struct scm_cookie *scm, bool forcecreds) 82 { 83 memset(scm, 0, sizeof(*scm)); 84 scm->creds.uid = INVALID_UID; 85 scm->creds.gid = INVALID_GID; 86 if (forcecreds) 87 scm_set_cred(scm, task_tgid(current), current_uid(), current_gid()); 88 unix_get_peersec_dgram(sock, scm); 89 if (msg->msg_controllen <= 0) 90 return 0; 91 return __scm_send(sock, msg, scm); 92 } 93 94 #ifdef CONFIG_SECURITY_NETWORK 95 static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) 96 { 97 char *secdata; 98 u32 seclen; 99 int err; 100 101 if (test_bit(SOCK_PASSSEC, &sock->flags)) { 102 err = security_secid_to_secctx(scm->secid, &secdata, &seclen); 103 104 if (!err) { 105 put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata); 106 security_release_secctx(secdata, seclen); 107 } 108 } 109 } 110 111 static inline bool scm_has_secdata(struct socket *sock) 112 { 113 return test_bit(SOCK_PASSSEC, &sock->flags); 114 } 115 #else 116 static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) 117 { } 118 119 static inline bool scm_has_secdata(struct socket *sock) 120 { 121 return false; 122 } 123 #endif /* CONFIG_SECURITY_NETWORK */ 124 125 static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm) 126 { 127 struct file *pidfd_file = NULL; 128 int len, pidfd; 129 130 /* put_cmsg() doesn't return an error if CMSG is truncated, 131 * that's why we need to opencode these checks here. 132 */ 133 if (msg->msg_flags & MSG_CMSG_COMPAT) 134 len = sizeof(struct compat_cmsghdr) + sizeof(int); 135 else 136 len = sizeof(struct cmsghdr) + sizeof(int); 137 138 if (msg->msg_controllen < len) { 139 msg->msg_flags |= MSG_CTRUNC; 140 return; 141 } 142 143 if (!scm->pid) 144 return; 145 146 pidfd = pidfd_prepare(scm->pid, 0, &pidfd_file); 147 148 if (put_cmsg(msg, SOL_SOCKET, SCM_PIDFD, sizeof(int), &pidfd)) { 149 if (pidfd_file) { 150 put_unused_fd(pidfd); 151 fput(pidfd_file); 152 } 153 154 return; 155 } 156 157 if (pidfd_file) 158 fd_install(pidfd, pidfd_file); 159 } 160 161 static inline bool __scm_recv_common(struct socket *sock, struct msghdr *msg, 162 struct scm_cookie *scm, int flags) 163 { 164 if (!msg->msg_control) { 165 if (test_bit(SOCK_PASSCRED, &sock->flags) || 166 test_bit(SOCK_PASSPIDFD, &sock->flags) || 167 scm->fp || scm_has_secdata(sock)) 168 msg->msg_flags |= MSG_CTRUNC; 169 scm_destroy(scm); 170 return false; 171 } 172 173 if (test_bit(SOCK_PASSCRED, &sock->flags)) { 174 struct user_namespace *current_ns = current_user_ns(); 175 struct ucred ucreds = { 176 .pid = scm->creds.pid, 177 .uid = from_kuid_munged(current_ns, scm->creds.uid), 178 .gid = from_kgid_munged(current_ns, scm->creds.gid), 179 }; 180 put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds); 181 } 182 183 scm_passec(sock, msg, scm); 184 185 if (scm->fp) 186 scm_detach_fds(msg, scm); 187 188 return true; 189 } 190 191 static inline void scm_recv(struct socket *sock, struct msghdr *msg, 192 struct scm_cookie *scm, int flags) 193 { 194 if (!__scm_recv_common(sock, msg, scm, flags)) 195 return; 196 197 scm_destroy_cred(scm); 198 } 199 200 static inline void scm_recv_unix(struct socket *sock, struct msghdr *msg, 201 struct scm_cookie *scm, int flags) 202 { 203 if (!__scm_recv_common(sock, msg, scm, flags)) 204 return; 205 206 if (test_bit(SOCK_PASSPIDFD, &sock->flags)) 207 scm_pidfd_recv(msg, scm); 208 209 scm_destroy_cred(scm); 210 } 211 212 static inline int scm_recv_one_fd(struct file *f, int __user *ufd, 213 unsigned int flags) 214 { 215 if (!ufd) 216 return -EFAULT; 217 return receive_fd(f, ufd, flags); 218 } 219 220 #endif /* __LINUX_NET_SCM_H */ 221 222