UDS: full rewrite

This new implementation of the UDS service is built on top of the
libsockevent library.  It thereby inherits all the advantages that
libsockevent brings.  However, the fundamental restructuring
required for that change also paved the way for resolution of a
number of other important open issues with the old UDS code.  Most
importantly, the rewrite brings the behavior of the service much
closer to POSIX compliance and NetBSD compatibility.  These are the
most important changes:

- due to the use of libsockevent, UDS now supports multiple suspending
  calls per socket and a large number of standard socket flags and
  options;
- socket address matching is now based on <device,inode> lookups
  instead of canonized path names, and socket addresses are no longer
  altered either due to canonization or at connect time;
- the socket state machine is now well defined, most importantly
  resolving the erroneous reset-on-EOF semantics of the old UDS, but
  also allowing socket reuse;
- sockets are now connected before being accepted instead of being
  held in connecting state, unless the LOCAL_CONNWAIT option is set
  on either the connecting or the listening socket;
- connect(2) on datagram sockets is now supported (needed by syslog),
  and proper datagram socket disconnect notification is provided;
- the receive queue now supports segmentation, associating ancillary
  data (in-flight file descriptors and credentials) with each segment
  instead of being kept fully separately; this is a POSIX requirement
  (and needed by tmux);
- as part of the segmentation support, the receive queue can now hold
  as many packets as can fit, instead of one;
- in addition to the flags supported by libsockevent, the MSG_PEEK,
  MSG_WAITALL, MSG_CMSG_CLOEXEC, MSG_TRUNC, and MSG_CTRUNC send and
  receive flags are now supported;
- the SO_PASSCRED and SO_PEERCRED socket options are replaced by
  LOCAL_CREDS and LOCAL_PEEREID respectively, now following NetBSD
  semantics and allowing use of NetBSD libc's getpeereid(3);
- memory usage is reduced by about 250 KB due to centralized in-flight
  file descriptor tracking, with a limit of OPEN_MAX total rather than
  of OPEN_MAX per socket;
- memory usage is reduced by another ~50 KB due to removal of state
  redundancy, despite the fact that socket path names may now be up to
  253 bytes rather than the previous 104 bytes;
- compared to the old UDS, there is now very little direct indexing on
  the static array of sockets, thus allowing dynamic allocation of
  sockets more easily in the future;
- the UDS service now has RMIB support for the net.local sysctl tree,
  implementing preliminary support for NetBSD netstat(1).

Change-Id: I4a9b6fe4aaeef0edf2547eee894e6c14403fcb32
This commit is contained in:
David van Moolenbroek 2016-02-21 22:59:04 +00:00
parent 241ebcae9b
commit 27852ebe53
39 changed files with 3775 additions and 2299 deletions

View File

@ -179,6 +179,7 @@
./etc/system.conf.d/ipc minix-base
./etc/system.conf.d/lwip minix-base
./etc/system.conf.d/random minix-base
./etc/system.conf.d/uds minix-base
./etc/system.conf.d/usb_hub minix-base
./etc/system.conf.d/usb_storage minix-base
./etc/termcap minix-base

View File

@ -477,7 +477,7 @@
./usr/man/man2/getgid.2 minix-man
./usr/man/man2/getitimer.2 minix-man
./usr/man/man2/getnucred.2 minix-man obsolete
./usr/man/man2/getpeereid.2 minix-man
./usr/man/man2/getpeereid.2 minix-man obsolete
./usr/man/man2/getpeername.2 minix-man
./usr/man/man2/getpid.2 minix-man
./usr/man/man2/getpriority.2 minix-man
@ -3463,7 +3463,7 @@
./usr/man/man8/syslogd.8 minix-man
./usr/man/man8/tcpd.8 minix-man
./usr/man/man8/traceroute.8 minix-man
./usr/man/man8/uds.8 minix-man
./usr/man/man8/uds.8 minix-man obsolete
./usr/man/man8/unix.8 minix-man
./usr/man/man8/unlink.8 minix-man
./usr/man/man8/unstr.8 minix-man

View File

@ -494,14 +494,6 @@ service vnd
uid 0; # only for copyfd(2)
};
service uds
{
ipc
SYSTEM vfs rs vm
;
uid 0; # only for checkperms(2) and copyfd(2)
};
service pty
{
system

View File

@ -201,7 +201,7 @@ start)
# pty needs to know the "tty" group ID
up pty -dev /dev/ptmx -args "gid=`stat -f '%g' /dev/ptmx`"
up uds -dev /dev/uds
up uds
up -n ipc

View File

@ -107,11 +107,7 @@ client_connect(char *path, int start_server)
}
retry:
#ifndef __minix
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
#else
if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1)
#endif /* !defined(__minix) */
fatal("socket failed");
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {

View File

@ -84,11 +84,7 @@ server_create_socket(void)
}
unlink(sa.sun_path);
#ifndef __minix
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
#else
if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1)
#endif /* !defined(__minix) */
fatal("socket failed");
mask = umask(S_IXUSR|S_IXGRP|S_IRWXO);
@ -114,11 +110,7 @@ server_start(int lockfd, char *lockfile)
char *cause;
/* The first client is special and gets a socketpair; create it. */
#ifndef __minix
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
#else
if (socketpair(AF_UNIX, SOCK_SEQPACKET, PF_UNSPEC, pair) != 0)
#endif /* !defined(__minix) */
fatal("socketpair failed");
switch (fork()) {

View File

@ -59,10 +59,6 @@ __RCSID("$NetBSD: syslog.c,v 1.54 2014/09/18 13:58:20 christos Exp $");
#include "reentrant.h"
#include "extern.h"
#if defined(__minix)
#include <sys/ioctl.h>
#endif /* defined(__minix) */
#ifdef __weak_alias
__weak_alias(closelog,_closelog)
__weak_alias(openlog,_openlog)
@ -452,11 +448,7 @@ vsyslogp_r(int pri, struct syslog_data *data, const char *msgid,
* to give syslogd a chance to empty its socket buffer.
*/
for (tries = 0; tries < MAXTRIES; tries++) {
#if defined(__minix)
if (write(data->log_file, tbuf, cnt) != -1)
#else
if (send(data->log_file, tbuf, cnt, 0) != -1)
#endif /* defined(__minix) */
break;
if (errno != ENOBUFS) {
disconnectlog_r(data);
@ -513,9 +505,7 @@ connectlog_r(struct syslog_data *data)
/* AF_UNIX address of local logger */
static const struct sockaddr_un sun = {
.sun_family = AF_LOCAL,
#if !defined(__minix)
.sun_len = sizeof(sun),
#endif /* !defined(__minix) */
.sun_path = _PATH_LOG,
};
@ -526,14 +516,9 @@ connectlog_r(struct syslog_data *data)
data->log_connected = 0;
}
if (!data->log_connected) {
#if defined(__minix)
if(ioctl(data->log_file, NWIOSUDSTADDR, __UNCONST(&sun)) < 0)
#else
if (connect(data->log_file,
(const struct sockaddr *)(const void *)&sun,
(socklen_t)sizeof(sun)) == -1)
#endif /* defined(__minix) */
{
(void)close(data->log_file);
data->log_file = -1;

View File

@ -2,13 +2,6 @@
# @(#)Makefile.inc 8.2 (Berkeley) 9/5/93
# net sources
.if defined(__MINIX)
.PATH: ${NETBSDSRCDIR}/minix/lib/libc/net
CPPFLAGS.getpeereid.c+= -D_MINIX_SYSTEM=1
CPPFLAGS.getsockopt.c+= -D_MINIX_SYSTEM=1
CPPFLAGS.setsockopt.c+= -D_MINIX_SYSTEM=1
.endif
.PATH: ${ARCHDIR}/net ${.CURDIR}/net
SRCS+= base64.c ethers.c gethnamaddr.c getifaddrs.c \

View File

@ -192,9 +192,6 @@ do
17,0)
des="hello" dev=hello
;;
18,0)
des="UNIX domain socket" dev=uds
;;
5[6-9],0|6[0-3],0)
drive=`expr $major - 56`
des="vnode disk $drive" dev=vnd$drive

View File

@ -49,7 +49,6 @@ STD_DEVICES="
ttypa ttypb ttypc ttypd ttype ttypf
ttyq0 ttyq1 ttyq2 ttyq3 ttyq4 ttyq5 ttyq6 ttyq7 ttyq8 ttyq9
ttyqa ttyqb ttyqc ttyqd ttyqe ttyqf
uds
vnd0 vnd0p0 vnd0p0s0 vnd1 vnd1p0 vnd1p0s0
vnd2 vnd3 vnd4 vnd5 vnd6 vnd7
"
@ -134,7 +133,6 @@ Where key is one of the following:
klog # Make /dev/klog
ptmx # Make /dev/ptmx
random # Make /dev/random, /dev/urandom
uds # Make /dev/uds
filter # Make /dev/filter
fbd # Make /dev/fbd
hello # Make /dev/hello
@ -438,10 +436,6 @@ do
makedev ${dev} c 4 ${minor} ${uname} tty ${permissions}
;;
uds)
# Unix domain sockets device
makedev ${dev} c 18 0 ${uname} ${gname} 666
;;
vnd[0-7])
# Whole vnode disk devices.
makedev ${dev} b ${major} 0 ${uname} ${gname} ${permissions}

View File

