1 /*	$NetBSD: netbsd32_socket.c,v 1.42 2015/07/22 14:25:39 maxv 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.42 2015/07/22 14:25:39 maxv 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_DATA(cmsg) \
57 	((u_char *)(void *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr)))
58 
59 #define	CMSG32_NXTHDR(mhdr, cmsg)	\
60 	(((char *)(cmsg) + CMSG32_ALIGN((cmsg)->cmsg_len) + \
61 			    CMSG32_ALIGN(sizeof(struct cmsghdr)) > \
62 	    (((char *)(mhdr)->msg_control) + (mhdr)->msg_controllen)) ? \
63 	    (struct cmsghdr *)0 : \
64 	    (struct cmsghdr *)((char *)(cmsg) + \
65 	        CMSG32_ALIGN((cmsg)->cmsg_len)))
66 #define	CMSG32_FIRSTHDR(mhdr) \
67 	((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
68 	 (struct cmsghdr *)(mhdr)->msg_control : \
69 	 (struct cmsghdr *)0)
70 
71 #define CMSG32_SPACE(l)	(CMSG32_ALIGN(sizeof(struct cmsghdr)) + CMSG32_ALIGN(l))
72 #define CMSG32_LEN(l)	(CMSG32_ALIGN(sizeof(struct cmsghdr)) + (l))
73 
74 static int
copyout32_msg_control_mbuf(struct lwp * l,struct msghdr * mp,int * len,struct mbuf * m,char ** q,bool * truncated)75 copyout32_msg_control_mbuf(struct lwp *l, struct msghdr *mp, int *len, struct mbuf *m, char **q, bool *truncated)
76 {
77 	struct cmsghdr *cmsg, cmsg32;
78 	int i, j, error;
79 
80 	*truncated = false;
81 	cmsg = mtod(m, struct cmsghdr *);
82 	do {
83 		if ((char *)cmsg == mtod(m, char *) + m->m_len)
84 			break;
85 		if ((char *)cmsg > mtod(m, char *) + m->m_len - sizeof(*cmsg))
86 			return EINVAL;
87 		cmsg32 = *cmsg;
88 		j = cmsg->cmsg_len - CMSG_LEN(0);
89 		i = cmsg32.cmsg_len = CMSG32_LEN(j);
90 		if (i > *len) {
91 			mp->msg_flags |= MSG_CTRUNC;
92 			if (cmsg->cmsg_level == SOL_SOCKET
93 			    && cmsg->cmsg_type == SCM_RIGHTS) {
94 				*truncated = true;
95 				return 0;
96 			}
97 			j -= i - *len;
98 			i = *len;
99 		}
100 
101 		ktrkuser("msgcontrol", cmsg, cmsg->cmsg_len);
102 		error = copyout(&cmsg32, *q, MAX(i, sizeof(cmsg32)));
103 		if (error)
104 			return (error);
105 		if (i > CMSG32_LEN(0)) {
106 			error = copyout(CMSG_DATA(cmsg), *q + CMSG32_LEN(0), i - CMSG32_LEN(0));
107 			if (error)
108 				return (error);
109 		}
110 		j = CMSG32_SPACE(cmsg->cmsg_len - CMSG_LEN(0));
111 		if (*len >= j) {
112 			*len -= j;
113 			*q += j;
114 		} else {
115 			*q += i;
116 			*len = 0;
117 		}
118 		cmsg = (void *)((char *)cmsg + CMSG_ALIGN(cmsg->cmsg_len));
119 	} while (*len > 0);
120 
121 	return 0;
122 }
123 
124 static int
copyout32_msg_control(struct lwp * l,struct msghdr * mp,struct mbuf * control)125 copyout32_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control)
126 {
127 	int len, error = 0;
128 	struct mbuf *m;
129 	char *q;
130 	bool truncated;
131 
132 	len = mp->msg_controllen;
133 	if (len <= 0 || control == 0) {
134 		mp->msg_controllen = 0;
135 		free_control_mbuf(l, control, control);
136 		return 0;
137 	}
138 
139 	q = (char *)mp->msg_control;
140 
141 	for (m = control; len > 0 && m != NULL; m = m->m_next) {
142 		error = copyout32_msg_control_mbuf(l, mp, &len, m, &q, &truncated);
143 		if (truncated) {
144 			m = control;
145 			break;
146 		}
147 		if (error)
148 			break;
149 	}
150 
151 	free_control_mbuf(l, control, m);
152 
153 	mp->msg_controllen = q - (char *)mp->msg_control;
154 	return error;
155 }
156 
157 int
netbsd32_recvmsg(struct lwp * l,const struct netbsd32_recvmsg_args * uap,register_t * retval)158 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap, register_t *retval)
159 {
160 	/* {
161 		syscallarg(int) s;
162 		syscallarg(netbsd32_msghdrp_t) msg;
163 		syscallarg(int) flags;
164 	} */
165 	struct netbsd32_msghdr	msg32;
166 	struct iovec aiov[UIO_SMALLIOV], *iov;
167 	struct msghdr	msg;
168 	int		error;
169 	struct mbuf	*from, *control;
170 	size_t iovsz;
171 
172 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
173 	if (error)
174 		return (error);
175 
176 	iovsz = msg32.msg_iovlen * sizeof(struct iovec);
177 	if (msg32.msg_iovlen > UIO_SMALLIOV) {
178 		if (msg32.msg_iovlen > IOV_MAX)
179 			return (EMSGSIZE);
180 		iov = kmem_alloc(iovsz, KM_SLEEP);
181 	} else
182 		iov = aiov;
183 	error = netbsd32_to_iovecin(NETBSD32PTR64(msg32.msg_iov), iov,
184 	    msg32.msg_iovlen);
185 	if (error)
186 		goto done;
187 
188 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
189 	msg.msg_name = NETBSD32PTR64(msg32.msg_name);
190 	msg.msg_namelen = msg32.msg_namelen;
191 	msg.msg_control = NETBSD32PTR64(msg32.msg_control);
192 	msg.msg_controllen = msg32.msg_controllen;
193 	msg.msg_iov = iov;
194 	msg.msg_iovlen = msg32.msg_iovlen;
195 
196 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from,
197 	    msg.msg_control != NULL ? &control : NULL, retval);
198 	if (error != 0)
199 		goto done;
200 
201 	if (msg.msg_control != NULL)
202 		error = copyout32_msg_control(l, &msg, control);
203 
204 	if (error == 0)
205 		error = copyout_sockname(msg.msg_name, &msg.msg_namelen, 0,
206 			from);
207 	if (from != NULL)
208 		m_free(from);
209 	if (error == 0) {
210 		ktrkuser("msghdr", &msg, sizeof msg);
211 		msg32.msg_namelen = msg.msg_namelen;
212 		msg32.msg_controllen = msg.msg_controllen;
213 		msg32.msg_flags = msg.msg_flags;
214 		error = copyout(&msg32, SCARG_P32(uap, msg), sizeof(msg32));
215 	}
216 
217  done:
218 	if (iov != aiov)
219 		kmem_free(iov, iovsz);
220 	return (error);
221 }
222 
223 static int
copyin32_msg_control(struct lwp * l,struct msghdr * mp)224 copyin32_msg_control(struct lwp *l, struct msghdr *mp)
225 {
226 	/*
227 	 * Handle cmsg if there is any.
228 	 */
229 	struct cmsghdr *cmsg, cmsg32, *cc;
230 	struct mbuf *ctl_mbuf;
231 	ssize_t resid = mp->msg_controllen;
232 	size_t clen, cidx = 0, cspace;
233 	u_int8_t *control;
234 	int error;
235 
236 	ctl_mbuf = m_get(M_WAIT, MT_CONTROL);
237 	clen = MLEN;
238 	control = mtod(ctl_mbuf, void *);
239 	memset(control, 0, clen);
240 
241 	cc = CMSG32_FIRSTHDR(mp);
242 	do {
243 		error = copyin(cc, &cmsg32, sizeof(cmsg32));
244 		if (error)
245 			goto failure;
246 
247 		/*
248 		 * Sanity check the control message length.
249 		 */
250 		if (cmsg32.cmsg_len > resid ||
251 		    cmsg32.cmsg_len < sizeof(cmsg32)) {
252 			error = EINVAL;
253 			goto failure;
254 		}
255 
256 		cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0));
257 
258 		/* Check the buffer is big enough */
259 		if (__predict_false(cidx + cspace > clen)) {
260 			u_int8_t *nc;
261 			size_t nclen;
262 
263 			nclen = cidx + cspace;
264 			if (nclen >= PAGE_SIZE) {
265 				error = EINVAL;
266 				goto failure;
267 			}
268 			nc = realloc(clen <= MLEN ? NULL : control,
269 				     nclen, M_TEMP, M_WAITOK);
270 			if (!nc) {
271 				error = ENOMEM;
272 				goto failure;
273 			}
274 			if (cidx <= MLEN) {
275 				/* Old buffer was in mbuf... */
276 				memcpy(nc, control, cidx);
277 				memset(nc + cidx, 0, nclen - cidx);
278 			} else {
279 				memset(nc + nclen, 0, nclen - clen);
280 			}
281 			control = nc;
282 			clen = nclen;
283 		}
284 
285 		/* Copy header */
286 		cmsg = (void *)&control[cidx];
287 		cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0));
288 		cmsg->cmsg_level = cmsg32.cmsg_level;
289 		cmsg->cmsg_type = cmsg32.cmsg_type;
290 
291 		/* Copyin the data */
292 		error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg),
293 		    cmsg32.cmsg_len - CMSG32_LEN(0));
294 		if (error)
295 			goto failure;
296 
297 		resid -= CMSG32_ALIGN(cmsg32.cmsg_len);
298 		cidx += cmsg->cmsg_len;
299 	} while (resid > 0 && (cc = CMSG32_NXTHDR(mp, &cmsg32)));
300 
301 	/* If we allocated a buffer, attach to mbuf */
302 	if (cidx > MLEN) {
303 		MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL);
304 		ctl_mbuf->m_flags |= M_EXT_RW;
305 	}
306 	control = NULL;
307 	mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx);
308 
309 	mp->msg_control = ctl_mbuf;
310 	mp->msg_flags |= MSG_CONTROLMBUF;
311 
312 	ktrkuser("msgcontrol", mtod(ctl_mbuf, void *),
313 	    mp->msg_controllen);
314 
315 	return 0;
316 
317 failure:
318 	if (control != mtod(ctl_mbuf, void *))
319 		free(control, M_MBUF);
320 	m_free(ctl_mbuf);
321 	return error;
322 }
323 
324 int
netbsd32_sendmsg(struct lwp * l,const struct netbsd32_sendmsg_args * uap,register_t * retval)325 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap, register_t *retval)
326 {
327 	/* {
328 		syscallarg(int) s;
329 		syscallarg(const netbsd32_msghdrp_t) msg;
330 		syscallarg(int) flags;
331 	} */
332 	struct msghdr msg;
333 	struct netbsd32_msghdr msg32;
334 	struct iovec aiov[UIO_SMALLIOV], *iov = aiov;
335 	struct netbsd32_iovec *iov32;
336 	size_t iovsz;
337 	int error;
338 
339 	error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
340 	if (error)
341 		return (error);
342 	netbsd32_to_msghdr(&msg32, &msg);
343 	msg.msg_flags = 0;
344 
345 	if (CMSG32_FIRSTHDR(&msg)) {
346 		error = copyin32_msg_control(l, &msg);
347 		if (error)
348 			return (error);
349 		/* From here on, msg.msg_control is allocated */
350 	} else {
351 		msg.msg_control = NULL;
352 		msg.msg_controllen = 0;
353 	}
354 
355 	iovsz = msg.msg_iovlen * sizeof(struct iovec);
356 	if ((u_int)msg.msg_iovlen > UIO_SMALLIOV) {
357 		if ((u_int)msg.msg_iovlen > IOV_MAX) {
358 			error = EMSGSIZE;
359 			goto out;
360 		}
361 		iov = kmem_alloc(iovsz, KM_SLEEP);
362 	}
363 
364 	iov32 = NETBSD32PTR64(msg32.msg_iov);
365 	error = netbsd32_to_iovecin(iov32, iov, msg.msg_iovlen);
366 	if (error)
367 		goto out;
368 	msg.msg_iov = iov;
369 
370 	error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
371 	/* msg.msg_control freed by do_sys_sendmsg() */
372 
373 	if (iov != aiov)
374 		kmem_free(iov, iovsz);
375 	return (error);
376 
377 out:
378 	if (iov != aiov)
379 		kmem_free(iov, iovsz);
380 	if (msg.msg_control)
381 		m_free(msg.msg_control);
382 	return error;
383 }
384 
385 int
netbsd32_recvfrom(struct lwp * l,const struct netbsd32_recvfrom_args * uap,register_t * retval)386 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap, register_t *retval)
387 {
388 	/* {
389 		syscallarg(int) s;
390 		syscallarg(netbsd32_voidp) buf;
391 		syscallarg(netbsd32_size_t) len;
392 		syscallarg(int) flags;
393 		syscallarg(netbsd32_sockaddrp_t) from;
394 		syscallarg(netbsd32_intp) fromlenaddr;
395 	} */
396 	struct msghdr	msg;
397 	struct iovec	aiov;
398 	int		error;
399 	struct mbuf	*from;
400 
401 	msg.msg_name = NULL;
402 	msg.msg_iov = &aiov;
403 	msg.msg_iovlen = 1;
404 	aiov.iov_base = SCARG_P32(uap, buf);
405 	aiov.iov_len = SCARG(uap, len);
406 	msg.msg_control = NULL;
407 	msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
408 
409 	error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
410 	if (error != 0)
411 		return error;
412 
413 	error = copyout_sockname(SCARG_P32(uap, from), SCARG_P32(uap, fromlenaddr),
414 	    MSG_LENUSRSPACE, from);
415 	if (from != NULL)
416 		m_free(from);
417 	return error;
418 }
419 
420 int
netbsd32_sendto(struct lwp * l,const struct netbsd32_sendto_args * uap,register_t * retval)421 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap, register_t *retval)
422 {
423 	/* {
424 		syscallarg(int) s;
425 		syscallarg(const netbsd32_voidp) buf;
426 		syscallarg(netbsd32_size_t) len;
427 		syscallarg(int) flags;
428 		syscallarg(const netbsd32_sockaddrp_t) to;
429 		syscallarg(int) tolen;
430 	} */
431 	struct msghdr msg;
432 	struct iovec aiov;
433 
434 	msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
435 	msg.msg_namelen = SCARG(uap, tolen);
436 	msg.msg_iov = &aiov;
437 	msg.msg_iovlen = 1;
438 	msg.msg_control = 0;
439 	aiov.iov_base = SCARG_P32(uap, buf);	/* XXX kills const */
440 	aiov.iov_len = SCARG(uap, len);
441 	msg.msg_flags = 0;
442 	return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
443 }
444