unix(4): Enhance LOCAL_CREDS_PERSISTENT ABI

As this ABI is still fresh (r367287), let's correct some mistakes now:

- Version the structure to allow for future changes
- Include sender's pid in control message structure
- Use a distinct control message type from the cmsgcred / sockcred mess

Discussed with:	kib, markj, trasz
Differential Revision:	https://reviews.freebsd.org/D27084
This commit is contained in:
Conrad Meyer 2020-11-17 20:01:21 +00:00
parent b1976ea14c
commit ede4af47ae
4 changed files with 109 additions and 19 deletions

View File

@ -28,7 +28,7 @@
.\" @(#)unix.4 8.1 (Berkeley) 6/9/93
.\" $FreeBSD$
.\"
.Dd November 2, 2020
.Dd November 9, 2020
.Dt UNIX 4
.Os
.Sh NAME
@ -295,6 +295,41 @@ except that socket credentials are passed on every read from a
or
.Dv SOCK_SEQPACKET
socket, instead of just the first read.
Additionally, the
.Va msg_control
field in the
.Vt msghdr
structure points to a buffer that contains a
.Vt cmsghdr
structure followed by a variable length
.Vt sockcred2
structure, defined in
.In sys/socket.h
as follows:
.Bd -literal
struct sockcred2 {
int sc_version; /* version of this structure */
pid_t sc_pid; /* PID of sending process */
uid_t sc_uid; /* real user id */
uid_t sc_euid; /* effective user id */
gid_t sc_gid; /* real group id */
gid_t sc_egid; /* effective group id */
int sc_ngroups; /* number of supplemental groups */
gid_t sc_groups[1]; /* variable length */
};
.Ed
.Pp
The current version is zero.
.Pp
The
.Vt cmsghdr
fields have the following values:
.Bd -literal
cmsg_len = CMSG_LEN(SOCKCRED2SIZE(ngroups))
cmsg_level = SOL_SOCKET
cmsg_type = SCM_CREDS2
.Ed
.Pp
The
.Dv LOCAL_CREDS
and

View File

