- 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:
parent
136b1ada11
commit
7493f24ee6
@ -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.
|
||||
#
|
||||
|
@ -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 \
|
||||
|
@ -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
109
lib/libc/sys/bindat.2
Normal 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.
|
@ -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
109
lib/libc/sys/connectat.2
Normal 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.
|
@ -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
|
||||
|
@ -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); }
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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" },
|
||||
|
Loading…
Reference in New Issue
Block a user