xref: /openbsd/sys/kern/uipc_syscalls.c (revision 4cfece93)
1 /*	$OpenBSD: uipc_syscalls.c,v 1.186 2020/06/10 13:24:57 visa Exp $	*/
2 /*	$NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1989, 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)uipc_syscalls.c	8.4 (Berkeley) 2/21/94
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/filedesc.h>
38 #include <sys/proc.h>
39 #include <sys/fcntl.h>
40 #include <sys/file.h>
41 #include <sys/ioctl.h>
42 #include <sys/malloc.h>
43 #include <sys/event.h>
44 #include <sys/mbuf.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #include <sys/signalvar.h>
49 #include <sys/pledge.h>
50 #include <sys/unpcb.h>
51 #include <sys/un.h>
52 #ifdef KTRACE
53 #include <sys/ktrace.h>
54 #endif
55 
56 #include <sys/mount.h>
57 #include <sys/syscallargs.h>
58 
59 #include <sys/domain.h>
60 #include <netinet/in.h>
61 #include <net/route.h>
62 
63 int	copyaddrout(struct proc *, struct mbuf *, struct sockaddr *, socklen_t,
64 	    socklen_t *);
65 
66 int
67 sys_socket(struct proc *p, void *v, register_t *retval)
68 {
69 	struct sys_socket_args /* {
70 		syscallarg(int) domain;
71 		syscallarg(int) type;
72 		syscallarg(int) protocol;
73 	} */ *uap = v;
74 	struct filedesc *fdp = p->p_fd;
75 	struct socket *so;
76 	struct file *fp;
77 	int type = SCARG(uap, type);
78 	int domain = SCARG(uap, domain);
79 	int fd, cloexec, nonblock, fflag, error;
80 	unsigned int ss = 0;
81 
82 	if ((type & SOCK_DNS) && !(domain == AF_INET || domain == AF_INET6))
83 		return (EINVAL);
84 
85 	if (ISSET(type, SOCK_DNS))
86 		ss |= SS_DNS;
87 	error = pledge_socket(p, domain, ss);
88 	if (error)
89 		return (error);
90 
91 	type &= ~(SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_DNS);
92 	cloexec = (SCARG(uap, type) & SOCK_CLOEXEC) ? UF_EXCLOSE : 0;
93 	nonblock = SCARG(uap, type) & SOCK_NONBLOCK;
94 	fflag = FREAD | FWRITE | (nonblock ? FNONBLOCK : 0);
95 
96 	error = socreate(SCARG(uap, domain), &so, type, SCARG(uap, protocol));
97 	if (error)
98 		return (error);
99 
100 	fdplock(fdp);
101 	error = falloc(p, &fp, &fd);
102 	if (error) {
103 		fdpunlock(fdp);
104 		soclose(so, MSG_DONTWAIT);
105 	} else {
106 		fp->f_flag = fflag;
107 		fp->f_type = DTYPE_SOCKET;
108 		fp->f_ops = &socketops;
109 		so->so_state |= ss;
110 		fp->f_data = so;
111 		fdinsert(fdp, fd, cloexec, fp);
112 		fdpunlock(fdp);
113 		FRELE(fp, p);
114 		*retval = fd;
115 	}
116 	return (error);
117 }
118 
119 static inline int
120 isdnssocket(struct socket *so)
121 {
122 	return (so->so_state & SS_DNS);
123 }
124 
125 /* For SS_DNS sockets, only allow port DNS (port 53) */
126 static int
127 dns_portcheck(struct proc *p, struct socket *so, void *nam, u_int *namelen)
128 {
129 	int error = EINVAL;
130 
131 	switch (so->so_proto->pr_domain->dom_family) {
132 	case AF_INET:
133 		if (*namelen < sizeof(struct sockaddr_in))
134 			break;
135 		if (((struct sockaddr_in *)nam)->sin_port == htons(53))
136 			error = 0;
137 		break;
138 #ifdef INET6
139 	case AF_INET6:
140 		if (*namelen < sizeof(struct sockaddr_in6))
141 			break;
142 		if (((struct sockaddr_in6 *)nam)->sin6_port == htons(53))
143 			error = 0;
144 #endif
145 	}
146 	if (error && p->p_p->ps_flags & PS_PLEDGE)
147 		return (pledge_fail(p, EPERM, PLEDGE_DNS));
148 	return error;
149 }
150 
151 int
152 sys_bind(struct proc *p, void *v, register_t *retval)
153 {
154 	struct sys_bind_args /* {
155 		syscallarg(int) s;
156 		syscallarg(const struct sockaddr *) name;
157 		syscallarg(socklen_t) namelen;
158 	} */ *uap = v;
159 	struct file *fp;
160 	struct mbuf *nam;
161 	struct socket *so;
162 	int s, error;
163 
164 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
165 		return (error);
166 	so = fp->f_data;
167 	error = pledge_socket(p, so->so_proto->pr_domain->dom_family,
168 	    so->so_state);
169 	if (error)
170 		goto out;
171 	error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
172 	    MT_SONAME);
173 	if (error)
174 		goto out;
175 #ifdef KTRACE
176 	if (KTRPOINT(p, KTR_STRUCT))
177 		ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen));
178 #endif
179 	s = solock(so);
180 	error = sobind(so, nam, p);
181 	sounlock(so, s);
182 	m_freem(nam);
183 out:
184 	FRELE(fp, p);
185 	return (error);
186 }
187 
188 int
189 sys_listen(struct proc *p, void *v, register_t *retval)
190 {
191 	struct sys_listen_args /* {
192 		syscallarg(int) s;
193 		syscallarg(int) backlog;
194 	} */ *uap = v;
195 	struct file *fp;
196 	struct socket *so;
197 	int error;
198 
199 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
200 		return (error);
201 	so = fp->f_data;
202 	error = solisten(so, SCARG(uap, backlog));
203 	FRELE(fp, p);
204 	return (error);
205 }
206 
207 int
208 sys_accept(struct proc *p, void *v, register_t *retval)
209 {
210 	struct sys_accept_args /* {
211 		syscallarg(int) s;
212 		syscallarg(struct sockaddr *) name;
213 		syscallarg(socklen_t *) anamelen;
214 	} */ *uap = v;
215 
216 	return (doaccept(p, SCARG(uap, s), SCARG(uap, name),
217 	    SCARG(uap, anamelen), SOCK_NONBLOCK_INHERIT, retval));
218 }
219 
220 int
221 sys_accept4(struct proc *p, void *v, register_t *retval)
222 {
223 	struct sys_accept4_args /* {
224 		syscallarg(int) s;
225 		syscallarg(struct sockaddr *) name;
226 		syscallarg(socklen_t *) anamelen;
227 		syscallarg(socklen_t *) int flags;
228 	} */ *uap = v;
229 
230 	if (SCARG(uap, flags) & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
231 		return (EINVAL);
232 
233 	return (doaccept(p, SCARG(uap, s), SCARG(uap, name),
234 	    SCARG(uap, anamelen), SCARG(uap, flags), retval));
235 }
236 
237 int
238 doaccept(struct proc *p, int sock, struct sockaddr *name, socklen_t *anamelen,
239     int flags, register_t *retval)
240 {
241 	struct filedesc *fdp = p->p_fd;
242 	struct file *fp, *headfp;
243 	struct mbuf *nam;
244 	socklen_t namelen;
245 	int error, s, tmpfd;
246 	struct socket *head, *so;
247 	int cloexec, nflag;
248 
249 	cloexec = (flags & SOCK_CLOEXEC) ? UF_EXCLOSE : 0;
250 
251 	if (name && (error = copyin(anamelen, &namelen, sizeof (namelen))))
252 		return (error);
253 	if ((error = getsock(p, sock, &fp)) != 0)
254 		return (error);
255 
256 	headfp = fp;
257 
258 	fdplock(fdp);
259 	error = falloc(p, &fp, &tmpfd);
260 	fdpunlock(fdp);
261 	if (error) {
262 		FRELE(headfp, p);
263 		return (error);
264 	}
265 
266 	nam = m_get(M_WAIT, MT_SONAME);
267 
268 	head = headfp->f_data;
269 	s = solock(head);
270 	if (isdnssocket(head) || (head->so_options & SO_ACCEPTCONN) == 0) {
271 		error = EINVAL;
272 		goto out;
273 	}
274 	if ((headfp->f_flag & FNONBLOCK) && head->so_qlen == 0) {
275 		if (head->so_state & SS_CANTRCVMORE)
276 			error = ECONNABORTED;
277 		else
278 			error = EWOULDBLOCK;
279 		goto out;
280 	}
281 	while (head->so_qlen == 0 && head->so_error == 0) {
282 		if (head->so_state & SS_CANTRCVMORE) {
283 			head->so_error = ECONNABORTED;
284 			break;
285 		}
286 		error = sosleep_nsec(head, &head->so_timeo, PSOCK | PCATCH,
287 		    "netcon", INFSLP);
288 		if (error)
289 			goto out;
290 	}
291 	if (head->so_error) {
292 		error = head->so_error;
293 		head->so_error = 0;
294 		goto out;
295 	}
296 
297 	/*
298 	 * Do not sleep after we have taken the socket out of the queue.
299 	 */
300 	so = TAILQ_FIRST(&head->so_q);
301 	if (soqremque(so, 1) == 0)
302 		panic("accept");
303 
304 	/* Figure out whether the new socket should be non-blocking. */
305 	nflag = flags & SOCK_NONBLOCK_INHERIT ? (headfp->f_flag & FNONBLOCK)
306 	    : (flags & SOCK_NONBLOCK ? FNONBLOCK : 0);
307 
308 	/* connection has been removed from the listen queue */
309 	KNOTE(&head->so_rcv.sb_sel.si_note, NOTE_SUBMIT);
310 
311 	fp->f_type = DTYPE_SOCKET;
312 	fp->f_flag = FREAD | FWRITE | nflag;
313 	fp->f_ops = &socketops;
314 	fp->f_data = so;
315 	error = soaccept(so, nam);
316 	if (!error && name != NULL)
317 		error = copyaddrout(p, nam, name, namelen, anamelen);
318 out:
319 	if (!error) {
320 		sounlock(head, s);
321 		fdplock(fdp);
322 		fdinsert(fdp, tmpfd, cloexec, fp);
323 		fdpunlock(fdp);
324 		FRELE(fp, p);
325 		*retval = tmpfd;
326 	} else {
327 		sounlock(head, s);
328 		fdplock(fdp);
329 		fdremove(fdp, tmpfd);
330 		fdpunlock(fdp);
331 		closef(fp, p);
332 	}
333 
334 	m_freem(nam);
335 	FRELE(headfp, p);
336 	return (error);
337 }
338 
339 int
340 sys_connect(struct proc *p, void *v, register_t *retval)
341 {
342 	struct sys_connect_args /* {
343 		syscallarg(int) s;
344 		syscallarg(const struct sockaddr *) name;
345 		syscallarg(socklen_t) namelen;
346 	} */ *uap = v;
347 	struct file *fp;
348 	struct socket *so;
349 	struct mbuf *nam = NULL;
350 	int error, s, interrupted = 0;
351 
352 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
353 		return (error);
354 	so = fp->f_data;
355 	s = solock(so);
356 	if (so->so_state & SS_ISCONNECTING) {
357 		error = EALREADY;
358 		goto out;
359 	}
360 	error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
361 	    MT_SONAME);
362 	if (error)
363 		goto out;
364 	error = pledge_socket(p, so->so_proto->pr_domain->dom_family,
365 	    so->so_state);
366 	if (error)
367 		goto out;
368 #ifdef KTRACE
369 	if (KTRPOINT(p, KTR_STRUCT))
370 		ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen));
371 #endif
372 
373 	if (isdnssocket(so)) {
374 		u_int namelen = nam->m_len;
375 		error = dns_portcheck(p, so, mtod(nam, void *), &namelen);
376 		if (error)
377 			goto out;
378 		nam->m_len = namelen;
379 	}
380 
381 	error = soconnect(so, nam);
382 	if (error)
383 		goto bad;
384 	if ((fp->f_flag & FNONBLOCK) && (so->so_state & SS_ISCONNECTING)) {
385 		error = EINPROGRESS;
386 		goto out;
387 	}
388 	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
389 		error = sosleep_nsec(so, &so->so_timeo, PSOCK | PCATCH,
390 		    "netcon2", INFSLP);
391 		if (error) {
392 			if (error == EINTR || error == ERESTART)
393 				interrupted = 1;
394 			break;
395 		}
396 	}
397 	if (error == 0) {
398 		error = so->so_error;
399 		so->so_error = 0;
400 	}
401 bad:
402 	if (!interrupted)
403 		so->so_state &= ~SS_ISCONNECTING;
404 out:
405 	sounlock(so, s);
406 	FRELE(fp, p);
407 	m_freem(nam);
408 	if (error == ERESTART)
409 		error = EINTR;
410 	return (error);
411 }
412 
413 int
414 sys_socketpair(struct proc *p, void *v, register_t *retval)
415 {
416 	struct sys_socketpair_args /* {
417 		syscallarg(int) domain;
418 		syscallarg(int) type;
419 		syscallarg(int) protocol;
420 		syscallarg(int *) rsv;
421 	} */ *uap = v;
422 	struct filedesc *fdp = p->p_fd;
423 	struct file *fp1 = NULL, *fp2 = NULL;
424 	struct socket *so1, *so2;
425 	int type, cloexec, nonblock, fflag, error, sv[2];
426 
427 	type  = SCARG(uap, type) & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
428 	cloexec = (SCARG(uap, type) & SOCK_CLOEXEC) ? UF_EXCLOSE : 0;
429 	nonblock = SCARG(uap, type) & SOCK_NONBLOCK;
430 	fflag = FREAD | FWRITE | (nonblock ? FNONBLOCK : 0);
431 
432 	error = socreate(SCARG(uap, domain), &so1, type, SCARG(uap, protocol));
433 	if (error)
434 		return (error);
435 	error = socreate(SCARG(uap, domain), &so2, type, SCARG(uap, protocol));
436 	if (error)
437 		goto free1;
438 
439 	error = soconnect2(so1, so2);
440 	if (error != 0)
441 		goto free2;
442 
443 	if ((SCARG(uap, type) & SOCK_TYPE_MASK) == SOCK_DGRAM) {
444 		/*
445 		 * Datagram socket connection is asymmetric.
446 		 */
447 		error = soconnect2(so2, so1);
448 		if (error != 0)
449 			goto free2;
450 	}
451 	fdplock(fdp);
452 	if ((error = falloc(p, &fp1, &sv[0])) != 0)
453 		goto free3;
454 	fp1->f_flag = fflag;
455 	fp1->f_type = DTYPE_SOCKET;
456 	fp1->f_ops = &socketops;
457 	fp1->f_data = so1;
458 	if ((error = falloc(p, &fp2, &sv[1])) != 0)
459 		goto free4;
460 	fp2->f_flag = fflag;
461 	fp2->f_type = DTYPE_SOCKET;
462 	fp2->f_ops = &socketops;
463 	fp2->f_data = so2;
464 	error = copyout(sv, SCARG(uap, rsv), 2 * sizeof (int));
465 	if (error == 0) {
466 #ifdef KTRACE
467 		if (KTRPOINT(p, KTR_STRUCT))
468 			ktrfds(p, sv, 2);
469 #endif
470 		fdinsert(fdp, sv[0], cloexec, fp1);
471 		fdinsert(fdp, sv[1], cloexec, fp2);
472 		fdpunlock(fdp);
473 		FRELE(fp1, p);
474 		FRELE(fp2, p);
475 		return (0);
476 	}
477 	fdremove(fdp, sv[1]);
478 free4:
479 	fdremove(fdp, sv[0]);
480 free3:
481 	fdpunlock(fdp);
482 
483 	if (fp2 != NULL) {
484 		closef(fp2, p);
485 		so2 = NULL;
486 	}
487 	if (fp1 != NULL) {
488 		closef(fp1, p);
489 		so1 = NULL;
490 	}
491 free2:
492 	if (so2 != NULL)
493 		(void)soclose(so2, 0);
494 free1:
495 	if (so1 != NULL)
496 		(void)soclose(so1, 0);
497 	return (error);
498 }
499 
500 int
501 sys_sendto(struct proc *p, void *v, register_t *retval)
502 {
503 	struct sys_sendto_args /* {
504 		syscallarg(int) s;
505 		syscallarg(const void *) buf;
506 		syscallarg(size_t) len;
507 		syscallarg(int) flags;
508 		syscallarg(const struct sockaddr *) to;
509 		syscallarg(socklen_t) tolen;
510 	} */ *uap = v;
511 	struct msghdr msg;
512 	struct iovec aiov;
513 
514 	msg.msg_name = (caddr_t)SCARG(uap, to);
515 	msg.msg_namelen = SCARG(uap, tolen);
516 	msg.msg_iov = &aiov;
517 	msg.msg_iovlen = 1;
518 	msg.msg_control = 0;
519 	msg.msg_flags = 0;
520 	aiov.iov_base = (char *)SCARG(uap, buf);
521 	aiov.iov_len = SCARG(uap, len);
522 	return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
523 }
524 
525 int
526 sys_sendmsg(struct proc *p, void *v, register_t *retval)
527 {
528 	struct sys_sendmsg_args /* {
529 		syscallarg(int) s;
530 		syscallarg(const struct msghdr *) msg;
531 		syscallarg(int) flags;
532 	} */ *uap = v;
533 	struct msghdr msg;
534 	struct iovec aiov[UIO_SMALLIOV], *iov;
535 	int error;
536 
537 	error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
538 	if (error)
539 		return (error);
540 #ifdef KTRACE
541 	if (KTRPOINT(p, KTR_STRUCT))
542 		ktrmsghdr(p, &msg);
543 #endif
544 
545 	if (msg.msg_iovlen > IOV_MAX)
546 		return (EMSGSIZE);
547 	if (msg.msg_iovlen > UIO_SMALLIOV)
548 		iov = mallocarray(msg.msg_iovlen, sizeof(struct iovec),
549 		    M_IOV, M_WAITOK);
550 	else
551 		iov = aiov;
552 	if (msg.msg_iovlen &&
553 	    (error = copyin(msg.msg_iov, iov,
554 		    msg.msg_iovlen * sizeof (struct iovec))))
555 		goto done;
556 #ifdef KTRACE
557 	if (msg.msg_iovlen && KTRPOINT(p, KTR_STRUCT))
558 		ktriovec(p, iov, msg.msg_iovlen);
559 #endif
560 	msg.msg_iov = iov;
561 	msg.msg_flags = 0;
562 	error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
563 done:
564 	if (iov != aiov)
565 		free(iov, M_IOV, sizeof(struct iovec) * msg.msg_iovlen);
566 	return (error);
567 }
568 
569 int
570 sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize)
571 {
572 	struct file *fp;
573 	struct uio auio;
574 	struct iovec *iov;
575 	int i;
576 	struct mbuf *to, *control;
577 	struct socket *so;
578 	size_t len;
579 	int error;
580 #ifdef KTRACE
581 	struct iovec *ktriov = NULL;
582 	int iovlen = 0;
583 #endif
584 
585 	to = NULL;
586 
587 	if ((error = getsock(p, s, &fp)) != 0)
588 		return (error);
589 	so = fp->f_data;
590 	if (fp->f_flag & FNONBLOCK)
591 		flags |= MSG_DONTWAIT;
592 
593 	error = pledge_sendit(p, mp->msg_name);
594 	if (error)
595 		goto bad;
596 
597 	auio.uio_iov = mp->msg_iov;
598 	auio.uio_iovcnt = mp->msg_iovlen;
599 	auio.uio_segflg = UIO_USERSPACE;
600 	auio.uio_rw = UIO_WRITE;
601 	auio.uio_procp = p;
602 	auio.uio_offset = 0;			/* XXX */
603 	auio.uio_resid = 0;
604 	iov = mp->msg_iov;
605 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
606 		/* Don't allow sum > SSIZE_MAX */
607 		if (iov->iov_len > SSIZE_MAX ||
608 		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
609 			error = EINVAL;
610 			goto bad;
611 		}
612 	}
613 	if (mp->msg_name) {
614 		error = sockargs(&to, mp->msg_name, mp->msg_namelen,
615 		    MT_SONAME);
616 		if (error)
617 			goto bad;
618 		if (isdnssocket(so)) {
619 			u_int namelen = mp->msg_namelen;
620 			error = dns_portcheck(p, so, mtod(to, caddr_t),
621 			    &namelen);
622 			if (error)
623 				goto bad;
624 			mp->msg_namelen = namelen;
625 		}
626 #ifdef KTRACE
627 		if (KTRPOINT(p, KTR_STRUCT))
628 			ktrsockaddr(p, mtod(to, caddr_t), mp->msg_namelen);
629 #endif
630 	}
631 	if (mp->msg_control) {
632 		if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))) {
633 			error = EINVAL;
634 			goto bad;
635 		}
636 		error = sockargs(&control, mp->msg_control,
637 		    mp->msg_controllen, MT_CONTROL);
638 		if (error)
639 			goto bad;
640 #ifdef KTRACE
641 		if (KTRPOINT(p, KTR_STRUCT) && mp->msg_controllen)
642 			ktrcmsghdr(p, mtod(control, char *),
643 			    mp->msg_controllen);
644 #endif
645 	} else
646 		control = 0;
647 #ifdef KTRACE
648 	if (KTRPOINT(p, KTR_GENIO)) {
649 		ktriov = mallocarray(auio.uio_iovcnt, sizeof(struct iovec),
650 		    M_TEMP, M_WAITOK);
651 		iovlen = auio.uio_iovcnt * sizeof (struct iovec);
652 
653 		memcpy(ktriov, auio.uio_iov, iovlen);
654 	}
655 #endif
656 	len = auio.uio_resid;
657 	error = sosend(so, to, &auio, NULL, control, flags);
658 	if (error) {
659 		if (auio.uio_resid != len && (error == ERESTART ||
660 		    error == EINTR || error == EWOULDBLOCK))
661 			error = 0;
662 		if (error == EPIPE && (flags & MSG_NOSIGNAL) == 0) {
663 			KERNEL_LOCK();
664 			ptsignal(p, SIGPIPE, STHREAD);
665 			KERNEL_UNLOCK();
666 		}
667 	}
668 	if (error == 0) {
669 		*retsize = len - auio.uio_resid;
670 		mtx_enter(&fp->f_mtx);
671 		fp->f_wxfer++;
672 		fp->f_wbytes += *retsize;
673 		mtx_leave(&fp->f_mtx);
674 	}
675 #ifdef KTRACE
676 	if (ktriov != NULL) {
677 		if (error == 0)
678 			ktrgenio(p, s, UIO_WRITE, ktriov, *retsize);
679 		free(ktriov, M_TEMP, iovlen);
680 	}
681 #endif
682 bad:
683 	FRELE(fp, p);
684 	m_freem(to);
685 	return (error);
686 }
687 
688 int
689 sys_recvfrom(struct proc *p, void *v, register_t *retval)
690 {
691 	struct sys_recvfrom_args /* {
692 		syscallarg(int) s;
693 		syscallarg(void *) buf;
694 		syscallarg(size_t) len;
695 		syscallarg(int) flags;
696 		syscallarg(struct sockaddr *) from;
697 		syscallarg(socklen_t *) fromlenaddr;
698 	} */ *uap = v;
699 	struct msghdr msg;
700 	struct iovec aiov;
701 	int error;
702 
703 	if (SCARG(uap, fromlenaddr)) {
704 		error = copyin(SCARG(uap, fromlenaddr),
705 		    &msg.msg_namelen, sizeof (msg.msg_namelen));
706 		if (error)
707 			return (error);
708 	} else
709 		msg.msg_namelen = 0;
710 	msg.msg_name = (caddr_t)SCARG(uap, from);
711 	msg.msg_iov = &aiov;
712 	msg.msg_iovlen = 1;
713 	aiov.iov_base = SCARG(uap, buf);
714 	aiov.iov_len = SCARG(uap, len);
715 	msg.msg_control = 0;
716 	msg.msg_flags = SCARG(uap, flags);
717 	return (recvit(p, SCARG(uap, s), &msg,
718 	    (caddr_t)SCARG(uap, fromlenaddr), retval));
719 }
720 
721 int
722 sys_recvmsg(struct proc *p, void *v, register_t *retval)
723 {
724 	struct sys_recvmsg_args /* {
725 		syscallarg(int) s;
726 		syscallarg(struct msghdr *) msg;
727 		syscallarg(int) flags;
728 	} */ *uap = v;
729 	struct msghdr msg;
730 	struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
731 	int error;
732 
733 	error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
734 	if (error)
735 		return (error);
736 
737 	if (msg.msg_iovlen > IOV_MAX)
738 		return (EMSGSIZE);
739 	if (msg.msg_iovlen > UIO_SMALLIOV)
740 		iov = mallocarray(msg.msg_iovlen, sizeof(struct iovec),
741 		    M_IOV, M_WAITOK);
742 	else
743 		iov = aiov;
744 	msg.msg_flags = SCARG(uap, flags);
745 	if (msg.msg_iovlen > 0) {
746 		error = copyin(msg.msg_iov, iov,
747 		    msg.msg_iovlen * sizeof(struct iovec));
748 		if (error)
749 			goto done;
750 	}
751 	uiov = msg.msg_iov;
752 	msg.msg_iov = iov;
753 	if ((error = recvit(p, SCARG(uap, s), &msg, NULL, retval)) == 0) {
754 		msg.msg_iov = uiov;
755 #ifdef KTRACE
756 		if (KTRPOINT(p, KTR_STRUCT)) {
757 			ktrmsghdr(p, &msg);
758 			if (msg.msg_iovlen)
759 				ktriovec(p, iov, msg.msg_iovlen);
760 		}
761 #endif
762 		error = copyout(&msg, SCARG(uap, msg), sizeof(msg));
763 	}
764 done:
765 	if (iov != aiov)
766 		free(iov, M_IOV, sizeof(struct iovec) * msg.msg_iovlen);
767 	return (error);
768 }
769 
770 int
771 recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp,
772     register_t *retsize)
773 {
774 	struct file *fp;
775 	struct uio auio;
776 	struct iovec *iov;
777 	int i;
778 	size_t len;
779 	int error;
780 	struct mbuf *from = NULL, *control = NULL;
781 #ifdef KTRACE
782 	struct iovec *ktriov = NULL;
783 	int iovlen = 0;
784 #endif
785 
786 	if ((error = getsock(p, s, &fp)) != 0)
787 		return (error);
788 
789 	auio.uio_iov = mp->msg_iov;
790 	auio.uio_iovcnt = mp->msg_iovlen;
791 	auio.uio_segflg = UIO_USERSPACE;
792 	auio.uio_rw = UIO_READ;
793 	auio.uio_procp = p;
794 	auio.uio_offset = 0;			/* XXX */
795 	auio.uio_resid = 0;
796 	iov = mp->msg_iov;
797 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
798 		/* Don't allow sum > SSIZE_MAX */
799 		if (iov->iov_len > SSIZE_MAX ||
800 		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
801 			error = EINVAL;
802 			goto out;
803 		}
804 	}
805 #ifdef KTRACE
806 	if (KTRPOINT(p, KTR_GENIO)) {
807 		ktriov = mallocarray(auio.uio_iovcnt, sizeof(struct iovec),
808 		    M_TEMP, M_WAITOK);
809 		iovlen = auio.uio_iovcnt * sizeof (struct iovec);
810 
811 		memcpy(ktriov, auio.uio_iov, iovlen);
812 	}
813 #endif
814 	len = auio.uio_resid;
815 	if (fp->f_flag & FNONBLOCK)
816 		mp->msg_flags |= MSG_DONTWAIT;
817 	error = soreceive(fp->f_data, &from, &auio, NULL,
818 			  mp->msg_control ? &control : NULL,
819 			  &mp->msg_flags,
820 			  mp->msg_control ? mp->msg_controllen : 0);
821 	if (error) {
822 		if (auio.uio_resid != len && (error == ERESTART ||
823 		    error == EINTR || error == EWOULDBLOCK))
824 			error = 0;
825 	}
826 #ifdef KTRACE
827 	if (ktriov != NULL) {
828 		if (error == 0)
829 			ktrgenio(p, s, UIO_READ, ktriov, len - auio.uio_resid);
830 		free(ktriov, M_TEMP, iovlen);
831 	}
832 #endif
833 	if (error)
834 		goto out;
835 	*retsize = len - auio.uio_resid;
836 	if (mp->msg_name) {
837 		socklen_t alen;
838 
839 		if (from == NULL)
840 			alen = 0;
841 		else {
842 			alen = from->m_len;
843 			error = copyout(mtod(from, caddr_t), mp->msg_name,
844 			    MIN(alen, mp->msg_namelen));
845 			if (error)
846 				goto out;
847 #ifdef KTRACE
848 			if (KTRPOINT(p, KTR_STRUCT))
849 				ktrsockaddr(p, mtod(from, caddr_t), alen);
850 #endif
851 		}
852 		mp->msg_namelen = alen;
853 		if (namelenp &&
854 		    (error = copyout(&alen, namelenp, sizeof(alen)))) {
855 			goto out;
856 		}
857 	}
858 	if (mp->msg_control) {
859 		len = mp->msg_controllen;
860 		if (len <= 0 || control == NULL)
861 			len = 0;
862 		else {
863 			struct mbuf *m = control;
864 			caddr_t cp = mp->msg_control;
865 
866 			do {
867 				i = m->m_len;
868 				if (len < i) {
869 					mp->msg_flags |= MSG_CTRUNC;
870 					i = len;
871 				}
872 				error = copyout(mtod(m, caddr_t), cp, i);
873 #ifdef KTRACE
874 				if (KTRPOINT(p, KTR_STRUCT) && error == 0 && i)
875 					ktrcmsghdr(p, mtod(m, char *), i);
876 #endif
877 				if (m->m_next)
878 					i = ALIGN(i);
879 				cp += i;
880 				len -= i;
881 				if (error != 0 || len <= 0)
882 					break;
883 			} while ((m = m->m_next) != NULL);
884 			len = cp - (caddr_t)mp->msg_control;
885 		}
886 		mp->msg_controllen = len;
887 	}
888 	if (!error) {
889 		mtx_enter(&fp->f_mtx);
890 		fp->f_rxfer++;
891 		fp->f_rbytes += *retsize;
892 		mtx_leave(&fp->f_mtx);
893 	}
894 out:
895 	FRELE(fp, p);
896 	m_freem(from);
897 	m_freem(control);
898 	return (error);
899 }
900 
901 int
902 sys_shutdown(struct proc *p, void *v, register_t *retval)
903 {
904 	struct sys_shutdown_args /* {
905 		syscallarg(int) s;
906 		syscallarg(int) how;
907 	} */ *uap = v;
908 	struct file *fp;
909 	int error;
910 
911 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
912 		return (error);
913 	error = soshutdown(fp->f_data, SCARG(uap, how));
914 	FRELE(fp, p);
915 	return (error);
916 }
917 
918 int
919 sys_setsockopt(struct proc *p, void *v, register_t *retval)
920 {
921 	struct sys_setsockopt_args /* {
922 		syscallarg(int) s;
923 		syscallarg(int) level;
924 		syscallarg(int) name;
925 		syscallarg(const void *) val;
926 		syscallarg(socklen_t) valsize;
927 	} */ *uap = v;
928 	struct file *fp;
929 	struct mbuf *m = NULL;
930 	struct socket *so;
931 	int s, error;
932 
933 
934 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
935 		return (error);
936 	error = pledge_sockopt(p, 1, SCARG(uap, level), SCARG(uap, name));
937 	if (error)
938 		goto bad;
939 	if (SCARG(uap, valsize) > MCLBYTES) {
940 		error = EINVAL;
941 		goto bad;
942 	}
943 	if (SCARG(uap, val)) {
944 		m = m_get(M_WAIT, MT_SOOPTS);
945 		if (SCARG(uap, valsize) > MLEN) {
946 			MCLGET(m, M_DONTWAIT);
947 			if ((m->m_flags & M_EXT) == 0) {
948 				error = ENOBUFS;
949 				goto bad;
950 			}
951 		}
952 		if (m == NULL) {
953 			error = ENOBUFS;
954 			goto bad;
955 		}
956 		error = copyin(SCARG(uap, val), mtod(m, caddr_t),
957 		    SCARG(uap, valsize));
958 		if (error) {
959 			goto bad;
960 		}
961 		m->m_len = SCARG(uap, valsize);
962 	}
963 	so = fp->f_data;
964 	s = solock(so);
965 	error = sosetopt(so, SCARG(uap, level), SCARG(uap, name), m);
966 	sounlock(so, s);
967 bad:
968 	m_freem(m);
969 	FRELE(fp, p);
970 	return (error);
971 }
972 
973 int
974 sys_getsockopt(struct proc *p, void *v, register_t *retval)
975 {
976 	struct sys_getsockopt_args /* {
977 		syscallarg(int) s;
978 		syscallarg(int) level;
979 		syscallarg(int) name;
980 		syscallarg(void *) val;
981 		syscallarg(socklen_t *) avalsize;
982 	} */ *uap = v;
983 	struct file *fp;
984 	struct mbuf *m = NULL;
985 	socklen_t valsize;
986 	struct socket *so;
987 	int s, error;
988 
989 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
990 		return (error);
991 	error = pledge_sockopt(p, 0, SCARG(uap, level), SCARG(uap, name));
992 	if (error)
993 		goto out;
994 	if (SCARG(uap, val)) {
995 		error = copyin(SCARG(uap, avalsize),
996 		    &valsize, sizeof (valsize));
997 		if (error)
998 			goto out;
999 	} else
1000 		valsize = 0;
1001 	m = m_get(M_WAIT, MT_SOOPTS);
1002 	so = fp->f_data;
1003 	s = solock(so);
1004 	error = sogetopt(so, SCARG(uap, level), SCARG(uap, name), m);
1005 	sounlock(so, s);
1006 	if (error == 0 && SCARG(uap, val) && valsize && m != NULL) {
1007 		if (valsize > m->m_len)
1008 			valsize = m->m_len;
1009 		error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize);
1010 		if (error == 0)
1011 			error = copyout(&valsize,
1012 			    SCARG(uap, avalsize), sizeof (valsize));
1013 	}
1014 	m_free(m);
1015 out:
1016 	FRELE(fp, p);
1017 	return (error);
1018 }
1019 
1020 /*
1021  * Get socket name.
1022  */
1023 int
1024 sys_getsockname(struct proc *p, void *v, register_t *retval)
1025 {
1026 	struct sys_getsockname_args /* {
1027 		syscallarg(int) fdes;
1028 		syscallarg(struct sockaddr *) asa;
1029 		syscallarg(socklen_t *) alen;
1030 	} */ *uap = v;
1031 	struct file *fp;
1032 	struct socket *so;
1033 	struct mbuf *m = NULL;
1034 	socklen_t len;
1035 	int error, s;
1036 
1037 	if ((error = getsock(p, SCARG(uap, fdes), &fp)) != 0)
1038 		return (error);
1039 	error = copyin(SCARG(uap, alen), &len, sizeof (len));
1040 	if (error)
1041 		goto bad;
1042 	so = fp->f_data;
1043 	error = pledge_socket(p, -1, so->so_state);
1044 	if (error)
1045 		goto bad;
1046 	m = m_getclr(M_WAIT, MT_SONAME);
1047 	s = solock(so);
1048 	error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0, p);
1049 	sounlock(so, s);
1050 	if (error)
1051 		goto bad;
1052 	error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen));
1053 bad:
1054 	FRELE(fp, p);
1055 	m_freem(m);
1056 	return (error);
1057 }
1058 
1059 /*
1060  * Get name of peer for connected socket.
1061  */
1062 int
1063 sys_getpeername(struct proc *p, void *v, register_t *retval)
1064 {
1065 	struct sys_getpeername_args /* {
1066 		syscallarg(int) fdes;
1067 		syscallarg(struct sockaddr *) asa;
1068 		syscallarg(socklen_t *) alen;
1069 	} */ *uap = v;
1070 	struct file *fp;
1071 	struct socket *so;
1072 	struct mbuf *m = NULL;
1073 	socklen_t len;
1074 	int error, s;
1075 
1076 	if ((error = getsock(p, SCARG(uap, fdes), &fp)) != 0)
1077 		return (error);
1078 	so = fp->f_data;
1079 	error = pledge_socket(p, -1, so->so_state);
1080 	if (error)
1081 		goto bad;
1082 	if ((so->so_state & SS_ISCONNECTED) == 0) {
1083 		error = ENOTCONN;
1084 		goto bad;
1085 	}
1086 	error = copyin(SCARG(uap, alen), &len, sizeof (len));
1087 	if (error)
1088 		goto bad;
1089 	m = m_getclr(M_WAIT, MT_SONAME);
1090 	s = solock(so);
1091 	error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0, p);
1092 	sounlock(so, s);
1093 	if (error)
1094 		goto bad;
1095 	error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen));
1096 bad:
1097 	FRELE(fp, p);
1098 	m_freem(m);
1099 	return (error);
1100 }
1101 
1102 int
1103 sockargs(struct mbuf **mp, const void *buf, size_t buflen, int type)
1104 {
1105 	struct sockaddr *sa;
1106 	struct mbuf *m;
1107 	int error;
1108 
1109 	/*
1110 	 * We can't allow socket names > UCHAR_MAX in length, since that
1111 	 * will overflow sa_len. Also, control data more than MCLBYTES in
1112 	 * length is just too much.
1113 	 * Memory for sa_len and sa_family must exist.
1114 	 */
1115 	if ((buflen > (type == MT_SONAME ? UCHAR_MAX : MCLBYTES)) ||
1116 	    (type == MT_SONAME && buflen < offsetof(struct sockaddr, sa_data)))
1117 		return (EINVAL);
1118 
1119 	/* Allocate an mbuf to hold the arguments. */
1120 	m = m_get(M_WAIT, type);
1121 	if (buflen > MLEN) {
1122 		MCLGET(m, M_WAITOK);
1123 		if ((m->m_flags & M_EXT) == 0) {
1124 			m_free(m);
1125 			return ENOBUFS;
1126 		}
1127 	}
1128 	m->m_len = buflen;
1129 	error = copyin(buf, mtod(m, caddr_t), buflen);
1130 	if (error) {
1131 		(void) m_free(m);
1132 		return (error);
1133 	}
1134 	*mp = m;
1135 	if (type == MT_SONAME) {
1136 		sa = mtod(m, struct sockaddr *);
1137 		sa->sa_len = buflen;
1138 	}
1139 	return (0);
1140 }
1141 
1142 int
1143 getsock(struct proc *p, int fdes, struct file **fpp)
1144 {
1145 	struct file *fp;
1146 
1147 	fp = fd_getfile(p->p_fd, fdes);
1148 	if (fp == NULL)
1149 		return (EBADF);
1150 	if (fp->f_type != DTYPE_SOCKET) {
1151 		FRELE(fp, p);
1152 		return (ENOTSOCK);
1153 	}
1154 	*fpp = fp;
1155 
1156 	return (0);
1157 }
1158 
1159 int
1160 sys_setrtable(struct proc *p, void *v, register_t *retval)
1161 {
1162 	struct sys_setrtable_args /* {
1163 		syscallarg(int) rtableid;
1164 	} */ *uap = v;
1165 	int rtableid, error;
1166 
1167 	rtableid = SCARG(uap, rtableid);
1168 
1169 	if (p->p_p->ps_rtableid == (u_int)rtableid)
1170 		return (0);
1171 	if (p->p_p->ps_rtableid != 0 && (error = suser(p)) != 0)
1172 		return (error);
1173 	if (rtableid < 0 || !rtable_exists((u_int)rtableid))
1174 		return (EINVAL);
1175 
1176 	p->p_p->ps_rtableid = (u_int)rtableid;
1177 	return (0);
1178 }
1179 
1180 int
1181 sys_getrtable(struct proc *p, void *v, register_t *retval)
1182 {
1183 	*retval = (int)p->p_p->ps_rtableid;
1184 	return (0);
1185 }
1186 
1187 int
1188 copyaddrout(struct proc *p, struct mbuf *name, struct sockaddr *sa,
1189     socklen_t buflen, socklen_t *outlen)
1190 {
1191 	int error;
1192 	socklen_t namelen = name->m_len;
1193 
1194 	/* SHOULD COPY OUT A CHAIN HERE */
1195 	error = copyout(mtod(name, caddr_t), sa, MIN(buflen, namelen));
1196 	if (error == 0) {
1197 #ifdef KTRACE
1198 		if (KTRPOINT(p, KTR_STRUCT))
1199 			ktrsockaddr(p, mtod(name, caddr_t), namelen);
1200 #endif
1201 		error = copyout(&namelen, outlen, sizeof(*outlen));
1202 	}
1203 
1204 	return (error);
1205 }
1206