@ -644,6 +644,8 @@ bsd_to_linux_cmsg_type(int cmsg_type)
return (LINUX_SCM_RIGHTS);
case SCM_CREDS:
return (LINUX_SCM_CREDENTIALS);
case SCM_CREDS2:
return (LINUX_SCM_CREDENTIALS);
case SCM_TIMESTAMP:
return (LINUX_SCM_TIMESTAMP);
}
@ -1508,6 +1510,7 @@ linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
{
struct cmsghdr *cm;
struct cmsgcred *cmcred;
struct sockcred2 *scred;
struct l_cmsghdr *linux_cmsg = NULL;
struct l_ucred linux_ucred;
socklen_t datalen, maxlen, outlen;
@ -1631,6 +1634,16 @@ linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
datalen = sizeof(linux_ucred);
break;
case SCM_CREDS2:
scred = data;
bzero(&linux_ucred, sizeof(linux_ucred));
linux_ucred.pid = scred->sc_pid;
linux_ucred.uid = scred->sc_uid;
linux_ucred.gid = scred->sc_gid;
data = &linux_ucred;
datalen = sizeof(linux_ucred);
break;
case SCM_TIMESTAMP:
if (datalen != sizeof(struct timeval)) {
error = EMSGSIZE;

View File

@ -308,7 +308,7 @@ static int unp_internalize(struct mbuf **, struct thread *);
static void unp_internalize_fp(struct file *);
static int unp_externalize(struct mbuf *, struct mbuf **, int);
static int unp_externalize_fp(struct file *);
static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *);
static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *, int);
static void unp_process_defers(void * __unused, int);
static void
@ -1043,7 +1043,8 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
}
if (unp2->unp_flags & UNP_WANTCRED_MASK)
control = unp_addsockcred(td, control);
control = unp_addsockcred(td, control,
unp2->unp_flags);
if (unp->unp_addr != NULL)
from = (struct sockaddr *)unp->unp_addr;
else
@ -1102,8 +1103,8 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
* SOCK_SEQPACKET (LOCAL_CREDS => WANTCRED_ONESHOT), or
* forever (LOCAL_CREDS_PERSISTENT => WANTCRED_ALWAYS).
*/
control = unp_addsockcred(td, control, unp2->unp_flags);
unp2->unp_flags &= ~UNP_WANTCRED_ONESHOT;
control = unp_addsockcred(td, control);
}
/*
@ -2383,34 +2384,58 @@ unp_internalize(struct mbuf **controlp, struct thread *td)
}
static struct mbuf *
unp_addsockcred(struct thread *td, struct mbuf *control)
unp_addsockcred(struct thread *td, struct mbuf *control, int mode)
{
struct mbuf *m, *n, *n_prev;
struct sockcred *sc;
const struct cmsghdr *cm;
int ngroups;
int i;
int ngroups, i, cmsgtype;
size_t ctrlsz;
ngroups = MIN(td->td_ucred->cr_ngroups, CMGROUP_MAX);
m = sbcreatecontrol(NULL, SOCKCREDSIZE(ngroups), SCM_CREDS, SOL_SOCKET);
if (mode & UNP_WANTCRED_ALWAYS) {
ctrlsz = SOCKCRED2SIZE(ngroups);
cmsgtype = SCM_CREDS2;
} else {
ctrlsz = SOCKCREDSIZE(ngroups);
cmsgtype = SCM_CREDS;
}
m = sbcreatecontrol(NULL, ctrlsz, cmsgtype, SOL_SOCKET);
if (m == NULL)
return (control);
sc = (struct sockcred *) CMSG_DATA(mtod(m, struct cmsghdr *));
sc->sc_uid = td->td_ucred->cr_ruid;
sc->sc_euid = td->td_ucred->cr_uid;
sc->sc_gid = td->td_ucred->cr_rgid;
sc->sc_egid = td->td_ucred->cr_gid;
sc->sc_ngroups = ngroups;
for (i = 0; i < sc->sc_ngroups; i++)
sc->sc_groups[i] = td->td_ucred->cr_groups[i];
if (mode & UNP_WANTCRED_ALWAYS) {
struct sockcred2 *sc;
sc = (void *)CMSG_DATA(mtod(m, struct cmsghdr *));
sc->sc_version = 0;
sc->sc_pid = td->td_proc->p_pid;
sc->sc_uid = td->td_ucred->cr_ruid;
sc->sc_euid = td->td_ucred->cr_uid;
sc->sc_gid = td->td_ucred->cr_rgid;
sc->sc_egid = td->td_ucred->cr_gid;
sc->sc_ngroups = ngroups;
for (i = 0; i < sc->sc_ngroups; i++)
sc->sc_groups[i] = td->td_ucred->cr_groups[i];
} else {
struct sockcred *sc;
sc = (void *)CMSG_DATA(mtod(m, struct cmsghdr *));
sc->sc_uid = td->td_ucred->cr_ruid;
sc->sc_euid = td->td_ucred->cr_uid;
sc->sc_gid = td->td_ucred->cr_rgid;
sc->sc_egid = td->td_ucred->cr_gid;
sc->sc_ngroups = ngroups;
for (i = 0; i < sc->sc_ngroups; i++)
sc->sc_groups[i] = td->td_ucred->cr_groups[i];
}
/*
* Unlink SCM_CREDS control messages (struct cmsgcred), since just
* created SCM_CREDS control message (struct sockcred) has another
* format.
*/
if (control != NULL)
if (control != NULL && cmsgtype == SCM_CREDS)
for (n = control, n_prev = NULL; n != NULL;) {
cm = mtod(n, struct cmsghdr *);
if (cm->cmsg_level == SOL_SOCKET &&

View File

@ -510,7 +510,7 @@ struct cmsgcred {
};
/*
* Socket credentials.
* Socket credentials (LOCAL_CREDS).
*/
struct sockcred {
uid_t sc_uid; /* real user id */
@ -527,6 +527,22 @@ struct sockcred {
#define SOCKCREDSIZE(ngrps) \
(sizeof(struct sockcred) + (sizeof(gid_t) * ((ngrps) - 1)))
/*
* Socket credentials (LOCAL_CREDS_PERSISTENT).
*/
struct sockcred2 {
int sc_version; /* version of this structure */
pid_t sc_pid; /* PID of sending process */
uid_t sc_uid; /* real user id */
uid_t sc_euid; /* effective user id */
gid_t sc_gid; /* real group id */
gid_t sc_egid; /* effective group id */
int sc_ngroups; /* number of supplemental groups */
gid_t sc_groups[1]; /* variable length */
};
#define SOCKCRED2SIZE(ngrps) \
(sizeof(struct sockcred2) + (sizeof(gid_t) * ((ngrps) - 1)))
#endif /* __BSD_VISIBLE */
/* given pointer to struct cmsghdr, return pointer to data */
@ -571,6 +587,7 @@ struct sockcred {
#define SCM_REALTIME 0x05 /* timestamp (struct timespec) */
#define SCM_MONOTONIC 0x06 /* timestamp (struct timespec) */
#define SCM_TIME_INFO 0x07 /* timestamp info */
#define SCM_CREDS2 0x08 /* process creds (struct sockcred2) */
struct sock_timestamp_info {
__uint32_t st_info_flags;