unix(4): Add SOL_LOCAL:LOCAL_CREDS_PERSISTENT

This option is intended to be semantically identical to Linux's
SOL_SOCKET:SO_PASSCRED.  For now, it is mutually exclusive with the
pre-existing sockopt SOL_LOCAL:LOCAL_CREDS.

Reviewed by:	markj (penultimate version)
Differential Revision:	https://reviews.freebsd.org/D27011
This commit is contained in:
Conrad Meyer 2020-11-03 01:17:45 +00:00
parent a98f03786e
commit 2de07e4096
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=367287
4 changed files with 58 additions and 21 deletions

View File

@ -28,7 +28,7 @@
.\" @(#)unix.4 8.1 (Berkeley) 6/9/93 .\" @(#)unix.4 8.1 (Berkeley) 6/9/93
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd August 3, 2020 .Dd November 2, 2020
.Dt UNIX 4 .Dt UNIX 4
.Os .Os
.Sh NAME .Sh NAME
@ -201,7 +201,7 @@ which can be set with
.Xr setsockopt 2 .Xr setsockopt 2
and tested with and tested with
.Xr getsockopt 2 : .Xr getsockopt 2 :
.Bl -tag -width ".Dv LOCAL_CONNWAIT" .Bl -tag -width ".Dv LOCAL_CREDS_PERSISTENT"
.It Dv LOCAL_CREDS .It Dv LOCAL_CREDS
This option may be enabled on This option may be enabled on
.Dv SOCK_DGRAM , .Dv SOCK_DGRAM ,
@ -287,6 +287,19 @@ such as error messages.
Therefore, a message accompanied by a particular Therefore, a message accompanied by a particular
.Fa sc_euid .Fa sc_euid
value should not be trusted as being from that user. value should not be trusted as being from that user.
.It Dv LOCAL_CREDS_PERSISTENT
This option is similar to
.Dv LOCAL_CREDS ,
except that socket credentials are passed on every read from a
.Dv SOCK_STREAM
or
.Dv SOCK_SEQPACKET
socket, instead of just the first read.
The
.Dv LOCAL_CREDS
and
.Dv LOCAL_CREDS_PERSISTENT
options are mutually exclusive.
.It Dv LOCAL_CONNWAIT .It Dv LOCAL_CONNWAIT
Used with Used with
.Dv SOCK_STREAM .Dv SOCK_STREAM

View File