@ -36,8 +36,8 @@
#define LOG_MAJOR 15 /* 15 = /dev/klog (log driver) */
#define RANDOM_MAJOR 16 /* 16 = /dev/random (random driver) */
#define HELLO_MAJOR 17 /* 17 = /dev/hello (hello driver) */
#define UDS_MAJOR 18 /* 18 = /dev/uds (pfs) */
#define FB_MAJOR 19 /* 18 = /dev/fb0 (fb driver) */
/* 18 = (unused) */
#define FB_MAJOR 19 /* 19 = /dev/fb0 (fb driver) */
#define I2C0_MAJOR 20 /* 20 = /dev/i2c-1 (i2c-dev) */
#define I2C1_MAJOR 21 /* 21 = /dev/i2c-2 (i2c-dev) */
#define I2C2_MAJOR 22 /* 22 = /dev/i2c-3 (i2c-dev) */

View File

@ -273,11 +273,10 @@ uid_t getnuid(endpoint_t proc_ep);
gid_t getngid(endpoint_t proc_ep);
int getsockcred(endpoint_t proc_ep, struct sockcred * sockcred, gid_t * groups,
int ngroups);
int socketpath(endpoint_t endpt, char *path, size_t size, int what, dev_t *dev,
ino_t *ino);
int socketpath(endpoint_t endpt, const char *path, size_t size, int what,
dev_t *dev, ino_t *ino);
#define SPATH_CHECK 0 /* check user permissions on socket path */
#define SPATH_CREATE 1 /* create socket file at given path */
#define SPATH_CANONIZE 0x8000 /* copy back canonized path (legacy support) */
int copyfd(endpoint_t endpt, int fd, int what);
#define COPYFD_FROM 0 /* copy file descriptor from remote process */
#define COPYFD_TO 1 /* copy file descriptor to remote process */

View File

@ -1,37 +0,0 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ucred.h>
/*
* get the effective user ID and effective group ID of a peer
* connected through a Unix domain socket.
*/
int getpeereid(int sd, uid_t *euid, gid_t *egid) {
int rc;
struct uucred cred;
socklen_t ucred_length;
/* Initialize Data Structures */
ucred_length = sizeof(struct uucred);
memset(&cred, '\0', ucred_length);
/* Validate Input Parameters */
if (euid == NULL || egid == NULL) {
errno = EFAULT;
return -1;
} /* getsockopt will handle validating 'sd' */
/* Get the credentials of the peer at the other end of 'sd' */
rc = getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &cred, &ucred_length);
if (rc == 0) {
/* Success - return the results */
*euid = cred.cr_uid;
*egid = cred.cr_gid;
return 0;
} else {
/* Failure - getsockopt takes care of setting errno */
return -1;
}
}

View File

@ -244,6 +244,7 @@ static int _uds_getsockopt(int sock, int level, int option_name,
return 0;
}
#ifdef SO_PEERCRED
if (level == SOL_SOCKET && option_name == SO_PEERCRED)
{
struct uucred cred;
@ -257,6 +258,7 @@ static int _uds_getsockopt(int sock, int level, int option_name,
option_len);
return 0;
}
#endif
if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
@ -269,12 +271,14 @@ static int _uds_getsockopt(int sock, int level, int option_name,
return 0;
}
#ifdef SO_PASSCRED
if (level == SOL_SOCKET && option_name == SO_PASSCRED)
{
i = 1; /* option is always 'on' */
getsockopt_copy(&i, sizeof(i), option_value, option_len);
return 0;
}
#endif
#if DEBUG
fprintf(stderr, "_uds_getsocketopt: level %d, name %d\n",

View File

@ -267,6 +267,7 @@ static int _uds_setsockopt(int sock, int level, int option_name,
return 0;
}
#ifdef SO_PASSCRED
if (level == SOL_SOCKET && option_name == SO_PASSCRED)
{
if (option_len != sizeof(i))
@ -283,6 +284,7 @@ static int _uds_setsockopt(int sock, int level, int option_name,
}
return 0;
}
#endif
#if DEBUG
fprintf(stderr, "_uds_setsocketopt: level %d, name %d\n",

View File

@ -5,22 +5,22 @@
#include <minix/safecopies.h>
int
socketpath(endpoint_t endpt, char * path, size_t size, int what, dev_t * dev,
ino_t * ino)
socketpath(endpoint_t endpt, const char * path, size_t size, int what,
dev_t * dev, ino_t * ino)
{
cp_grant_id_t grant;
message m;
int r;
if ((grant = cpf_grant_direct(VFS_PROC_NR, (vir_bytes)path, size,
CPF_READ | CPF_WRITE)) == GRANT_INVALID)
CPF_READ)) == GRANT_INVALID)
return ENOMEM;
memset(&m, 0, sizeof(m));
m.m_lsys_vfs_socketpath.endpt = endpt;
m.m_lsys_vfs_socketpath.grant = grant;
m.m_lsys_vfs_socketpath.count = size;
m.m_lsys_vfs_socketpath.what = what | SPATH_CANONIZE;
m.m_lsys_vfs_socketpath.what = what;
r = _taskcall(VFS_PROC_NR, VFS_SOCKETPATH, &m);

View File

@ -1,6 +1,6 @@
MAN= accept.2 access.2 bind.2 brk.2 chdir.2 chmod.2 chown.2 \
chroot.2 close.2 connect.2 creat.2 dup.2 execve.2 exit.2 fcntl.2 \
fork.2 getgid.2 getitimer.2 getpeereid.2 \
fork.2 getgid.2 getitimer.2 \
getpeername.2 getpid.2 getpriority.2 getsockname.2 getsockopt.2 \
gettimeofday.2 getuid.2 intro.2 ioctl.2 kill.2 link.2 listen.2 \
lseek.2 mkdir.2 mknod.2 mount.2 open.2 ptrace.2 \

View File

@ -1,42 +0,0 @@
.TH GETPEEREID 2
.SH NAME
getpeereid \- get the effective user ID and effective group ID of a peer
connected through a Unix domain socket.
.SH SYNOPSIS
.ft B
#include <sys/socket.h>
.in +5
.ti -5
int getpeereid(int \fIsd\fP, uid_t *\fIeuid\fP, gid_t *\fIegid\fP);
.br
.ft P
.SH DESCRIPTION
getpeereid() is often used to authenticate clients connecting to a
server through a Unix domain socket. The server can call this function
with a socket descriptor \fIsd\fP and this function will fill\-in
\fIeuid\fP and \fIegid\fP with the effective user ID and the effective
group ID of the client process.
.SH RETURN VALUES
On success, this function returns 0, \fIeuid\fP is set to the effective
user ID of the peer connected through Unix domain socket \fIsd\fP, and
\fIegid\fP is set to the effective group ID of the peer connected
through Unix domain socket \fIsd\fP. On error, -1 is returned and
\fIerrno\fP is set.
.SH ERRORS
.TP 15
[EBADF]
The argument \fIsd\fP is not a descriptor.
.TP 15
[ENOTSOCK]
The argument \fIsd\fP is a descriptor, but not a socket descriptor.
.TP 15
[EFAULT]
The address pointed to by \fIeuid\fP and/or \fIegid\fP is not in a
valid part of the process address space.
.SH SEE ALSO
.BR socket(2),
.BR socketpair(2),
.BR unix(8)
.SH HISTORY
This function first appeared in Minix 3.1.8.

View File

@ -1,9 +1,15 @@
# Makefile for the UNIX Domain Sockets driver (UDS)
PROG= uds
SRCS= uds.c ioc_uds.c
MAN= uds.8 unix.8
SRCS= uds.c io.c stat.c
MAN= unix.8
DPADD+= ${LIBCHARDRIVER} ${LIBSYS}
LDADD+= -lchardriver -lsys
FILES=${PROG}.conf
FILESNAME=${PROG}
FILESDIR= /etc/system.conf.d
DPADD+= ${LIBSOCKEVENT} ${LIBSOCKDRIVER} ${LIBSYS} ${LIBTIMERS}
LDADD+= -lsockevent -lsockdriver -lsys -ltimers
WARNS?= 5
.include <minix.service.mk>

1795
minix/net/uds/io.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

186
minix/net/uds/stat.c Normal file
View File

