Index: head/share/man/man4/unix.4 =================================================================== --- head/share/man/man4/unix.4 +++ head/share/man/man4/unix.4 @@ -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 @@ 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 Index: head/sys/compat/linux/linux_socket.c =================================================================== --- head/sys/compat/linux/linux_socket.c +++ head/sys/compat/linux/linux_socket.c @@ -644,6 +644,8 @@ 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 @@ { 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; @@ -1627,6 +1630,16 @@ linux_ucred.pid = cmcred->cmcred_pid; linux_ucred.uid = cmcred->cmcred_uid; linux_ucred.gid = cmcred->cmcred_gid; + data = &linux_ucred; + 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; Index: head/sys/kern/uipc_usrreq.c =================================================================== --- head/sys/kern/uipc_usrreq.c +++ head/sys/kern/uipc_usrreq.c @@ -308,7 +308,7 @@ 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 @@ } 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 @@ * 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 @@ } 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 && Index: head/sys/sys/socket.h =================================================================== --- head/sys/sys/socket.h +++ head/sys/sys/socket.h @@ -510,7 +510,7 @@ }; /* - * Socket credentials. + * Socket credentials (LOCAL_CREDS). */ struct sockcred { uid_t sc_uid; /* real user id */ @@ -527,6 +527,22 @@ #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 @@ #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;