- Implement two new system calls:

int bindat(int fd, int s, const struct sockaddr *addr, socklen_t addrlen);
	int connectat(int fd, int s, const struct sockaddr *name, socklen_t namelen);

  which allow to bind and connect respectively to a UNIX domain socket with a
  path relative to the directory associated with the given file descriptor 'fd'.

- Add manual pages for the new syscalls.

- Make the new syscalls available for processes in capability mode sandbox.

- Add capability rights CAP_BINDAT and CAP_CONNECTAT that has to be present on
  the directory descriptor for the syscalls to work.

- Update audit(4) to support those two new syscalls and to handle path
  in sockaddr_un structure relative to the given directory descriptor.

- Update procstat(1) to recognize the new capability rights.

- Document the new capability rights in cap_rights_limit(2).

Sponsored by:	The FreeBSD Foundation
Discussed with:	rwatson, jilles, kib, des
This commit is contained in:
Pawel Jakub Dawidek 2013-03-02 21:11:30 +00:00
parent 136b1ada11
commit 7493f24ee6
22 changed files with 475 additions and 54 deletions

View File

@ -568,6 +568,8 @@
43204:AUE_CAP_IOCTLS_GET:cap_ioctls_get(2):fm
43205:AUE_CAP_FCNTLS_LIMIT:cap_fcntls_limit(2):fm
43206:AUE_CAP_FCNTLS_GET:cap_fcntls_get(2):fm
43207:AUE_BINDAT:bindat(2):nt
43208:AUE_CONNECTAT:connectat(2):nt
#
# Solaris userspace events.
#

View File

@ -91,6 +91,7 @@ MAN+= abort2.2 \
aio_waitcomplete.2 \
aio_write.2 \
bind.2 \
bindat.2 \
brk.2 \
cap_enter.2 \
cap_fcntls_limit.2 \
@ -105,6 +106,7 @@ MAN+= abort2.2 \
close.2 \
closefrom.2 \
connect.2 \
connectat.2 \
cpuset.2 \
cpuset_getaffinity.2 \
dup.2 \

View File