@ -0,0 +1,186 @@
/* UNIX Domain Sockets - stat.c - network status */
#include "uds.h"
#include <sys/socketvar.h>
#include <sys/unpcb.h>
/*
* Fill the given 'ki' structure with information about the socket 'uds'.
*/
static void
uds_get_info(struct kinfo_pcb * ki, const struct udssock * uds)
{
struct udssock *peer;
socklen_t len;
int type;
type = uds_get_type(uds);
peer = uds_get_peer(uds);
ki->ki_pcbaddr = (uint64_t)(uintptr_t)uds;
ki->ki_ppcbaddr = (uint64_t)(uintptr_t)uds;
ki->ki_sockaddr = (uint64_t)(uintptr_t)&uds->uds_sock;
ki->ki_family = AF_UNIX;
ki->ki_type = type;
ki->ki_protocol = UDSPROTO_UDS;
ki->ki_pflags = 0;
if (uds->uds_flags & UDSF_CONNWAIT)
ki->ki_pflags |= UNP_CONNWAIT;
if (uds->uds_flags & UDSF_PASSCRED)
ki->ki_pflags |= UNP_WANTCRED;
if (type != SOCK_DGRAM && uds->uds_cred.unp_pid != -1) {
if (uds_is_listening(uds))
ki->ki_pflags |= UNP_EIDSBIND;
else if (uds_is_connecting(uds) || uds_is_connected(uds))
ki->ki_pflags |= UNP_EIDSVALID;
}
/* Not sure about NetBSD connection states. First attempt here. */
if (uds_is_connecting(uds))
ki->ki_sostate = SS_ISCONNECTING;
else if (uds_is_connected(uds))
ki->ki_sostate = SS_ISCONNECTED;
else if (uds_is_disconnected(uds))
ki->ki_sostate = SS_ISDISCONNECTED;
ki->ki_rcvq = uds->uds_len;
/* We currently mirror the peer's receive queue size when connected. */
if (uds_is_connected(uds))
ki->ki_sndq = peer->uds_len;
/* The source is not set for bound connection-type sockets here. */
if (type == SOCK_DGRAM || uds_is_listening(uds))
uds_make_addr(uds->uds_path, (size_t)uds->uds_pathlen,
&ki->ki_src, &len);
if (peer != NULL)
uds_make_addr(peer->uds_path, (size_t)peer->uds_pathlen,
&ki->ki_dst, &len);
/* TODO: we should set ki_inode and ki_vnode, but to what? */
ki->ki_conn = (uint64_t)(uintptr_t)peer;
if (!TAILQ_EMPTY(&uds->uds_queue))
ki->ki_refs =
(uint64_t)(uintptr_t)TAILQ_FIRST(&uds->uds_queue);
if (uds_has_link(uds))
ki->ki_nextref =
(uint64_t)(uintptr_t)TAILQ_NEXT(uds, uds_next);
}
/*
* Remote MIB implementation of CTL_NET PF_LOCAL {SOCK_STREAM,SOCK_DGRAM,
* SOCK_SEQPACKET} 0. This function handles all queries on the
* "net.local.{stream,dgram,seqpacket}.pcblist" sysctl(7) nodes.
*
* The 0 for "pcblist" is a MINIXism: we use it to keep our arrays small.
* NetBSD numbers these nodes dynamically and so they have numbers above
* CREATE_BASE. That also means that no userland application can possibly
* hardcode their numbers, and must perform lookups by name. In turn, that
* means that we can safely change the 0 to another number if NetBSD ever
* introduces statically numbered nodes in these subtrees.
*/
static ssize_t
net_local_pcblist(struct rmib_call * call, struct rmib_node * node __unused,
struct rmib_oldp * oldp, struct rmib_newp * newp __unused)
{
struct udssock *uds;
struct kinfo_pcb ki;
ssize_t off;
int r, type, size, max;
if (call->call_namelen != 4)
return EINVAL;
/* The first two added name fields are not used. */
size = call->call_name[2];
if (size < 0 || (size_t)size > sizeof(ki))
return EINVAL;
if (size == 0)
size = sizeof(ki);
max = call->call_name[3];
type = call->call_oname[2];
off = 0;
for (uds = uds_enum(NULL, type); uds != NULL;
uds = uds_enum(uds, type)) {
if (rmib_inrange(oldp, off)) {
memset(&ki, 0, sizeof(ki));
uds_get_info(&ki, uds);
if ((r = rmib_copyout(oldp, off, &ki, size)) < 0)
return r;
}
off += size;
if (max > 0 && --max == 0)
break;
}
/*
* Margin to limit the possible effects of the inherent race condition
* between receiving just the data size and receiving the actual data.
*/
if (oldp == NULL)
off += PCB_SLOP * size;
return off;
}
/* The CTL_NET PF_LOCAL SOCK_STREAM subtree. */
static struct rmib_node net_local_stream_table[] = {
[0] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist,
"pcblist", "SOCK_STREAM protocol control block list"),
};
/* The CTL_NET PF_LOCAL SOCK_DGRAM subtree. */
static struct rmib_node net_local_dgram_table[] = {
[0] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist,
"pcblist", "SOCK_DGRAM protocol control block list"),
};
/* The CTL_NET PF_LOCAL SOCK_SEQPACKET subtree. */
static struct rmib_node net_local_seqpacket_table[] = {
[0] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist,
"pcblist", "SOCK_SEQPACKET protocol control block list"),
};
/* The CTL_NET PF_LOCAL subtree. */
static struct rmib_node net_local_table[] = {
/* 1*/ [SOCK_STREAM] = RMIB_NODE(RMIB_RO, net_local_stream_table,
"stream", "SOCK_STREAM settings"),
/* 2*/ [SOCK_DGRAM] = RMIB_NODE(RMIB_RO, net_local_dgram_table,
"dgram", "SOCK_DGRAM settings"),
/* 5*/ [SOCK_SEQPACKET] = RMIB_NODE(RMIB_RO, net_local_seqpacket_table,
"seqpacket", "SOCK_SEQPACKET settings"),
};
static struct rmib_node net_local_node =
RMIB_NODE(RMIB_RO, net_local_table, "local", "PF_LOCAL related settings");
/*
* Initialize the status module.
*/
void
uds_stat_init(void)
{
const int mib[] = { CTL_NET, PF_LOCAL };
int r;
/*
* Register our own "net.local" subtree with the MIB service.
*
* This call only returns local failures. Remote failures (in the MIB
* service) are silently ignored. So, we can safely panic on failure.
*/
if ((r = rmib_register(mib, __arraycount(mib), &net_local_node)) != OK)
panic("UDS: unable to register remote MIB tree: %d", r);
}
/*
* Clean up the status module.
*/
void
uds_stat_cleanup(void)
{
rmib_deregister(&net_local_node);
}

View File

@ -1,15 +0,0 @@
.TH UDS 8
.SH NAME
uds \- unix domain sockets device
.SH DESCRIPTION
The \fIuds\fP device gives access to the unix domain socket services in
Minix. It is a virtual device similar to the \fItcp\fP and \fIudp\fP
Internet Protocol server devices.
.SH SEE ALSO
.BR socket(2),
.BR socketpair(2),
.BR dev(4),
.BR ip(4),
.BR unix(8)
.SH HISTORY
This device first appeared in Minix 3.1.8.

File diff suppressed because it is too large Load Diff

9
minix/net/uds/uds.conf Normal file
View File

@ -0,0 +1,9 @@
service uds
{
domain LOCAL;
system KILL; # for SIGPIPE
uid 0; # for socketpath(2) and copyfd(2)
ipc
SYSTEM vfs rs vm mib
;
};

View File

