From owner-svn-src-all@FreeBSD.ORG Sat Mar 2 21:11:35 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 9A72B8BF; Sat, 2 Mar 2013 21:11:35 +0000 (UTC) (envelope-from pjd@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 6DCE1273; Sat, 2 Mar 2013 21:11:35 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r22LBZix045616; Sat, 2 Mar 2013 21:11:35 GMT (envelope-from pjd@svn.freebsd.org) Received: (from pjd@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r22LBVEd045583; Sat, 2 Mar 2013 21:11:31 GMT (envelope-from pjd@svn.freebsd.org) Message-Id: <201303022111.r22LBVEd045583@svn.freebsd.org> From: Pawel Jakub Dawidek Date: Sat, 2 Mar 2013 21:11:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r247667 - in head: contrib/openbsm/etc lib/libc/sys sys/bsm sys/compat/freebsd32 sys/kern sys/security/audit sys/sys usr.bin/procstat X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 02 Mar 2013 21:11:35 -0000 Author: pjd Date: Sat Mar 2 21:11:30 2013 New Revision: 247667 URL: http://svnweb.freebsd.org/changeset/base/247667 Log: - 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 Added: head/lib/libc/sys/bindat.2 (contents, props changed) head/lib/libc/sys/connectat.2 (contents, props changed) Modified: head/contrib/openbsm/etc/audit_event head/lib/libc/sys/Makefile.inc head/lib/libc/sys/Symbol.map head/lib/libc/sys/cap_rights_limit.2 head/sys/bsm/audit_kevents.h head/sys/compat/freebsd32/syscalls.master head/sys/kern/capabilities.conf head/sys/kern/syscalls.master head/sys/kern/uipc_domain.c head/sys/kern/uipc_socket.c head/sys/kern/uipc_syscalls.c head/sys/kern/uipc_usrreq.c head/sys/security/audit/audit.h head/sys/security/audit/audit_arg.c head/sys/security/audit/audit_bsm.c head/sys/sys/capability.h head/sys/sys/protosw.h head/sys/sys/socket.h head/sys/sys/socketvar.h head/usr.bin/procstat/procstat_files.c Modified: head/contrib/openbsm/etc/audit_event ============================================================================== --- head/contrib/openbsm/etc/audit_event Sat Mar 2 18:51:26 2013 (r247666) +++ head/contrib/openbsm/etc/audit_event Sat Mar 2 21:11:30 2013 (r247667) @@ -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. # Modified: head/lib/libc/sys/Makefile.inc ============================================================================== --- head/lib/libc/sys/Makefile.inc Sat Mar 2 18:51:26 2013 (r247666) +++ head/lib/libc/sys/Makefile.inc Sat Mar 2 21:11:30 2013 (r247667) @@ -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 \ Modified: head/lib/libc/sys/Symbol.map ============================================================================== --- head/lib/libc/sys/Symbol.map Sat Mar 2 18:51:26 2013 (r247666) +++ head/lib/libc/sys/Symbol.map Sat Mar 2 21:11:30 2013 (r247667) @@ -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; Added: head/lib/libc/sys/bindat.2 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libc/sys/bindat.2 Sat Mar 2 21:11:30 2013 (r247667) @@ -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. Modified: head/lib/libc/sys/cap_rights_limit.2 ============================================================================== --- head/lib/libc/sys/cap_rights_limit.2 Sat Mar 2 18:51:26 2013 (r247666) +++ head/lib/libc/sys/cap_rights_limit.2 Sat Mar 2 21:11:30 2013 (r247667) @@ -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 , Added: head/lib/libc/sys/connectat.2 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libc/sys/connectat.2 Sat Mar 2 21:11:30 2013 (r247667) @@ -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. Modified: head/sys/bsm/audit_kevents.h ============================================================================== --- head/sys/bsm/audit_kevents.h Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/bsm/audit_kevents.h Sat Mar 2 21:11:30 2013 (r247667) @@ -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 Modified: head/sys/compat/freebsd32/syscalls.master ============================================================================== --- head/sys/compat/freebsd32/syscalls.master Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/compat/freebsd32/syscalls.master Sat Mar 2 21:11:30 2013 (r247667) @@ -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); } Modified: head/sys/kern/capabilities.conf ============================================================================== --- head/sys/kern/capabilities.conf Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/kern/capabilities.conf Sat Mar 2 21:11:30 2013 (r247667) @@ -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 Modified: head/sys/kern/syscalls.master ============================================================================== --- head/sys/kern/syscalls.master Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/kern/syscalls.master Sat Mar 2 21:11:30 2013 (r247667) @@ -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 Modified: head/sys/kern/uipc_domain.c ============================================================================== --- head/sys/kern/uipc_domain.c Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/kern/uipc_domain.c Sat Mar 2 21:11:30 2013 (r247667) @@ -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); Modified: head/sys/kern/uipc_socket.c ============================================================================== --- head/sys/kern/uipc_socket.c Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/kern/uipc_socket.c Sat Mar 2 21:11:30 2013 (r247667) @@ -615,7 +615,18 @@ sobind(struct socket *so, struct sockadd 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, 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 socka 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 sock * 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, stru } 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, s } 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) { Modified: head/sys/kern/uipc_syscalls.c ============================================================================== --- head/sys/kern/uipc_syscalls.c Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/kern/uipc_syscalls.c Sat Mar 2 21:11:30 2013 (r247667) @@ -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, st *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, s 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; Modified: head/sys/kern/uipc_usrreq.c ============================================================================== --- head/sys/kern/uipc_usrreq.c Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/kern/uipc_usrreq.c Sat Mar 2 21:11:30 2013 (r247667) @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include +#include #include #include #include /* XXX must be before */ @@ -271,6 +272,8 @@ static int uipc_connect2(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 } 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 sock 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 s 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_dg .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_se .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_st .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 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 so 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; Modified: head/sys/security/audit/audit.h ============================================================================== --- head/sys/security/audit/audit.h Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/security/audit/audit.h Sat Mar 2 21:11:30 2013 (r247667) @@ -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 *t 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 *t #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) Modified: head/sys/security/audit/audit_arg.c ============================================================================== --- head/sys/security/audit/audit_arg.c Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/security/audit/audit_arg.c Sat Mar 2 21:11:30 2013 (r247667) @@ -441,7 +441,7 @@ audit_arg_socket(int sodomain, int sotyp } 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, st 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; Modified: head/sys/security/audit/audit_bsm.c ============================================================================== --- head/sys/security/audit/audit_bsm.c Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/security/audit/audit_bsm.c Sat Mar 2 21:11:30 2013 (r247667) @@ -554,6 +554,21 @@ kaudit_to_bsm(struct kaudit_record *kar, /* 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)) { Modified: head/sys/sys/capability.h ============================================================================== --- head/sys/sys/capability.h Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/sys/capability.h Sat Mar 2 21:11:30 2013 (r247667) @@ -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 Modified: head/sys/sys/protosw.h ============================================================================== --- head/sys/sys/protosw.h Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/sys/protosw.h Sat Mar 2 21:11:30 2013 (r247667) @@ -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 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); Modified: head/sys/sys/socket.h ============================================================================== --- head/sys/sys/socket.h Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/sys/socket.h Sat Mar 2 21:11:30 2013 (r247667) @@ -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); Modified: head/sys/sys/socketvar.h ============================================================================== --- head/sys/sys/socketvar.h Sat Mar 2 18:51:26 2013 (r247666) +++ head/sys/sys/socketvar.h Sat Mar 2 21:11:30 2013 (r247667) @@ -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, Modified: head/usr.bin/procstat/procstat_files.c ============================================================================== --- head/usr.bin/procstat/procstat_files.c Sat Mar 2 18:51:26 2013 (r247666) +++ head/usr.bin/procstat/procstat_files.c Sat Mar 2 21:11:30 2013 (r247667) @@ -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" },