Implement SOCK_CLOEXEC, SOCK_NONBLOCK and MSG_CMSG_CLOEXEC.
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
This commit is contained in:
parent
f0db652cf6
commit
c2e3c52e0d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=248534
@ -28,7 +28,7 @@
|
|||||||
.\" @(#)recv.2 8.3 (Berkeley) 2/21/94
|
.\" @(#)recv.2 8.3 (Berkeley) 2/21/94
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd September 12, 2012
|
.Dd March 19, 2013
|
||||||
.Dt RECV 2
|
.Dt RECV 2
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -121,11 +121,12 @@ argument to a
|
|||||||
function is formed by
|
function is formed by
|
||||||
.Em or Ap ing
|
.Em or Ap ing
|
||||||
one or more of the values:
|
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_OOB Ta process out-of-band data
|
||||||
.It Dv MSG_PEEK Ta peek at incoming message
|
.It Dv MSG_PEEK Ta peek at incoming message
|
||||||
.It Dv MSG_WAITALL Ta wait for full request or error
|
.It Dv MSG_WAITALL Ta wait for full request or error
|
||||||
.It Dv MSG_DONTWAIT Ta do not block
|
.It Dv MSG_DONTWAIT Ta do not block
|
||||||
|
.It Dv MSG_CMSG_CLOEXEC Ta set received fds close-on-exec
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The
|
The
|
||||||
@ -227,6 +228,10 @@ and
|
|||||||
.Fa cmsg_type
|
.Fa cmsg_type
|
||||||
set to
|
set to
|
||||||
.Dv SCM_RIGHTS .
|
.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
|
.Pp
|
||||||
Process credentials can also be passed as ancillary data for
|
Process credentials can also be passed as ancillary data for
|
||||||
.Dv AF_UNIX
|
.Dv AF_UNIX
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
.\" From: @(#)socket.2 8.1 (Berkeley) 6/4/93
|
.\" From: @(#)socket.2 8.1 (Berkeley) 6/4/93
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd December 7, 2012
|
.Dd March 19, 2013
|
||||||
.Dt SOCKET 2
|
.Dt SOCKET 2
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -115,6 +115,15 @@ which is available only to the super-user, and
|
|||||||
which is planned,
|
which is planned,
|
||||||
but not yet implemented, are not described here.
|
but not yet implemented, are not described here.
|
||||||
.Pp
|
.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
|
The
|
||||||
.Fa protocol
|
.Fa protocol
|
||||||
argument
|
argument
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
.\" @(#)socketpair.2 8.1 (Berkeley) 6/4/93
|
.\" @(#)socketpair.2 8.1 (Berkeley) 6/4/93
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd June 4, 1993
|
.Dd March 19, 2013
|
||||||
.Dt SOCKETPAIR 2
|
.Dt SOCKETPAIR 2
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -57,6 +57,14 @@ are returned in
|
|||||||
and
|
and
|
||||||
.Fa sv Ns [1] .
|
.Fa sv Ns [1] .
|
||||||
The two sockets are indistinguishable.
|
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
|
.Sh RETURN VALUES
|
||||||
.Rv -std socketpair
|
.Rv -std socketpair
|
||||||
.Sh ERRORS
|
.Sh ERRORS
|
||||||
@ -79,6 +87,7 @@ process address space.
|
|||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr pipe 2 ,
|
.Xr pipe 2 ,
|
||||||
.Xr read 2 ,
|
.Xr read 2 ,
|
||||||
|
.Xr socket 2 ,
|
||||||
.Xr write 2
|
.Xr write 2
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
The
|
The
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
.\" @(#)unix.4 8.1 (Berkeley) 6/9/93
|
.\" @(#)unix.4 8.1 (Berkeley) 6/9/93
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd November 16, 2012
|
.Dd March 19, 2013
|
||||||
.Dt UNIX 4
|
.Dt UNIX 4
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -153,13 +153,15 @@ plus the size of the array of file descriptors.
|
|||||||
.Pp
|
.Pp
|
||||||
The received descriptor is a
|
The received descriptor is a
|
||||||
.Em duplicate
|
.Em duplicate
|
||||||
of the sender's descriptor, as if it were created with a call to
|
of the sender's descriptor, as if it were created via
|
||||||
.Xr dup 2 .
|
.Li dup(fd)
|
||||||
Per-process descriptor flags, set with
|
or
|
||||||
.Xr fcntl 2 ,
|
.Li fcntl(fd, F_DUPFD_CLOEXEC, 0)
|
||||||
are
|
depending on whether
|
||||||
.Em not
|
.Dv MSG_CMSG_CLOEXEC
|
||||||
passed to a receiver.
|
is passed in the
|
||||||
|
.Xr recvmsg 2
|
||||||
|
call.
|
||||||
Descriptors that are awaiting delivery, or that are
|
Descriptors that are awaiting delivery, or that are
|
||||||
purposely not received, are automatically closed by the system
|
purposely not received, are automatically closed by the system
|
||||||
when the destination socket is closed.
|
when the destination socket is closed.
|
||||||
|
@ -1727,7 +1727,7 @@ soreceive_generic(struct socket *so, struct sockaddr **psa, struct uio *uio,
|
|||||||
SOCKBUF_UNLOCK(&so->so_rcv);
|
SOCKBUF_UNLOCK(&so->so_rcv);
|
||||||
VNET_SO_ASSERT(so);
|
VNET_SO_ASSERT(so);
|
||||||
error = (*pr->pr_domain->dom_externalize)
|
error = (*pr->pr_domain->dom_externalize)
|
||||||
(cm, controlp);
|
(cm, controlp, flags);
|
||||||
SOCKBUF_LOCK(&so->so_rcv);
|
SOCKBUF_LOCK(&so->so_rcv);
|
||||||
} else if (controlp != NULL)
|
} else if (controlp != NULL)
|
||||||
*controlp = cm;
|
*controlp = cm;
|
||||||
@ -2361,7 +2361,7 @@ soreceive_dgram(struct socket *so, struct sockaddr **psa, struct uio *uio,
|
|||||||
cm->m_next = NULL;
|
cm->m_next = NULL;
|
||||||
if (pr->pr_domain->dom_externalize != NULL) {
|
if (pr->pr_domain->dom_externalize != NULL) {
|
||||||
error = (*pr->pr_domain->dom_externalize)
|
error = (*pr->pr_domain->dom_externalize)
|
||||||
(cm, controlp);
|
(cm, controlp, flags);
|
||||||
} else if (controlp != NULL)
|
} else if (controlp != NULL)
|
||||||
*controlp = cm;
|
*controlp = cm;
|
||||||
else
|
else
|
||||||
|
@ -164,25 +164,40 @@ sys_socket(td, uap)
|
|||||||
{
|
{
|
||||||
struct socket *so;
|
struct socket *so;
|
||||||
struct file *fp;
|
struct file *fp;
|
||||||
int fd, error;
|
int fd, error, type, oflag, fflag;
|
||||||
|
|
||||||
AUDIT_ARG_SOCKET(uap->domain, uap->type, uap->protocol);
|
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
|
#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);
|
uap->protocol);
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
#endif
|
#endif
|
||||||
error = falloc(td, &fp, &fd, 0);
|
error = falloc(td, &fp, &fd, oflag);
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
/* An extra reference on `fp' has been held for us by falloc(). */
|
/* 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);
|
td->td_ucred, td);
|
||||||
if (error) {
|
if (error) {
|
||||||
fdclose(td->td_proc->p_fd, fp, fd, td);
|
fdclose(td->td_proc->p_fd, fp, fd, td);
|
||||||
} else {
|
} 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;
|
td->td_retval[0] = fd;
|
||||||
}
|
}
|
||||||
fdrop(fp, td);
|
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 filedesc *fdp = td->td_proc->p_fd;
|
||||||
struct file *fp1, *fp2;
|
struct file *fp1, *fp2;
|
||||||
struct socket *so1, *so2;
|
struct socket *so1, *so2;
|
||||||
int fd, error;
|
int fd, error, oflag, fflag;
|
||||||
|
|
||||||
AUDIT_ARG_SOCKET(domain, type, protocol);
|
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
|
#ifdef MAC
|
||||||
/* We might want to have a separate check for socket pairs. */
|
/* We might want to have a separate check for socket pairs. */
|
||||||
error = mac_socket_check_create(td->td_ucred, domain, type,
|
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)
|
if (error)
|
||||||
goto free1;
|
goto free1;
|
||||||
/* On success extra reference to `fp1' and 'fp2' is set by falloc. */
|
/* 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)
|
if (error)
|
||||||
goto free2;
|
goto free2;
|
||||||
rsv[0] = fd;
|
rsv[0] = fd;
|
||||||
fp1->f_data = so1; /* so1 already has ref count */
|
fp1->f_data = so1; /* so1 already has ref count */
|
||||||
error = falloc(td, &fp2, &fd, 0);
|
error = falloc(td, &fp2, &fd, oflag);
|
||||||
if (error)
|
if (error)
|
||||||
goto free3;
|
goto free3;
|
||||||
fp2->f_data = so2; /* so2 already has ref count */
|
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)
|
if (error)
|
||||||
goto free4;
|
goto free4;
|
||||||
}
|
}
|
||||||
finit(fp1, FREAD | FWRITE, DTYPE_SOCKET, fp1->f_data, &socketops);
|
finit(fp1, FREAD | FWRITE | fflag, DTYPE_SOCKET, fp1->f_data,
|
||||||
finit(fp2, FREAD | FWRITE, DTYPE_SOCKET, fp2->f_data, &socketops);
|
&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(fp1, td);
|
||||||
fdrop(fp2, td);
|
fdrop(fp2, td);
|
||||||
return (0);
|
return (0);
|
||||||
|
@ -288,7 +288,7 @@ static void unp_freerights(struct filedescent **, int);
|
|||||||
static void unp_init(void);
|
static void unp_init(void);
|
||||||
static int unp_internalize(struct mbuf **, struct thread *);
|
static int unp_internalize(struct mbuf **, struct thread *);
|
||||||
static void unp_internalize_fp(struct file *);
|
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 int unp_externalize_fp(struct file *);
|
||||||
static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *);
|
static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *);
|
||||||
static void unp_process_defers(void * __unused, int);
|
static void unp_process_defers(void * __unused, int);
|
||||||
@ -1695,7 +1695,7 @@ unp_freerights(struct filedescent **fdep, int fdcount)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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 thread *td = curthread; /* XXX */
|
||||||
struct cmsghdr *cm = mtod(control, struct cmsghdr *);
|
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;
|
fde->fde_file = fdep[0]->fde_file;
|
||||||
filecaps_move(&fdep[0]->fde_caps,
|
filecaps_move(&fdep[0]->fde_caps,
|
||||||
&fde->fde_caps);
|
&fde->fde_caps);
|
||||||
|
if ((flags & MSG_CMSG_CLOEXEC) != 0)
|
||||||
|
fde->fde_flags |= UF_EXCLOSE;
|
||||||
unp_externalize_fp(fde->fde_file);
|
unp_externalize_fp(fde->fde_file);
|
||||||
*fdp = f;
|
*fdp = f;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ struct domain {
|
|||||||
void (*dom_destroy) /* cleanup structures / state */
|
void (*dom_destroy) /* cleanup structures / state */
|
||||||
(void);
|
(void);
|
||||||
int (*dom_externalize) /* externalize access rights */
|
int (*dom_externalize) /* externalize access rights */
|
||||||
(struct mbuf *, struct mbuf **);
|
(struct mbuf *, struct mbuf **, int);
|
||||||
void (*dom_dispose) /* dispose of internalized rights */
|
void (*dom_dispose) /* dispose of internalized rights */
|
||||||
(struct mbuf *);
|
(struct mbuf *);
|
||||||
struct protosw *dom_protosw, *dom_protoswNPROTOSW;
|
struct protosw *dom_protosw, *dom_protoswNPROTOSW;
|
||||||
|
@ -95,6 +95,14 @@ typedef __uid_t uid_t;
|
|||||||
#endif
|
#endif
|
||||||
#define SOCK_SEQPACKET 5 /* sequenced packet stream */
|
#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.
|
* Option flags per-socket.
|
||||||
*/
|
*/
|
||||||
@ -459,6 +467,7 @@ struct msghdr {
|
|||||||
#endif
|
#endif
|
||||||
#if __BSD_VISIBLE
|
#if __BSD_VISIBLE
|
||||||
#define MSG_NOSIGNAL 0x20000 /* do not generate SIGPIPE on EOF */
|
#define MSG_NOSIGNAL 0x20000 /* do not generate SIGPIPE on EOF */
|
||||||
|
#define MSG_CMSG_CLOEXEC 0x40000 /* make received fds close-on-exec */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user