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
unix_get_peersec_dgram(struct socket * sock,struct scm_cookie * scm)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
unix_get_peersec_dgram(struct socket * sock,struct scm_cookie * scm)65  static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
66  { }
67  #endif /* CONFIG_SECURITY_NETWORK */
68  
scm_set_cred(struct scm_cookie * scm,struct pid * pid,kuid_t uid,kgid_t gid)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  
scm_destroy_cred(struct scm_cookie * scm)78  static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
79  {
80  	put_pid(scm->pid);
81  	scm->pid  = NULL;
82  }
83  
scm_destroy(struct scm_cookie * scm)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  
scm_send(struct socket * sock,struct msghdr * msg,struct scm_cookie * scm,bool forcecreds)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
scm_passec(struct socket * sock,struct msghdr * msg,struct scm_cookie * scm)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  
scm_has_secdata(struct socket * sock)122  static inline bool scm_has_secdata(struct socket *sock)
123  {
124  	return test_bit(SOCK_PASSSEC, &sock->flags);
125  }
126  #else
scm_passec(struct socket * sock,struct msghdr * msg,struct scm_cookie * scm)127  static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
128  { }
129  
scm_has_secdata(struct socket * sock)130  static inline bool scm_has_secdata(struct socket *sock)
131  {
132  	return false;
133  }
134  #endif /* CONFIG_SECURITY_NETWORK */
135  
scm_pidfd_recv(struct msghdr * msg,struct scm_cookie * scm)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  
__scm_recv_common(struct socket * sock,struct msghdr * msg,struct scm_cookie * scm,int flags)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  
scm_recv(struct socket * sock,struct msghdr * msg,struct scm_cookie * scm,int flags)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  
scm_recv_unix(struct socket * sock,struct msghdr * msg,struct scm_cookie * scm,int flags)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  
scm_recv_one_fd(struct file * f,int __user * ufd,unsigned int flags)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