@ -1,23 +1,48 @@
#ifndef __UDS_UDS_H
#define __UDS_UDS_H
#ifndef MINIX_NET_UDS_UDS_H
#define MINIX_NET_UDS_UDS_H
#include <minix/drivers.h>
#include <minix/chardriver.h>
#undef send
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/ucred.h>
#include <minix/sockevent.h>
#include <minix/rmib.h>
#include <sys/un.h>
#include <sys/mman.h>
/* Maximum number of UNIX domain sockets. */
#define NR_FDS 256
/*
* Maximum number of UNIX domain sockets. The control structures for all of
* these are allocated statically, although each socket's receive buffer is
* allocated only when the socket is in use. If this constant is increased
* beyond 65535, a few field sizes need to be changed.
*/
#define NR_UDSSOCK 256
/* Connection backlog size for incoming connections. */
#define UDS_SOMAXCONN 64
/* Number of slots in the <dev,ino>-to-udssock hash table. */
#define UDSHASH_SLOTS 64
/* Maximum UDS socket buffer size. */
#define UDS_BUF PIPE_BUF
/* UDS has no protocols, so we accept only an "any protocol" value. */
#define UDSPROTO_UDS 0
/*
* The size of each socket's receive buffer. This size is currently a global
* setting which cannot be changed per socket at run time, and it would be
* rather tricky to change that. In order not to waste resources, this size
* should be a multiple of the page size. Due to the fact that data and
* metadata (such as lengths, source addresses and sender credentials) are
* intermixed in the same buffer, the actual amount of data that can be in
* transit at once is typically less than this value. If this constant is
* increased beyond 65535, several fields and field sizes need to be changed.
*/
#define UDS_BUF 32768
/* Maximum size of control data that can be sent or received at once. */
#define UDS_CTL_MAX 4096
/*
* We allow longer path names than the size of struct sockaddr_un's sun_path
* field. The actual limit is determined by the maximum value of the sun_len
* field, which is 255 and includes the first two fields of the structure (one
* byte each) but not the null terminator of the path. Thus, the maximum
* length of the path minus null terminator is 253; with terminator it is 254.
*/
#define UDS_PATH_MAX (UINT8_MAX - sizeof(uint8_t) - sizeof(sa_family_t) + 1)
/* Output debugging information? */
#define DEBUG 0
@ -29,191 +54,201 @@
#endif
/*
* A light version of the "uucred" credentials structure. We basically do not
* support passing around groups lists, and by not using struct uucred as
* storage, we save memory for those groups lists as well. Note that the
* original Linux uucred structure has a 'cr_pid' field as well, but this is
* unsupported in NetBSD's version of the structure (and rightly so).
* We declare this structure only for the static assert right below it. We
* have no need for the structure otherwise, as we use "struct sockaddr"
* directly instead.
*/
struct luucred {
uid_t uid;
gid_t gid;
struct sockaddr_unx {
uint8_t sunx_len;
sa_family_t sunx_family;
char sunx_path[UDS_PATH_MAX];
};
/* ancillary data to be sent */
struct ancillary {
int fds[OPEN_MAX];
int nfiledes;
struct luucred cred;
};
#define UDS_R 0x1
#define UDS_W 0x2
STATIC_SOCKADDR_MAX_ASSERT(sockaddr_unx);
/*
* Internal State Information for a socket descriptor.
* In-flight file descriptor object. Each in-use object is part of a socket's
* file descriptor queue, and the file descriptor is for a file open by this
* service. For each set of in-flight file descriptors associated with a
* particular segment, the first object's count field contains the number of
* file descriptors in that set. For all other objects in that set, the count
* field is zero. TODO: the count should be stored in the segment itself.
*/
struct uds_fd {
/* Flags */
enum UDS_STATE {
/* This file descriptor is UDS_FREE and can be allocated. */
UDS_FREE = 0,
/* OR it is UDS_INUSE and can't be allocated. */
UDS_INUSE = 1
/* state is set to UDS_INUSE in uds_open(). state is Set to
* UDS_FREE in uds_init() and uds_close(). state should be
* checked prior to all operations.
*/
} state;
/* Owner Info */
/* Socket Owner */
endpoint_t owner;
/* Pipe Housekeeping */
char *buf; /* ring buffer */
size_t pos; /* tail position into ring buffer */
size_t size; /* size of used part of ring buffer */
/* control read/write, set by uds_open() and shutdown(2).
* Can be set to UDS_R|UDS_W, UDS_R, UDS_W, or 0
* for read and write, read only, write only, or neither.
* default is UDS_R|UDS_W.
*/
int mode;
/* Socket Info */
/* socket type - SOCK_STREAM, SOCK_DGRAM, or SOCK_SEQPACKET
* Set by uds_ioctl(NWIOSUDSTYPE). It defaults to -1 in
* uds_open(). Any action on a socket with type -1 besides
* uds_ioctl(NWIOSUDSTYPE) and uds_close() will result in
* an error.
*/
int type;
/* queue of pending connections for server sockets.
* connect(2) inserts and accept(2) removes from the queue
*/
int backlog[UDS_SOMAXCONN];
/* requested connection backlog size. Set by listen(2)
* Bounds (0 <= backlog_size <= UDS_SOMAXCONN)
* Defaults to UDS_SOMAXCONN which is defined above.
*/
unsigned char backlog_size;
/* index of peer in uds_fd_table for connected sockets.
* -1 is used to mean no peer. Assumptions: peer != -1 means
* connected.
*/
int peer;
/* index of child (client sd returned by accept(2))
* -1 is used to mean no child.
*/
int child;
/* address -- the address the socket is bound to.
* Assumptions: addr.sun_family == AF_UNIX means its bound.
*/
struct sockaddr_un addr;
/* target -- where DGRAMs are sent to on the next uds_write(). */
struct sockaddr_un target;
/* source -- address where DGRAMs are from. used to fill in the
* from address in recvfrom(2) and recvmsg(2).
*/
struct sockaddr_un source;
/* Flag (TRUE or FALSE) - address overridden by newer socket.
* Default to FALSE. Set to TRUE by do_bind() on another socket with
* the same path but its on-disk socket file removed in the meantime.
*/
int stale;
/* Flag (TRUE or FALSE) - listening for incoming connections.
* Default to FALSE. Set to TRUE by do_listen().
*/
int listening;
/* stores file pointers and credentials being sent between
* processes with sendmsg(2) and recvmsg(2).
*/
struct ancillary ancillary_data;
/* Holds an errno. This is set when a connected socket is
* closed and we need to pass ECONNRESET on to a suspended
* peer.
*/
int err;
/* Suspend/Revive Housekeeping */
/* SUSPEND State Flags */
enum UDS_SUSPENDED {
/* Socket isn't blocked. */
UDS_NOT_SUSPENDED = 0,
/* Socket is blocked on read(2) waiting for data to read. */
UDS_SUSPENDED_READ = 1,
/* Socket is blocked on write(2) for space to write data. */
UDS_SUSPENDED_WRITE = 2,
/* Socket is blocked on connect(2) waiting for the server. */
UDS_SUSPENDED_CONNECT = 4,
/* Socket is blocked on accept(2) waiting for clients. */
UDS_SUSPENDED_ACCEPT = 8
} suspended;
/* source endpoint, saved for later use by suspended procs */
endpoint_t susp_endpt;
/* i/o grant, saved for later use by suspended procs */
cp_grant_id_t susp_grant;
/* size of request, saved for later use by suspended procs */
size_t susp_size;
/* request ID, saved for later use by suspended procs */
cdev_id_t susp_id;
/* select() */
/* when a select is in progress, we notify this endpoint
* of new data.
*/
endpoint_t sel_endpt;
/* Options (CDEV_OP_RD,WR,ERR) that are requested. */
unsigned int sel_ops;
SIMPLEQ_ENTRY(uds_fd) ufd_next; /* next FD object for this socket */
int ufd_fd; /* local file descriptor number */
unsigned int ufd_count; /* number of FDs for this segment */
};
typedef struct uds_fd uds_fd_t;
/*
* Connection-type sockets (SOCK_STREAM, SOCK_SEQPACKET) are always in one of
* the following five states, each with unique characteristics:
*
* - Unconnected: this socket is not in any of the other states, usually
* because it either has just been created, or because it has failed a
* connection attempt. This socket has no connected peer and does not have
* the SO_ACCEPTCONN socket option set.
* - Listening: this socket is in listening mode. It has a queue with sockets
* that are connecting or connected to it but have not yet been accepted on
* it. This socket has no connected peer. It has the SO_ACCEPTCONN socket
* option set.
* - Connecting: this socket is on a listening socket's queue. While in this
* state, the socket has the listening socket as its linked peer, and it has
* no connected peer.
* - Connected: this socket is connected to another socket, which is its
* connected peer socket. It has the UDSF_CONNECTED flag set. A socket may
* be connected and still be involved with a listening socket; see below.
* - Disconnected: this socket was connected to another socket, but that other
* socket has been closed. As a result, this socket has no peer. It does
* have the UDSF_CONNECTED flag set.
*
* The UDS service supports two different type of connect behaviors, depending
* on what the LOCAL_CONNWAIT option is set to on either the connecting or the
* listening socket. If LOCAL_CONNWAIT is not set on either (the default), the
* connecting socket socket (let's call it "A") enters the connected state
* right away, even if the connection is not immediately accepted through
* accept(2). In that case, a new limbo socket "B" is allocated as its
* connection peer. Limbo socket B is also in connected state, and either
* returned from accept(2) later, or freed when socket A leaves the connected
* state. Socket A can leave the connected state either by being closed or
* when the listening socket is closed. If LOCAL_CONNWAIT is set, socket A
* stays in the connecting state until it is accepted through accept(2).
* Importantly, in both cases, it is socket A, and (in the first case) *not*
* socket B, that is on the queue of the listening socket!
*
* Connected peers (uds_conn) are always symmetric: if one socket is connected
* to another socket, that other socket is connected to it. Any socket that is
* on the queue of another socket, is said to be "linked" to that other socket
* (uds_link). This is an asymmetric, one-to-many relationship: many sockets
* may be linked to one other socket, which keeps all those sockets on its
* queue. From the above story it should now be clear that for connection-type
* sockets, only listening sockets may have sockets on its queue, and while
* connecting sockets are always on a listening socket's queue, connected
* sockets may or may not be. Sockets in other states never are.
*
* UNIX domain sockets are generally reusable. This means that the listening
* state is the only final state; all other socket states allow the socket to
* enter another state, although not necessarily every other state. For
* example, a disconnected socket may be reconnected to another target; if that
* connection fails, the socket will enter the unconnected state. As a result,
* a socket in any state (even the listening state) may still have incoming
* data pending from a previous connection. However, EOF is currently produced
* only for disconnected sockets. To be sure: connecting and connected sockets
* must first enter the unconnected or disconnected state, respectively, before
* possibly being reconnected.
*
* For connectionless (i.e., SOCK_DGRAM) sockets, there are no separate states.
* However, a connectionless socket may have been connected to another socket.
* We maintain these links not with uds_conn but with uds_link, because such
* connections are not symmetric, and there is an interest in keeping track of
* which datagram sockets are connected to a particular socket (namely, to
* break the connection on close without doing an exhaustive search). For that
* reason, when a datagram socket connects to another socket, it is linked to
* that other socket, and the other socket has this socket on its queue. As a
* strange corner case, a connectionless socket may be connected to itself, in
* which case it is its own linked peer and it is also on its own queue. For
* datagram sockets, uds_conn is always NULL and UDSF_CONNECTED is never set.
*
* For the purposes of sending and receiving, we generally refer to the
* communication partner of a socket as its "peer". As should now be clear,
* for connection-type sockets, the socket's peer is identified with uds_conn;
* for connectionless sockets, the socket's peer is identified with uds_link.
*/
struct udssock {
struct sock uds_sock; /* sock object */
struct udssock *uds_conn; /* connected socket, or NULL if none */
struct udssock *uds_link; /* linked socket, or NULL if none */
unsigned char *uds_buf; /* receive buffer (memory-mapped) */
unsigned short uds_tail; /* tail of data in receive buffer */
unsigned short uds_len; /* length of data in receive buffer */
unsigned short uds_last; /* offset to last header in buffer */
unsigned short uds_queued; /* current nr of sockets on queue */
unsigned short uds_backlog; /* maximum nr of connecting sockets */
unsigned char uds_flags; /* UDS-specific flags (UDSF_) */
unsigned char uds_pathlen; /* socket file path length (w/o nul) */
char uds_path[UDS_PATH_MAX - 1];/* socket file path (not terminated) */
dev_t uds_dev; /* socket file device number */
ino_t uds_ino; /* socket file inode number */
struct unpcbid uds_cred; /* bind/connect-time credentials */
SLIST_ENTRY(udssock) uds_hash; /* next in hash chain */
TAILQ_ENTRY(udssock) uds_next; /* next in free list or queue */
SIMPLEQ_HEAD(, uds_fd) uds_fds; /* in-flight file descriptors */
TAILQ_HEAD(, udssock) uds_queue;/* queue of linked sockets */
};
/* File Descriptor Table -- Defined in uds.c */
EXTERN uds_fd_t uds_fd_table[NR_FDS];
#define UDSF_IN_USE 0x01 /* in use (for enumeration only) */
#define UDSF_CONNECTED 0x02 /* connected or disconnected */
#define UDSF_CONNWAIT 0x04 /* leave connecting until accept */
#define UDSF_PASSCRED 0x08 /* pass credentials when receiving */
/* Macros. */
#define uds_get_type(uds) sockevent_get_type(&(uds)->uds_sock)
/*
* A socket that can be found through hash table lookups always has a non-empty
* path as well as a valid <dev,ino> pair identifying the socket file that is,
* or once was, identified by that path. However, a socket that is bound, even
* though it will still have an associated path, is not necessarily hashed.
* The reason for the difference is <dev,ino> pair reuse. This case is
* elaborated on in uds_bind().
*/
#define uds_is_bound(uds) ((uds)->uds_pathlen != 0)
#define uds_is_hashed(uds) ((uds)->uds_dev != NO_DEV)
/*
* These macros may be used on all socket types. However, the uds_is_connected
* macro returns TRUE only for connection-oriented sockets. To see if a
* datagram socket is connected to a target, use uds_has_link instead.
*/
#define uds_has_conn(uds) ((uds)->uds_conn != NULL)
#define uds_has_link(uds) ((uds)->uds_link != NULL)
#define uds_get_peer(uds) \
((uds_get_type(uds) != SOCK_DGRAM) ? (uds)->uds_conn : (uds)->uds_link)
#define uds_is_listening(uds) sockevent_is_listening(&(uds)->uds_sock)
#define uds_is_connecting(uds) \
(uds_has_link(uds) && !((uds)->uds_flags & UDSF_CONNECTED) && \
uds_get_type(uds) != SOCK_DGRAM)
#define uds_is_connected(uds) \
(((uds)->uds_flags & UDSF_CONNECTED) && uds_has_conn(uds))
#define uds_is_disconnected(uds) \
(((uds)->uds_flags & UDSF_CONNECTED) && !uds_has_conn(uds))
#define uds_is_shutdown(uds, mask) \
sockevent_is_shutdown(&(uds)->uds_sock, (mask))
/* Function prototypes. */
/* ioc_uds.c */
int uds_clear_fds(devminor_t minor, struct ancillary *data);
int uds_do_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
cp_grant_id_t grant);
/* uds.c */
ssize_t uds_perform_read(devminor_t minor, endpoint_t endpt,
cp_grant_id_t grant, size_t size, int pretend);
void uds_unsuspend(devminor_t minor);
sockid_t uds_get_id(struct udssock * uds);
struct udssock *uds_enum(struct udssock * prev, int type);
void uds_make_addr(const char * path, size_t len, struct sockaddr * addr,
socklen_t * addr_len);
int uds_lookup(struct udssock * uds, const struct sockaddr * addr,
socklen_t addr_len, endpoint_t user_endpt, struct udssock ** peerp);
#endif /* !__UDS_UDS_H */
/* io.c */
void uds_io_init(void);
int uds_io_setup(struct udssock * uds);
void uds_io_cleanup(struct udssock * uds);
void uds_io_reset(struct udssock * uds);
size_t uds_io_buflen(void);
int uds_pre_send(struct sock * sock, size_t len, socklen_t ctl_len,
const struct sockaddr * addr, socklen_t addr_len,
endpoint_t user_endpt, int flags);
int uds_send(struct sock * sock, const struct sockdriver_data * data,
size_t len, size_t * off, const struct sockdriver_data * ctl,
socklen_t ctl_len, socklen_t * ctl_off, const struct sockaddr * addr,
socklen_t addr_len, endpoint_t user_endpt, int flags, size_t min);
int uds_test_send(struct sock * sock, size_t min);
int uds_pre_recv(struct sock * sock, endpoint_t user_endpt, int flags);
int uds_recv(struct sock * sock, const struct sockdriver_data * data,
size_t len, size_t * off, const struct sockdriver_data * ctl,
socklen_t ctl_len, socklen_t * ctl_off, struct sockaddr * addr,
socklen_t * addr_len, endpoint_t user_endpt, int flags, size_t min,
int * rflags);
int uds_test_recv(struct sock * sock, size_t min, size_t * size);
/* stat.c */
void uds_stat_init(void);
void uds_stat_cleanup(void);
#endif /* !MINIX_NET_UDS_UDS_H */