@ -378,6 +378,7 @@ FBSD_1.2 {
};
FBSD_1.3 {
bindat;
cap_fcntls_get;
cap_fcntls_limit;
cap_ioctls_get;
@ -386,6 +387,7 @@ FBSD_1.3 {
cap_rights_limit;
cap_sandboxed;
clock_getcpuclockid2;
connectat;
ffclock_getcounter;
ffclock_getestimate;
ffclock_setestimate;

109
lib/libc/sys/bindat.2 Normal file
View File

@ -0,0 +1,109 @@
.\" Copyright (c) 2013 The FreeBSD Foundation
.\" All rights reserved.
.\"
.\" This documentation was written by Pawel Jakub Dawidek under sponsorship from
.\" the FreeBSD Foundation.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd February 13, 2013
.Dt BINDAT 2
.Os
.Sh NAME
.Nm bindat
.Nd assign a local protocol address to a socket
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
.In sys/types.h
.In sys/socket.h
.Pp
.In fcntl.h
.Ft int
.Fn bindat "int fd" "int s" "const struct sockaddr *addr" "socklen_t addrlen"
.Sh DESCRIPTION
The
.Fn bindat
system call assigns the local protocol address to a socket.
It works just like the
.Xr bind 2
system call with two exceptions:
.Pp
.Bl -enum -offset indent -compact
.It
It is limited to sockets in the PF_LOCAL domain.
.Pp
.It
If the file path stored in the
.Fa sun_path
field of the sockaddr_un structure is a relative path, it is located relative
to the directory associated with the file descriptor
.Fa fd .
If
.Fn bindat
is passed the special value
.Dv AT_FDCWD
in the
.Fa fd
parameter, the current working directory is used and the behavior is identical
to a call to
.Xr bind 2 .
.El
.Sh RETURN VALUES
.Rv -std bindat
.Sh ERRORS
The
.Fn bindat
system call may fail with the same errors as the
.Xr bind 2
system call for a UNIX domain socket or with the following errors:
.Bl -tag -width Er
.It Bq Er EBADF
The
.Fa sun_path
field does not specify an absolute path and the
.Fa fd
argument is neither
.Dv AT_FDCWD
nor a valid file descriptor.
.It Bq Er ENOTDIR
The
.Fa sun_path
field is not an absolute path and
.Fa fd
is neither
.Dv AT_FDCWD
nor a file descriptor associated with a directory.
.El
.Sh SEE ALSO
.Xr bind 2 ,
.Xr connectat 2 ,
.Xr socket 2 ,
.Xr unix 4
.Sh AUTHORS
The
.Nm
was developed by
.An Pawel Jakub Dawidek Aq pawel@dawidek.net
under sponsorship from the FreeBSD Foundation.

View File

@ -104,12 +104,20 @@ or
and that socket options set with
.Xr setsockopt 2
may also affect binding behavior.
.It Dv CAP_BINDAT
Permit
.Xr bindat 2 .
This right has to be present on the directory descriptor.
.It Dv CAP_CONNECT
Permit
.Xr connect 2 ;
also required for
.Xr sendto 2
with a non-NULL destination address.
.It Dv CAP_CONNECTAT
Permit
.Xr connectat 2 .
This right has to be present on the directory descriptor.
.It Dv CAP_CREATE
Permit
.Xr openat 2
@ -511,11 +519,13 @@ argument points at an invalid address.
.Xr aio_read 2 ,
.Xr aio_write 2 ,
.Xr bind 2 ,
.Xr bindat 2 ,
.Xr cap_enter 2 ,
.Xr cap_fcntls_limit 2 ,
.Xr cap_ioctls_limit 2 ,
.Xr cap_rights_limit 2 ,
.Xr connect 2 ,
.Xr connectat 2 ,
.Xr dup 2 ,
.Xr dup2 2 ,
.Xr extattr_delete_fd 2 ,

109
lib/libc/sys/connectat.2 Normal file
View File

@ -0,0 +1,109 @@
.\" Copyright (c) 2013 The FreeBSD Foundation
.\" All rights reserved.
.\"
.\" This documentation was written by Pawel Jakub Dawidek under sponsorship from
.\" the FreeBSD Foundation.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd February 13, 2013
.Dt CONNECTAT 2
.Os
.Sh NAME
.Nm connectat
.Nd initiate a connection on a socket
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
.In sys/types.h
.In sys/socket.h
.Pp
.In fcntl.h
.Ft int
.Fn connectat "int fd" "int s" "const struct sockaddr *name" "socklen_t namelen"
.Sh DESCRIPTION
The
.Fn connectat
system call initiates a connection on a socket.
It works just like the
.Xr connect 2
system call with two exceptions:
.Pp
.Bl -enum -offset indent -compact
.It
It is limited to sockets in the PF_LOCAL domain.
.Pp
.It
If the file path stored in the
.Fa sun_path
field of the sockaddr_un structure is a relative path, it is located relative
to the directory associated with the file descriptor
.Fa fd .
If
.Fn connectat
is passed the special value
.Dv AT_FDCWD
in the
.Fa fd
parameter, the current working directory is used and the behavior is identical
to a call to
.Xr connect 2 .
.El
.Sh RETURN VALUES
.Rv -std connectat
.Sh ERRORS
The
.Fn connectat
system call may fail with the same errors as the
.Xr connect 2
system call for a UNIX domain socket or with the following errors:
.Bl -tag -width Er
.It Bq Er EBADF
The
.Fa sun_path
field does not specify an absolute path and the
.Fa fd
argument is neither
.Dv AT_FDCWD
nor a valid file descriptor.
.It Bq Er ENOTDIR
The
.Fa sun_path
field is not an absolute path and
.Fa fd
is neither
.Dv AT_FDCWD
nor a file descriptor associated with a directory.
.El
.Sh SEE ALSO
.Xr bindat 2 ,
.Xr connect 2 ,
.Xr socket 2 ,
.Xr unix 4
.Sh AUTHORS
The
.Nm
was developed by
.An Pawel Jakub Dawidek Aq pawel@dawidek.net
under sponsorship from the FreeBSD Foundation.

View File

@ -608,6 +608,8 @@
#define AUE_CAP_IOCTLS_GET 43204 /* TrustedBSD. */
#define AUE_CAP_FCNTLS_LIMIT 43205 /* TrustedBSD. */
#define AUE_CAP_FCNTLS_GET 43206 /* TrustedBSD. */
#define AUE_BINDAT 43207 /* TrustedBSD. */
#define AUE_CONNECTAT 43208 /* TrustedBSD. */
/*
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the

View File

@ -1015,3 +1015,7 @@
uint32_t fcntlrights); }
537 AUE_CAP_FCNTLS_GET NOPROTO { int cap_fcntls_get(int fd, \
uint32_t *fcntlrightsp); }
538 AUE_BINDAT NOPROTO { int bindat(int fd, int s, caddr_t name, \
int namelen); }
539 AUE_CONNECTAT NOPROTO { int connectat(int fd, int s, caddr_t name, \
int namelen); }

View File

@ -100,11 +100,9 @@ aio_write
#audit
##
## Disllow bind(2) for now, even though we support CAP_BIND.
## Allow bindat(2).
##
## XXXRW: Revisit this.
##
#bind
bindat
##
## Allow capability mode and capability system calls.
@ -132,11 +130,9 @@ close
closefrom
##
## Disallow connect(2) for now, despite CAP_CONNECT.
## Allow connectat(2).
##
## XXXRW: Revisit this.
##
#connect
connectat
##
## cpuset(2) and related calls require scoping by process, but should

View File

@ -965,5 +965,9 @@
uint32_t fcntlrights); }
537 AUE_CAP_FCNTLS_GET STD { int cap_fcntls_get(int fd, \
uint32_t *fcntlrightsp); }
538 AUE_BINDAT STD { int bindat(int fd, int s, caddr_t name, \
int namelen); }
539 AUE_CONNECTAT STD { int connectat(int fd, int s, caddr_t name, \
int namelen); }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master

View File

@ -136,8 +136,10 @@ protosw_init(struct protosw *pr)
#define DEFAULT(foo, bar) if ((foo) == NULL) (foo) = (bar)
DEFAULT(pu->pru_accept, pru_accept_notsupp);
DEFAULT(pu->pru_bind, pru_bind_notsupp);
DEFAULT(pu->pru_bindat, pru_bindat_notsupp);
DEFAULT(pu->pru_connect, pru_connect_notsupp);
DEFAULT(pu->pru_connect2, pru_connect2_notsupp);
DEFAULT(pu->pru_connectat, pru_connectat_notsupp);
DEFAULT(pu->pru_control, pru_control_notsupp);
DEFAULT(pu->pru_disconnect, pru_disconnect_notsupp);
DEFAULT(pu->pru_listen, pru_listen_notsupp);

View File

@ -615,7 +615,18 @@ sobind(struct socket *so, struct sockaddr *nam, struct thread *td)
CURVNET_SET(so->so_vnet);
error = (*so->so_proto->pr_usrreqs->pru_bind)(so, nam, td);
CURVNET_RESTORE();
return error;
return (error);
}
int
sobindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td)
{
int error;
CURVNET_SET(so->so_vnet);
error = (*so->so_proto->pr_usrreqs->pru_bindat)(fd, so, nam, td);
CURVNET_RESTORE();
return (error);
}
/*
@ -638,7 +649,7 @@ solisten(struct socket *so, int backlog, struct thread *td)
CURVNET_SET(so->so_vnet);
error = (*so->so_proto->pr_usrreqs->pru_listen)(so, backlog, td);
CURVNET_RESTORE();
return error;
return (error);
}
int
@ -895,6 +906,13 @@ soaccept(struct socket *so, struct sockaddr **nam)
int
soconnect(struct socket *so, struct sockaddr *nam, struct thread *td)
{
return (soconnectat(AT_FDCWD, so, nam, td));
}
int
soconnectat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td)
{
int error;
@ -917,7 +935,13 @@ soconnect(struct socket *so, struct sockaddr *nam, struct thread *td)
* biting us.
*/
so->so_error = 0;
error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, td);
if (fd == AT_FDCWD) {
error = (*so->so_proto->pr_usrreqs->pru_connect)(so,
nam, td);
} else {
error = (*so->so_proto->pr_usrreqs->pru_connectat)(fd,
so, nam, td);
}
}
CURVNET_RESTORE();
@ -3140,6 +3164,14 @@ pru_bind_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
return EOPNOTSUPP;
}
int
pru_bindat_notsupp(int fd, struct socket *so, struct sockaddr *nam,
struct thread *td)
{
return EOPNOTSUPP;
}
int
pru_connect_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
{
@ -3147,6 +3179,14 @@ pru_connect_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
return EOPNOTSUPP;
}
int
pru_connectat_notsupp(int fd, struct socket *so, struct sockaddr *nam,
struct thread *td)
{
return EOPNOTSUPP;
}
int
pru_connect2_notsupp(struct socket *so1, struct socket *so2)
{

View File

@ -201,26 +201,23 @@ sys_bind(td, uap)
struct sockaddr *sa;
int error;
if ((error = getsockaddr(&sa, uap->name, uap->namelen)) != 0)
return (error);
error = kern_bind(td, uap->s, sa);
free(sa, M_SONAME);
error = getsockaddr(&sa, uap->name, uap->namelen);
if (error == 0) {
error = kern_bind(td, uap->s, sa);
free(sa, M_SONAME);
}
return (error);
}
int
kern_bind(td, fd, sa)
struct thread *td;
int fd;
struct sockaddr *sa;
static int
kern_bindat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
{
struct socket *so;
struct file *fp;
int error;
AUDIT_ARG_FD(fd);
AUDIT_ARG_SOCKADDR(td, sa);
AUDIT_ARG_SOCKADDR(td, dirfd, sa);
error = getsock_cap(td->td_proc->p_fd, fd, CAP_BIND, &fp, NULL);
if (error)
return (error);
@ -231,13 +228,48 @@ kern_bind(td, fd, sa)
#endif
#ifdef MAC
error = mac_socket_check_bind(td->td_ucred, so, sa);
if (error == 0)
if (error == 0) {
#endif
if (dirfd == AT_FDCWD)
error = sobind(so, sa, td);
else
error = sobindat(dirfd, so, sa, td);
#ifdef MAC
}
#endif
error = sobind(so, sa, td);
fdrop(fp, td);
return (error);
}
int
kern_bind(struct thread *td, int fd, struct sockaddr *sa)
{
return (kern_bindat(td, AT_FDCWD, fd, sa));
}
/* ARGSUSED */
int
sys_bindat(td, uap)
struct thread *td;
struct bindat_args /* {
int fd;
int s;
caddr_t name;
int namelen;
} */ *uap;
{
struct sockaddr *sa;
int error;
error = getsockaddr(&sa, uap->name, uap->namelen);
if (error == 0) {
error = kern_bindat(td, uap->fd, uap->s, sa);
free(sa, M_SONAME);
}
return (error);
}
/* ARGSUSED */
int
sys_listen(td, uap)
@ -435,7 +467,7 @@ kern_accept(struct thread *td, int s, struct sockaddr **name,
*namelen = 0;
goto done;
}
AUDIT_ARG_SOCKADDR(td, sa);
AUDIT_ARG_SOCKADDR(td, AT_FDCWD, sa);
if (name) {
/* check sa_len before it is destroyed */
if (*namelen > sa->sa_len)
@ -510,20 +542,15 @@ sys_connect(td, uap)
int error;
error = getsockaddr(&sa, uap->name, uap->namelen);
if (error)
return (error);
error = kern_connect(td, uap->s, sa);
free(sa, M_SONAME);
if (error == 0) {
error = kern_connect(td, uap->s, sa);
free(sa, M_SONAME);
}
return (error);
}
int
kern_connect(td, fd, sa)
struct thread *td;
int fd;
struct sockaddr *sa;
static int
kern_connectat(struct thread *td, int dirfd, int fd, struct sockaddr *sa)
{
struct socket *so;
struct file *fp;
@ -531,7 +558,7 @@ kern_connect(td, fd, sa)
int interrupted = 0;
AUDIT_ARG_FD(fd);
AUDIT_ARG_SOCKADDR(td, sa);
AUDIT_ARG_SOCKADDR(td, dirfd, sa);
error = getsock_cap(td->td_proc->p_fd, fd, CAP_CONNECT, &fp, NULL);
if (error)
return (error);
@ -549,7 +576,10 @@ kern_connect(td, fd, sa)
if (error)
goto bad;
#endif
error = soconnect(so, sa, td);
if (dirfd == AT_FDCWD)
error = soconnect(so, sa, td);
else
error = soconnectat(dirfd, so, sa, td);
if (error)
goto bad;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
@ -581,6 +611,35 @@ kern_connect(td, fd, sa)
return (error);
}
int
kern_connect(struct thread *td, int fd, struct sockaddr *sa)
{
return (kern_connectat(td, AT_FDCWD, fd, sa));
}
/* ARGSUSED */
int
sys_connectat(td, uap)
struct thread *td;
struct connectat_args /* {
int fd;
int s;
caddr_t name;
int namelen;
} */ *uap;
{
struct sockaddr *sa;
int error;
error = getsockaddr(&sa, uap->name, uap->namelen);
if (error == 0) {
error = kern_connectat(td, uap->fd, uap->s, sa);
free(sa, M_SONAME);
}
return (error);
}
int
kern_socketpair(struct thread *td, int domain, int type, int protocol,
int *rsv)
@ -749,7 +808,7 @@ kern_sendit(td, s, mp, flags, control, segflg)
AUDIT_ARG_FD(s);
rights = CAP_SEND;
if (mp->msg_name != NULL) {
AUDIT_ARG_SOCKADDR(td, mp->msg_name);
AUDIT_ARG_SOCKADDR(td, AT_FDCWD, mp->msg_name);
rights |= CAP_CONNECT;
}
error = getsock_cap(td->td_proc->p_fd, s, rights, &fp, NULL);
@ -997,7 +1056,7 @@ kern_recvit(td, s, mp, fromseg, controlp)
error = 0;
}
if (fromsa != NULL)
AUDIT_ARG_SOCKADDR(td, fromsa);
AUDIT_ARG_SOCKADDR(td, AT_FDCWD, fromsa);
#ifdef KTRACE
if (ktruio != NULL) {
ktruio->uio_resid = len - auio.uio_resid;

View File

@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include "opt_ddb.h"
#include <sys/param.h>
#include <sys/capability.h>
#include <sys/domain.h>
#include <sys/fcntl.h>
#include <sys/malloc.h> /* XXX must be before <sys/file.h> */
@ -271,6 +272,8 @@ static int uipc_connect2(struct socket *, struct socket *);
static int uipc_ctloutput(struct socket *, struct sockopt *);
static int unp_connect(struct socket *, struct sockaddr *,
struct thread *);
static int unp_connectat(int, struct socket *, struct sockaddr *,
struct thread *);
static int unp_connect2(struct socket *so, struct socket *so2, int);
static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2);
static void unp_dispose(struct mbuf *);
@ -450,7 +453,7 @@ uipc_attach(struct socket *so, int proto, struct thread *td)
}
static int
uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
uipc_bindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td)
{
struct sockaddr_un *soun = (struct sockaddr_un *)nam;
struct vattr vattr;
@ -496,8 +499,8 @@ uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
buf[namelen] = 0;
restart:
NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT | SAVENAME,
UIO_SYSSPACE, buf, td);
NDINIT_ATRIGHTS(&nd, CREATE, NOFOLLOW | LOCKPARENT | SAVENAME,
UIO_SYSSPACE, buf, fd, CAP_BINDAT, td);
/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
error = namei(&nd);
if (error)
@ -559,6 +562,13 @@ uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
return (error);
}
static int
uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
{
return (uipc_bindat(AT_FDCWD, so, nam, td));
}
static int
uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
{
@ -571,6 +581,19 @@ uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
return (error);
}
static int
uipc_connectat(int fd, struct socket *so, struct sockaddr *nam,
struct thread *td)
{
int error;
KASSERT(td == curthread, ("uipc_connectat: td != curthread"));
UNP_LINK_WLOCK();
error = unp_connectat(fd, so, nam, td);
UNP_LINK_WUNLOCK();
return (error);
}
static void
uipc_close(struct socket *so)
{
@ -1081,7 +1104,9 @@ static struct pr_usrreqs uipc_usrreqs_dgram = {
.pru_accept = uipc_accept,
.pru_attach = uipc_attach,
.pru_bind = uipc_bind,
.pru_bindat = uipc_bindat,
.pru_connect = uipc_connect,
.pru_connectat = uipc_connectat,
.pru_connect2 = uipc_connect2,
.pru_detach = uipc_detach,
.pru_disconnect = uipc_disconnect,
@ -1101,7 +1126,9 @@ static struct pr_usrreqs uipc_usrreqs_seqpacket = {
.pru_accept = uipc_accept,
.pru_attach = uipc_attach,
.pru_bind = uipc_bind,
.pru_bindat = uipc_bindat,
.pru_connect = uipc_connect,
.pru_connectat = uipc_connectat,
.pru_connect2 = uipc_connect2,
.pru_detach = uipc_detach,
.pru_disconnect = uipc_disconnect,
@ -1121,7 +1148,9 @@ static struct pr_usrreqs uipc_usrreqs_stream = {
.pru_accept = uipc_accept,
.pru_attach = uipc_attach,
.pru_bind = uipc_bind,
.pru_bindat = uipc_bindat,
.pru_connect = uipc_connect,
.pru_connectat = uipc_connectat,
.pru_connect2 = uipc_connect2,
.pru_detach = uipc_detach,
.pru_disconnect = uipc_disconnect,
@ -1232,6 +1261,14 @@ uipc_ctloutput(struct socket *so, struct sockopt *sopt)
static int
unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
{
return (unp_connectat(AT_FDCWD, so, nam, td));
}
static int
unp_connectat(int fd, struct socket *so, struct sockaddr *nam,
struct thread *td)
{
struct sockaddr_un *soun = (struct sockaddr_un *)nam;
struct vnode *vp;
@ -1265,8 +1302,8 @@ unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
UNP_PCB_UNLOCK(unp);
sa = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF,
UIO_SYSSPACE, buf, td);
NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF,
UIO_SYSSPACE, buf, fd, CAP_CONNECTAT, td);
error = namei(&nd);
if (error)
vp = NULL;

View File

@ -95,7 +95,7 @@ void audit_arg_pid(pid_t pid);
void audit_arg_process(struct proc *p);
void audit_arg_signum(u_int signum);
void audit_arg_socket(int sodomain, int sotype, int soprotocol);
void audit_arg_sockaddr(struct thread *td, struct sockaddr *sa);
void audit_arg_sockaddr(struct thread *td, int dirfd, struct sockaddr *sa);
void audit_arg_auid(uid_t auid);
void audit_arg_auditinfo(struct auditinfo *au_info);
void audit_arg_auditinfo_addr(struct auditinfo_addr *au_info);
@ -267,9 +267,9 @@ void audit_thread_free(struct thread *td);
audit_arg_socket((sodomain), (sotype), (soprotocol)); \
} while (0)
#define AUDIT_ARG_SOCKADDR(td, sa) do { \
#define AUDIT_ARG_SOCKADDR(td, dirfd, sa) do { \
if (AUDITING_TD(curthread)) \
audit_arg_sockaddr((td), (sa)); \
audit_arg_sockaddr((td), (dirfd), (sa)); \
} while (0)
#define AUDIT_ARG_SUID(suid) do { \
@ -365,7 +365,7 @@ void audit_thread_free(struct thread *td);
#define AUDIT_ARG_SIGNUM(signum)
#define AUDIT_ARG_SGID(sgid)
#define AUDIT_ARG_SOCKET(sodomain, sotype, soprotocol)
#define AUDIT_ARG_SOCKADDR(td, sa)
#define AUDIT_ARG_SOCKADDR(td, dirfd, sa)
#define AUDIT_ARG_SUID(suid)
#define AUDIT_ARG_TEXT(text)
#define AUDIT_ARG_UID(uid)

View File

@ -441,7 +441,7 @@ audit_arg_socket(int sodomain, int sotype, int soprotocol)
}
void
audit_arg_sockaddr(struct thread *td, struct sockaddr *sa)
audit_arg_sockaddr(struct thread *td, int dirfd, struct sockaddr *sa)
{
struct kaudit_record *ar;
@ -463,7 +463,9 @@ audit_arg_sockaddr(struct thread *td, struct sockaddr *sa)
break;
case AF_UNIX:
audit_arg_upath1(td, AT_FDCWD,
if (dirfd != AT_FDCWD)
audit_arg_atfd1(dirfd);
audit_arg_upath1(td, dirfd,
((struct sockaddr_un *)sa)->sun_path);
ARG_SET_VALID(ar, ARG_SADDRUNIX);
break;

View File

@ -554,6 +554,21 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau)
/* XXX Need to handle ARG_SADDRINET6 */
break;
case AUE_BINDAT:
case AUE_CONNECTAT:
ATFD1_TOKENS(1);
if (ARG_IS_VALID(kar, ARG_FD)) {
tok = au_to_arg32(2, "fd", ar->ar_arg_fd);
kau_write(rec, tok);
}
if (ARG_IS_VALID(kar, ARG_SADDRUNIX)) {
tok = au_to_sock_unix((struct sockaddr_un *)
&ar->ar_arg_sockaddr);
kau_write(rec, tok);
UPATH1_TOKENS;
}
break;
case AUE_SOCKET:
case AUE_SOCKETPAIR:
if (ARG_IS_VALID(kar, ARG_SOCKINFO)) {

View File

@ -182,13 +182,18 @@
#define CAP_PDWAIT 0x0020000000000000ULL
#define CAP_PDKILL 0x0040000000000000ULL
/*
* Rights that allow to use bindat(2) and connectat(2) syscalls on a
* directory descriptor.
*/
#define CAP_BINDAT 0x0400000000000000ULL
#define CAP_CONNECTAT 0x0800000000000000ULL
/* The mask of all valid method rights. */
#define CAP_MASK_VALID 0x03ffffffffffffffULL
#define CAP_MASK_VALID 0x0fffffffffffffffULL
#define CAP_ALL CAP_MASK_VALID
/* Available bits. */
#define CAP_UNUSED5 0x0400000000000000ULL
#define CAP_UNUSED4 0x0800000000000000ULL
#define CAP_UNUSED3 0x1000000000000000ULL
#define CAP_UNUSED2 0x2000000000000000ULL
#define CAP_UNUSED1 0x4000000000000000ULL

View File

@ -223,6 +223,10 @@ struct pr_usrreqs {
struct ucred *cred, struct thread *td);
void (*pru_sosetlabel)(struct socket *so);
void (*pru_close)(struct socket *so);
int (*pru_bindat)(int fd, struct socket *so, struct sockaddr *nam,
struct thread *td);
int (*pru_connectat)(int fd, struct socket *so,
struct sockaddr *nam, struct thread *td);
};
/*
@ -232,8 +236,12 @@ int pru_accept_notsupp(struct socket *so, struct sockaddr **nam);
int pru_attach_notsupp(struct socket *so, int proto, struct thread *td);
int pru_bind_notsupp(struct socket *so, struct sockaddr *nam,
struct thread *td);
int pru_bindat_notsupp(int fd, struct socket *so, struct sockaddr *nam,
struct thread *td);
int pru_connect_notsupp(struct socket *so, struct sockaddr *nam,
struct thread *td);
int pru_connectat_notsupp(int fd, struct socket *so, struct sockaddr *nam,
struct thread *td);
int pru_connect2_notsupp(struct socket *so1, struct socket *so2);
int pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data,
struct ifnet *ifp, struct thread *td);

View File

@ -620,7 +620,9 @@ struct sf_hdtr {
__BEGIN_DECLS
int accept(int, struct sockaddr * __restrict, socklen_t * __restrict);
int bind(int, const struct sockaddr *, socklen_t);
int bindat(int, int, const struct sockaddr *, socklen_t);
int connect(int, const struct sockaddr *, socklen_t);
int connectat(int, int, const struct sockaddr *, socklen_t);
int getpeername(int, struct sockaddr * __restrict, socklen_t * __restrict);
int getsockname(int, struct sockaddr * __restrict, socklen_t * __restrict);
int getsockopt(int, int, int, void * __restrict, socklen_t * __restrict);

View File

@ -318,8 +318,12 @@ void soabort(struct socket *so);
int soaccept(struct socket *so, struct sockaddr **nam);
int socheckuid(struct socket *so, uid_t uid);
int sobind(struct socket *so, struct sockaddr *nam, struct thread *td);
int sobindat(int fd, struct socket *so, struct sockaddr *nam,
struct thread *td);
int soclose(struct socket *so);
int soconnect(struct socket *so, struct sockaddr *nam, struct thread *td);
int soconnectat(int fd, struct socket *so, struct sockaddr *nam,
struct thread *td);
int soconnect2(struct socket *so1, struct socket *so2);
int socow_setup(struct mbuf *m0, struct uio *uio);
int socreate(int dom, struct socket **aso, int type, int proto,

View File

@ -215,6 +215,13 @@ static struct cap_desc {
{ CAP_PDWAIT, "pw" },
{ CAP_PDKILL, "pk" },
/*
* Rights that allow to use bindat(2) and connectat(2) syscalls on a
* directory descriptor.
*/
{ CAP_BINDAT, "ba" },
{ CAP_CONNECTAT, "ca" },
/* Aliases and defines that combine multiple rights. */
{ CAP_PREAD, "prd" },
{ CAP_PWRITE, "pwr" },