aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/openbsm/etc/audit_event2
-rw-r--r--lib/libc/sys/Makefile.inc2
-rw-r--r--lib/libc/sys/Symbol.map2
-rw-r--r--lib/libc/sys/bindat.2109
-rw-r--r--lib/libc/sys/cap_rights_limit.210
-rw-r--r--lib/libc/sys/connectat.2109
-rw-r--r--sys/bsm/audit_kevents.h2
-rw-r--r--sys/compat/freebsd32/syscalls.master4
-rw-r--r--sys/kern/capabilities.conf12
-rw-r--r--sys/kern/syscalls.master4
-rw-r--r--sys/kern/uipc_domain.c2
-rw-r--r--sys/kern/uipc_socket.c46
-rw-r--r--sys/kern/uipc_syscalls.c117
-rw-r--r--sys/kern/uipc_usrreq.c47
-rw-r--r--sys/security/audit/audit.h8
-rw-r--r--sys/security/audit/audit_arg.c6
-rw-r--r--sys/security/audit/audit_bsm.c15
-rw-r--r--sys/sys/capability.h11
-rw-r--r--sys/sys/protosw.h8
-rw-r--r--sys/sys/socket.h2
-rw-r--r--sys/sys/socketvar.h4
-rw-r--r--usr.bin/procstat/procstat_files.c7
22 files changed, 475 insertions, 54 deletions
diff --git a/contrib/openbsm/etc/audit_event b/contrib/openbsm/etc/audit_event
index f82841ae7739..49b5f9d26d71 100644
--- a/contrib/openbsm/etc/audit_event
+++ b/contrib/openbsm/etc/audit_event
@@ -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.
#
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index 03c00900e22f..62aab6c96e11 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -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 \
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index 7738e46d8c84..fc000641ad0b 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -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;
diff --git a/lib/libc/sys/bindat.2 b/lib/libc/sys/bindat.2
new file mode 100644
index 000000000000..9274679374a8
--- /dev/null
+++ b/lib/libc/sys/bindat.2
@@ -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.
diff --git a/lib/libc/sys/cap_rights_limit.2 b/lib/libc/sys/cap_rights_limit.2
index 0c527aad775f..d0605af1e024 100644
--- a/lib/libc/sys/cap_rights_limit.2
+++ b/lib/libc/sys/cap_rights_limit.2
@@ -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 ,
diff --git a/lib/libc/sys/connectat.2 b/lib/libc/sys/connectat.2
new file mode 100644
index 000000000000..8cebf98372eb
--- /dev/null
+++ b/lib/libc/sys/connectat.2
@@ -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.
diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h
index 9d71fa28335c..d56a96b4e687 100644
--- a/sys/bsm/audit_kevents.h
+++ b/sys/bsm/audit_kevents.h
@@ -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
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index 6552d137e5a0..655296c779ef 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -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); }
diff --git a/sys/kern/capabilities.conf b/sys/kern/capabilities.conf
index 3c087827d8b6..71c22bf2264f 100644
--- a/sys/kern/capabilities.conf
+++ b/sys/kern/capabilities.conf
@@ -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.
-##
-## XXXRW: Revisit this.
+## Allow connectat(2).
##
-#connect
+connectat
##
## cpuset(2) and related calls require scoping by process, but should
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 1a890104c56f..9c22f2ba9e9f 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -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
diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c
index c1462328ed74..709cc0eb0569 100644
--- a/sys/kern/uipc_domain.c
+++ b/sys/kern/uipc_domain.c
@@ -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);
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index de8ae5a7243d..7fcac1ceef36 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -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
@@ -896,6 +907,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;
if (so->so_options & SO_ACCEPTCONN)
@@ -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();
@@ -3141,6 +3165,14 @@ 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)
+{
+
+ return EOPNOTSUPP;
+}
+
+int
pru_connect_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
{
@@ -3148,6 +3180,14 @@ 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)
+{
+
+ return EOPNOTSUPP;
+}
+
+int
pru_connect2_notsupp(struct socket *so1, struct socket *so2)
{
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index 847db35b5038..cd37a4d24dba 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -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)) {
@@ -582,6 +612,35 @@ done1:
}
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;
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index dcfd009d62a6..1da80e0cedbc 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -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)
@@ -560,6 +563,13 @@ 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)
{
int error;
@@ -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,
@@ -1233,6 +1262,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;
struct socket *so2, *so3;
@@ -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;
diff --git a/sys/security/audit/audit.h b/sys/security/audit/audit.h
index 733a3c79166f..dd55875be5b4 100644
--- a/sys/security/audit/audit.h
+++ b/sys/security/audit/audit.h
@@ -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)
diff --git a/sys/security/audit/audit_arg.c b/sys/security/audit/audit_arg.c
index ec04b8bef7be..4927be0d1349 100644
--- a/sys/security/audit/audit_arg.c
+++ b/sys/security/audit/audit_arg.c
@@ -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;
diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c
index 9c69b1e040d6..03b3c23e5c42 100644
--- a/sys/security/audit/audit_bsm.c
+++ b/sys/security/audit/audit_bsm.c
@@ -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)) {
diff --git a/sys/sys/capability.h b/sys/sys/capability.h
index 27e56c2952ec..0d1ea5c16ac9 100644
--- a/sys/sys/capability.h
+++ b/sys/sys/capability.h
@@ -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
diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h
index 78d6e069a05b..8553bafdff16 100644
--- a/sys/sys/protosw.h
+++ b/sys/sys/protosw.h
@@ -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);
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index c29a689b5915..632dae4bc88c 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -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);
diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h
index 9012f24065e5..77f31df336a7 100644
--- a/sys/sys/socketvar.h
+++ b/sys/sys/socketvar.h
@@ -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,
diff --git a/usr.bin/procstat/procstat_files.c b/usr.bin/procstat/procstat_files.c
index 030bba138f46..a3137db0852a 100644
--- a/usr.bin/procstat/procstat_files.c
+++ b/usr.bin/procstat/procstat_files.c
@@ -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" },