View File

@ -10,6 +10,7 @@ unix \- Unix Domain Sockets (PF_UNIX) / Local Sockets (PF_LOCAL)
.in +5
.ti -5
int socket(int \fIdomain\fP, int \fItype\fP, int \fIprotocol\fP);
.br
.ti -5
int socketpair(int \fIdomain\fP, int \fItype\fP, int \fIprotocol\fP, int \fIsv[2]\fP);
.br
@ -18,9 +19,8 @@ int socketpair(int \fIdomain\fP, int \fItype\fP, int \fIprotocol\fP, int \fIsv[2
Local sockets, more commonly known as Unix Domain Sockets, provide a
means of interprocess communication using the socket API.
.SH SEE ALSO
.BR socket(2),
.BR socketpair(2),
.BR getpeereid(2),
.BR uds(8)
.BR socket(2) ,
.BR socketpair(2) ,
.BR getpeereid(3)
.SH HISTORY
This Unix Domain Sockets first appeared in Minix 3.1.8.
This Unix Domain Sockets first appeared in MINIX 3.1.8.

View File

@ -525,7 +525,8 @@ int do_copyfd(void)
{
/* Copy a file descriptor between processes, or close a remote file descriptor.
* This call is used as back-call by device drivers (UDS, VND), and is expected
* to be used in response to an IOCTL to such device drivers.
* to be used in response to either an IOCTL to VND or a SEND or RECV socket
* request to UDS.
*/
struct fproc *rfp;
struct filp *rfilp;
@ -548,9 +549,9 @@ int do_copyfd(void)
rfp = &fproc[slot];
/* FIXME: we should now check that the user process is indeed blocked on an
* IOCTL call, so that we can safely mess with its file descriptors. We
* currently do not have the necessary state to verify this, so we assume
* that the call is always used in the right way.
* IOCTL or socket call, so that we can safely mess with its file
* descriptors. We currently do not have the necessary state to verify this,
* so we assume that the call is always used in the right way.
*/
/* Depending on the operation, get the file descriptor from the caller or the
@ -566,7 +567,7 @@ int do_copyfd(void)
* passes in the file descriptor to the device node on which it is performing
* the IOCTL. We do not allow manipulation of such device nodes. In
* practice, this only applies to block-special files (and thus VND), because
* character-special files (as used by UDS) are unlocked during the IOCTL.
* socket files (as used by UDS) are unlocked during the socket operation.
*/
if (rfilp->filp_ioctl_fp == rfp)
return(EBADF);

View File

@ -535,9 +535,9 @@ int do_mknod(void)
resolve.l_vnode_lock = VNODE_WRITE;
/* Only the super_user may make nodes other than fifos. */
if (!super_user && (!S_ISFIFO(mode_bits) && !S_ISSOCK(mode_bits))) {
if (!super_user && !S_ISFIFO(mode_bits))
return(EPERM);
}
bits = (mode_bits & S_IFMT) | (mode_bits & ACCESSPERMS & fp->fp_umask);
/* Open directory that's going to hold the new node. */

View File

@ -15,7 +15,6 @@
#include <minix/vfsif.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/dirent.h>
#include "vmnt.h"
#include "vnode.h"
@ -819,7 +818,6 @@ int do_socketpath(void)
struct fproc *rfp;
char path[PATH_MAX];
struct lookup resolve, resolve2;
struct sockaddr_un sun;
mode_t bits;
/* This should be replaced by an ACL check. */
@ -831,24 +829,16 @@ int do_socketpath(void)
what = job_m_in.m_lsys_vfs_socketpath.what;
if (isokendpt(ep, &slot) != OK) return(EINVAL);
if (pathlen < sizeof(sun.sun_path) || pathlen >= PATH_MAX) return(EINVAL);
rfp = &fproc[slot];
rfp = &(fproc[slot]);
/* Copy in the path name, which must not be empty. It is typically not null
* terminated.
*/
if (pathlen < 1 || pathlen >= sizeof(path)) return(EINVAL);
r = sys_safecopyfrom(who_e, io_gr, (vir_bytes)0, (vir_bytes)path, pathlen);
if (r != OK) return(r);
path[pathlen] = '\0';
/* If requested, turn path into canonical path to the socket file */
if (what & SPATH_CANONIZE) {
if ((r = canonical_path(path, rfp)) != OK) return(r);
if (strlen(path) >= pathlen) return(ENAMETOOLONG);
/* copy path back to the caller */
r = sys_safecopyto(who_e, (cp_grant_id_t)io_gr, (vir_bytes)0,
(vir_bytes)path, pathlen);
if (r != OK) return(r);
}
/* Now perform the requested action. For the SPATH_CHECK action, a socket
* file is expected to exist already, and we should check whether the given
* user process has access to it. For the SPATH_CREATE action, no file is
@ -859,7 +849,7 @@ int do_socketpath(void)
* Since the above canonicalization releases all locks once done, we need to
* recheck absolutely everything now. TODO: do not release locks in between.
*/
switch (what & ~SPATH_CANONIZE) {
switch (what) {
case SPATH_CHECK:
lookup_init(&resolve, path, PATH_NOFLAGS, &vmp, &vp);
resolve.l_vmnt_lock = VMNT_READ;

View File

@ -50,16 +50,19 @@ static char *get_timestamp(void)
void test_fail_fl(char *msg, char *file, int line)
{
char *timestamp;
int e;
e = errno;
timestamp = get_timestamp();
if (errct == 0) fprintf(stderr, "\n");
errno = e;
fprintf(stderr, "[ERROR][%s] (%s Line %d) %s [pid=%d:errno=%d:%s]\n",
timestamp, file, line, msg, getpid(),
errno, strerror(errno));
timestamp, file, line, msg, getpid(), errno, strerror(errno));
fflush(stderr);
if (timestamp != NULL) {
free(timestamp);
timestamp = NULL;
}
errno = e;
e(7);
}
@ -317,7 +320,7 @@ void test_shutdown(const struct socket_test_info *info)
SOCKET(sd, info->domain, info->type, 0);
errno = 0;
rc = shutdown(sd, how[i]);
if (!(rc == -1 && errno == ENOTCONN) &&
if (rc != 0 && !(rc == -1 && errno == ENOTCONN) &&
!info->bug_shutdown_not_conn &&
!info->bug_shutdown) {
test_fail("shutdown() should have failed");
@ -328,10 +331,10 @@ void test_shutdown(const struct socket_test_info *info)
SOCKET(sd, info->domain, info->type, 0);
errno = 0;
rc = shutdown(sd, -1);
if (!(rc == -1 && errno == ENOTCONN) &&
if (!(rc == -1 && errno == EINVAL) &&
!info->bug_shutdown_not_conn &&
!info->bug_shutdown) {
test_fail("shutdown(sd, -1) should have failed with ENOTCONN");
test_fail("shutdown(sd, -1) should have failed with EINVAL");
}
CLOSE(sd);
@ -431,8 +434,6 @@ void test_sockopts(const struct socket_test_info *info)
CLOSE(sd);
}
SOCKET(sd, info->domain, info->type, 0);
debug("Test setsockopt() works");
@ -901,9 +902,6 @@ static void test_xfer_client(const struct socket_test_info *info)
test_fail("[client] getpeername() should have worked");
}
/* we need to use the full path "/usr/src/test/DIR_56/test.sock"
* because that is what is returned by getpeername().
*/
info->callback_check_sockaddr((struct sockaddr *) &peer_addr,
peer_addr_len, "getpeername", 1);
@ -1299,8 +1297,8 @@ static void test_abort_client(const struct socket_test_info *info,
if (!info->ignore_write_conn_reset) {
test_fail("write should have failed\n");
}
} else if (errno != ECONNRESET) {
test_fail("errno should've been ECONNRESET\n");
} else if (errno != EPIPE && errno != ECONNRESET) {
test_fail("errno should've been EPIPE/ECONNRESET\n");
}
}
@ -1353,7 +1351,7 @@ static void test_abort_server(const struct socket_test_info *info,
if (abort_type == 1) {
memset(buf, '\0', BUFSIZE);
rc = read(client_sd, buf, BUFSIZE);
if (rc != -1 && (rc != 0 || !info->ignore_read_conn_reset)) {
if (rc != 0 && rc != -1) {
test_fail("read should've failed or returned zero\n");
}
if (rc != 0 && errno != ECONNRESET) {
@ -1518,9 +1516,6 @@ void test_msg_dgram(const struct socket_test_info *info)
test_fail("recvmsg");
}
/* we need to use the full path "/usr/src/test/DIR_56/testb.sock"
* because that is what is returned by recvmsg().
*/
info->callback_check_sockaddr((struct sockaddr *) &addr,
msg2.msg_namelen, "recvmsg", 2);
@ -1603,6 +1598,9 @@ test_nonblock(const struct socket_test_info *info)
if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
test_fail("bind() should have worked");
if (info->callback_set_listen_opt != NULL)
info->callback_set_listen_opt(server_sd);
if (listen(server_sd, 8) == -1)
test_fail("listen() should have worked");
@ -1813,6 +1811,9 @@ test_intr(const struct socket_test_info *info)
if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
test_fail("bind() should have worked");
if (info->callback_set_listen_opt != NULL)
info->callback_set_listen_opt(server_sd);
if (listen(server_sd, 8) == -1)
test_fail("listen() should have worked");
@ -1844,6 +1845,9 @@ test_intr(const struct socket_test_info *info)
errct = 0;
close(client_sd);
/* Ensure that the parent is blocked on the send(). */
sleep(1);
check_select(server_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/);
len = sizeof(addr);
@ -1932,6 +1936,9 @@ test_connect_close(const struct socket_test_info *info)
if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
test_fail("bind() should have worked");
if (info->callback_set_listen_opt != NULL)
info->callback_set_listen_opt(server_sd);
if (listen(server_sd, 8) == -1)
test_fail("listen() should have worked");
@ -1989,6 +1996,9 @@ test_listen_close(const struct socket_test_info *info)
if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
test_fail("bind() should have worked");
if (info->callback_set_listen_opt != NULL)
info->callback_set_listen_opt(server_sd);
if (listen(server_sd, 8) == -1)
test_fail("listen() should have worked");
@ -2009,7 +2019,6 @@ test_listen_close(const struct socket_test_info *info)
byte = 0;
if (write(client_sd, &byte, 1) != -1 || errno != ENOTCONN)
/* Yes, you fucked up the fix for the FIXME below. */
test_fail("write() should have yielded ENOTCONN");
if (connect(client_sd, info->clientaddr, info->clientaddrlen) != -1) {
@ -2021,14 +2030,16 @@ test_listen_close(const struct socket_test_info *info)
}
/*
* FIXME: currently UDS cannot distinguish between sockets that have
* not yet been connected, and sockets that have been disconnected.
* Thus, we get the same error for both: ENOTCONN instead of EPIPE.
* The error we get on the next write() depends on whether the socket
* may be reused after a failed connect: for TCP/IP, it may not, so we
* get EPIPE; for UDS, it may be reused, so we get ENOTCONN.
*/
#if 0
if (write(client_sd, &byte, 1) != -1 || errno != EPIPE)
test_fail("write() should have yielded EPIPE");
#endif
if (!info->bug_connect_after_close) {
if (write(client_sd, &byte, 1) != -1 ||
(errno != EPIPE && errno != ENOTCONN))
test_fail("write() should have yielded "
"EPIPE/ENOTCONN");
}
close(client_sd);
@ -2059,6 +2070,9 @@ test_listen_close_nb(const struct socket_test_info *info)
if (bind(server_sd, info->serveraddr, info->serveraddrlen) == -1)
test_fail("bind() should have worked");
if (info->callback_set_listen_opt != NULL)
info->callback_set_listen_opt(server_sd);
if (listen(server_sd, 8) == -1)
test_fail("listen() should have worked");
@ -2097,16 +2111,6 @@ test_listen_close_nb(const struct socket_test_info *info)
test_fail("write() should have yielded ECONNRESET");
}
/*
* FIXME: currently UDS cannot distinguish between sockets that have
* not yet been connected, and sockets that have been disconnected.
* Thus, we get the same error for both: ENOTCONN instead of EPIPE.
*/
#if 0
if (write(client_sd, &byte, 1) != -1 || errno != EPIPE)
test_fail("write() should have yielded EPIPE");
#endif
check_select_cond(client_sd, 1 /*read*/, 1 /*write*/, 0 /*block*/,
!info->ignore_select_delay);

View File

@ -88,7 +88,6 @@ struct socket_test_info {
int ignore_accept_delay; /* success from accept after aborted connect */
int ignore_connect_delay; /* nb connect not instant */
int ignore_connect_unaccepted; /* connect succeeds without accept */
int ignore_read_conn_reset; /* read does not guarantee ECONNRESET */
int ignore_select_delay; /* select delay reflecting other side nb op */
int ignore_send_waiting; /* can send while waiting for nb recv */
int ignore_write_conn_reset; /* write does not guarantee ECONNRESET */
@ -98,6 +97,7 @@ struct socket_test_info {
void (* callback_cleanup)(void);
void (* callback_xfer_peercred)(int sd); /* can be NULL */
void (* callback_xfer_prepclient)(void); /* can be NULL */
void (* callback_set_listen_opt)(int sd); /* can be NULL */
};
void test_abort_client_server(const struct socket_test_info *info,

View File

@ -78,20 +78,6 @@ int max_error = 4;
/* socket types supported */
static int types[3] = {SOCK_STREAM, SOCK_SEQPACKET, SOCK_DGRAM};
static char sock_fullpath[PATH_MAX + 1];
/* Convert name to the full path of the socket. Assumes name is in cwd. */
static char *fullpath(const char *name)
{
char cwd[PATH_MAX + 1];
if (realpath(".", cwd) == NULL)
test_fail("Couldn't retrieve current working dir");
snprintf(sock_fullpath, PATH_MAX, "%s/%s", cwd, name);
return(sock_fullpath);
}
static void test_header(void)
{
@ -187,16 +173,16 @@ static void test_socketpair(void)
static void test_ucred(void)
{
struct uucred credentials;
struct unpcbid credentials;
socklen_t ucred_length;
uid_t euid = geteuid();
gid_t egid = getegid();
int sv[2];
int rc;
debug("Test credentials passing");
debug("Test peer credentials");
ucred_length = sizeof(struct uucred);
ucred_length = sizeof(credentials);
rc = socketpair(PF_UNIX, SOCK_STREAM, 0, sv);
if (rc == -1) {
@ -204,22 +190,24 @@ static void test_ucred(void)
}
memset(&credentials, '\0', ucred_length);
rc = getsockopt(sv[0], SOL_SOCKET, SO_PEERCRED, &credentials,
rc = getsockopt(sv[0], 0, LOCAL_PEEREID, &credentials,
&ucred_length);
if (rc == -1) {
test_fail("getsockopt(SO_PEERCRED) failed");
} else if (credentials.cr_ngroups != 0 ||
credentials.cr_uid != geteuid() ||
credentials.cr_gid != getegid()) {
/* printf("%d=%d %d=%d %d=%d",credentials.cr_ngroups, 0,
credentials.cr_uid, geteuid(), credentials.cr_gid, getegid()); */
test_fail("getsockopt(LOCAL_PEEREID) failed");
} else if (credentials.unp_pid != getpid() ||
credentials.unp_euid != geteuid() ||
credentials.unp_egid != getegid()) {
printf("%d=%d %d=%d %d=%d",credentials.unp_pid, getpid(),
credentials.unp_euid, geteuid(),
credentials.unp_egid, getegid());
test_fail("Credential passing gave us the wrong cred");
}
rc = getpeereid(sv[0], &euid, &egid);
if (rc == -1) {
test_fail("getpeereid(sv[0], &euid, &egid) failed");
} else if (credentials.cr_uid != euid || credentials.cr_gid != egid) {
} else if (credentials.unp_euid != euid ||
credentials.unp_egid != egid) {
test_fail("getpeereid() didn't give the correct euid/egid");
}
@ -245,7 +233,7 @@ static void callback_check_sockaddr(const struct sockaddr *sockaddr,
if (!(sockaddr_un->sun_family == AF_UNIX &&
strncmp(sockaddr_un->sun_path,
fullpath(path),
path,
sizeof(sockaddr_un->sun_path) - 1) == 0)) {
snprintf(buf, sizeof(buf), "%s() didn't return the right addr",
@ -293,7 +281,6 @@ static void test_bind_unix(void)
UNLINK(TEST_SYM_A);
UNLINK(TEST_SYM_B);
SYMLINK(TEST_SYM_A, TEST_SYM_B);
SYMLINK(TEST_SYM_B, TEST_SYM_A);
SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
@ -301,6 +288,19 @@ static void test_bind_unix(void)
strncpy(addr.sun_path, TEST_SYM_A, sizeof(addr.sun_path) - 1);
errno = 0;
rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
if (!((rc == -1) && (errno == EADDRINUSE))) {
test_fail("bind() should have failed with EADDRINUSE");
}
CLOSE(sd);
SYMLINK(TEST_SYM_A, TEST_SYM_B);
SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
strncpy(addr.sun_path, TEST_SYM_A, sizeof(addr.sun_path) - 1);
strlcat(addr.sun_path, "/x", sizeof(addr.sun_path));
errno = 0;
rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
if (!((rc == -1) && (errno == ELOOP))) {
test_fail("bind() should have failed with ELOOP");
}
@ -337,28 +337,49 @@ static void callback_xfer_prepclient(void) {
}
static void callback_xfer_peercred(int sd) {
struct uucred credentials;
struct unpcbid credentials;
int rc;
socklen_t ucred_length;
ucred_length = sizeof(struct uucred);
ucred_length = sizeof(credentials);
debug("Test passing the client credentials to the server");
debug("Test obtaining the peer credentials");
memset(&credentials, '\0', ucred_length);
rc = getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &credentials,
&ucred_length);
rc = getsockopt(sd, 0, LOCAL_PEEREID, &credentials, &ucred_length);
if (rc == -1) {
test_fail("[client] getsockopt() failed");
} else if (credentials.cr_uid != geteuid() ||
credentials.cr_gid != getegid()) {
printf("%d=%d=%d %d=%d=%d\n", credentials.cr_uid, getuid(),
geteuid(), credentials.cr_gid, getgid(), getegid());
} else if (credentials.unp_euid != geteuid() ||
credentials.unp_egid != getegid()) {
printf("%d=* %d=%d %d=%d", credentials.unp_pid,
credentials.unp_euid, geteuid(),
credentials.unp_egid, getegid());
test_fail("[client] Credential passing gave us a bad UID/GID");
}
}
static void
callback_set_listen_opt(int sd)
{
int val;
/*
* Several of the tests assume that a new connection to a server will
* not be established (i.e., go from "connecting" to "connected" state)
* until the server actually accepts the connection with an accept(2)
* call. With the new UDS implementation, this is no longer true: to
* match the behavior of other systems, UDS now preemptively connects
* the socket in anticipation of the accept(2) call. We can change
* back to the old behavior by setting LOCAL_CONNWAIT however, and
* since the test effectively tests a larger set of socket transitions
* that way, that is what we do for these tests.
*/
val = 1;
if (setsockopt(sd, 0, LOCAL_CONNWAIT, &val, sizeof(val)) != 0)
test_fail("setsockopt(LOCAL_CONNWAIT)");
}
static void test_vectorio(int type)
{
int sv[2];
@ -563,7 +584,11 @@ static void test_scm_credentials(void)
int rc;
int src;
int dst;
struct uucred cred;
int one;
union {
struct sockcred cred;
char buf[SOCKCREDSIZE(NGROUPS_MAX)];
} cred;
struct cmsghdr *cmsg = NULL;
struct sockaddr_un addr;
struct iovec iov[3];
@ -573,7 +598,7 @@ static void test_scm_credentials(void)
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char ctrl[BUFSIZE];
socklen_t addrlen = sizeof(struct sockaddr_un);
socklen_t len, addrlen = sizeof(struct sockaddr_un);
debug("test_scm_credentials");
@ -615,6 +640,16 @@ static void test_scm_credentials(void)
test_fail("bind");
}
debug("request credential passing");
one = 1;
rc = setsockopt(dst, 0, LOCAL_CREDS, &one, sizeof(one));
if (rc == -1) {
test_fail("setsockopt(LOCAL_CREDS)");
}
debug("sending msg1");
memset(&buf1, '\0', BUFSIZE);
memset(&buf2, '\0', BUFSIZE);
memset(&buf3, '\0', BUFSIZE);
@ -640,8 +675,6 @@ static void test_scm_credentials(void)
msg1.msg_controllen = 0;
msg1.msg_flags = 0;
debug("sending msg1");
rc = sendmsg(src, &msg1, 0);
if (rc == -1) {
test_fail("sendmsg");
@ -684,27 +717,50 @@ static void test_scm_credentials(void)
* because that is what is returned by recvmsg().
*/
if (addr.sun_family != AF_UNIX || strcmp(addr.sun_path,
fullpath(TEST_SUN_PATHB))) {
TEST_SUN_PATHB)) {
test_fail("recvmsg");
}
debug("looking for credentials");
memset(&cred, '\0', sizeof(struct uucred));
len = 0;
memset(&cred, 'x', sizeof(cred));
for (cmsg = CMSG_FIRSTHDR(&msg2); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg2, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_CREDS) {
/* Great, this alignment business! But then at least
* give me a macro to compute the actual data length..
*/
len = cmsg->cmsg_len - (socklen_t)
((char *)CMSG_DATA(cmsg) - (char *)cmsg);
memcpy(&cred, CMSG_DATA(cmsg), sizeof(struct uucred));
if (len < sizeof(struct sockcred))
test_fail("credentials too small");
else if (len > sizeof(cred))
test_fail("credentials too large");
memcpy(cred.buf, CMSG_DATA(cmsg), len);
break;
}
}
if (cred.cr_ngroups != 0 || cred.cr_uid != geteuid() ||
cred.cr_gid != getegid()) {
if (len == 0)
test_fail("no credentials found");
if (len != SOCKCREDSIZE(cred.cred.sc_ngroups))
test_fail("wrong credentials size");
/*
* TODO: check supplementary groups. This whole test is pretty much
* pointless since we're running with very standard credentials anyway.
*/
if (cred.cred.sc_uid != getuid() ||
cred.cred.sc_euid != geteuid() ||
cred.cred.sc_gid != getgid() ||
cred.cred.sc_egid != getegid() ||
cred.cred.sc_ngroups < 0 || cred.cred.sc_ngroups > NGROUPS_MAX) {
test_fail("did no receive the proper credentials");
}
@ -1384,22 +1440,18 @@ static void test_fchmod(void)
* Test various aspects related to the socket files on the file system.
* This subtest is woefully incomplete and currently only attempts to test
* aspects that have recently been affected by code changes. In the future,
* there should be tests for path canonicalization and the entire range of file
* system path and access related error codes (TODO).
* there should be tests for the entire range of file system path and access
* related error codes (TODO).
*/
static void
test_file(void)
{
struct sockaddr_un addr;
#if NOT_YET
struct sockaddr_un saddr, saddr2;
struct sockaddr_un addr, saddr, saddr2;
char buf[1];
socklen_t len;
struct stat st;
mode_t omask;
int, csd, fd;
#endif
int sd, sd2;
int sd, sd2, csd, fd;
/*
* If the provided socket path exists on the file system, the bind(2)
@ -1426,7 +1478,6 @@ test_file(void)
CLOSE(sd);
#if NOT_YET
if (bind(sd2, (struct sockaddr *)&addr, sizeof(addr)) != -1)
test_fail("Binding socket unexpectedly succeeded");
if (errno != EADDRINUSE)
@ -1497,29 +1548,8 @@ test_file(void)
if (memcmp(&saddr, &saddr2, sizeof(saddr)))
test_fail("Unexpected old socket address");
/*
* Currently, our implementation "hides" the old socket even if the new
* socket is closed, but since this is not standard behavior and may be
* changed later, we do not test for it. However, in any case,
* rebinding the hidden socket should make it "visible" again.
*/
strlcpy(saddr2.sun_path, TEST_SUN_PATHB, sizeof(saddr2.sun_path));
if (bind(sd, (struct sockaddr *)&saddr2, sizeof(saddr2)) != 0)
test_fail("Can't rebind socket");
memset(buf, 'Z', sizeof(buf));
if (sendto(csd, buf, sizeof(buf), 0, (struct sockaddr *)&saddr2,
sizeof(saddr2)) != sizeof(buf))
test_fail("Can't send to socket");
if (recvfrom(sd, buf, sizeof(buf), 0, NULL, 0) != sizeof(buf))
test_fail("Can't receive from socket");
if (buf[0] != 'Z')
test_fail("Transmission failure");
if (unlink(TEST_SUN_PATH) != 0)
test_fail("Can't unlink socket");
if (unlink(TEST_SUN_PATHB) != 0)
test_fail("Can't unlink other socket");
CLOSE(sd);
CLOSE(sd2);
@ -1580,7 +1610,6 @@ test_file(void)
UNLINK(TEST_SUN_PATH);
umask(omask);
#endif
/*
* Only socket(2), socketpair(2), and accept(2) may be used to obtain
@ -1631,8 +1660,8 @@ int main(int argc, char *argv[])
.clientaddrsym = (struct sockaddr *) &clientaddrsym,
.clientaddrsymlen = sizeof(clientaddrsym),
.domain = PF_UNIX,
.expected_rcvbuf = PIPE_BUF,
.expected_sndbuf = PIPE_BUF,
.expected_rcvbuf = 32768 - 5, /* no constants: */
.expected_sndbuf = 32768 - 5, /* UDS internals */
.serveraddr = (struct sockaddr *) &clientaddr,
.serveraddrlen = sizeof(clientaddr),
.serveraddr2 = (struct sockaddr *) &clientaddr2,
@ -1644,12 +1673,16 @@ int main(int argc, char *argv[])
.callback_cleanup = callback_cleanup,
.callback_xfer_prepclient = callback_xfer_prepclient,
.callback_xfer_peercred = callback_xfer_peercred,
.callback_set_listen_opt = callback_set_listen_opt,
};
debug("entering main()");
start(56);
/* This test was written before UDS started supporting SIGPIPE. */
signal(SIGPIPE, SIG_IGN);
test_socket(&info);
test_bind(&info);
test_bind_unix();

View File

@ -96,7 +96,6 @@ int main(int argc, char *argv[])
.ignore_accept_delay = 1,
.ignore_connect_unaccepted = 1,
.ignore_connect_delay = 1,
.ignore_read_conn_reset = 1,
.ignore_select_delay = 1,
.ignore_send_waiting = 1,
.ignore_write_conn_reset = 1,

View File

@ -99,7 +99,6 @@ int main(int argc, char *argv[])
.ignore_accept_delay = 1,
.ignore_connect_unaccepted = 1,
.ignore_connect_delay = 1,
.ignore_read_conn_reset = 1,
.ignore_select_delay = 1,
.ignore_send_waiting = 1,
.ignore_write_conn_reset = 1,

View File

@ -189,6 +189,27 @@ static const struct flags udpopt_flags[] = {
FLAG(NWUO_DI_IPOPT),
};
static void
put_struct_uucred(struct trace_proc * proc, const char * name, int flags,
vir_bytes addr)
{
struct uucred cred;
if (!put_open_struct(proc, name, flags, addr, &cred, sizeof(cred)))
return;
put_value(proc, "cr_uid", "%u", cred.cr_uid);
if (verbose > 0) {
put_value(proc, "cr_gid", "%u", cred.cr_gid);
if (verbose > 1)
put_value(proc, "cr_ngroups", "%d", cred.cr_ngroups);
put_groups(proc, "cr_groups", PF_LOCADDR,
(vir_bytes)&cred.cr_groups, cred.cr_ngroups);
}
put_close_struct(proc, verbose > 0);
}
static void
put_msg_control(struct trace_proc * proc, struct msg_control * ptr)
{

View File

@ -115,8 +115,6 @@ void put_dev(struct trace_proc *proc, const char *name, dev_t dev);
void put_in_addr(struct trace_proc *proc, const char *name, struct in_addr in);
void put_socket_type(struct trace_proc *proc, const char *name, int type);
void put_socket_family(struct trace_proc *proc, const char *name, int family);
void put_struct_uucred(struct trace_proc *proc, const char *name, int flags,
vir_bytes addr);
void put_cmsg_type(struct trace_proc *proc, const char *name, int type);
void put_shutdown_how(struct trace_proc *proc, const char *name, int how);

View File

@ -1802,25 +1802,32 @@ put_struct_iovec(struct trace_proc * proc, const char * name, int flags,
put_close(proc, "]");
}
void
put_struct_uucred(struct trace_proc * proc, const char * name, int flags,
vir_bytes addr)
static void
put_struct_sockcred(struct trace_proc * proc, const char * name, int flags,
vir_bytes addr, size_t left)
{
struct uucred cred;
struct sockcred sc;
if (!put_open_struct(proc, name, flags, addr, &cred, sizeof(cred)))
if (!put_open_struct(proc, name, flags, addr, &sc, sizeof(sc)))
return;
put_value(proc, "cr_uid", "%u", cred.cr_uid);
put_value(proc, "sc_uid", "%u", sc.sc_uid);
if (verbose > 0)
put_value(proc, "sc_euid", "%u", sc.sc_euid);
put_value(proc, "sc_gid", "%u", sc.sc_gid);
if (verbose > 0) {
put_value(proc, "cr_gid", "%u", cred.cr_gid);
put_value(proc, "sc_egid", "%u", sc.sc_egid);
if (verbose > 1)
put_value(proc, "cr_ngroups", "%d", cred.cr_ngroups);
put_groups(proc, "cr_groups", PF_LOCADDR,
(vir_bytes)&cred.cr_groups, cred.cr_ngroups);
put_value(proc, "sc_ngroups", "%d", sc.sc_ngroups);
if (left >= sizeof(sc.sc_groups[0]) * (sc.sc_ngroups - 1)) {
put_groups(proc, "sc_groups", flags,
addr + offsetof(struct sockcred, sc_groups),
sc.sc_ngroups);
} else
put_field(proc, "sc_groups", "..");
}
put_close_struct(proc, verbose > 0);
put_close_struct(proc, verbose > 1);
}
static void
@ -1907,7 +1914,7 @@ put_cmsg(struct trace_proc * proc, const char * name, vir_bytes addr,
size_t len)
{
struct cmsghdr cmsg;
char buf[CMSG_SPACE(sizeof(struct uucred))];
char buf[CMSG_SPACE(sizeof(struct sockcred))];
size_t off, chunk, datalen;
if (valuesonly > 1 || addr == 0 || len < CMSG_LEN(0)) {
@ -1960,10 +1967,11 @@ put_cmsg(struct trace_proc * proc, const char * name, vir_bytes addr,
addr + off + chunk, datalen);
} else if (cmsg.cmsg_level == SOL_SOCKET &&
cmsg.cmsg_type == SCM_CREDS &&
datalen >= sizeof(struct uucred) &&
datalen >= sizeof(struct sockcred) &&
chunk >= CMSG_LEN(datalen)) {
put_struct_uucred(proc, "cmsg_data", PF_LOCADDR,
(vir_bytes)&buf[CMSG_LEN(0)]);
put_struct_sockcred(proc, "cmsg_data", PF_LOCADDR,
(vir_bytes)&buf[CMSG_LEN(0)],
datalen - sizeof(struct sockcred));
} else if (datalen > 0)
put_field(proc, "cmsg_data", "..");
@ -2129,8 +2137,6 @@ put_sockopt_name(struct trace_proc * proc, const char * name, int level,
TEXT(SO_REUSEPORT);
TEXT(SO_NOSIGPIPE);
TEXT(SO_TIMESTAMP);
TEXT(SO_PASSCRED);
TEXT(SO_PEERCRED);
TEXT(SO_SNDBUF);
TEXT(SO_RCVBUF);
TEXT(SO_SNDLOWAT);
@ -2157,7 +2163,6 @@ put_sockopt_data(struct trace_proc * proc, const char * name, int flags,
const char *text;
int i;
struct linger l;
struct uucred cr;
struct timeval tv;
void *ptr;
size_t size;
@ -2183,7 +2188,6 @@ put_sockopt_data(struct trace_proc * proc, const char * name, int flags,
case SO_REUSEPORT:
case SO_NOSIGPIPE:
case SO_TIMESTAMP:
case SO_PASSCRED:
case SO_SNDBUF:
case SO_RCVBUF:
case SO_SNDLOWAT:
@ -2199,10 +2203,6 @@ put_sockopt_data(struct trace_proc * proc, const char * name, int flags,
ptr = &l;
size = sizeof(l);
break;
case SO_PEERCRED:
ptr = &cr;
size = sizeof(cr);
break;
case SO_SNDTIMEO:
case SO_RCVTIMEO:
ptr = &tv;
@ -2229,9 +2229,6 @@ put_sockopt_data(struct trace_proc * proc, const char * name, int flags,
put_value(proc, "l_linger", "%d", l.l_linger);
put_close(proc, "}");
break;
case SO_PEERCRED:
put_struct_uucred(proc, name, PF_LOCADDR, (vir_bytes)&cr);
break;
case SO_ERROR:
put_open(proc, name, 0, "{", ", ");
if (!valuesonly && (text = get_error_name(i)) != NULL)

View File

@ -133,12 +133,6 @@ typedef _BSD_SSIZE_T_ ssize_t;
#define SO_ACCEPTFILTER 0x1000 /* there is an accept filter */
#define SO_TIMESTAMP 0x2000 /* timestamp received dgram traffic */
#if defined(__minix) && defined(_MINIX_SYSTEM)
/* Minixism which should go, so hide it from userland. */
#define SO_PASSCRED 0x100000
#define SO_PEERCRED 0x200000
#endif /* defined(__minix) */
/*
* Additional options, not kept in so_options.
*/