Skip to content

Commit

Permalink
Implement SOCK_CLOEXEC, SOCK_NONBLOCK and MSG_CMSG_CLOEXEC.
Browse files Browse the repository at this point in the history
This change allows creating file descriptors with close-on-exec set in some
situations. SOCK_CLOEXEC and SOCK_NONBLOCK can be OR'ed in socket() and
socketpair()'s type parameter, and MSG_CMSG_CLOEXEC to recvmsg() makes file
descriptors (SCM_RIGHTS) atomically close-on-exec.

The numerical values for SOCK_CLOEXEC and SOCK_NONBLOCK are as in NetBSD.
MSG_CMSG_CLOEXEC is the first free bit for MSG_*.

The SOCK_* flags are not passed to MAC because this may cause incorrect
failures and can be done later via fcntl() anyway. On the other hand, audit
is expected to cope with the new flags.

For MSG_CMSG_CLOEXEC, unp_externalize() is extended to take a flags
argument.

Reviewed by:	kib
  • Loading branch information
jillest committed Mar 19, 2013
1 parent 30ce276 commit c9066bd
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 27 deletions.
9 changes: 7 additions & 2 deletions lib/libc/sys/recv.2
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
11 changes: 10 additions & 1 deletion lib/libc/sys/socket.2
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
11 changes: 10 additions & 1 deletion lib/libc/sys/socketpair.2
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
18 changes: 10 additions & 8 deletions share/man/man4/unix.4
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions sys/kern/uipc_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
52 changes: 42 additions & 10 deletions sys/kern/uipc_syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand All @@ -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 */
Expand All @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions sys/kern/uipc_usrreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 *);
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion sys/sys/domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions sys/sys/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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

/*
Expand Down

0 comments on commit c9066bd

Please sign in to comment.