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