diff --git a/lib/libc/sys/recv.2 b/lib/libc/sys/recv.2 index 74f275c7d68f..e0a1f04ce080 100644 --- a/lib/libc/sys/recv.2 +++ b/lib/libc/sys/recv.2 @@ -28,7 +28,7 @@ .\" @(#)recv.2 8.3 (Berkeley) 2/21/94 .\" $FreeBSD$ .\" -.Dd September 12, 2012 +.Dd March 19, 2013 .Dt RECV 2 .Os .Sh NAME @@ -121,11 +121,12 @@ argument to a function is formed by .Em or Ap ing one or more of the values: -.Bl -column ".Dv MSG_DONTWAIT" -offset indent +.Bl -column ".Dv MSG_CMSG_CLOEXEC" -offset indent .It Dv MSG_OOB Ta process out-of-band data .It Dv MSG_PEEK Ta peek at incoming message .It Dv MSG_WAITALL Ta wait for full request or error .It Dv MSG_DONTWAIT Ta do not block +.It Dv MSG_CMSG_CLOEXEC Ta set received fds close-on-exec .El .Pp The @@ -227,6 +228,10 @@ and .Fa cmsg_type set to .Dv SCM_RIGHTS . +The close-on-exec flag on received descriptors is set according to the +.Dv MSG_CMSG_CLOEXEC +flag passed to +.Fn recvmsg . .Pp Process credentials can also be passed as ancillary data for .Dv AF_UNIX diff --git a/lib/libc/sys/socket.2 b/lib/libc/sys/socket.2 index 24e42936655e..74730be9bf36 100644 --- a/lib/libc/sys/socket.2 +++ b/lib/libc/sys/socket.2 @@ -28,7 +28,7 @@ .\" From: @(#)socket.2 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd December 7, 2012 +.Dd March 19, 2013 .Dt SOCKET 2 .Os .Sh NAME @@ -115,6 +115,15 @@ which is available only to the super-user, and which is planned, but not yet implemented, are not described here. .Pp +Additionally, the following flags are allowed in the +.Fa type +argument: +.Pp +.Bd -literal -offset indent -compact +SOCK_CLOEXEC Set close-on-exec on the new descriptor, +SOCK_NONBLOCK Set non-blocking mode on the new socket +.Ed +.Pp The .Fa protocol argument diff --git a/lib/libc/sys/socketpair.2 b/lib/libc/sys/socketpair.2 index c86db43f7ae6..08d00d3c0e5f 100644 --- a/lib/libc/sys/socketpair.2 +++ b/lib/libc/sys/socketpair.2 @@ -28,7 +28,7 @@ .\" @(#)socketpair.2 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd June 4, 1993 +.Dd March 19, 2013 .Dt SOCKETPAIR 2 .Os .Sh NAME @@ -57,6 +57,14 @@ are returned in and .Fa sv Ns [1] . The two sockets are indistinguishable. +.Pp +The +.Dv SOCK_CLOEXEC +and +.Dv SOCK_NONBLOCK +flags in the +.Fa type +argument apply to both descriptors. .Sh RETURN VALUES .Rv -std socketpair .Sh ERRORS @@ -79,6 +87,7 @@ process address space. .Sh SEE ALSO .Xr pipe 2 , .Xr read 2 , +.Xr socket 2 , .Xr write 2 .Sh HISTORY The diff --git a/share/man/man4/unix.4 b/share/man/man4/unix.4 index 363f185349b3..c53cc4267173 100644 --- a/share/man/man4/unix.4 +++ b/share/man/man4/unix.4 @@ -32,7 +32,7 @@ .\" @(#)unix.4 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd November 16, 2012 +.Dd March 19, 2013 .Dt UNIX 4 .Os .Sh NAME @@ -153,13 +153,15 @@ plus the size of the array of file descriptors. .Pp The received descriptor is a .Em duplicate -of the sender's descriptor, as if it were created with a call to -.Xr dup 2 . -Per-process descriptor flags, set with -.Xr fcntl 2 , -are -.Em not -passed to a receiver. +of the sender's descriptor, as if it were created via +.Li dup(fd) +or +.Li fcntl(fd, F_DUPFD_CLOEXEC, 0) +depending on whether +.Dv MSG_CMSG_CLOEXEC +is passed in the +.Xr recvmsg 2 +call. Descriptors that are awaiting delivery, or that are purposely not received, are automatically closed by the system when the destination socket is closed. diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index aa5448c29f49..bce61e5bfb9b 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1727,7 +1727,7 @@ soreceive_generic(struct socket *so, struct sockaddr **psa, struct uio *uio, SOCKBUF_UNLOCK(&so->so_rcv); VNET_SO_ASSERT(so); error = (*pr->pr_domain->dom_externalize) - (cm, controlp); + (cm, controlp, flags); SOCKBUF_LOCK(&so->so_rcv); } else if (controlp != NULL) *controlp = cm; @@ -2361,7 +2361,7 @@ soreceive_dgram(struct socket *so, struct sockaddr **psa, struct uio *uio, cm->m_next = NULL; if (pr->pr_domain->dom_externalize != NULL) { error = (*pr->pr_domain->dom_externalize) - (cm, controlp); + (cm, controlp, flags); } else if (controlp != NULL) *controlp = cm; else diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 3a2f0329f537..42a1ff1763c6 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -164,25 +164,40 @@ sys_socket(td, uap) { struct socket *so; struct file *fp; - int fd, error; + int fd, error, type, oflag, fflag; AUDIT_ARG_SOCKET(uap->domain, uap->type, uap->protocol); + + type = uap->type; + oflag = 0; + fflag = 0; + if ((type & SOCK_CLOEXEC) != 0) { + type &= ~SOCK_CLOEXEC; + oflag |= O_CLOEXEC; + } + if ((type & SOCK_NONBLOCK) != 0) { + type &= ~SOCK_NONBLOCK; + fflag |= FNONBLOCK; + } + #ifdef MAC - error = mac_socket_check_create(td->td_ucred, uap->domain, uap->type, + error = mac_socket_check_create(td->td_ucred, uap->domain, type, uap->protocol); if (error) return (error); #endif - error = falloc(td, &fp, &fd, 0); + error = falloc(td, &fp, &fd, oflag); if (error) return (error); /* An extra reference on `fp' has been held for us by falloc(). */ - error = socreate(uap->domain, &so, uap->type, uap->protocol, + error = socreate(uap->domain, &so, type, uap->protocol, td->td_ucred, td); if (error) { fdclose(td->td_proc->p_fd, fp, fd, td); } else { - finit(fp, FREAD | FWRITE, DTYPE_SOCKET, so, &socketops); + finit(fp, FREAD | FWRITE | fflag, DTYPE_SOCKET, so, &socketops); + if ((fflag & FNONBLOCK) != 0) + (void) fo_ioctl(fp, FIONBIO, &fflag, td->td_ucred, td); td->td_retval[0] = fd; } fdrop(fp, td); @@ -648,9 +663,20 @@ kern_socketpair(struct thread *td, int domain, int type, int protocol, struct filedesc *fdp = td->td_proc->p_fd; struct file *fp1, *fp2; struct socket *so1, *so2; - int fd, error; + int fd, error, oflag, fflag; AUDIT_ARG_SOCKET(domain, type, protocol); + + oflag = 0; + fflag = 0; + if ((type & SOCK_CLOEXEC) != 0) { + type &= ~SOCK_CLOEXEC; + oflag |= O_CLOEXEC; + } + if ((type & SOCK_NONBLOCK) != 0) { + type &= ~SOCK_NONBLOCK; + fflag |= FNONBLOCK; + } #ifdef MAC /* We might want to have a separate check for socket pairs. */ error = mac_socket_check_create(td->td_ucred, domain, type, @@ -665,12 +691,12 @@ kern_socketpair(struct thread *td, int domain, int type, int protocol, if (error) goto free1; /* On success extra reference to `fp1' and 'fp2' is set by falloc. */ - error = falloc(td, &fp1, &fd, 0); + error = falloc(td, &fp1, &fd, oflag); if (error) goto free2; rsv[0] = fd; fp1->f_data = so1; /* so1 already has ref count */ - error = falloc(td, &fp2, &fd, 0); + error = falloc(td, &fp2, &fd, oflag); if (error) goto free3; fp2->f_data = so2; /* so2 already has ref count */ @@ -686,8 +712,14 @@ kern_socketpair(struct thread *td, int domain, int type, int protocol, if (error) goto free4; } - finit(fp1, FREAD | FWRITE, DTYPE_SOCKET, fp1->f_data, &socketops); - finit(fp2, FREAD | FWRITE, DTYPE_SOCKET, fp2->f_data, &socketops); + finit(fp1, FREAD | FWRITE | fflag, DTYPE_SOCKET, fp1->f_data, + &socketops); + finit(fp2, FREAD | FWRITE | fflag, DTYPE_SOCKET, fp2->f_data, + &socketops); + if ((fflag & FNONBLOCK) != 0) { + (void) fo_ioctl(fp1, FIONBIO, &fflag, td->td_ucred, td); + (void) fo_ioctl(fp2, FIONBIO, &fflag, td->td_ucred, td); + } fdrop(fp1, td); fdrop(fp2, td); return (0); diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 2ec83c50d09e..9b60eab9ec77 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -288,7 +288,7 @@ static void unp_freerights(struct filedescent **, int); static void unp_init(void); static int unp_internalize(struct mbuf **, struct thread *); static void unp_internalize_fp(struct file *); -static int unp_externalize(struct mbuf *, struct mbuf **); +static int unp_externalize(struct mbuf *, struct mbuf **, int); static int unp_externalize_fp(struct file *); static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *); static void unp_process_defers(void * __unused, int); @@ -1695,7 +1695,7 @@ unp_freerights(struct filedescent **fdep, int fdcount) } static int -unp_externalize(struct mbuf *control, struct mbuf **controlp) +unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags) { struct thread *td = curthread; /* XXX */ struct cmsghdr *cm = mtod(control, struct cmsghdr *); @@ -1765,6 +1765,8 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp) fde->fde_file = fdep[0]->fde_file; filecaps_move(&fdep[0]->fde_caps, &fde->fde_caps); + if ((flags & MSG_CMSG_CLOEXEC) != 0) + fde->fde_flags |= UF_EXCLOSE; unp_externalize_fp(fde->fde_file); *fdp = f; } diff --git a/sys/sys/domain.h b/sys/sys/domain.h index 2563cb6e05c2..30e42491b15a 100644 --- a/sys/sys/domain.h +++ b/sys/sys/domain.h @@ -51,7 +51,7 @@ struct domain { void (*dom_destroy) /* cleanup structures / state */ (void); int (*dom_externalize) /* externalize access rights */ - (struct mbuf *, struct mbuf **); + (struct mbuf *, struct mbuf **, int); void (*dom_dispose) /* dispose of internalized rights */ (struct mbuf *); struct protosw *dom_protosw, *dom_protoswNPROTOSW; diff --git a/sys/sys/socket.h b/sys/sys/socket.h index 632dae4bc88c..56101b717158 100644 --- a/sys/sys/socket.h +++ b/sys/sys/socket.h @@ -95,6 +95,14 @@ typedef __uid_t uid_t; #endif #define SOCK_SEQPACKET 5 /* sequenced packet stream */ +#if __BSD_VISIBLE +/* + * Creation flags, OR'ed into socket() and socketpair() type argument. + */ +#define SOCK_CLOEXEC 0x10000000 +#define SOCK_NONBLOCK 0x20000000 +#endif + /* * Option flags per-socket. */ @@ -459,6 +467,7 @@ struct msghdr { #endif #if __BSD_VISIBLE #define MSG_NOSIGNAL 0x20000 /* do not generate SIGPIPE on EOF */ +#define MSG_CMSG_CLOEXEC 0x40000 /* make received fds close-on-exec */ #endif /*