@ -1040,7 +1040,7 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
break; break;
} }
if (unp2->unp_flags & UNP_WANTCRED) if (unp2->unp_flags & UNP_WANTCRED_MASK)
control = unp_addsockcred(td, control); control = unp_addsockcred(td, control);
if (unp->unp_addr != NULL) if (unp->unp_addr != NULL)
from = (struct sockaddr *)unp->unp_addr; from = (struct sockaddr *)unp->unp_addr;
@ -1094,12 +1094,13 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
break; break;
} }
SOCKBUF_LOCK(&so2->so_rcv); SOCKBUF_LOCK(&so2->so_rcv);
if (unp2->unp_flags & UNP_WANTCRED) { if (unp2->unp_flags & UNP_WANTCRED_MASK) {
/* /*
* Credentials are passed only once on SOCK_STREAM * Credentials are passed only once on SOCK_STREAM and
* and SOCK_SEQPACKET. * SOCK_SEQPACKET (LOCAL_CREDS => WANTCRED_ONESHOT), or
* forever (LOCAL_CREDS_PERSISTENT => WANTCRED_ALWAYS).
*/ */
unp2->unp_flags &= ~UNP_WANTCRED; unp2->unp_flags &= ~UNP_WANTCRED_ONESHOT;
control = unp_addsockcred(td, control); control = unp_addsockcred(td, control);
} }
@ -1405,7 +1406,13 @@ uipc_ctloutput(struct socket *so, struct sockopt *sopt)
case LOCAL_CREDS: case LOCAL_CREDS:
/* Unlocked read. */ /* Unlocked read. */
optval = unp->unp_flags & UNP_WANTCRED ? 1 : 0; optval = unp->unp_flags & UNP_WANTCRED_ONESHOT ? 1 : 0;
error = sooptcopyout(sopt, &optval, sizeof(optval));
break;
case LOCAL_CREDS_PERSISTENT:
/* Unlocked read. */
optval = unp->unp_flags & UNP_WANTCRED_ALWAYS ? 1 : 0;
error = sooptcopyout(sopt, &optval, sizeof(optval)); error = sooptcopyout(sopt, &optval, sizeof(optval));
break; break;
@ -1424,28 +1431,38 @@ uipc_ctloutput(struct socket *so, struct sockopt *sopt)
case SOPT_SET: case SOPT_SET:
switch (sopt->sopt_name) { switch (sopt->sopt_name) {
case LOCAL_CREDS: case LOCAL_CREDS:
case LOCAL_CREDS_PERSISTENT:
case LOCAL_CONNWAIT: case LOCAL_CONNWAIT:
error = sooptcopyin(sopt, &optval, sizeof(optval), error = sooptcopyin(sopt, &optval, sizeof(optval),
sizeof(optval)); sizeof(optval));
if (error) if (error)
break; break;
#define OPTSET(bit) do { \ #define OPTSET(bit, exclusive) do { \
UNP_PCB_LOCK(unp); \ UNP_PCB_LOCK(unp); \
if (optval) \ if (optval) { \
unp->unp_flags |= bit; \ if ((unp->unp_flags & (exclusive)) != 0) { \
else \ UNP_PCB_UNLOCK(unp); \
unp->unp_flags &= ~bit; \ error = EINVAL; \
break; \
} \
unp->unp_flags |= (bit); \
} else \
unp->unp_flags &= ~(bit); \
UNP_PCB_UNLOCK(unp); \ UNP_PCB_UNLOCK(unp); \
} while (0) } while (0)
switch (sopt->sopt_name) { switch (sopt->sopt_name) {
case LOCAL_CREDS: case LOCAL_CREDS:
OPTSET(UNP_WANTCRED); OPTSET(UNP_WANTCRED_ONESHOT, UNP_WANTCRED_ALWAYS);
break;
case LOCAL_CREDS_PERSISTENT:
OPTSET(UNP_WANTCRED_ALWAYS, UNP_WANTCRED_ONESHOT);
break; break;
case LOCAL_CONNWAIT: case LOCAL_CONNWAIT:
OPTSET(UNP_CONNWAIT); OPTSET(UNP_CONNWAIT, 0);
break; break;
default: default:
@ -1651,8 +1668,7 @@ unp_copy_peercred(struct thread *td, struct unpcb *client_unp,
memcpy(&server_unp->unp_peercred, &listen_unp->unp_peercred, memcpy(&server_unp->unp_peercred, &listen_unp->unp_peercred,
sizeof(server_unp->unp_peercred)); sizeof(server_unp->unp_peercred));
server_unp->unp_flags |= UNP_HAVEPC; server_unp->unp_flags |= UNP_HAVEPC;
if (listen_unp->unp_flags & UNP_WANTCRED) client_unp->unp_flags |= (listen_unp->unp_flags & UNP_WANTCRED_MASK);
client_unp->unp_flags |= UNP_WANTCRED;
} }
static int static int
@ -2853,8 +2869,12 @@ db_print_unpflags(int unp_flags)
db_printf("%sUNP_HAVEPC", comma ? ", " : ""); db_printf("%sUNP_HAVEPC", comma ? ", " : "");
comma = 1; comma = 1;
} }
if (unp_flags & UNP_WANTCRED) { if (unp_flags & UNP_WANTCRED_ALWAYS) {
db_printf("%sUNP_WANTCRED", comma ? ", " : ""); db_printf("%sUNP_WANTCRED_ALWAYS", comma ? ", " : "");
comma = 1;
}
if (unp_flags & UNP_WANTCRED_ONESHOT) {
db_printf("%sUNP_WANTCRED_ONESHOT", comma ? ", " : "");
comma = 1; comma = 1;
} }
if (unp_flags & UNP_CONNWAIT) { if (unp_flags & UNP_CONNWAIT) {

View File

@ -67,6 +67,7 @@ struct sockaddr_un {
/* Socket options. */ /* Socket options. */
#define LOCAL_PEERCRED 1 /* retrieve peer credentials */ #define LOCAL_PEERCRED 1 /* retrieve peer credentials */
#define LOCAL_CREDS 2 /* pass credentials to receiver */ #define LOCAL_CREDS 2 /* pass credentials to receiver */
#define LOCAL_CREDS_PERSISTENT 3 /* pass credentials to receiver */
#define LOCAL_CONNWAIT 4 /* connects block until accepted */ #define LOCAL_CONNWAIT 4 /* connects block until accepted */
/* Start of reserved space for third-party socket options. */ /* Start of reserved space for third-party socket options. */

View File

@ -107,10 +107,13 @@ struct unpcb {
* to determine whether the contents should be sent to the user or * to determine whether the contents should be sent to the user or
* not. * not.
*/ */
#define UNP_HAVEPC 0x001 #define UNP_HAVEPC 0x001
#define UNP_WANTCRED 0x004 /* credentials wanted */ #define UNP_WANTCRED_ALWAYS 0x002 /* credentials wanted always */
#define UNP_WANTCRED_ONESHOT 0x004 /* credentials wanted once */
#define UNP_CONNWAIT 0x008 /* connect blocks until accepted */ #define UNP_CONNWAIT 0x008 /* connect blocks until accepted */
#define UNP_WANTCRED_MASK (UNP_WANTCRED_ONESHOT | UNP_WANTCRED_ALWAYS)
/* /*
* These flags are used to handle non-atomicity in connect() and bind() * These flags are used to handle non-atomicity in connect() and bind()
* operations on a socket: in particular, to avoid races between multiple * operations on a socket: in particular, to avoid races between multiple