xref: /netbsd-src/sys/compat/netbsd32/netbsd32_socket.c (revision c38e7cc395b1472a774ff828e46123de44c628e9)
1 /*	$NetBSD: netbsd32_socket.c,v 1.45 2018/05/03 21:43:33 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1998, 2001 Matthew R. Green
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.45 2018/05/03 21:43:33 christos Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #define msg __msg /* Don't ask me! */
35 #include <sys/mount.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/socketvar.h>
39 #include <sys/mbuf.h>
40 #include <sys/ktrace.h>
41 #include <sys/file.h>
42 #include <sys/filedesc.h>
43 #include <sys/syscallargs.h>
44 #include <sys/proc.h>
45 #include <sys/dirent.h>
46 
47 #include <compat/netbsd32/netbsd32.h>
48 #include <compat/netbsd32/netbsd32_syscallargs.h>
49 #include <compat/netbsd32/netbsd32_conv.h>
50 
51 /*
52  * XXX Assumes that struct sockaddr is compatible.
53  */
54 
55 #define	CMSG32_ALIGN(n)	(((n) + ALIGNBYTES32) & ~ALIGNBYTES32)
56 #define CMSG32_ASIZE	CMSG32_ALIGN(sizeof(struct cmsghdr))
57 #define	CMSG32_DATA(cmsg) (__CASTV(u_char *, cmsg) + CMSG32_ASIZE)
58 #define CMSG32_MSGNEXT(ucmsg, kcmsg) \
59     (__CASTV(char *, kcmsg) + CMSG32_ALIGN((ucmsg)->cmsg_len))
60 #define CMSG32_MSGEND(mhdr) \
61     (__CASTV(char *, (mhdr)->msg_control) + (mhdr)->msg_controllen)
62 
63 #define	CMSG32_NXTHDR(mhdr, ucmsg, kcmsg)	\
64     __CASTV(struct cmsghdr *,  \
65 	CMSG32_MSGNEXT(ucmsg, kcmsg) + \
66 	CMSG32_ASIZE > CMSG32_MSGEND(mhdr) ? 0 : \
67 	CMSG32_MSGNEXT(ucmsg, kcmsg))
68 #define	CMSG32_FIRSTHDR(mhdr) \
69     __CASTV(struct cmsghdr *, \
70 	(mhdr)->msg_controllen < sizeof(struct cmsghdr) ? 0 : \
71 	(mhdr)->msg_control)
72 
73 #define CMSG32_SPACE(l)	(CMSG32_ALIGN(sizeof(struct cmsghdr)) + CMSG32_ALIGN(l))
74 #define CMSG32_LEN(l)	(CMSG32_ALIGN(sizeof(struct cmsghdr)) + (l))
75 
76 static int
77 copyout32_msg_control_mbuf(struct lwp *l, struct msghdr *mp, int *len,
78     struct mbuf *m, char **q, bool *truncated)
79 {
80 	struct cmsghdr *cmsg, cmsg32;
81 	int i, j, error;
82 
83 	*truncated = false;
84 	cmsg = mtod(m, struct cmsghdr *);
85 	do {
86 		if ((char *)cmsg == mtod(m, char *) + m->m_len)
87 			break;
88 		if ((char *)cmsg > mtod(m, char *) + m->m_len - sizeof(*cmsg))
89 			return EINVAL;
90 		cmsg32 = *cmsg;
91 		j = cmsg->cmsg_len - CMSG_LEN(0);
92 		i = cmsg32.cmsg_len = CMSG32_LEN(j);
93 		if (i > *len) {
94 			mp->msg_flags |= MSG_CTRUNC;
95 			if (cmsg->cmsg_level == SOL_SOCKET
96 			    && cmsg->cmsg_type == SCM_RIGHTS) {
97 				*truncated = true;
98 				return 0;
99 			}
100 			j -= i - *len;
101 			i = *len;
102 		}
103 
104 		ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
105 		error = copyout(&cmsg32, *q, MAX(i, sizeof(cmsg32)));
106 		if (error)
107 			return (error);
108 		if (i > CMSG32_LEN(0)) {
109 			error = copyout(CMSG_DATA(cmsg), *q + CMSG32_LEN(0),
110 			    i - CMSG32_LEN(0));
111 			if (error)
112 				return (error);
113 		}
114 		j = CMSG32_SPACE(cmsg->cmsg_len - CMSG_LEN(0));
115 		if (*len >= j) {
116 			*len -= j;
117 			*q += j;
118 		} else {
119 			*q += i;
120 			*len = 0;
121 		}
122 		cmsg = (void *)((char *)cmsg + CMSG_ALIGN(cmsg->cmsg_len));
123 	} while (*len > 0);
124 
125 	return 0;
126 }
127 
128 static int
129 copyout32_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control)
130 {
131 	int len, error = 0;
132 	struct mbuf *m;
133 	char *q;
134 	bool truncated;
135 
136 	len = mp->msg_controllen;
137 	if (len <= 0 || control == 0) {
138 		mp->msg_controllen = 0;
139 		free_control_mbuf(l, control, control);
140 		return 0;
141 	}
142 
143 	q = (char *)mp->msg_control;
144 
145 	for (m = control; len > 0 && m != NULL; m = m->m_next) {
146 		error = copyout32_msg_control_mbuf(l, mp, &len, m, &q,
147 		    &truncated);
148 		if (truncated) {
149 			m = control;
150 			break;
151 		}
152 		if (error)
153 			break;
154 	}
155 
156 	free_control_mbuf(l, control, m);
157 
158 	mp->msg_controllen = q - (char *)mp->msg_control;
159 	return error;
160 }
161 
162 int
163 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap,
164     register_t *retval)
165 {
166 	/* {
167 		syscallarg(int) s;
168 		syscallarg(netbsd32_msghdrp_t) msg;
169 		syscallarg(int) flags;
170 	} */
171 	struct netbsd32_msghdr	msg32;
172 	struct iovec aiov[UIO_SMALLIOV], *iov;
173 	struct msghdr	msg;
174 	int		error;
175 	struct mbuf	*from, *control;
176 	size_t iovsz;
177 
178 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
179 	if (error)
180 		return (error);
181 
182 	iovsz = msg32.msg_iovlen * sizeof(struct iovec);
183 	if (msg32.msg_iovlen > UIO_SMALLIOV) {
184 		if (msg32.msg_iovlen > IOV_MAX)
185 			return (EMSGSIZE);
186 		iov = kmem_alloc(iovsz, KM_SLEEP);
187 	} else
188 		iov = aiov;
189 	error = netbsd32_to_iovecin(NETBSD32PTR64(msg32.msg_iov), iov,
190 	    msg32.msg_iovlen);
191 	if (error)
192 		goto done;
193 
194 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
195 	msg.msg_name = NETBSD32PTR64(msg32.msg_name);
196 	msg.msg_namelen = msg32.msg_namelen;
197 	msg.msg_control = NETBSD32PTR64(msg32.msg_control);
198 	msg.msg_controllen = msg32.msg_controllen;
199 	msg.msg_iov = iov;
200 	msg.msg_iovlen = msg32.msg_iovlen;
201 
202 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg,
203 	    &from, msg.msg_control != NULL ? &control : NULL, retval);
204 	if (error != 0)
205 		goto done;
206 
207 	if (msg.msg_control != NULL)
208 		error = copyout32_msg_control(l, &msg, control);
209 
210 	if (error == 0)
211 		error = copyout_sockname(msg.msg_name, &msg.msg_namelen, 0,
212 			from);
213 	if (from != NULL)
214 		m_free(from);
215 	if (error == 0) {
216 		msg32.msg_namelen = msg.msg_namelen;
217 		msg32.msg_controllen = msg.msg_controllen;
218 		msg32.msg_flags = msg.msg_flags;
219 		ktrkuser("msghdr", &msg, sizeof msg);
220 		error = copyout(&msg32, SCARG_P32(uap, msg), sizeof(msg32));
221 	}
222 
223  done:
224 	if (iov != aiov)
225 		kmem_free(iov, iovsz);
226 	return (error);
227 }
228 
229 static int
230 copyin32_msg_control(struct lwp *l, struct msghdr *mp)
231 {
232 	/*
233 	 * Handle cmsg if there is any.
234 	 */
235 	struct cmsghdr *cmsg, cmsg32, *cc;
236 	struct mbuf *ctl_mbuf;
237 	ssize_t resid = mp->msg_controllen;
238 	size_t clen, cidx = 0, cspace;
239 	u_int8_t *control;
240 	int error;
241 
242 	ctl_mbuf = m_get(M_WAIT, MT_CONTROL);
243 	clen = MLEN;
244 	control = mtod(ctl_mbuf, void *);
245 	memset(control, 0, clen);
246 
247 	for (cc = CMSG32_FIRSTHDR(mp); cc; cc = CMSG32_NXTHDR(mp, &cmsg32, cc))
248 	{
249 		error = copyin(cc, &cmsg32, sizeof(cmsg32));
250 		if (error)
251 			goto failure;
252 
253 		/*
254 		 * Sanity check the control message length.
255 		 */
256 		if (cmsg32.cmsg_len > resid ||
257 		    cmsg32.cmsg_len < sizeof(cmsg32)) {
258 			error = EINVAL;
259 			goto failure;
260 		}
261 
262 		cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0));
263 
264 		/* Check the buffer is big enough */
265 		if (__predict_false(cidx + cspace > clen)) {
266 			u_int8_t *nc;
267 			size_t nclen;
268 
269 			nclen = cidx + cspace;
270 			if (nclen >= PAGE_SIZE) {
271 				error = EINVAL;
272 				goto failure;
273 			}
274 			nc = realloc(clen <= MLEN ? NULL : control,
275 				     nclen, M_TEMP, M_WAITOK);
276 			if (!nc) {
277 				error = ENOMEM;
278 				goto failure;
279 			}
280 			if (cidx <= MLEN) {
281 				/* Old buffer was in mbuf... */
282 				memcpy(nc, control, cidx);
283 				memset(nc + cidx, 0, nclen - cidx);
284 			} else {
285 				memset(nc + nclen, 0, nclen - clen);
286 			}
287 			control = nc;
288 			clen = nclen;
289 		}
290 
291 		/* Copy header */
292 		cmsg = (void *)&control[cidx];
293 		cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0));
294 		cmsg->cmsg_level = cmsg32.cmsg_level;
295 		cmsg->cmsg_type = cmsg32.cmsg_type;
296 
297 		/* Copyin the data */
298 		error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg),
299 		    cmsg32.cmsg_len - CMSG32_LEN(0));
300 		if (error)
301 			goto failure;
302 		ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
303 
304 		resid -= CMSG32_ALIGN(cmsg32.cmsg_len);
305 		cidx += CMSG_ALIGN(cmsg->cmsg_len);
306 	}
307 
308 	/* If we allocated a buffer, attach to mbuf */
309 	if (cidx > MLEN) {
310 		MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL);
311 		ctl_mbuf->m_flags |= M_EXT_RW;
312 	}
313 	control = NULL;
314 	mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx);
315 
316 	mp->msg_control = ctl_mbuf;
317 	mp->msg_flags |= MSG_CONTROLMBUF;
318 
319 
320 	return 0;
321 
322 failure:
323 	if (control != mtod(ctl_mbuf, void *))
324 		free(control, M_MBUF);
325 	m_free(ctl_mbuf);
326 	return error;
327 }
328 
329 int
330 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap,
331     register_t *retval)
332 {
333 	/* {
334 		syscallarg(int) s;
335 		syscallarg(const netbsd32_msghdrp_t) msg;
336 		syscallarg(int) flags;
337 	} */
338 	struct msghdr msg;
339 	struct netbsd32_msghdr msg32;
340 	struct iovec aiov[UIO_SMALLIOV], *iov = aiov;
341 	struct netbsd32_iovec *iov32;
342 	size_t iovsz;
343 	int error;
344 
345 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
346 	if (error)
347 		return (error);
348 	netbsd32_to_msghdr(&msg32, &msg);
349 	msg.msg_flags = 0;
350 
351 	if (CMSG32_FIRSTHDR(&msg)) {
352 		error = copyin32_msg_control(l, &msg);
353 		if (error)
354 			return (error);
355 		/* From here on, msg.msg_control is allocated */
356 	} else {
357 		msg.msg_control = NULL;
358 		msg.msg_controllen = 0;
359 	}
360 
361 	iovsz = msg.msg_iovlen * sizeof(struct iovec);
362 	if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) {
363 		if ((u_int)msg.msg_iovlen > IOV_MAX) {
364 			error = EMSGSIZE;
365 			goto out;
366 		}
367 		iov = kmem_alloc(iovsz, KM_SLEEP);
368 	}
369 
370 	iov32 = NETBSD32PTR64(msg32.msg_iov);
371 	error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen);
372 	if (error)
373 		goto out;
374 	msg.msg_iov = iov;
375 
376 	error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
377 	    retval);
378 	/* msg.msg_control freed by do_sys_sendmsg() */
379 
380 	if (iov != aiov)
381 		kmem_free(iov, iovsz);
382 	return (error);
383 
384 out:
385 	if (iov != aiov)
386 		kmem_free(iov, iovsz);
387 	if (msg.msg_control)
388 		m_free(msg.msg_control);
389 	return error;
390 }
391 
392 int
393 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap,
394     register_t *retval)
395 {
396 	/* {
397 		syscallarg(int) s;
398 		syscallarg(netbsd32_voidp) buf;
399 		syscallarg(netbsd32_size_t) len;
400 		syscallarg(int) flags;
401 		syscallarg(netbsd32_sockaddrp_t) from;
402 		syscallarg(netbsd32_intp) fromlenaddr;
403 	} */
404 	struct msghdr	msg;
405 	struct iovec	aiov;
406 	int		error;
407 	struct mbuf	*from;
408 
409 	msg.msg_name = NULL;
410 	msg.msg_iov = &aiov;
411 	msg.msg_iovlen = 1;
412 	aiov.iov_base = SCARG_P32(uap, buf);
413 	aiov.iov_len = SCARG(uap, len);
414 	msg.msg_control = NULL;
415 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
416 
417 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
418 	if (error != 0)
419 		return error;
420 
421 	error = copyout_sockname(SCARG_P32(uap, from),
422 	    SCARG_P32(uap, fromlenaddr), MSG_LENUSRSPACE, from);
423 	if (from != NULL)
424 		m_free(from);
425 	return error;
426 }
427 
428 int
429 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap,
430     register_t *retval)
431 {
432 	/* {
433 		syscallarg(int) s;
434 		syscallarg(const netbsd32_voidp) buf;
435 		syscallarg(netbsd32_size_t) len;
436 		syscallarg(int) flags;
437 		syscallarg(const netbsd32_sockaddrp_t) to;
438 		syscallarg(int) tolen;
439 	} */
440 	struct msghdr msg;
441 	struct iovec aiov;
442 
443 	msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
444 	msg.msg_namelen = SCARG(uap, tolen);
445 	msg.msg_iov = &aiov;
446 	msg.msg_iovlen = 1;
447 	msg.msg_control = 0;
448 	aiov.iov_base = SCARG_P32(uap, buf);	/* XXX kills const */
449 	aiov.iov_len = SCARG(uap, len);
450 	msg.msg_flags = 0;
451 	return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
452 	    retval);
453 }
454