xref: /openbsd/sys/kern/uipc_syscalls.c (revision efc6e0a4)
1 /*	$OpenBSD: uipc_syscalls.c,v 1.222 2025/01/16 16:35:01 bluhm 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/namei.h>
39 #include <sys/pool.h>
40 #include <sys/proc.h>
41 #include <sys/fcntl.h>
42 #include <sys/kernel.h>
43 #include <sys/file.h>
44 #include <sys/vnode.h>
45 #include <sys/malloc.h>
46 #include <sys/event.h>
47 #include <sys/mbuf.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/signalvar.h>
52 #include <sys/pledge.h>
53 #ifdef KTRACE
54 #include <sys/ktrace.h>
55 #endif
56 #include <sys/unistd.h>
57 
58 #include <sys/mount.h>
59 #include <sys/syscallargs.h>
60 
61 #include <sys/domain.h>
62 #include <netinet/in.h>
63 #include <netinet/ip.h>
64 #include <net/route.h>
65 #include <netinet/in_pcb.h>
66 #include <net/rtable.h>
67 
68 int	copyaddrout(struct proc *, struct mbuf *, struct sockaddr *, socklen_t,
69 	    socklen_t *);
70 
71 int
sys_socket(struct proc * p,void * v,register_t * retval)72 sys_socket(struct proc *p, void *v, register_t *retval)
73 {
74 	struct sys_socket_args /* {
75 		syscallarg(int) domain;
76 		syscallarg(int) type;
77 		syscallarg(int) protocol;
78 	} */ *uap = v;
79 	struct filedesc *fdp = p->p_fd;
80 	struct socket *so;
81 	struct file *fp;
82 	int type = SCARG(uap, type);
83 	int domain = SCARG(uap, domain);
84 	int fd, cloexec, nonblock, fflag, error;
85 	unsigned int ss = 0;
86 
87 	if ((type & SOCK_DNS) && !(domain == AF_INET || domain == AF_INET6))
88 		return (EINVAL);
89 
90 	if (ISSET(type, SOCK_DNS))
91 		ss |= SS_DNS;
92 	error = pledge_socket(p, domain, ss);
93 	if (error)
94 		return (error);
95 
96 	type &= ~(SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_DNS);
97 	cloexec = (SCARG(uap, type) & SOCK_CLOEXEC) ? UF_EXCLOSE : 0;
98 	nonblock = SCARG(uap, type) & SOCK_NONBLOCK;
99 	fflag = FREAD | FWRITE | (nonblock ? FNONBLOCK : 0);
100 
101 	error = socreate(SCARG(uap, domain), &so, type, SCARG(uap, protocol));
102 	if (error)
103 		return (error);
104 
105 	fdplock(fdp);
106 	error = falloc(p, &fp, &fd);
107 	if (error) {
108 		fdpunlock(fdp);
109 		soclose(so, MSG_DONTWAIT);
110 	} else {
111 		fp->f_flag = fflag;
112 		fp->f_type = DTYPE_SOCKET;
113 		fp->f_ops = &socketops;
114 		so->so_state |= ss;
115 		fp->f_data = so;
116 		fdinsert(fdp, fd, cloexec, fp);
117 		fdpunlock(fdp);
118 		FRELE(fp, p);
119 		*retval = fd;
120 	}
121 	return (error);
122 }
123 
124 static inline int
isdnssocket(struct socket * so)125 isdnssocket(struct socket *so)
126 {
127 	return (so->so_state & SS_DNS);
128 }
129 
130 /* For SS_DNS sockets, only allow port DNS (port 53) */
131 static int
dns_portcheck(struct proc * p,struct socket * so,void * nam,size_t namelen)132 dns_portcheck(struct proc *p, struct socket *so, void *nam, size_t namelen)
133 {
134 	int error = EINVAL;
135 
136 	switch (so->so_proto->pr_domain->dom_family) {
137 	case AF_INET:
138 		if (namelen < sizeof(struct sockaddr_in))
139 			break;
140 		if (((struct sockaddr_in *)nam)->sin_port == htons(53))
141 			error = 0;
142 		break;
143 #ifdef INET6
144 	case AF_INET6:
145 		if (namelen < sizeof(struct sockaddr_in6))
146 			break;
147 		if (((struct sockaddr_in6 *)nam)->sin6_port == htons(53))
148 			error = 0;
149 #endif
150 	}
151 	if (error && p->p_p->ps_flags & PS_PLEDGE)
152 		return (pledge_fail(p, EPERM, PLEDGE_DNS));
153 	return error;
154 }
155 
156 int
sys_bind(struct proc * p,void * v,register_t * retval)157 sys_bind(struct proc *p, void *v, register_t *retval)
158 {
159 	struct sys_bind_args /* {
160 		syscallarg(int) s;
161 		syscallarg(const struct sockaddr *) name;
162 		syscallarg(socklen_t) namelen;
163 	} */ *uap = v;
164 	struct file *fp;
165 	struct mbuf *nam;
166 	struct socket *so;
167 	int error;
168 
169 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
170 		return (error);
171 	so = fp->f_data;
172 	error = pledge_socket(p, so->so_proto->pr_domain->dom_family,
173 	    so->so_state);
174 	if (error)
175 		goto out;
176 	if (so->so_state & SS_YP) {
177 		error = ENOTSOCK;
178 		goto out;
179 	}
180 	error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
181 	    MT_SONAME);
182 	if (error)
183 		goto out;
184 #ifdef KTRACE
185 	if (KTRPOINT(p, KTR_STRUCT))
186 		ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen));
187 #endif
188 	solock_shared(so);
189 	error = sobind(so, nam, p);
190 	sounlock_shared(so);
191 	m_freem(nam);
192 out:
193 	FRELE(fp, p);
194 	return (error);
195 }
196 
197 int
sys_listen(struct proc * p,void * v,register_t * retval)198 sys_listen(struct proc *p, void *v, register_t *retval)
199 {
200 	struct sys_listen_args /* {
201 		syscallarg(int) s;
202 		syscallarg(int) backlog;
203 	} */ *uap = v;
204 	struct file *fp;
205 	struct socket *so;
206 	int error;
207 
208 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
209 		return (error);
210 	so = fp->f_data;
211 	if (so->so_state & SS_YP)
212 		return ENOTSOCK;
213 	solock(so);
214 	error = solisten(so, SCARG(uap, backlog));
215 	sounlock(so);
216 	FRELE(fp, p);
217 	return (error);
218 }
219 
220 int
sys_accept(struct proc * p,void * v,register_t * retval)221 sys_accept(struct proc *p, void *v, register_t *retval)
222 {
223 	struct sys_accept_args /* {
224 		syscallarg(int) s;
225 		syscallarg(struct sockaddr *) name;
226 		syscallarg(socklen_t *) anamelen;
227 	} */ *uap = v;
228 
229 	return (doaccept(p, SCARG(uap, s), SCARG(uap, name),
230 	    SCARG(uap, anamelen), SOCK_NONBLOCK_INHERIT, retval));
231 }
232 
233 int
sys_accept4(struct proc * p,void * v,register_t * retval)234 sys_accept4(struct proc *p, void *v, register_t *retval)
235 {
236 	struct sys_accept4_args /* {
237 		syscallarg(int) s;
238 		syscallarg(struct sockaddr *) name;
239 		syscallarg(socklen_t *) anamelen;
240 		syscallarg(socklen_t *) int flags;
241 	} */ *uap = v;
242 
243 	if (SCARG(uap, flags) & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
244 		return (EINVAL);
245 
246 	return (doaccept(p, SCARG(uap, s), SCARG(uap, name),
247 	    SCARG(uap, anamelen), SCARG(uap, flags), retval));
248 }
249 
250 int
doaccept(struct proc * p,int sock,struct sockaddr * name,socklen_t * anamelen,int flags,register_t * retval)251 doaccept(struct proc *p, int sock, struct sockaddr *name, socklen_t *anamelen,
252     int flags, register_t *retval)
253 {
254 	struct filedesc *fdp = p->p_fd;
255 	struct file *fp, *headfp;
256 	struct mbuf *nam;
257 	socklen_t namelen;
258 	int error, tmpfd;
259 	struct socket *head, *so;
260 	int cloexec, nflag;
261 
262 	cloexec = (flags & SOCK_CLOEXEC) ? UF_EXCLOSE : 0;
263 
264 	if (name && (error = copyin(anamelen, &namelen, sizeof (namelen))))
265 		return (error);
266 	if ((error = getsock(p, sock, &fp)) != 0)
267 		return (error);
268 
269 	headfp = fp;
270 
271 	fdplock(fdp);
272 	error = falloc(p, &fp, &tmpfd);
273 	fdpunlock(fdp);
274 	if (error) {
275 		FRELE(headfp, p);
276 		return (error);
277 	}
278 
279 	nam = m_get(M_WAIT, MT_SONAME);
280 
281 	head = headfp->f_data;
282 	solock_shared(head);
283 
284 	if (isdnssocket(head) || (head->so_options & SO_ACCEPTCONN) == 0) {
285 		error = EINVAL;
286 		goto out_unlock;
287 	}
288 	if ((headfp->f_flag & FNONBLOCK) && head->so_qlen == 0) {
289 		if (head->so_rcv.sb_state & SS_CANTRCVMORE)
290 			error = ECONNABORTED;
291 		else
292 			error = EWOULDBLOCK;
293 		goto out_unlock;
294 	}
295 	while (head->so_qlen == 0 && head->so_error == 0) {
296 		if (head->so_rcv.sb_state & SS_CANTRCVMORE) {
297 			head->so_error = ECONNABORTED;
298 			break;
299 		}
300 		error = sosleep_nsec(head, &head->so_timeo, PSOCK | PCATCH,
301 		    "netacc", INFSLP);
302 		if (error)
303 			goto out_unlock;
304 	}
305 	if (head->so_error) {
306 		error = head->so_error;
307 		head->so_error = 0;
308 		goto out_unlock;
309 	}
310 
311 	/*
312 	 * Do not sleep after we have taken the socket out of the queue.
313 	 */
314 	so = TAILQ_FIRST(&head->so_q);
315 
316 	solock_nonet(so);
317 
318 	if (soqremque(so, 1) == 0)
319 		panic("accept");
320 
321 	/* Figure out whether the new socket should be non-blocking. */
322 	nflag = flags & SOCK_NONBLOCK_INHERIT ? (headfp->f_flag & FNONBLOCK)
323 	    : (flags & SOCK_NONBLOCK ? FNONBLOCK : 0);
324 
325 	/* connection has been removed from the listen queue */
326 	knote(&head->so_rcv.sb_klist, 0);
327 
328 	sounlock_nonet(head);
329 
330 	fp->f_type = DTYPE_SOCKET;
331 	fp->f_flag = FREAD | FWRITE | nflag;
332 	fp->f_ops = &socketops;
333 	fp->f_data = so;
334 
335 	error = soaccept(so, nam);
336 
337 	sounlock_shared(so);
338 
339 	if (error)
340 		goto out;
341 
342 	if (name != NULL) {
343 		error = copyaddrout(p, nam, name, namelen, anamelen);
344 		if (error)
345 			goto out;
346 	}
347 
348 	fdplock(fdp);
349 	fdinsert(fdp, tmpfd, cloexec, fp);
350 	fdpunlock(fdp);
351 	FRELE(fp, p);
352 	*retval = tmpfd;
353 
354 	m_freem(nam);
355 	FRELE(headfp, p);
356 
357 	return 0;
358 
359 out_unlock:
360 	sounlock_shared(head);
361 out:
362 	fdplock(fdp);
363 	fdremove(fdp, tmpfd);
364 	fdpunlock(fdp);
365 	closef(fp, p);
366 
367 	m_freem(nam);
368 	FRELE(headfp, p);
369 
370 	return (error);
371 }
372 
373 int
sys_connect(struct proc * p,void * v,register_t * retval)374 sys_connect(struct proc *p, void *v, register_t *retval)
375 {
376 	struct sys_connect_args /* {
377 		syscallarg(int) s;
378 		syscallarg(const struct sockaddr *) name;
379 		syscallarg(socklen_t) namelen;
380 	} */ *uap = v;
381 	struct file *fp;
382 	struct socket *so;
383 	struct mbuf *nam;
384 	int error, interrupted = 0;
385 
386 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
387 		return (error);
388 	so = fp->f_data;
389 	error = pledge_socket(p, so->so_proto->pr_domain->dom_family,
390 	    so->so_state);
391 	if (error)
392 		goto out;
393 	if (so->so_state & SS_YP) {
394 		error = ENOTSOCK;
395 		goto out;
396 	}
397 	error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
398 	    MT_SONAME);
399 	if (error)
400 		goto out;
401 #ifdef KTRACE
402 	if (KTRPOINT(p, KTR_STRUCT))
403 		ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen));
404 #endif
405 	solock_shared(so);
406 	if (isdnssocket(so)) {
407 		error = dns_portcheck(p, so, mtod(nam, void *), nam->m_len);
408 		if (error)
409 			goto unlock;
410 	}
411 	if (so->so_state & SS_ISCONNECTING) {
412 		error = EALREADY;
413 		goto unlock;
414 	}
415 	error = soconnect(so, nam);
416 	if (error)
417 		goto bad;
418 	if ((fp->f_flag & FNONBLOCK) && (so->so_state & SS_ISCONNECTING)) {
419 		error = EINPROGRESS;
420 		goto unlock;
421 	}
422 	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
423 		error = sosleep_nsec(so, &so->so_timeo, PSOCK | PCATCH,
424 		    "netcon", INFSLP);
425 		if (error) {
426 			if (error == EINTR || error == ERESTART)
427 				interrupted = 1;
428 			break;
429 		}
430 	}
431 	if (error == 0) {
432 		error = so->so_error;
433 		so->so_error = 0;
434 	}
435 bad:
436 	if (!interrupted)
437 		so->so_state &= ~SS_ISCONNECTING;
438 unlock:
439 	sounlock_shared(so);
440 	m_freem(nam);
441 out:
442 	FRELE(fp, p);
443 	if (error == ERESTART)
444 		error = EINTR;
445 	return (error);
446 }
447 
448 int
sys_socketpair(struct proc * p,void * v,register_t * retval)449 sys_socketpair(struct proc *p, void *v, register_t *retval)
450 {
451 	struct sys_socketpair_args /* {
452 		syscallarg(int) domain;
453 		syscallarg(int) type;
454 		syscallarg(int) protocol;
455 		syscallarg(int *) rsv;
456 	} */ *uap = v;
457 	struct filedesc *fdp = p->p_fd;
458 	struct file *fp1 = NULL, *fp2 = NULL;
459 	struct socket *so1, *so2;
460 	int type, cloexec, nonblock, fflag, error, sv[2];
461 
462 	type  = SCARG(uap, type) & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
463 	cloexec = (SCARG(uap, type) & SOCK_CLOEXEC) ? UF_EXCLOSE : 0;
464 	nonblock = SCARG(uap, type) & SOCK_NONBLOCK;
465 	fflag = FREAD | FWRITE | (nonblock ? FNONBLOCK : 0);
466 
467 	error = socreate(SCARG(uap, domain), &so1, type, SCARG(uap, protocol));
468 	if (error)
469 		return (error);
470 	error = socreate(SCARG(uap, domain), &so2, type, SCARG(uap, protocol));
471 	if (error)
472 		goto free1;
473 
474 	error = soconnect2(so1, so2);
475 	if (error != 0)
476 		goto free2;
477 
478 	if ((SCARG(uap, type) & SOCK_TYPE_MASK) == SOCK_DGRAM) {
479 		/*
480 		 * Datagram socket connection is asymmetric.
481 		 */
482 		error = soconnect2(so2, so1);
483 		if (error != 0)
484 			goto free2;
485 	}
486 	fdplock(fdp);
487 	if ((error = falloc(p, &fp1, &sv[0])) != 0)
488 		goto free3;
489 	fp1->f_flag = fflag;
490 	fp1->f_type = DTYPE_SOCKET;
491 	fp1->f_ops = &socketops;
492 	fp1->f_data = so1;
493 	if ((error = falloc(p, &fp2, &sv[1])) != 0)
494 		goto free4;
495 	fp2->f_flag = fflag;
496 	fp2->f_type = DTYPE_SOCKET;
497 	fp2->f_ops = &socketops;
498 	fp2->f_data = so2;
499 	error = copyout(sv, SCARG(uap, rsv), 2 * sizeof (int));
500 	if (error == 0) {
501 		fdinsert(fdp, sv[0], cloexec, fp1);
502 		fdinsert(fdp, sv[1], cloexec, fp2);
503 		fdpunlock(fdp);
504 #ifdef KTRACE
505 		if (KTRPOINT(p, KTR_STRUCT))
506 			ktrfds(p, sv, 2);
507 #endif
508 		FRELE(fp1, p);
509 		FRELE(fp2, p);
510 		return (0);
511 	}
512 	fdremove(fdp, sv[1]);
513 free4:
514 	fdremove(fdp, sv[0]);
515 free3:
516 	fdpunlock(fdp);
517 
518 	if (fp2 != NULL) {
519 		closef(fp2, p);
520 		so2 = NULL;
521 	}
522 	if (fp1 != NULL) {
523 		closef(fp1, p);
524 		so1 = NULL;
525 	}
526 free2:
527 	if (so2 != NULL)
528 		(void)soclose(so2, 0);
529 free1:
530 	if (so1 != NULL)
531 		(void)soclose(so1, 0);
532 	return (error);
533 }
534 
535 int
sys_sendto(struct proc * p,void * v,register_t * retval)536 sys_sendto(struct proc *p, void *v, register_t *retval)
537 {
538 	struct sys_sendto_args /* {
539 		syscallarg(int) s;
540 		syscallarg(const void *) buf;
541 		syscallarg(size_t) len;
542 		syscallarg(int) flags;
543 		syscallarg(const struct sockaddr *) to;
544 		syscallarg(socklen_t) tolen;
545 	} */ *uap = v;
546 	struct msghdr msg;
547 	struct iovec aiov;
548 
549 	msg.msg_name = (caddr_t)SCARG(uap, to);
550 	msg.msg_namelen = SCARG(uap, tolen);
551 	msg.msg_iov = &aiov;
552 	msg.msg_iovlen = 1;
553 	msg.msg_control = NULL;
554 	msg.msg_flags = 0;
555 	aiov.iov_base = (char *)SCARG(uap, buf);
556 	aiov.iov_len = SCARG(uap, len);
557 	return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
558 }
559 
560 int
sys_sendmsg(struct proc * p,void * v,register_t * retval)561 sys_sendmsg(struct proc *p, void *v, register_t *retval)
562 {
563 	struct sys_sendmsg_args /* {
564 		syscallarg(int) s;
565 		syscallarg(const struct msghdr *) msg;
566 		syscallarg(int) flags;
567 	} */ *uap = v;
568 	struct msghdr msg;
569 	struct iovec aiov[UIO_SMALLIOV], *iov;
570 	int error;
571 
572 	error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
573 	if (error)
574 		return (error);
575 #ifdef KTRACE
576 	if (KTRPOINT(p, KTR_STRUCT))
577 		ktrmsghdr(p, &msg);
578 #endif
579 
580 	if (msg.msg_iovlen > IOV_MAX)
581 		return (EMSGSIZE);
582 	if (msg.msg_iovlen > UIO_SMALLIOV)
583 		iov = mallocarray(msg.msg_iovlen, sizeof(struct iovec),
584 		    M_IOV, M_WAITOK);
585 	else
586 		iov = aiov;
587 	if (msg.msg_iovlen &&
588 	    (error = copyin(msg.msg_iov, iov,
589 		    msg.msg_iovlen * sizeof (struct iovec))))
590 		goto done;
591 #ifdef KTRACE
592 	if (msg.msg_iovlen && KTRPOINT(p, KTR_STRUCT))
593 		ktriovec(p, iov, msg.msg_iovlen);
594 #endif
595 	msg.msg_iov = iov;
596 	msg.msg_flags = 0;
597 	error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
598 done:
599 	if (iov != aiov)
600 		free(iov, M_IOV, sizeof(struct iovec) * msg.msg_iovlen);
601 	return (error);
602 }
603 
604 int
sys_sendmmsg(struct proc * p,void * v,register_t * retval)605 sys_sendmmsg(struct proc *p, void *v, register_t *retval)
606 {
607 	struct sys_sendmmsg_args /* {
608 		syscallarg(int)			s;
609 		syscallarg(struct mmsghdr *)	mmsg;
610 		syscallarg(unsigned int)	vlen;
611 		syscallarg(int)			flags;
612 	} */ *uap = v;
613 	struct mmsghdr mmsg, *mmsgp;
614 	struct iovec aiov[UIO_SMALLIOV], *iov = aiov, *uiov;
615 	size_t iovlen = UIO_SMALLIOV;
616 	register_t retsnd;
617 	unsigned int vlen, dgrams;
618 	int error = 0, flags, s;
619 
620 	s = SCARG(uap, s);
621 	flags = SCARG(uap, flags);
622 
623 	/* Arbitrarily capped at 1024 datagrams. */
624 	vlen = SCARG(uap, vlen);
625 	if (vlen > 1024)
626 		vlen = 1024;
627 
628 	mmsgp = SCARG(uap, mmsg);
629 	for (dgrams = 0; dgrams < vlen; dgrams++) {
630 		error = copyin(&mmsgp[dgrams], &mmsg, sizeof(mmsg));
631 		if (error)
632 			break;
633 
634 #ifdef KTRACE
635 		if (KTRPOINT(p, KTR_STRUCT))
636 			ktrmmsghdr(p, &mmsg);
637 #endif
638 
639 		if (mmsg.msg_hdr.msg_iovlen > IOV_MAX) {
640 			error = EMSGSIZE;
641 			break;
642 		}
643 
644 		if (mmsg.msg_hdr.msg_iovlen > iovlen) {
645 			if (iov != aiov)
646 				free(iov, M_IOV, iovlen *
647 				    sizeof(struct iovec));
648 
649 			iovlen = mmsg.msg_hdr.msg_iovlen;
650 			iov = mallocarray(iovlen, sizeof(struct iovec),
651 			    M_IOV, M_WAITOK);
652 		}
653 
654 		if (mmsg.msg_hdr.msg_iovlen > 0) {
655 			error = copyin(mmsg.msg_hdr.msg_iov, iov,
656 			    mmsg.msg_hdr.msg_iovlen * sizeof(struct iovec));
657 			if (error)
658 				break;
659 		}
660 
661 #ifdef KTRACE
662 		if (mmsg.msg_hdr.msg_iovlen && KTRPOINT(p, KTR_STRUCT))
663 			ktriovec(p, iov, mmsg.msg_hdr.msg_iovlen);
664 #endif
665 
666 		uiov = mmsg.msg_hdr.msg_iov;
667 		mmsg.msg_hdr.msg_iov = iov;
668 		mmsg.msg_hdr.msg_flags = 0;
669 
670 		error = sendit(p, s, &mmsg.msg_hdr, flags, &retsnd);
671 		if (error)
672 			break;
673 
674 		mmsg.msg_hdr.msg_iov = uiov;
675 		mmsg.msg_len = retsnd;
676 
677 		error = copyout(&mmsg, &mmsgp[dgrams], sizeof(mmsg));
678 		if (error)
679 			break;
680 	}
681 
682 	if (iov != aiov)
683 		free(iov, M_IOV, sizeof(struct iovec) * iovlen);
684 
685 	*retval = dgrams;
686 
687 	if (error && dgrams > 0)
688 		error = 0;
689 
690 	return (error);
691 }
692 
693 int
sendit(struct proc * p,int s,struct msghdr * mp,int flags,register_t * retsize)694 sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize)
695 {
696 	struct file *fp;
697 	struct uio auio;
698 	struct iovec *iov;
699 	int i;
700 	struct mbuf *to, *control;
701 	struct socket *so;
702 	size_t len;
703 	int error;
704 #ifdef KTRACE
705 	struct iovec *ktriov = NULL;
706 	int iovlen = 0;
707 #endif
708 
709 	to = NULL;
710 
711 	if ((error = getsock(p, s, &fp)) != 0)
712 		return (error);
713 	so = fp->f_data;
714 	if (fp->f_flag & FNONBLOCK)
715 		flags |= MSG_DONTWAIT;
716 
717 	error = pledge_sendit(p, mp->msg_name);
718 	if (error)
719 		goto bad;
720 
721 	auio.uio_iov = mp->msg_iov;
722 	auio.uio_iovcnt = mp->msg_iovlen;
723 	auio.uio_segflg = UIO_USERSPACE;
724 	auio.uio_rw = UIO_WRITE;
725 	auio.uio_procp = p;
726 	auio.uio_offset = 0;			/* XXX */
727 	auio.uio_resid = 0;
728 	iov = mp->msg_iov;
729 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
730 		/* Don't allow sum > SSIZE_MAX */
731 		if (iov->iov_len > SSIZE_MAX ||
732 		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
733 			error = EINVAL;
734 			goto bad;
735 		}
736 	}
737 	if (mp->msg_name) {
738 		error = sockargs(&to, mp->msg_name, mp->msg_namelen,
739 		    MT_SONAME);
740 		if (error)
741 			goto bad;
742 		if (isdnssocket(so)) {
743 			error = dns_portcheck(p, so, mtod(to, caddr_t),
744 			    mp->msg_namelen);
745 			if (error)
746 				goto bad;
747 		}
748 #ifdef KTRACE
749 		if (KTRPOINT(p, KTR_STRUCT))
750 			ktrsockaddr(p, mtod(to, caddr_t), mp->msg_namelen);
751 #endif
752 	}
753 	if (mp->msg_control) {
754 		if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))) {
755 			error = EINVAL;
756 			goto bad;
757 		}
758 		error = sockargs(&control, mp->msg_control,
759 		    mp->msg_controllen, MT_CONTROL);
760 		if (error)
761 			goto bad;
762 #ifdef KTRACE
763 		if (KTRPOINT(p, KTR_STRUCT) && mp->msg_controllen)
764 			ktrcmsghdr(p, mtod(control, char *),
765 			    mp->msg_controllen);
766 #endif
767 	} else
768 		control = NULL;
769 #ifdef KTRACE
770 	if (KTRPOINT(p, KTR_GENIO)) {
771 		ktriov = mallocarray(auio.uio_iovcnt, sizeof(struct iovec),
772 		    M_TEMP, M_WAITOK);
773 		iovlen = auio.uio_iovcnt * sizeof (struct iovec);
774 
775 		memcpy(ktriov, auio.uio_iov, iovlen);
776 	}
777 #endif
778 	len = auio.uio_resid;
779 	error = sosend(so, to, &auio, NULL, control, flags);
780 	if (error) {
781 		if (auio.uio_resid != len && (error == ERESTART ||
782 		    error == EINTR || error == EWOULDBLOCK))
783 			error = 0;
784 		if (error == EPIPE && (flags & MSG_NOSIGNAL) == 0)
785 			ptsignal(p, SIGPIPE, STHREAD);
786 	}
787 	if (error == 0) {
788 		*retsize = len - auio.uio_resid;
789 		mtx_enter(&fp->f_mtx);
790 		fp->f_wxfer++;
791 		fp->f_wbytes += *retsize;
792 		mtx_leave(&fp->f_mtx);
793 	}
794 #ifdef KTRACE
795 	if (ktriov != NULL) {
796 		if (error == 0)
797 			ktrgenio(p, s, UIO_WRITE, ktriov, *retsize);
798 		free(ktriov, M_TEMP, iovlen);
799 	}
800 #endif
801 bad:
802 	FRELE(fp, p);
803 	m_freem(to);
804 	return (error);
805 }
806 
807 int
sys_recvfrom(struct proc * p,void * v,register_t * retval)808 sys_recvfrom(struct proc *p, void *v, register_t *retval)
809 {
810 	struct sys_recvfrom_args /* {
811 		syscallarg(int) s;
812 		syscallarg(void *) buf;
813 		syscallarg(size_t) len;
814 		syscallarg(int) flags;
815 		syscallarg(struct sockaddr *) from;
816 		syscallarg(socklen_t *) fromlenaddr;
817 	} */ *uap = v;
818 	struct msghdr msg;
819 	struct iovec aiov;
820 	int error;
821 
822 	if (SCARG(uap, fromlenaddr)) {
823 		error = copyin(SCARG(uap, fromlenaddr),
824 		    &msg.msg_namelen, sizeof (msg.msg_namelen));
825 		if (error)
826 			return (error);
827 	} else
828 		msg.msg_namelen = 0;
829 	msg.msg_name = (caddr_t)SCARG(uap, from);
830 	msg.msg_iov = &aiov;
831 	msg.msg_iovlen = 1;
832 	aiov.iov_base = SCARG(uap, buf);
833 	aiov.iov_len = SCARG(uap, len);
834 	msg.msg_control = NULL;
835 	msg.msg_flags = SCARG(uap, flags);
836 	return (recvit(p, SCARG(uap, s), &msg,
837 	    (caddr_t)SCARG(uap, fromlenaddr), retval));
838 }
839 
840 int
sys_recvmsg(struct proc * p,void * v,register_t * retval)841 sys_recvmsg(struct proc *p, void *v, register_t *retval)
842 {
843 	struct sys_recvmsg_args /* {
844 		syscallarg(int) s;
845 		syscallarg(struct msghdr *) msg;
846 		syscallarg(int) flags;
847 	} */ *uap = v;
848 	struct msghdr msg;
849 	struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
850 	int error;
851 
852 	error = copyin(SCARG(uap, msg), &msg, sizeof (msg));
853 	if (error)
854 		return (error);
855 
856 	if (msg.msg_iovlen > IOV_MAX)
857 		return (EMSGSIZE);
858 	if (msg.msg_iovlen > UIO_SMALLIOV)
859 		iov = mallocarray(msg.msg_iovlen, sizeof(struct iovec),
860 		    M_IOV, M_WAITOK);
861 	else
862 		iov = aiov;
863 	msg.msg_flags = SCARG(uap, flags);
864 	if (msg.msg_iovlen > 0) {
865 		error = copyin(msg.msg_iov, iov,
866 		    msg.msg_iovlen * sizeof(struct iovec));
867 		if (error)
868 			goto done;
869 	}
870 	uiov = msg.msg_iov;
871 	msg.msg_iov = iov;
872 	if ((error = recvit(p, SCARG(uap, s), &msg, NULL, retval)) == 0) {
873 		msg.msg_iov = uiov;
874 #ifdef KTRACE
875 		if (KTRPOINT(p, KTR_STRUCT)) {
876 			ktrmsghdr(p, &msg);
877 			if (msg.msg_iovlen)
878 				ktriovec(p, iov, msg.msg_iovlen);
879 		}
880 #endif
881 		error = copyout(&msg, SCARG(uap, msg), sizeof(msg));
882 	}
883 done:
884 	if (iov != aiov)
885 		free(iov, M_IOV, sizeof(struct iovec) * msg.msg_iovlen);
886 	return (error);
887 }
888 
889 int
sys_recvmmsg(struct proc * p,void * v,register_t * retval)890 sys_recvmmsg(struct proc *p, void *v, register_t *retval)
891 {
892 	struct sys_recvmmsg_args /* {
893 		syscallarg(int)			s;
894 		syscallarg(struct mmsghdr *)	mmsg;
895 		syscallarg(unsigned int)	vlen;
896 		syscallarg(int)			flags;
897 		syscallarg(struct timespec *)	timeout;
898 	} */ *uap = v;
899 	struct mmsghdr mmsg, *mmsgp;
900 	struct timespec ts, now, *timeout;
901 	struct iovec aiov[UIO_SMALLIOV], *uiov, *iov = aiov;
902 	size_t iovlen = UIO_SMALLIOV;
903 	register_t retrec;
904 	unsigned int vlen, dgrams;
905 	int error = 0, flags, s;
906 
907 	timeout = SCARG(uap, timeout);
908 	if (timeout != NULL) {
909 		error = copyin(timeout, &ts, sizeof(ts));
910 		if (error)
911 			return (error);
912 #ifdef KTRACE
913 		if (KTRPOINT(p, KTR_STRUCT))
914 			ktrreltimespec(p, &ts);
915 #endif
916 		if (!timespecisvalid(&ts))
917 			return (EINVAL);
918 
919 		getnanotime(&now);
920 		timespecadd(&now, &ts, &ts);
921 	}
922 
923 	s = SCARG(uap, s);
924 	flags = SCARG(uap, flags);
925 
926 	/* Arbitrarily capped at 1024 datagrams. */
927 	vlen = SCARG(uap, vlen);
928 	if (vlen > 1024)
929 		vlen = 1024;
930 
931 	mmsgp = SCARG(uap, mmsg);
932 	for (dgrams = 0; dgrams < vlen;) {
933 		error = copyin(&mmsgp[dgrams], &mmsg, sizeof(mmsg));
934 		if (error)
935 			break;
936 
937 		if (mmsg.msg_hdr.msg_iovlen > IOV_MAX) {
938 			error = EMSGSIZE;
939 			break;
940 		}
941 
942 		if (mmsg.msg_hdr.msg_iovlen > iovlen) {
943 			if (iov != aiov)
944 				free(iov, M_IOV, iovlen *
945 				    sizeof(struct iovec));
946 
947 			iovlen = mmsg.msg_hdr.msg_iovlen;
948 			iov = mallocarray(iovlen, sizeof(struct iovec),
949 			    M_IOV, M_WAITOK);
950 		}
951 
952 		if (mmsg.msg_hdr.msg_iovlen > 0) {
953 			error = copyin(mmsg.msg_hdr.msg_iov, iov,
954 			    mmsg.msg_hdr.msg_iovlen * sizeof(struct iovec));
955 			if (error)
956 				break;
957 		}
958 
959 		uiov = mmsg.msg_hdr.msg_iov;
960 		mmsg.msg_hdr.msg_iov = iov;
961 		mmsg.msg_hdr.msg_flags = flags & ~MSG_WAITFORONE;
962 
963 		error = recvit(p, s, &mmsg.msg_hdr, NULL, &retrec);
964 		if (error) {
965 			if (error == EAGAIN && dgrams > 0)
966 				error = 0;
967 			break;
968 		}
969 
970 		if (flags & MSG_WAITFORONE)
971 			flags |= MSG_DONTWAIT;
972 
973 		mmsg.msg_hdr.msg_iov = uiov;
974 		mmsg.msg_len = retrec;
975 #ifdef KTRACE
976 		if (KTRPOINT(p, KTR_STRUCT)) {
977 			ktrmmsghdr(p, &mmsg);
978 			if (mmsg.msg_hdr.msg_iovlen)
979 				ktriovec(p, iov, mmsg.msg_hdr.msg_iovlen);
980 		}
981 #endif
982 
983 		error = copyout(&mmsg, &mmsgp[dgrams], sizeof(mmsg));
984 		if (error)
985 			break;
986 
987 		dgrams++;
988 		if (mmsg.msg_hdr.msg_flags & MSG_OOB)
989 			break;
990 
991 		if (timeout != NULL) {
992 			getnanotime(&now);
993 			timespecsub(&now, &ts, &now);
994 			if (now.tv_sec > 0)
995 				break;
996 		}
997 	}
998 
999 	if (iov != aiov)
1000 		free(iov, M_IOV, iovlen * sizeof(struct iovec));
1001 
1002 	*retval = dgrams;
1003 
1004 	/*
1005 	 * If we succeeded at least once, return 0, hopefully so->so_error
1006 	 * will catch it next time.
1007 	 */
1008 	if (error && dgrams > 0) {
1009 		struct file *fp;
1010 		struct socket *so;
1011 
1012 		if (getsock(p, s, &fp) == 0) {
1013 			so = (struct socket *)fp->f_data;
1014 			so->so_error = error;
1015 
1016 			FRELE(fp, p);
1017 		}
1018 		error = 0;
1019 	}
1020 
1021 	return (error);
1022 }
1023 
1024 int
recvit(struct proc * p,int s,struct msghdr * mp,caddr_t namelenp,register_t * retsize)1025 recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp,
1026     register_t *retsize)
1027 {
1028 	struct file *fp;
1029 	struct uio auio;
1030 	struct iovec *iov;
1031 	int i;
1032 	size_t len;
1033 	int error;
1034 	struct mbuf *from = NULL, *control = NULL;
1035 #ifdef KTRACE
1036 	struct iovec *ktriov = NULL;
1037 	int iovlen = 0, kmsgflags;
1038 #endif
1039 
1040 	if ((error = getsock(p, s, &fp)) != 0)
1041 		return (error);
1042 
1043 	auio.uio_iov = mp->msg_iov;
1044 	auio.uio_iovcnt = mp->msg_iovlen;
1045 	auio.uio_segflg = UIO_USERSPACE;
1046 	auio.uio_rw = UIO_READ;
1047 	auio.uio_procp = p;
1048 	auio.uio_offset = 0;			/* XXX */
1049 	auio.uio_resid = 0;
1050 	iov = mp->msg_iov;
1051 	for (i = 0; i < mp->msg_iovlen; i++, iov++) {
1052 		/* Don't allow sum > SSIZE_MAX */
1053 		if (iov->iov_len > SSIZE_MAX ||
1054 		    (auio.uio_resid += iov->iov_len) > SSIZE_MAX) {
1055 			error = EINVAL;
1056 			goto out;
1057 		}
1058 	}
1059 #ifdef KTRACE
1060 	if (KTRPOINT(p, KTR_GENIO)) {
1061 		ktriov = mallocarray(auio.uio_iovcnt, sizeof(struct iovec),
1062 		    M_TEMP, M_WAITOK);
1063 		iovlen = auio.uio_iovcnt * sizeof (struct iovec);
1064 
1065 		memcpy(ktriov, auio.uio_iov, iovlen);
1066 	}
1067 	kmsgflags = mp->msg_flags;
1068 #endif
1069 	len = auio.uio_resid;
1070 	if (fp->f_flag & FNONBLOCK)
1071 		mp->msg_flags |= MSG_DONTWAIT;
1072 	error = soreceive(fp->f_data, &from, &auio, NULL,
1073 			  mp->msg_control ? &control : NULL,
1074 			  &mp->msg_flags,
1075 			  mp->msg_control ? mp->msg_controllen : 0);
1076 	if (error) {
1077 		if (auio.uio_resid != len && (error == ERESTART ||
1078 		    error == EINTR || error == EWOULDBLOCK))
1079 			error = 0;
1080 	}
1081 #ifdef KTRACE
1082 	if (ktriov != NULL) {
1083 		if (error == 0)
1084 			ktrgenio(p, s, UIO_READ, ktriov, len - auio.uio_resid);
1085 		free(ktriov, M_TEMP, iovlen);
1086 	}
1087 #endif
1088 	if (error)
1089 		goto out;
1090 	*retsize = len - auio.uio_resid;
1091 	if (mp->msg_name) {
1092 		socklen_t alen;
1093 
1094 		if (from == NULL)
1095 			alen = 0;
1096 		else {
1097 			alen = from->m_len;
1098 			error = copyout(mtod(from, caddr_t), mp->msg_name,
1099 			    MIN(alen, mp->msg_namelen));
1100 			if (error)
1101 				goto out;
1102 #ifdef KTRACE
1103 			if (KTRPOINT(p, KTR_STRUCT))
1104 				ktrsockaddr(p, mtod(from, caddr_t), alen);
1105 #endif
1106 		}
1107 		mp->msg_namelen = alen;
1108 		if (namelenp &&
1109 		    (error = copyout(&alen, namelenp, sizeof(alen)))) {
1110 			goto out;
1111 		}
1112 	}
1113 	if (mp->msg_control) {
1114 		len = mp->msg_controllen;
1115 		if (len <= 0 || control == NULL)
1116 			len = 0;
1117 		else {
1118 			struct mbuf *m = control;
1119 			caddr_t cp = mp->msg_control;
1120 
1121 			do {
1122 				i = m->m_len;
1123 				if (len < i) {
1124 					mp->msg_flags |= MSG_CTRUNC;
1125 					i = len;
1126 				}
1127 				error = copyout(mtod(m, caddr_t), cp, i);
1128 #ifdef KTRACE
1129 				if (KTRPOINT(p, KTR_STRUCT) && error == 0 && i) {
1130 					/* msg_flags potentially incorrect */
1131 					int rmsgflags = mp->msg_flags;
1132 
1133 					mp->msg_flags = kmsgflags;
1134 					ktrcmsghdr(p, mtod(m, char *), i);
1135 					mp->msg_flags = rmsgflags;
1136 				}
1137 #endif
1138 				if (m->m_next)
1139 					i = ALIGN(i);
1140 				cp += i;
1141 				len -= i;
1142 				if (error != 0 || len <= 0)
1143 					break;
1144 			} while ((m = m->m_next) != NULL);
1145 			len = cp - (caddr_t)mp->msg_control;
1146 		}
1147 		mp->msg_controllen = len;
1148 	}
1149 	if (!error) {
1150 		mtx_enter(&fp->f_mtx);
1151 		fp->f_rxfer++;
1152 		fp->f_rbytes += *retsize;
1153 		mtx_leave(&fp->f_mtx);
1154 	}
1155 out:
1156 	FRELE(fp, p);
1157 	m_freem(from);
1158 	m_freem(control);
1159 	return (error);
1160 }
1161 
1162 int
sys_shutdown(struct proc * p,void * v,register_t * retval)1163 sys_shutdown(struct proc *p, void *v, register_t *retval)
1164 {
1165 	struct sys_shutdown_args /* {
1166 		syscallarg(int) s;
1167 		syscallarg(int) how;
1168 	} */ *uap = v;
1169 	struct file *fp;
1170 	int error;
1171 
1172 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
1173 		return (error);
1174 	error = soshutdown(fp->f_data, SCARG(uap, how));
1175 	FRELE(fp, p);
1176 	return (error);
1177 }
1178 
1179 int
sys_setsockopt(struct proc * p,void * v,register_t * retval)1180 sys_setsockopt(struct proc *p, void *v, register_t *retval)
1181 {
1182 	struct sys_setsockopt_args /* {
1183 		syscallarg(int) s;
1184 		syscallarg(int) level;
1185 		syscallarg(int) name;
1186 		syscallarg(const void *) val;
1187 		syscallarg(socklen_t) valsize;
1188 	} */ *uap = v;
1189 	struct file *fp;
1190 	struct mbuf *m = NULL;
1191 	struct socket *so;
1192 	int error;
1193 
1194 
1195 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
1196 		return (error);
1197 	error = pledge_sockopt(p, 1, SCARG(uap, level), SCARG(uap, name));
1198 	if (error)
1199 		goto bad;
1200 	if (SCARG(uap, valsize) > MCLBYTES) {
1201 		error = EINVAL;
1202 		goto bad;
1203 	}
1204 	if (SCARG(uap, val)) {
1205 		m = m_get(M_WAIT, MT_SOOPTS);
1206 		if (SCARG(uap, valsize) > MLEN) {
1207 			MCLGET(m, M_WAIT);
1208 			if ((m->m_flags & M_EXT) == 0) {
1209 				error = ENOBUFS;
1210 				goto bad;
1211 			}
1212 		}
1213 		error = copyin(SCARG(uap, val), mtod(m, caddr_t),
1214 		    SCARG(uap, valsize));
1215 		if (error) {
1216 			goto bad;
1217 		}
1218 		m->m_len = SCARG(uap, valsize);
1219 	}
1220 	so = fp->f_data;
1221 	error = sosetopt(so, SCARG(uap, level), SCARG(uap, name), m);
1222 bad:
1223 	m_freem(m);
1224 	FRELE(fp, p);
1225 	return (error);
1226 }
1227 
1228 int
sys_getsockopt(struct proc * p,void * v,register_t * retval)1229 sys_getsockopt(struct proc *p, void *v, register_t *retval)
1230 {
1231 	struct sys_getsockopt_args /* {
1232 		syscallarg(int) s;
1233 		syscallarg(int) level;
1234 		syscallarg(int) name;
1235 		syscallarg(void *) val;
1236 		syscallarg(socklen_t *) avalsize;
1237 	} */ *uap = v;
1238 	struct file *fp;
1239 	struct mbuf *m = NULL;
1240 	socklen_t valsize;
1241 	struct socket *so;
1242 	int error;
1243 
1244 	if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
1245 		return (error);
1246 	error = pledge_sockopt(p, 0, SCARG(uap, level), SCARG(uap, name));
1247 	if (error)
1248 		goto out;
1249 	if (SCARG(uap, val)) {
1250 		error = copyin(SCARG(uap, avalsize),
1251 		    &valsize, sizeof (valsize));
1252 		if (error)
1253 			goto out;
1254 	} else
1255 		valsize = 0;
1256 	m = m_get(M_WAIT, MT_SOOPTS);
1257 	so = fp->f_data;
1258 	error = sogetopt(so, SCARG(uap, level), SCARG(uap, name), m);
1259 	if (error == 0 && SCARG(uap, val) && valsize && m != NULL) {
1260 		if (valsize > m->m_len)
1261 			valsize = m->m_len;
1262 		error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize);
1263 		if (error == 0)
1264 			error = copyout(&valsize,
1265 			    SCARG(uap, avalsize), sizeof (valsize));
1266 	}
1267 	m_free(m);
1268 out:
1269 	FRELE(fp, p);
1270 	return (error);
1271 }
1272 
1273 /*
1274  * Get socket name.
1275  */
1276 int
sys_getsockname(struct proc * p,void * v,register_t * retval)1277 sys_getsockname(struct proc *p, void *v, register_t *retval)
1278 {
1279 	struct sys_getsockname_args /* {
1280 		syscallarg(int) fdes;
1281 		syscallarg(struct sockaddr *) asa;
1282 		syscallarg(socklen_t *) alen;
1283 	} */ *uap = v;
1284 	struct file *fp;
1285 	struct socket *so;
1286 	struct mbuf *m = NULL;
1287 	socklen_t len;
1288 	int error;
1289 
1290 	if ((error = getsock(p, SCARG(uap, fdes), &fp)) != 0)
1291 		return (error);
1292 	error = copyin(SCARG(uap, alen), &len, sizeof (len));
1293 	if (error)
1294 		goto bad;
1295 	so = fp->f_data;
1296 	if (so->so_state & SS_YP) {
1297 		error = ENOTSOCK;
1298 		goto bad;
1299 	}
1300 	error = pledge_socket(p, -1, so->so_state);
1301 	if (error)
1302 		goto bad;
1303 	if (so->so_state & SS_YP) {
1304 		error = ENOTSOCK;
1305 		goto bad;
1306 	}
1307 	m = m_getclr(M_WAIT, MT_SONAME);
1308 	solock_shared(so);
1309 	error = pru_sockaddr(so, m);
1310 	sounlock_shared(so);
1311 	if (error)
1312 		goto bad;
1313 	error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen));
1314 bad:
1315 	FRELE(fp, p);
1316 	m_freem(m);
1317 	return (error);
1318 }
1319 
1320 /*
1321  * Get name of peer for connected socket.
1322  */
1323 int
sys_getpeername(struct proc * p,void * v,register_t * retval)1324 sys_getpeername(struct proc *p, void *v, register_t *retval)
1325 {
1326 	struct sys_getpeername_args /* {
1327 		syscallarg(int) fdes;
1328 		syscallarg(struct sockaddr *) asa;
1329 		syscallarg(socklen_t *) alen;
1330 	} */ *uap = v;
1331 	struct file *fp;
1332 	struct socket *so;
1333 	struct mbuf *m = NULL;
1334 	socklen_t len;
1335 	int error;
1336 
1337 	if ((error = getsock(p, SCARG(uap, fdes), &fp)) != 0)
1338 		return (error);
1339 	so = fp->f_data;
1340 	error = pledge_socket(p, -1, so->so_state);
1341 	if (error)
1342 		goto bad;
1343 	if (so->so_state & SS_YP) {
1344 		error = ENOTSOCK;
1345 		goto bad;
1346 	}
1347 	if ((so->so_state & SS_ISCONNECTED) == 0) {
1348 		error = ENOTCONN;
1349 		goto bad;
1350 	}
1351 	error = copyin(SCARG(uap, alen), &len, sizeof (len));
1352 	if (error)
1353 		goto bad;
1354 	m = m_getclr(M_WAIT, MT_SONAME);
1355 	solock_shared(so);
1356 	error = pru_peeraddr(so, m);
1357 	sounlock_shared(so);
1358 	if (error)
1359 		goto bad;
1360 	error = copyaddrout(p, m, SCARG(uap, asa), len, SCARG(uap, alen));
1361 bad:
1362 	FRELE(fp, p);
1363 	m_freem(m);
1364 	return (error);
1365 }
1366 
1367 int
sockargs(struct mbuf ** mp,const void * buf,size_t buflen,int type)1368 sockargs(struct mbuf **mp, const void *buf, size_t buflen, int type)
1369 {
1370 	struct sockaddr *sa;
1371 	struct mbuf *m;
1372 	int error;
1373 
1374 	/*
1375 	 * We can't allow socket names > UCHAR_MAX in length, since that
1376 	 * will overflow sa_len. Also, control data more than MCLBYTES in
1377 	 * length is just too much.
1378 	 * Memory for sa_len and sa_family must exist.
1379 	 */
1380 	if ((buflen > (type == MT_SONAME ? UCHAR_MAX : MCLBYTES)) ||
1381 	    (type == MT_SONAME && buflen < offsetof(struct sockaddr, sa_data)))
1382 		return (EINVAL);
1383 
1384 	/* Allocate an mbuf to hold the arguments. */
1385 	m = m_get(M_WAIT, type);
1386 	if (buflen > MLEN) {
1387 		MCLGET(m, M_WAITOK);
1388 		if ((m->m_flags & M_EXT) == 0) {
1389 			m_free(m);
1390 			return ENOBUFS;
1391 		}
1392 	}
1393 	m->m_len = buflen;
1394 	error = copyin(buf, mtod(m, caddr_t), buflen);
1395 	if (error) {
1396 		(void) m_free(m);
1397 		return (error);
1398 	}
1399 	*mp = m;
1400 	if (type == MT_SONAME) {
1401 		sa = mtod(m, struct sockaddr *);
1402 		sa->sa_len = buflen;
1403 	}
1404 	return (0);
1405 }
1406 
1407 int
getsock(struct proc * p,int fdes,struct file ** fpp)1408 getsock(struct proc *p, int fdes, struct file **fpp)
1409 {
1410 	struct file *fp;
1411 
1412 	fp = fd_getfile(p->p_fd, fdes);
1413 	if (fp == NULL)
1414 		return (EBADF);
1415 	if (fp->f_type != DTYPE_SOCKET) {
1416 		FRELE(fp, p);
1417 		return (ENOTSOCK);
1418 	}
1419 	*fpp = fp;
1420 
1421 	return (0);
1422 }
1423 
1424 int
sys_setrtable(struct proc * p,void * v,register_t * retval)1425 sys_setrtable(struct proc *p, void *v, register_t *retval)
1426 {
1427 	struct sys_setrtable_args /* {
1428 		syscallarg(int) rtableid;
1429 	} */ *uap = v;
1430 	u_int ps_rtableid = p->p_p->ps_rtableid;
1431 	int rtableid, error;
1432 
1433 	rtableid = SCARG(uap, rtableid);
1434 
1435 	if (ps_rtableid == rtableid)
1436 		return (0);
1437 	if (ps_rtableid != 0 && (error = suser(p)) != 0)
1438 		return (error);
1439 	if (rtableid < 0 || !rtable_exists((u_int)rtableid))
1440 		return (EINVAL);
1441 
1442 	p->p_p->ps_rtableid = (u_int)rtableid;
1443 	return (0);
1444 }
1445 
1446 int
sys_getrtable(struct proc * p,void * v,register_t * retval)1447 sys_getrtable(struct proc *p, void *v, register_t *retval)
1448 {
1449 	*retval = (int)p->p_p->ps_rtableid;
1450 	return (0);
1451 }
1452 
1453 int
copyaddrout(struct proc * p,struct mbuf * name,struct sockaddr * sa,socklen_t buflen,socklen_t * outlen)1454 copyaddrout(struct proc *p, struct mbuf *name, struct sockaddr *sa,
1455     socklen_t buflen, socklen_t *outlen)
1456 {
1457 	int error;
1458 	socklen_t namelen = name->m_len;
1459 
1460 	/* SHOULD COPY OUT A CHAIN HERE */
1461 	error = copyout(mtod(name, caddr_t), sa, MIN(buflen, namelen));
1462 	if (error == 0) {
1463 #ifdef KTRACE
1464 		if (KTRPOINT(p, KTR_STRUCT))
1465 			ktrsockaddr(p, mtod(name, caddr_t), namelen);
1466 #endif
1467 		error = copyout(&namelen, outlen, sizeof(*outlen));
1468 	}
1469 
1470 	return (error);
1471 }
1472 
1473 #ifndef SMALL_KERNEL
1474 int
ypsockargs(struct mbuf ** mp,const void * buf,size_t buflen,int type)1475 ypsockargs(struct mbuf **mp, const void *buf, size_t buflen, int type)
1476 {
1477 	struct sockaddr *sa;
1478 	struct mbuf *m;
1479 
1480 	/*
1481 	 * We can't allow socket names > UCHAR_MAX in length, since that
1482 	 * will overflow sa_len. Also, control data more than MCLBYTES in
1483 	 * length is just too much.
1484 	 * Memory for sa_len and sa_family must exist.
1485 	 */
1486 	if ((buflen > (type == MT_SONAME ? UCHAR_MAX : MCLBYTES)) ||
1487 	    (type == MT_SONAME && buflen < offsetof(struct sockaddr, sa_data)))
1488 		return (EINVAL);
1489 
1490 	/* Allocate an mbuf to hold the arguments. */
1491 	m = m_get(M_WAIT, type);
1492 	if (buflen > MLEN) {
1493 		MCLGET(m, M_WAITOK);
1494 		if ((m->m_flags & M_EXT) == 0) {
1495 			m_free(m);
1496 			return ENOBUFS;
1497 		}
1498 	}
1499 	m->m_len = buflen;
1500 	bcopy(buf, mtod(m, caddr_t), buflen);
1501 	*mp = m;
1502 	if (type == MT_SONAME) {
1503 		sa = mtod(m, struct sockaddr *);
1504 		sa->sa_len = buflen;
1505 	}
1506 	return (0);
1507 }
1508 #endif /* SMALL_KERNEL */
1509 
1510 int
sys_ypconnect(struct proc * p,void * v,register_t * retval)1511 sys_ypconnect(struct proc *p, void *v, register_t *retval)
1512 {
1513 #ifdef SMALL_KERNEL
1514 	return EAFNOSUPPORT;
1515 #else
1516 	struct sys_ypconnect_args /* {
1517 		syscallarg(int) type;
1518 	} */ *uap = v;
1519 	struct nameidata nid;
1520 	struct vattr va;
1521 	struct uio uio;
1522 	struct iovec iov;
1523 	struct filedesc *fdp = p->p_fd;
1524 	struct socket *so;
1525 	struct file *fp;
1526 	struct flock fl;
1527 	char *name;
1528 	struct mbuf *nam = NULL;
1529 	int error, fd = -1;
1530 	struct ypbinding {
1531 		u_short ypbind_port;
1532 		int status;
1533 		in_addr_t in;
1534 		u_short ypserv_udp_port;
1535 		u_short garbage;
1536 		u_short ypserv_tcp_port;
1537 	} __packed data;
1538 	struct sockaddr_in ypsin;
1539 
1540 	if (!domainname[0] || strchr(domainname, '/'))
1541 		return EAFNOSUPPORT;
1542 
1543 	switch (SCARG(uap, type)) {
1544 	case SOCK_STREAM:
1545 	case SOCK_DGRAM:
1546 		break;
1547 	default:
1548 		return EAFNOSUPPORT;
1549 	}
1550 
1551 	if (p->p_p->ps_flags & PS_CHROOT)
1552 		return EACCES;
1553 	KERNEL_LOCK();
1554 	name = pool_get(&namei_pool, PR_WAITOK);
1555 	snprintf(name, MAXPATHLEN, "/var/yp/binding/%s.2", domainname);
1556 	NDINIT(&nid, 0, NOFOLLOW|LOCKLEAF|KERNELPATH, UIO_SYSSPACE, name, p);
1557 	nid.ni_pledge = PLEDGE_RPATH;
1558 
1559 	error = namei(&nid);
1560 	pool_put(&namei_pool, name);
1561 	if (error)
1562 		goto out;
1563 	error = VOP_GETATTR(nid.ni_vp, &va, p->p_ucred, p);
1564 	if (error)
1565 		goto verror;
1566 	if (nid.ni_vp->v_type != VREG || va.va_size != sizeof data) {
1567 		error = EFTYPE;
1568 		goto verror;
1569 	}
1570 
1571 	/*
1572 	 * Check that a lock is held on the file (hopefully by ypbind),
1573 	 * otherwise the file might be old
1574 	 */
1575 	fl.l_start = 0;
1576 	fl.l_len = 0;
1577 	fl.l_pid = 0;
1578 	fl.l_type = F_WRLCK;
1579 	fl.l_whence = SEEK_SET;
1580 	error = VOP_ADVLOCK(nid.ni_vp, fdp, F_GETLK, &fl, F_POSIX);
1581 	if (error)
1582 		goto verror;
1583 	if (fl.l_type == F_UNLCK) {
1584 		error = EOWNERDEAD;
1585 		goto verror;
1586 	}
1587 
1588 	iov.iov_base = &data;
1589 	iov.iov_len = sizeof data;
1590 	uio.uio_iov = &iov;
1591 	uio.uio_iovcnt = 1;
1592 	uio.uio_offset = 0;
1593 	uio.uio_resid = iov.iov_len;
1594 	uio.uio_segflg = UIO_SYSSPACE;
1595 	uio.uio_rw = UIO_READ;
1596 	uio.uio_procp = p;
1597 
1598 	error = VOP_READ(nid.ni_vp, &uio, 0, p->p_ucred);
1599 	if (error) {
1600 verror:
1601 		if (nid.ni_vp)
1602 			vput(nid.ni_vp);
1603 out:
1604 		KERNEL_UNLOCK();
1605 		return (error);
1606 	}
1607 	vput(nid.ni_vp);
1608 	KERNEL_UNLOCK();
1609 
1610 	bzero(&ypsin, sizeof ypsin);
1611 	ypsin.sin_len = sizeof ypsin;
1612 	ypsin.sin_family = AF_INET;
1613 	if (SCARG(uap, type) == SOCK_STREAM)
1614 		ypsin.sin_port = data.ypserv_tcp_port;
1615 	else
1616 		ypsin.sin_port = data.ypserv_udp_port;
1617 	if (ntohs(ypsin.sin_port) >= IPPORT_RESERVED || ntohs(ypsin.sin_port) == 20)
1618 		return EPERM;
1619 	memcpy(&ypsin.sin_addr.s_addr, &data.in, sizeof ypsin.sin_addr.s_addr);
1620 
1621 	error = socreate(AF_INET, &so, SCARG(uap, type), 0);
1622 	if (error)
1623 		return (error);
1624 
1625 	error = ypsockargs(&nam, &ypsin, sizeof ypsin, MT_SONAME);
1626 	if (error) {
1627 		soclose(so, MSG_DONTWAIT);
1628 		return (error);
1629 	}
1630 
1631 #ifdef KTRACE
1632 	if (KTRPOINT(p, KTR_STRUCT))
1633 		ktrsockaddr(p, mtod(nam, caddr_t), sizeof(struct sockaddr_in));
1634 #endif
1635 	solock(so);
1636 
1637 	/* Secure YP maps require reserved ports */
1638 	if (suser(p) == 0)
1639 		sotoinpcb(so)->inp_flags |= INP_LOWPORT;
1640 
1641 	error = soconnect(so, nam);
1642 	while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
1643 		error = sosleep_nsec(so, &so->so_timeo, PSOCK | PCATCH,
1644 		    "ypcon", INFSLP);
1645 		if (error)
1646 			break;
1647 	}
1648 	m_freem(nam);
1649 	so->so_state |= SS_YP;		/* impose some restrictions */
1650 	sounlock(so);
1651 	if (error) {
1652 		soclose(so, MSG_DONTWAIT);
1653 		return (error);
1654 	}
1655 
1656 	fdplock(fdp);
1657 	error = falloc(p, &fp, &fd);
1658 	if (error) {
1659 		fdpunlock(fdp);
1660 		soclose(so, MSG_DONTWAIT);
1661 		return (error);
1662 	}
1663 
1664 	fp->f_flag = FREAD | FWRITE | FNONBLOCK;
1665 	fp->f_type = DTYPE_SOCKET;
1666 	fp->f_ops = &socketops;
1667 	fp->f_data = so;
1668 	fdinsert(fdp, fd, UF_EXCLOSE, fp);
1669 	fdpunlock(fdp);
1670 	FRELE(fp, p);
1671 	*retval = fd;
1672 	return (error);
1673 #endif /* SMALL_KERNEL */
1674 }
1675