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