Line data Source code
1 : /* $OpenBSD: uipc_usrreq.c,v 1.134 2018/07/09 10:58:21 claudio Exp $ */
2 : /* $NetBSD: uipc_usrreq.c,v 1.18 1996/02/09 19:00:50 christos Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1982, 1986, 1989, 1991, 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_usrreq.c 8.3 (Berkeley) 1/4/94
33 : */
34 :
35 : #include <sys/param.h>
36 : #include <sys/systm.h>
37 : #include <sys/proc.h>
38 : #include <sys/filedesc.h>
39 : #include <sys/domain.h>
40 : #include <sys/protosw.h>
41 : #include <sys/queue.h>
42 : #include <sys/socket.h>
43 : #include <sys/socketvar.h>
44 : #include <sys/unpcb.h>
45 : #include <sys/un.h>
46 : #include <sys/namei.h>
47 : #include <sys/vnode.h>
48 : #include <sys/file.h>
49 : #include <sys/stat.h>
50 : #include <sys/mbuf.h>
51 : #include <sys/task.h>
52 : #include <sys/pledge.h>
53 :
54 : void uipc_setaddr(const struct unpcb *, struct mbuf *);
55 :
56 : /* list of all UNIX domain sockets, for unp_gc() */
57 : LIST_HEAD(unp_head, unpcb) unp_head = LIST_HEAD_INITIALIZER(unp_head);
58 :
59 : /*
60 : * Stack of sets of files that were passed over a socket but were
61 : * not received and need to be closed.
62 : */
63 : struct unp_deferral {
64 : SLIST_ENTRY(unp_deferral) ud_link;
65 : int ud_n;
66 : /* followed by ud_n struct fdpass */
67 : struct fdpass ud_fp[];
68 : };
69 :
70 : void unp_discard(struct fdpass *, int);
71 : void unp_mark(struct fdpass *, int);
72 : void unp_scan(struct mbuf *, void (*)(struct fdpass *, int));
73 : int unp_nam2sun(struct mbuf *, struct sockaddr_un **, size_t *);
74 :
75 : /* list of sets of files that were sent over sockets that are now closed */
76 : SLIST_HEAD(,unp_deferral) unp_deferred = SLIST_HEAD_INITIALIZER(unp_deferred);
77 :
78 : struct task unp_gc_task = TASK_INITIALIZER(unp_gc, NULL);
79 :
80 :
81 : /*
82 : * Unix communications domain.
83 : *
84 : * TODO:
85 : * RDM
86 : * rethink name space problems
87 : * need a proper out-of-band
88 : */
89 : struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
90 : ino_t unp_ino; /* prototype for fake inode numbers */
91 :
92 : void
93 0 : uipc_setaddr(const struct unpcb *unp, struct mbuf *nam)
94 : {
95 0 : if (unp != NULL && unp->unp_addr != NULL) {
96 0 : nam->m_len = unp->unp_addr->m_len;
97 0 : memcpy(mtod(nam, caddr_t), mtod(unp->unp_addr, caddr_t),
98 : nam->m_len);
99 0 : } else {
100 0 : nam->m_len = sizeof(sun_noname);
101 0 : memcpy(mtod(nam, struct sockaddr *), &sun_noname,
102 : nam->m_len);
103 : }
104 0 : }
105 :
106 : int
107 0 : uipc_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
108 : struct mbuf *control, struct proc *p)
109 : {
110 0 : struct unpcb *unp = sotounpcb(so);
111 : struct socket *so2;
112 : int error = 0;
113 :
114 0 : if (req == PRU_CONTROL)
115 0 : return (EOPNOTSUPP);
116 0 : if (req != PRU_SEND && control && control->m_len) {
117 : error = EOPNOTSUPP;
118 0 : goto release;
119 : }
120 0 : if (unp == NULL) {
121 : error = EINVAL;
122 0 : goto release;
123 : }
124 :
125 0 : NET_ASSERT_UNLOCKED();
126 :
127 0 : switch (req) {
128 :
129 : case PRU_BIND:
130 0 : error = unp_bind(unp, nam, p);
131 0 : break;
132 :
133 : case PRU_LISTEN:
134 0 : if (unp->unp_vnode == NULL)
135 0 : error = EINVAL;
136 : break;
137 :
138 : case PRU_CONNECT:
139 0 : error = unp_connect(so, nam, p);
140 0 : break;
141 :
142 : case PRU_CONNECT2:
143 0 : error = unp_connect2(so, (struct socket *)nam);
144 0 : break;
145 :
146 : case PRU_DISCONNECT:
147 0 : unp_disconnect(unp);
148 0 : break;
149 :
150 : case PRU_ACCEPT:
151 : /*
152 : * Pass back name of connected socket,
153 : * if it was bound and we are still connected
154 : * (our peer may have closed already!).
155 : */
156 0 : uipc_setaddr(unp->unp_conn, nam);
157 0 : break;
158 :
159 : case PRU_SHUTDOWN:
160 0 : socantsendmore(so);
161 0 : unp_shutdown(unp);
162 0 : break;
163 :
164 : case PRU_RCVD:
165 0 : switch (so->so_type) {
166 :
167 : case SOCK_DGRAM:
168 0 : panic("uipc 1");
169 : /*NOTREACHED*/
170 :
171 : case SOCK_STREAM:
172 : case SOCK_SEQPACKET:
173 0 : if (unp->unp_conn == NULL)
174 : break;
175 0 : so2 = unp->unp_conn->unp_socket;
176 : /*
177 : * Adjust backpressure on sender
178 : * and wakeup any waiting to write.
179 : */
180 0 : so2->so_snd.sb_mbcnt = so->so_rcv.sb_mbcnt;
181 0 : so2->so_snd.sb_cc = so->so_rcv.sb_cc;
182 0 : sowwakeup(so2);
183 0 : break;
184 :
185 : default:
186 0 : panic("uipc 2");
187 : }
188 : break;
189 :
190 : case PRU_SEND:
191 0 : if (control && (error = unp_internalize(control, p)))
192 : break;
193 0 : switch (so->so_type) {
194 :
195 : case SOCK_DGRAM: {
196 : struct sockaddr *from;
197 :
198 0 : if (nam) {
199 0 : if (unp->unp_conn) {
200 : error = EISCONN;
201 0 : break;
202 : }
203 0 : error = unp_connect(so, nam, p);
204 0 : if (error)
205 0 : break;
206 : } else {
207 0 : if (unp->unp_conn == NULL) {
208 : error = ENOTCONN;
209 0 : break;
210 : }
211 : }
212 0 : so2 = unp->unp_conn->unp_socket;
213 0 : if (unp->unp_addr)
214 0 : from = mtod(unp->unp_addr, struct sockaddr *);
215 : else
216 : from = &sun_noname;
217 0 : if (sbappendaddr(so2, &so2->so_rcv, from, m, control)) {
218 0 : sorwakeup(so2);
219 : m = NULL;
220 : control = NULL;
221 0 : } else
222 : error = ENOBUFS;
223 0 : if (nam)
224 0 : unp_disconnect(unp);
225 0 : break;
226 : }
227 :
228 : case SOCK_STREAM:
229 : case SOCK_SEQPACKET:
230 0 : if (so->so_state & SS_CANTSENDMORE) {
231 : error = EPIPE;
232 0 : break;
233 : }
234 0 : if (unp->unp_conn == NULL) {
235 : error = ENOTCONN;
236 0 : break;
237 : }
238 0 : so2 = unp->unp_conn->unp_socket;
239 : /*
240 : * Send to paired receive port, and then raise
241 : * send buffer counts to maintain backpressure.
242 : * Wake up readers.
243 : */
244 0 : if (control) {
245 0 : if (sbappendcontrol(so2, &so2->so_rcv, m,
246 : control)) {
247 : control = NULL;
248 : } else {
249 : error = ENOBUFS;
250 0 : break;
251 : }
252 0 : } else if (so->so_type == SOCK_SEQPACKET)
253 0 : sbappendrecord(so2, &so2->so_rcv, m);
254 : else
255 0 : sbappend(so2, &so2->so_rcv, m);
256 0 : so->so_snd.sb_mbcnt = so2->so_rcv.sb_mbcnt;
257 0 : so->so_snd.sb_cc = so2->so_rcv.sb_cc;
258 0 : sorwakeup(so2);
259 : m = NULL;
260 0 : break;
261 :
262 : default:
263 0 : panic("uipc 4");
264 : }
265 : /* we need to undo unp_internalize in case of errors */
266 0 : if (control && error)
267 0 : unp_dispose(control);
268 : break;
269 :
270 : case PRU_ABORT:
271 0 : unp_drop(unp, ECONNABORTED);
272 0 : break;
273 :
274 : case PRU_SENSE: {
275 0 : struct stat *sb = (struct stat *)m;
276 :
277 0 : sb->st_blksize = so->so_snd.sb_hiwat;
278 0 : sb->st_dev = NODEV;
279 0 : if (unp->unp_ino == 0)
280 0 : unp->unp_ino = unp_ino++;
281 0 : sb->st_atim.tv_sec =
282 0 : sb->st_mtim.tv_sec =
283 0 : sb->st_ctim.tv_sec = unp->unp_ctime.tv_sec;
284 0 : sb->st_atim.tv_nsec =
285 0 : sb->st_mtim.tv_nsec =
286 0 : sb->st_ctim.tv_nsec = unp->unp_ctime.tv_nsec;
287 0 : sb->st_ino = unp->unp_ino;
288 : return (0);
289 : }
290 :
291 : case PRU_RCVOOB:
292 0 : return (EOPNOTSUPP);
293 :
294 : case PRU_SENDOOB:
295 : error = EOPNOTSUPP;
296 0 : break;
297 :
298 : case PRU_SOCKADDR:
299 0 : uipc_setaddr(unp, nam);
300 0 : break;
301 :
302 : case PRU_PEERADDR:
303 0 : uipc_setaddr(unp->unp_conn, nam);
304 0 : break;
305 :
306 : case PRU_SLOWTIMO:
307 : break;
308 :
309 : default:
310 0 : panic("uipc_usrreq");
311 : }
312 : release:
313 0 : m_freem(control);
314 0 : m_freem(m);
315 0 : return (error);
316 0 : }
317 :
318 : /*
319 : * Both send and receive buffers are allocated PIPSIZ bytes of buffering
320 : * for stream sockets, although the total for sender and receiver is
321 : * actually only PIPSIZ.
322 : * Datagram sockets really use the sendspace as the maximum datagram size,
323 : * and don't really want to reserve the sendspace. Their recvspace should
324 : * be large enough for at least one max-size datagram plus address.
325 : */
326 : #define PIPSIZ 4096
327 : u_long unpst_sendspace = PIPSIZ;
328 : u_long unpst_recvspace = PIPSIZ;
329 : u_long unpdg_sendspace = 2*1024; /* really max datagram size */
330 : u_long unpdg_recvspace = 4*1024;
331 :
332 : int unp_rights; /* file descriptors in flight */
333 :
334 : int
335 0 : uipc_attach(struct socket *so, int proto)
336 : {
337 : struct unpcb *unp;
338 : int error;
339 :
340 0 : if (so->so_pcb)
341 0 : return EISCONN;
342 0 : if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
343 0 : switch (so->so_type) {
344 :
345 : case SOCK_STREAM:
346 : case SOCK_SEQPACKET:
347 0 : error = soreserve(so, unpst_sendspace, unpst_recvspace);
348 0 : break;
349 :
350 : case SOCK_DGRAM:
351 0 : error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
352 0 : break;
353 :
354 : default:
355 0 : panic("unp_attach");
356 : }
357 0 : if (error)
358 0 : return (error);
359 : }
360 0 : unp = malloc(sizeof(*unp), M_PCB, M_NOWAIT|M_ZERO);
361 0 : if (unp == NULL)
362 0 : return (ENOBUFS);
363 0 : unp->unp_socket = so;
364 0 : so->so_pcb = unp;
365 0 : getnanotime(&unp->unp_ctime);
366 0 : LIST_INSERT_HEAD(&unp_head, unp, unp_link);
367 0 : return (0);
368 0 : }
369 :
370 : int
371 0 : uipc_detach(struct socket *so)
372 : {
373 0 : struct unpcb *unp = sotounpcb(so);
374 :
375 0 : if (unp == NULL)
376 0 : return (EINVAL);
377 :
378 0 : NET_ASSERT_UNLOCKED();
379 :
380 0 : unp_detach(unp);
381 :
382 0 : return (0);
383 0 : }
384 :
385 : void
386 0 : unp_detach(struct unpcb *unp)
387 : {
388 : struct vnode *vp;
389 :
390 0 : LIST_REMOVE(unp, unp_link);
391 0 : if (unp->unp_vnode) {
392 0 : unp->unp_vnode->v_socket = NULL;
393 0 : vp = unp->unp_vnode;
394 0 : unp->unp_vnode = NULL;
395 0 : vrele(vp);
396 0 : }
397 0 : if (unp->unp_conn)
398 0 : unp_disconnect(unp);
399 0 : while (!SLIST_EMPTY(&unp->unp_refs))
400 0 : unp_drop(SLIST_FIRST(&unp->unp_refs), ECONNRESET);
401 0 : soisdisconnected(unp->unp_socket);
402 0 : unp->unp_socket->so_pcb = NULL;
403 0 : m_freem(unp->unp_addr);
404 0 : free(unp, M_PCB, sizeof *unp);
405 0 : if (unp_rights)
406 0 : task_add(systq, &unp_gc_task);
407 0 : }
408 :
409 : int
410 0 : unp_bind(struct unpcb *unp, struct mbuf *nam, struct proc *p)
411 : {
412 0 : struct sockaddr_un *soun;
413 : struct mbuf *nam2;
414 : struct vnode *vp;
415 0 : struct vattr vattr;
416 : int error;
417 0 : struct nameidata nd;
418 0 : size_t pathlen;
419 :
420 0 : if (unp->unp_vnode != NULL)
421 0 : return (EINVAL);
422 0 : if ((error = unp_nam2sun(nam, &soun, &pathlen)))
423 0 : return (error);
424 :
425 0 : nam2 = m_getclr(M_WAITOK, MT_SONAME);
426 0 : nam2->m_len = sizeof(struct sockaddr_un);
427 0 : memcpy(mtod(nam2, struct sockaddr_un *), soun,
428 : offsetof(struct sockaddr_un, sun_path) + pathlen);
429 : /* No need to NUL terminate: m_getclr() returns zero'd mbufs. */
430 :
431 0 : soun = mtod(nam2, struct sockaddr_un *);
432 :
433 : /* Fixup sun_len to keep it in sync with m_len. */
434 0 : soun->sun_len = nam2->m_len;
435 :
436 0 : NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT, UIO_SYSSPACE,
437 : soun->sun_path, p);
438 0 : nd.ni_pledge = PLEDGE_UNIX;
439 : /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
440 0 : if ((error = namei(&nd)) != 0) {
441 0 : m_freem(nam2);
442 0 : return (error);
443 : }
444 0 : vp = nd.ni_vp;
445 0 : if (vp != NULL) {
446 0 : VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
447 0 : if (nd.ni_dvp == vp)
448 0 : vrele(nd.ni_dvp);
449 : else
450 0 : vput(nd.ni_dvp);
451 0 : vrele(vp);
452 0 : m_freem(nam2);
453 0 : return (EADDRINUSE);
454 : }
455 0 : VATTR_NULL(&vattr);
456 0 : vattr.va_type = VSOCK;
457 0 : vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
458 0 : error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
459 0 : vput(nd.ni_dvp);
460 0 : if (error) {
461 0 : m_freem(nam2);
462 0 : return (error);
463 : }
464 0 : unp->unp_addr = nam2;
465 0 : vp = nd.ni_vp;
466 0 : vp->v_socket = unp->unp_socket;
467 0 : unp->unp_vnode = vp;
468 0 : unp->unp_connid.uid = p->p_ucred->cr_uid;
469 0 : unp->unp_connid.gid = p->p_ucred->cr_gid;
470 0 : unp->unp_connid.pid = p->p_p->ps_pid;
471 0 : unp->unp_flags |= UNP_FEIDSBIND;
472 0 : VOP_UNLOCK(vp);
473 0 : return (0);
474 0 : }
475 :
476 : int
477 0 : unp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
478 : {
479 0 : struct sockaddr_un *soun;
480 : struct vnode *vp;
481 : struct socket *so2, *so3;
482 : struct unpcb *unp, *unp2, *unp3;
483 0 : struct nameidata nd;
484 : int error;
485 :
486 0 : if ((error = unp_nam2sun(nam, &soun, NULL)))
487 0 : return (error);
488 :
489 0 : NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);
490 0 : nd.ni_pledge = PLEDGE_UNIX;
491 0 : if ((error = namei(&nd)) != 0)
492 0 : return (error);
493 0 : vp = nd.ni_vp;
494 0 : if (vp->v_type != VSOCK) {
495 : error = ENOTSOCK;
496 0 : goto bad;
497 : }
498 0 : if ((error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) != 0)
499 : goto bad;
500 0 : so2 = vp->v_socket;
501 0 : if (so2 == NULL) {
502 : error = ECONNREFUSED;
503 0 : goto bad;
504 : }
505 0 : if (so->so_type != so2->so_type) {
506 : error = EPROTOTYPE;
507 0 : goto bad;
508 : }
509 0 : if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
510 0 : if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
511 0 : (so3 = sonewconn(so2, 0)) == 0) {
512 : error = ECONNREFUSED;
513 0 : goto bad;
514 : }
515 0 : unp = sotounpcb(so);
516 0 : unp2 = sotounpcb(so2);
517 0 : unp3 = sotounpcb(so3);
518 0 : if (unp2->unp_addr)
519 0 : unp3->unp_addr =
520 0 : m_copym(unp2->unp_addr, 0, M_COPYALL, M_NOWAIT);
521 0 : unp3->unp_connid.uid = p->p_ucred->cr_uid;
522 0 : unp3->unp_connid.gid = p->p_ucred->cr_gid;
523 0 : unp3->unp_connid.pid = p->p_p->ps_pid;
524 0 : unp3->unp_flags |= UNP_FEIDS;
525 : so2 = so3;
526 0 : if (unp2->unp_flags & UNP_FEIDSBIND) {
527 0 : unp->unp_connid = unp2->unp_connid;
528 0 : unp->unp_flags |= UNP_FEIDS;
529 0 : }
530 : }
531 0 : error = unp_connect2(so, so2);
532 : bad:
533 0 : vput(vp);
534 0 : return (error);
535 0 : }
536 :
537 : int
538 0 : unp_connect2(struct socket *so, struct socket *so2)
539 : {
540 0 : struct unpcb *unp = sotounpcb(so);
541 : struct unpcb *unp2;
542 :
543 0 : if (so2->so_type != so->so_type)
544 0 : return (EPROTOTYPE);
545 0 : unp2 = sotounpcb(so2);
546 0 : unp->unp_conn = unp2;
547 0 : switch (so->so_type) {
548 :
549 : case SOCK_DGRAM:
550 0 : SLIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_nextref);
551 0 : soisconnected(so);
552 0 : break;
553 :
554 : case SOCK_STREAM:
555 : case SOCK_SEQPACKET:
556 0 : unp2->unp_conn = unp;
557 0 : soisconnected(so);
558 0 : soisconnected(so2);
559 0 : break;
560 :
561 : default:
562 0 : panic("unp_connect2");
563 : }
564 0 : return (0);
565 0 : }
566 :
567 : void
568 0 : unp_disconnect(struct unpcb *unp)
569 : {
570 0 : struct unpcb *unp2 = unp->unp_conn;
571 :
572 0 : if (unp2 == NULL)
573 0 : return;
574 0 : unp->unp_conn = NULL;
575 0 : switch (unp->unp_socket->so_type) {
576 :
577 : case SOCK_DGRAM:
578 0 : SLIST_REMOVE(&unp2->unp_refs, unp, unpcb, unp_nextref);
579 0 : unp->unp_socket->so_state &= ~SS_ISCONNECTED;
580 0 : break;
581 :
582 : case SOCK_STREAM:
583 : case SOCK_SEQPACKET:
584 0 : unp->unp_socket->so_snd.sb_mbcnt = 0;
585 0 : unp->unp_socket->so_snd.sb_cc = 0;
586 0 : soisdisconnected(unp->unp_socket);
587 0 : unp2->unp_conn = NULL;
588 0 : unp2->unp_socket->so_snd.sb_mbcnt = 0;
589 0 : unp2->unp_socket->so_snd.sb_cc = 0;
590 0 : soisdisconnected(unp2->unp_socket);
591 0 : break;
592 : }
593 0 : }
594 :
595 : void
596 0 : unp_shutdown(struct unpcb *unp)
597 : {
598 : struct socket *so;
599 :
600 0 : switch (unp->unp_socket->so_type) {
601 : case SOCK_STREAM:
602 : case SOCK_SEQPACKET:
603 0 : if (unp->unp_conn && (so = unp->unp_conn->unp_socket))
604 0 : socantrcvmore(so);
605 : break;
606 : default:
607 : break;
608 : }
609 0 : }
610 :
611 : void
612 0 : unp_drop(struct unpcb *unp, int errno)
613 : {
614 0 : struct socket *so = unp->unp_socket;
615 :
616 0 : KERNEL_ASSERT_LOCKED();
617 :
618 0 : so->so_error = errno;
619 0 : unp_disconnect(unp);
620 0 : if (so->so_head) {
621 0 : so->so_pcb = NULL;
622 : /*
623 : * As long as the KERNEL_LOCK() is the default lock for Unix
624 : * sockets, do not release it.
625 : */
626 0 : sofree(so, SL_NOUNLOCK);
627 0 : m_freem(unp->unp_addr);
628 0 : free(unp, M_PCB, sizeof *unp);
629 0 : }
630 0 : }
631 :
632 : #ifdef notdef
633 : unp_drain(void)
634 : {
635 :
636 : }
637 : #endif
638 :
639 : extern struct domain unixdomain;
640 :
641 : static struct unpcb *
642 0 : fptounp(struct file *fp)
643 : {
644 : struct socket *so;
645 :
646 0 : if (fp->f_type != DTYPE_SOCKET)
647 0 : return (NULL);
648 0 : if ((so = fp->f_data) == NULL)
649 0 : return (NULL);
650 0 : if (so->so_proto->pr_domain != &unixdomain)
651 0 : return (NULL);
652 0 : return (sotounpcb(so));
653 0 : }
654 :
655 : int
656 0 : unp_externalize(struct mbuf *rights, socklen_t controllen, int flags)
657 : {
658 0 : struct proc *p = curproc; /* XXX */
659 0 : struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
660 0 : struct filedesc *fdp = p->p_fd;
661 : int i, *fds = NULL;
662 : struct fdpass *rp;
663 : struct file *fp;
664 : int nfds, error = 0;
665 :
666 0 : nfds = (cm->cmsg_len - CMSG_ALIGN(sizeof(*cm))) /
667 : sizeof(struct fdpass);
668 0 : if (controllen < CMSG_ALIGN(sizeof(struct cmsghdr)))
669 0 : controllen = 0;
670 : else
671 0 : controllen -= CMSG_ALIGN(sizeof(struct cmsghdr));
672 0 : if (nfds > controllen / sizeof(int)) {
673 : error = EMSGSIZE;
674 0 : goto restart;
675 : }
676 :
677 : /* Make sure the recipient should be able to see the descriptors.. */
678 0 : rp = (struct fdpass *)CMSG_DATA(cm);
679 0 : for (i = 0; i < nfds; i++) {
680 0 : fp = rp->fp;
681 0 : rp++;
682 0 : error = pledge_recvfd(p, fp);
683 0 : if (error)
684 : break;
685 :
686 : /*
687 : * No to block devices. If passing a directory,
688 : * make sure that it is underneath the root.
689 : */
690 0 : if (fdp->fd_rdir != NULL && fp->f_type == DTYPE_VNODE) {
691 0 : struct vnode *vp = (struct vnode *)fp->f_data;
692 :
693 0 : if (vp->v_type == VBLK ||
694 0 : (vp->v_type == VDIR &&
695 0 : !vn_isunder(vp, fdp->fd_rdir, p))) {
696 : error = EPERM;
697 0 : break;
698 : }
699 0 : }
700 : }
701 :
702 0 : fds = mallocarray(nfds, sizeof(int), M_TEMP, M_WAITOK);
703 :
704 : restart:
705 0 : fdplock(fdp);
706 0 : if (error != 0) {
707 0 : if (nfds > 0) {
708 0 : rp = ((struct fdpass *)CMSG_DATA(cm));
709 0 : unp_discard(rp, nfds);
710 0 : }
711 : goto out;
712 : }
713 :
714 : /*
715 : * First loop -- allocate file descriptor table slots for the
716 : * new descriptors.
717 : */
718 0 : rp = ((struct fdpass *)CMSG_DATA(cm));
719 0 : for (i = 0; i < nfds; i++) {
720 0 : if ((error = fdalloc(p, 0, &fds[i])) != 0) {
721 : /*
722 : * Back out what we've done so far.
723 : */
724 0 : for (--i; i >= 0; i--)
725 0 : fdremove(fdp, fds[i]);
726 :
727 0 : if (error == ENOSPC) {
728 0 : fdexpand(p);
729 : error = 0;
730 0 : } else {
731 : /*
732 : * This is the error that has historically
733 : * been returned, and some callers may
734 : * expect it.
735 : */
736 : error = EMSGSIZE;
737 : }
738 0 : fdpunlock(fdp);
739 0 : goto restart;
740 : }
741 :
742 : /*
743 : * Make the slot reference the descriptor so that
744 : * fdalloc() works properly.. We finalize it all
745 : * in the loop below.
746 : */
747 0 : mtx_enter(&fdp->fd_fplock);
748 0 : KASSERT(fdp->fd_ofiles[fds[i]] == NULL);
749 0 : fdp->fd_ofiles[fds[i]] = rp->fp;
750 0 : mtx_leave(&fdp->fd_fplock);
751 :
752 0 : fdp->fd_ofileflags[fds[i]] = (rp->flags & UF_PLEDGED);
753 0 : if (flags & MSG_CMSG_CLOEXEC)
754 0 : fdp->fd_ofileflags[fds[i]] |= UF_EXCLOSE;
755 :
756 0 : rp++;
757 : }
758 :
759 : /*
760 : * Now that adding them has succeeded, update all of the
761 : * descriptor passing state.
762 : */
763 : rp = (struct fdpass *)CMSG_DATA(cm);
764 0 : for (i = 0; i < nfds; i++) {
765 : struct unpcb *unp;
766 :
767 0 : fp = rp->fp;
768 0 : rp++;
769 0 : if ((unp = fptounp(fp)) != NULL)
770 0 : unp->unp_msgcount--;
771 0 : unp_rights--;
772 : }
773 :
774 : /*
775 : * Copy temporary array to message and adjust length, in case of
776 : * transition from large struct file pointers to ints.
777 : */
778 0 : memcpy(CMSG_DATA(cm), fds, nfds * sizeof(int));
779 0 : cm->cmsg_len = CMSG_LEN(nfds * sizeof(int));
780 0 : rights->m_len = CMSG_LEN(nfds * sizeof(int));
781 : out:
782 0 : fdpunlock(fdp);
783 0 : if (fds != NULL)
784 0 : free(fds, M_TEMP, nfds * sizeof(int));
785 0 : return (error);
786 : }
787 :
788 : int
789 0 : unp_internalize(struct mbuf *control, struct proc *p)
790 : {
791 0 : struct filedesc *fdp = p->p_fd;
792 0 : struct cmsghdr *cm = mtod(control, struct cmsghdr *);
793 : struct fdpass *rp;
794 : struct file *fp;
795 : struct unpcb *unp;
796 : int i, error;
797 : int nfds, *ip, fd, neededspace;
798 :
799 : /*
800 : * Check for two potential msg_controllen values because
801 : * IETF stuck their nose in a place it does not belong.
802 : */
803 0 : if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
804 0 : !(cm->cmsg_len == control->m_len ||
805 0 : control->m_len == CMSG_ALIGN(cm->cmsg_len)))
806 0 : return (EINVAL);
807 0 : nfds = (cm->cmsg_len - CMSG_ALIGN(sizeof(*cm))) / sizeof (int);
808 :
809 0 : if (unp_rights + nfds > maxfiles / 10)
810 0 : return (EMFILE);
811 :
812 : /* Make sure we have room for the struct file pointers */
813 : morespace:
814 0 : neededspace = CMSG_SPACE(nfds * sizeof(struct fdpass)) -
815 0 : control->m_len;
816 0 : if (neededspace > M_TRAILINGSPACE(control)) {
817 : char *tmp;
818 : /* if we already have a cluster, the message is just too big */
819 0 : if (control->m_flags & M_EXT)
820 0 : return (E2BIG);
821 :
822 : /* copy cmsg data temporarily out of the mbuf */
823 0 : tmp = malloc(control->m_len, M_TEMP, M_WAITOK);
824 0 : memcpy(tmp, mtod(control, caddr_t), control->m_len);
825 :
826 : /* allocate a cluster and try again */
827 0 : MCLGET(control, M_WAIT);
828 0 : if ((control->m_flags & M_EXT) == 0) {
829 0 : free(tmp, M_TEMP, control->m_len);
830 0 : return (ENOBUFS); /* allocation failed */
831 : }
832 :
833 : /* copy the data back into the cluster */
834 0 : cm = mtod(control, struct cmsghdr *);
835 0 : memcpy(cm, tmp, control->m_len);
836 0 : free(tmp, M_TEMP, control->m_len);
837 0 : goto morespace;
838 : }
839 :
840 : /* adjust message & mbuf to note amount of space actually used. */
841 0 : cm->cmsg_len = CMSG_LEN(nfds * sizeof(struct fdpass));
842 0 : control->m_len = CMSG_SPACE(nfds * sizeof(struct fdpass));
843 :
844 0 : ip = ((int *)CMSG_DATA(cm)) + nfds - 1;
845 0 : rp = ((struct fdpass *)CMSG_DATA(cm)) + nfds - 1;
846 0 : fdplock(fdp);
847 0 : for (i = 0; i < nfds; i++) {
848 0 : memcpy(&fd, ip, sizeof fd);
849 0 : ip--;
850 0 : if ((fp = fd_getfile(fdp, fd)) == NULL) {
851 : error = EBADF;
852 0 : goto fail;
853 : }
854 0 : if (fp->f_count >= FDUP_MAX_COUNT) {
855 : error = EDEADLK;
856 0 : goto fail;
857 : }
858 0 : error = pledge_sendfd(p, fp);
859 0 : if (error)
860 : goto fail;
861 :
862 : /* kqueue descriptors cannot be copied */
863 0 : if (fp->f_type == DTYPE_KQUEUE) {
864 : error = EINVAL;
865 0 : goto fail;
866 : }
867 0 : rp->fp = fp;
868 0 : rp->flags = fdp->fd_ofileflags[fd] & UF_PLEDGED;
869 0 : rp--;
870 0 : if ((unp = fptounp(fp)) != NULL) {
871 0 : unp->unp_file = fp;
872 0 : unp->unp_msgcount++;
873 0 : }
874 0 : unp_rights++;
875 : }
876 0 : fdpunlock(fdp);
877 0 : return (0);
878 : fail:
879 0 : fdpunlock(fdp);
880 0 : if (fp != NULL)
881 0 : FRELE(fp, p);
882 : /* Back out what we just did. */
883 0 : for ( ; i > 0; i--) {
884 0 : rp++;
885 0 : fp = rp->fp;
886 0 : if ((unp = fptounp(fp)) != NULL)
887 0 : unp->unp_msgcount--;
888 0 : FRELE(fp, p);
889 0 : unp_rights--;
890 : }
891 :
892 0 : return (error);
893 0 : }
894 :
895 : int unp_defer, unp_gcing;
896 :
897 : void
898 0 : unp_gc(void *arg __unused)
899 : {
900 : struct unp_deferral *defer;
901 : struct file *fp;
902 : struct socket *so;
903 : struct unpcb *unp;
904 : int nunref, i;
905 :
906 0 : if (unp_gcing)
907 0 : return;
908 0 : unp_gcing = 1;
909 :
910 : /* close any fds on the deferred list */
911 0 : while ((defer = SLIST_FIRST(&unp_deferred)) != NULL) {
912 0 : SLIST_REMOVE_HEAD(&unp_deferred, ud_link);
913 0 : for (i = 0; i < defer->ud_n; i++) {
914 0 : fp = defer->ud_fp[i].fp;
915 0 : if (fp == NULL)
916 : continue;
917 : /* closef() expects a refcount of 2 */
918 0 : FREF(fp);
919 0 : if ((unp = fptounp(fp)) != NULL)
920 0 : unp->unp_msgcount--;
921 0 : unp_rights--;
922 0 : (void) closef(fp, NULL);
923 0 : }
924 0 : free(defer, M_TEMP, sizeof(*defer) +
925 0 : sizeof(struct fdpass) * defer->ud_n);
926 : }
927 :
928 0 : unp_defer = 0;
929 0 : LIST_FOREACH(unp, &unp_head, unp_link)
930 0 : unp->unp_flags &= ~(UNP_GCMARK | UNP_GCDEFER | UNP_GCDEAD);
931 0 : do {
932 : nunref = 0;
933 0 : LIST_FOREACH(unp, &unp_head, unp_link) {
934 0 : fp = unp->unp_file;
935 0 : if (unp->unp_flags & UNP_GCDEFER) {
936 : /*
937 : * This socket is referenced by another
938 : * socket which is known to be live,
939 : * so it's certainly live.
940 : */
941 0 : unp->unp_flags &= ~UNP_GCDEFER;
942 0 : unp_defer--;
943 0 : } else if (unp->unp_flags & UNP_GCMARK) {
944 : /* marked as live in previous pass */
945 : continue;
946 0 : } else if (fp == NULL) {
947 : /* not being passed, so can't be in loop */
948 0 : } else if (fp->f_count == 0) {
949 : /*
950 : * Already being closed, let normal close
951 : * path take its course
952 : */
953 : } else {
954 : /*
955 : * Unreferenced by other sockets so far,
956 : * so if all the references (f_count) are
957 : * from passing (unp_msgcount) then this
958 : * socket is prospectively dead
959 : */
960 0 : if (fp->f_count == unp->unp_msgcount) {
961 0 : nunref++;
962 0 : unp->unp_flags |= UNP_GCDEAD;
963 0 : continue;
964 : }
965 : }
966 :
967 : /*
968 : * This is the first time we've seen this socket on
969 : * the mark pass and known it has a live reference,
970 : * so mark it, then scan its receive buffer for
971 : * sockets and note them as deferred (== referenced,
972 : * but not yet marked).
973 : */
974 0 : unp->unp_flags |= UNP_GCMARK;
975 :
976 0 : so = unp->unp_socket;
977 0 : unp_scan(so->so_rcv.sb_mb, unp_mark);
978 0 : }
979 0 : } while (unp_defer);
980 :
981 : /*
982 : * If there are any unreferenced sockets, then for each dispose
983 : * of files in its receive buffer and then close it.
984 : */
985 0 : if (nunref) {
986 0 : LIST_FOREACH(unp, &unp_head, unp_link) {
987 0 : if (unp->unp_flags & UNP_GCDEAD)
988 0 : unp_scan(unp->unp_socket->so_rcv.sb_mb,
989 : unp_discard);
990 : }
991 : }
992 0 : unp_gcing = 0;
993 0 : }
994 :
995 : void
996 0 : unp_dispose(struct mbuf *m)
997 : {
998 :
999 0 : if (m)
1000 0 : unp_scan(m, unp_discard);
1001 0 : }
1002 :
1003 : void
1004 0 : unp_scan(struct mbuf *m0, void (*op)(struct fdpass *, int))
1005 : {
1006 : struct mbuf *m;
1007 : struct fdpass *rp;
1008 : struct cmsghdr *cm;
1009 : int qfds;
1010 :
1011 0 : while (m0) {
1012 0 : for (m = m0; m; m = m->m_next) {
1013 0 : if (m->m_type == MT_CONTROL &&
1014 0 : m->m_len >= sizeof(*cm)) {
1015 0 : cm = mtod(m, struct cmsghdr *);
1016 0 : if (cm->cmsg_level != SOL_SOCKET ||
1017 0 : cm->cmsg_type != SCM_RIGHTS)
1018 : continue;
1019 0 : qfds = (cm->cmsg_len - CMSG_ALIGN(sizeof *cm))
1020 0 : / sizeof(struct fdpass);
1021 0 : if (qfds > 0) {
1022 0 : rp = (struct fdpass *)CMSG_DATA(cm);
1023 0 : op(rp, qfds);
1024 0 : }
1025 : break; /* XXX, but saves time */
1026 : }
1027 : }
1028 0 : m0 = m0->m_nextpkt;
1029 : }
1030 0 : }
1031 :
1032 : void
1033 0 : unp_mark(struct fdpass *rp, int nfds)
1034 : {
1035 : struct unpcb *unp;
1036 : int i;
1037 :
1038 0 : for (i = 0; i < nfds; i++) {
1039 0 : if (rp[i].fp == NULL)
1040 : continue;
1041 :
1042 0 : unp = fptounp(rp[i].fp);
1043 0 : if (unp == NULL)
1044 : continue;
1045 :
1046 0 : if (unp->unp_flags & (UNP_GCMARK|UNP_GCDEFER))
1047 : continue;
1048 :
1049 0 : unp_defer++;
1050 0 : unp->unp_flags |= UNP_GCDEFER;
1051 0 : unp->unp_flags &= ~UNP_GCDEAD;
1052 0 : }
1053 0 : }
1054 :
1055 : void
1056 0 : unp_discard(struct fdpass *rp, int nfds)
1057 : {
1058 : struct unp_deferral *defer;
1059 :
1060 : /* copy the file pointers to a deferral structure */
1061 0 : defer = malloc(sizeof(*defer) + sizeof(*rp) * nfds, M_TEMP, M_WAITOK);
1062 0 : defer->ud_n = nfds;
1063 0 : memcpy(&defer->ud_fp[0], rp, sizeof(*rp) * nfds);
1064 0 : memset(rp, 0, sizeof(*rp) * nfds);
1065 0 : SLIST_INSERT_HEAD(&unp_deferred, defer, ud_link);
1066 :
1067 0 : task_add(systq, &unp_gc_task);
1068 0 : }
1069 :
1070 : int
1071 0 : unp_nam2sun(struct mbuf *nam, struct sockaddr_un **sun, size_t *pathlen)
1072 : {
1073 0 : struct sockaddr *sa = mtod(nam, struct sockaddr *);
1074 : size_t size, len;
1075 :
1076 0 : if (nam->m_len < offsetof(struct sockaddr, sa_data))
1077 0 : return EINVAL;
1078 0 : if (sa->sa_family != AF_UNIX)
1079 0 : return EAFNOSUPPORT;
1080 0 : if (sa->sa_len != nam->m_len)
1081 0 : return EINVAL;
1082 0 : if (sa->sa_len > sizeof(struct sockaddr_un))
1083 0 : return EINVAL;
1084 0 : *sun = (struct sockaddr_un *)sa;
1085 :
1086 : /* ensure that sun_path is NUL terminated and fits */
1087 0 : size = (*sun)->sun_len - offsetof(struct sockaddr_un, sun_path);
1088 0 : len = strnlen((*sun)->sun_path, size);
1089 0 : if (len == sizeof((*sun)->sun_path))
1090 0 : return EINVAL;
1091 0 : if (len == size) {
1092 0 : if (M_TRAILINGSPACE(nam) == 0)
1093 0 : return EINVAL;
1094 0 : nam->m_len++;
1095 0 : (*sun)->sun_len++;
1096 0 : (*sun)->sun_path[len] = '\0';
1097 0 : }
1098 0 : if (pathlen != NULL)
1099 0 : *pathlen = len;
1100 :
1101 0 : return 0;
1102 0 : }
|