From e8ddc0f46e4fc678592a6e14b745c2c889390ecf Mon Sep 17 00:00:00 2001 From: Thomas Veerman Date: Mon, 30 Aug 2010 13:46:44 +0000 Subject: [PATCH] - Add support for file descriptor passing to PFS. - For security reasons move some libc code to PFS. - Fix a few bugs in PFS. Contributed by Thomas Cort. --- lib/libc/ip/bind.c | 121 +------- lib/libc/ip/connect.c | 134 +-------- lib/libc/ip/recvmsg.c | 57 +++- lib/libc/ip/sendmsg.c | 77 +++-- lib/libc/ip/sendto.c | 45 +-- servers/pfs/dev_uds.c | 45 ++- servers/pfs/inc.h | 1 + servers/pfs/proto.h | 5 +- servers/pfs/uds.c | 666 +++++++++++++++++++++++++++++++++++++++++- servers/pfs/uds.h | 18 +- 10 files changed, 805 insertions(+), 364 deletions(-) diff --git a/lib/libc/ip/bind.c b/lib/libc/ip/bind.c index 2749ab7b1..72393526f 100644 --- a/lib/libc/ip/bind.c +++ b/lib/libc/ip/bind.c @@ -207,14 +207,7 @@ static int in_group(uid_t uid, gid_t gid) static int _uds_bind(int socket, const struct sockaddr *address, socklen_t address_len, struct sockaddr_un *uds_addr) { - mode_t bits, perm_bits, access_desired; - struct stat buf; - uid_t euid; - gid_t egid; - char real_sun_path[PATH_MAX+1]; - char *realpath_result; - int i, r, shift; - int null_found; + int r; int did_mknod; if (address == NULL) { @@ -222,120 +215,14 @@ static int _uds_bind(int socket, const struct sockaddr *address, return -1; } - /* sun_family is always supposed to be AF_UNIX */ - if (((struct sockaddr_un *) address)->sun_family != AF_UNIX) { - errno = EAFNOSUPPORT; - return -1; - } - - /* an empty path is not supported */ - if (((struct sockaddr_un *) address)->sun_path[0] == '\0') { - errno = ENOENT; - return -1; - } - - /* the path must be a null terminated string for realpath to work */ - for (null_found = i = 0; - i < sizeof(((struct sockaddr_un *) address)->sun_path); i++) { - if (((struct sockaddr_un *) address)->sun_path[i] == '\0') { - null_found = 1; - break; - } - } - - if (!null_found) { - errno = EINVAL; - return -1; - } - - /* - * Get the realpath(3) of the socket file. - */ - - realpath_result = realpath(((struct sockaddr_un *) address)->sun_path, - real_sun_path); - if (realpath_result == NULL) { - return -1; - } - - if (strlen(real_sun_path) >= UNIX_PATH_MAX) { - errno = ENAMETOOLONG; - return -1; - } - - strcpy(((struct sockaddr_un *) address)->sun_path, real_sun_path); - - /* - * input parameters look good -- create the socket file on the - * file system - */ - did_mknod = 0; r = mknod(((struct sockaddr_un *) address)->sun_path, S_IFSOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0); - if (r == -1) { - if (errno == EEXIST) { - /* file already exists, verify that it is a socket */ - - r = stat(((struct sockaddr_un *) address)->sun_path, - &buf); - if (r == -1) { - return -1; - } - - if (!S_ISSOCK(buf.st_mode)) { - errno = EADDRINUSE; - return -1; - } - - /* check permissions the permissions of the - * socket file. - */ - - /* read + write access */ - access_desired = R_BIT | W_BIT; - - euid = geteuid(); - egid = getegid(); - - if (euid == -1 || egid == -1) { - errno = EACCES; - return -1; - } - - bits = buf.st_mode; - - if (euid == ((uid_t) 0)) { - perm_bits = R_BIT | W_BIT; - } else { - if (euid == buf.st_uid) { - shift = 6; /* owner */ - } else if (egid == buf.st_gid) { - shift = 3; /* group */ - } else if (in_group(euid, buf.st_gid)) { - shift = 3; /* suppl. groups */ - } else { - shift = 0; /* other */ - } - - perm_bits = - (bits >> shift) & (R_BIT | W_BIT | X_BIT); - } - - if ((perm_bits | access_desired) != perm_bits) { - errno = EACCES; - return -1; - } - - /* if we get here permissions are OK */ - - } else { - - return -1; - } - } else { + if (r == -1 && errno != EEXIST) { + return -1; + } else if (r == 0) { did_mknod = 1; } diff --git a/lib/libc/ip/connect.c b/lib/libc/ip/connect.c index 292df6e79..f1f4b66a5 100644 --- a/lib/libc/ip/connect.c +++ b/lib/libc/ip/connect.c @@ -160,147 +160,15 @@ static int _udp_connect(int socket, const struct sockaddr *address, return r; } -static int in_group(uid_t uid, gid_t gid) -{ - int r, i; - int size; - gid_t *list; - - size = sysconf(_SC_NGROUPS_MAX); - list = malloc(size * sizeof(gid_t)); - - if (list == NULL) { - return 0; - } - - r= getgroups(size, list); - if (r == -1) { - free(list); - return 0; - } - - for (i = 0; i < r; i++) { - if (gid == list[i]) { - free(list); - return 1; - } - } - - free(list); - return 0; -} - static int _uds_connect(int socket, const struct sockaddr *address, socklen_t address_len) { - mode_t bits, perm_bits, access_desired; - struct stat buf; - uid_t euid; - gid_t egid; - char real_sun_path[PATH_MAX+1]; - char *realpath_result; - int i, r, shift; - int null_found; if (address == NULL) { errno = EFAULT; return -1; } - /* sun_family is always supposed to be AF_UNIX */ - if (((struct sockaddr_un *) address)->sun_family != AF_UNIX) { - errno = EAFNOSUPPORT; - return -1; - } - - /* an empty path is not supported */ - if (((struct sockaddr_un *) address)->sun_path[0] == '\0') { - errno = EINVAL; - return -1; - } - - /* the path must be a null terminated string for realpath to work */ - for (null_found = i = 0; - i < sizeof(((struct sockaddr_un *) address)->sun_path); i++) { - - if (((struct sockaddr_un *) address)->sun_path[i] == '\0') { - null_found = 1; - break; - } - } - - if (!null_found) { - errno = EINVAL; - return -1; - } - - /* - * Get the realpath(3) of the socket file. - */ - - realpath_result = realpath(((struct sockaddr_un *) address)->sun_path, - real_sun_path); - if (realpath_result == NULL) { - return -1; - } - - if (strlen(real_sun_path) >= UNIX_PATH_MAX) { - errno = ENAMETOOLONG; - return -1; - } - - strcpy(((struct sockaddr_un *) address)->sun_path, real_sun_path); - - /* - * input parameters look good -- check the permissions of the - * socket file. emulate eaccess() (i.e. the access(2) function - * with effective UID/GID). - */ - - access_desired = R_BIT | W_BIT; /* read + write access */ - - euid = geteuid(); - egid = getegid(); - - if (euid == -1 || egid == -1) { - errno = EACCES; - return -1; - } - - r= stat(((struct sockaddr_un *) address)->sun_path, &buf); - if (r == -1) { - return -1; - } - - if (!S_ISSOCK(buf.st_mode)) { - errno = EINVAL; - return -1; - } - - bits = buf.st_mode; - - if (euid == ((uid_t) 0)) { - perm_bits = R_BIT | W_BIT; - } else { - if (euid == buf.st_uid) { - shift = 6; /* owner */ - } else if (egid == buf.st_gid) { - shift = 3; /* group */ - } else if (in_group(euid, buf.st_gid)) { - shift = 3; /* suppl. groups */ - } else { - shift = 0; /* other */ - } - - perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT); - } - - if ((perm_bits | access_desired) != perm_bits) { - errno = EACCES; - return -1; - } - /* perform the connect */ - r= ioctl(socket, NWIOSUDSCONN, (void *) address); - return r; + return ioctl(socket, NWIOSUDSCONN, (void *) address); } diff --git a/lib/libc/ip/recvmsg.c b/lib/libc/ip/recvmsg.c index 426c719f0..9b8f4fccf 100644 --- a/lib/libc/ip/recvmsg.c +++ b/lib/libc/ip/recvmsg.c @@ -23,8 +23,7 @@ ssize_t recvmsg(int socket, struct msghdr *msg, int flags) } r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) - { + if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) { if (r == -1) { return r; } @@ -46,7 +45,7 @@ ssize_t recvmsg(int socket, struct msghdr *msg, int flags) static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags) { - int r; + int r, rc; if (flags != 0) { #if DEBUG @@ -56,13 +55,30 @@ static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags) return -1; } - r = readv(socket, msg->msg_iov, msg->msg_iovlen); + r= readv(socket, msg->msg_iov, msg->msg_iovlen); - if (r >= 0 && msg->msg_name && msg->msg_namelen > 0) - { + if (r >= 0 && msg->msg_name && msg->msg_namelen > 0) { getpeername(socket, msg->msg_name, &msg->msg_namelen); } + /* get control data */ + if (r >= 0 && msg->msg_control && msg->msg_controllen > 0) { + struct msg_control msg_ctrl; + + memset(&msg_ctrl, '\0', sizeof(struct msg_control)); + msg_ctrl.msg_controllen = msg->msg_controllen; + rc = ioctl(socket, NWIOGUDSCTRL, &msg_ctrl); + if (rc == -1) { + return rc; + } + + if (msg_ctrl.msg_controllen <= msg->msg_controllen) { + memcpy(msg->msg_control, msg_ctrl.msg_control, + msg_ctrl.msg_controllen); + msg->msg_controllen = msg_ctrl.msg_controllen; + } + } + msg->msg_flags = 0; return r; @@ -70,7 +86,7 @@ static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags) static ssize_t _uds_recvmsg_dgram(int socket, struct msghdr *msg, int flags) { - int r; + int r, rc; if (flags != 0) { #if DEBUG @@ -80,13 +96,34 @@ static ssize_t _uds_recvmsg_dgram(int socket, struct msghdr *msg, int flags) return -1; } - r = readv(socket, msg->msg_iov, msg->msg_iovlen); + r= readv(socket, msg->msg_iov, msg->msg_iovlen); - if (r >= 0 && msg->msg_name && msg->msg_namelen > 0) + if (r >= 0 && msg->msg_name && + msg->msg_namelen >= sizeof(struct sockaddr_un)) { - ioctl(socket, NWIOGUDSFADDR, msg->msg_name); + rc= ioctl(socket, NWIOGUDSFADDR, msg->msg_name); + if (rc == -1) { + return rc; + } msg->msg_namelen= sizeof(struct sockaddr_un); + } + /* get control data */ + if (r >= 0 && msg->msg_control && msg->msg_controllen > 0) { + struct msg_control msg_ctrl; + + memset(&msg_ctrl, '\0', sizeof(struct msg_control)); + msg_ctrl.msg_controllen = msg->msg_controllen; + rc = ioctl(socket, NWIOGUDSCTRL, &msg_ctrl); + if (rc == -1) { + return rc; + } + + if (msg_ctrl.msg_controllen <= msg->msg_controllen) { + memcpy(msg->msg_control, msg_ctrl.msg_control, + msg_ctrl.msg_controllen); + msg->msg_controllen = msg_ctrl.msg_controllen; + } } msg->msg_flags = 0; diff --git a/lib/libc/ip/sendmsg.c b/lib/libc/ip/sendmsg.c index 3e70951e0..dc1ebf6cb 100644 --- a/lib/libc/ip/sendmsg.c +++ b/lib/libc/ip/sendmsg.c @@ -26,8 +26,7 @@ ssize_t sendmsg(int socket, const struct msghdr *msg, int flags) } r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype); - if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) - { + if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL)) { if (r == -1) { return r; } @@ -51,6 +50,8 @@ ssize_t sendmsg(int socket, const struct msghdr *msg, int flags) static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg, int flags) { + struct msg_control msg_ctrl; + int r; if (flags != 0) { #if DEBUG @@ -61,6 +62,23 @@ static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg, } + /* grab the control data */ + memset(&msg_ctrl, '\0', sizeof(struct msg_control)); + if (msg->msg_controllen > MSG_CONTROL_MAX) { + errno = ENOMEM; + return -1; + } else if (msg->msg_controllen > 0) { + memcpy(&msg_ctrl.msg_control, msg->msg_control, + msg->msg_controllen); + } + msg_ctrl.msg_controllen = msg->msg_controllen; + + /* send the control data to PFS */ + r= ioctl(socket, NWIOSUDSCTRL, (void *) &msg_ctrl); + if (r == -1) { + return r; + } + /* Silently ignore destination, if given. */ return writev(socket, msg->msg_iov, msg->msg_iovlen); @@ -69,10 +87,8 @@ static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg, static ssize_t _uds_sendmsg_dgram(int socket, const struct msghdr *msg, int flags) { - char real_sun_path[PATH_MAX+1]; - char *realpath_result; - char *dest_addr; - int null_found; + struct msg_control msg_ctrl; + struct sockaddr_un *dest_addr; int i, r; if (flags != 0) { @@ -90,46 +106,25 @@ static ssize_t _uds_sendmsg_dgram(int socket, const struct msghdr *msg, return -1; } - /* sun_family is always supposed to be AF_UNIX */ - if (((struct sockaddr_un *) dest_addr)->sun_family != AF_UNIX) { - errno = EAFNOSUPPORT; - return -1; - } - - /* an empty path is not supported */ - if (((struct sockaddr_un *) dest_addr)->sun_path[0] == '\0') { - errno = ENOENT; - return -1; - } - - /* the path must be a null terminated string for realpath to work */ - for (null_found = i = 0; - i < sizeof(((struct sockaddr_un *) dest_addr)->sun_path); i++) { - if (((struct sockaddr_un *) dest_addr)->sun_path[i] == '\0') { - null_found = 1; - break; - } - } - - if (!null_found) { - errno = EINVAL; - return -1; - } - - realpath_result = realpath( - ((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path); - - if (realpath_result == NULL) { - return -1; + /* set the target address */ + r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr); + if (r == -1) { + return r; } - if (strlen(real_sun_path) >= UNIX_PATH_MAX) { - errno = ENAMETOOLONG; + /* grab the control data */ + memset(&msg_ctrl, '\0', sizeof(struct msg_control)); + if (msg->msg_controllen > MSG_CONTROL_MAX) { + errno = ENOMEM; return -1; + } else if (msg->msg_controllen > 0) { + memcpy(&msg_ctrl.msg_control, msg->msg_control, + msg->msg_controllen); } + msg_ctrl.msg_controllen = msg->msg_controllen; - /* set the target address */ - r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr); + /* send the control data to PFS */ + r= ioctl(socket, NWIOSUDSCTRL, (void *) &msg_ctrl); if (r == -1) { return r; } diff --git a/lib/libc/ip/sendto.c b/lib/libc/ip/sendto.c index ae62a2658..eaffc565f 100644 --- a/lib/libc/ip/sendto.c +++ b/lib/libc/ip/sendto.c @@ -206,10 +206,7 @@ static ssize_t _uds_sendto_conn(int socket, const void *message, size_t length, static ssize_t _uds_sendto_dgram(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len) { - char real_sun_path[PATH_MAX+1]; - char *realpath_result; - int null_found; - int i, r; + int r; /* for connectionless unix domain sockets (SOCK_DGRAM) */ @@ -226,46 +223,6 @@ static ssize_t _uds_sendto_dgram(int socket, const void *message, size_t length, return -1; } - /* sun_family is always supposed to be AF_UNIX */ - if (((struct sockaddr_un *) dest_addr)->sun_family != AF_UNIX) { - errno = EAFNOSUPPORT; - return -1; - } - - /* an empty path is not supported */ - if (((struct sockaddr_un *) dest_addr)->sun_path[0] == '\0') { - errno = ENOENT; - return -1; - } - - /* the path must be a null terminated string for realpath to work */ - for (null_found = i = 0; - i < sizeof(((struct sockaddr_un *) dest_addr)->sun_path); i++) { - if (((struct sockaddr_un *) dest_addr)->sun_path[i] == '\0') { - null_found = 1; - break; - } - } - - if (!null_found) { - errno = EINVAL; - return -1; - } - - realpath_result = realpath( - ((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path); - - if (realpath_result == NULL) { - return -1; - } - - if (strlen(real_sun_path) >= UNIX_PATH_MAX) { - errno = ENAMETOOLONG; - return -1; - } - - strcpy(((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path); - /* set the target address */ r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr); if (r == -1) { diff --git a/servers/pfs/dev_uds.c b/servers/pfs/dev_uds.c index 83fa49f88..6b14682e7 100644 --- a/servers/pfs/dev_uds.c +++ b/servers/pfs/dev_uds.c @@ -55,12 +55,13 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out) * Find a slot in the descriptor table for the new descriptor. * The index of the descriptor in the table will be returned. * Subsequent calls to read/write/close/ioctl/etc will use this - * minor number. + * minor number. The minor number must be different from the + * the /dev/uds device's minor number (currently 0). */ minor = -1; /* to trap error */ - for (i = 0; i < NR_FDS; i++) { + for (i = 1; i < NR_FDS; i++) { if (uds_fd_table[i].state == UDS_FREE) { minor = i; break; @@ -122,6 +123,12 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out) uds_fd_table[minor].backlog[i] = -1; } + memset(&uds_fd_table[minor].ancillary_data, '\0', sizeof(struct + ancillary)); + for (i = 0; i < OPEN_MAX; i++) { + uds_fd_table[minor].ancillary_data.fds[i] = -1; + } + /* default the size to UDS_SOMAXCONN */ uds_fd_table[minor].backlog_size = UDS_SOMAXCONN; @@ -138,6 +145,8 @@ PUBLIC int uds_open(message *dev_m_in, message *dev_m_out) /* initially the socket is not bound or listening on an address */ memset(&(uds_fd_table[minor].addr), '\0', sizeof(struct sockaddr_un)); + memset(&(uds_fd_table[minor].source), '\0', sizeof(struct sockaddr_un)); + memset(&(uds_fd_table[minor].target), '\0', sizeof(struct sockaddr_un)); /* Initially the socket isn't suspended. */ uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED; @@ -245,6 +254,10 @@ PUBLIC int uds_close(message *dev_m_in, message *dev_m_out) } } + if (uds_fd_table[minor].ancillary_data.nfiledes > 0) { + clear_fds(minor, &(uds_fd_table[minor].ancillary_data)); + } + /* Prepare Request to the FS side of PFS */ fs_m_in.m_type = REQ_PUTNODE; @@ -325,8 +338,8 @@ PUBLIC int uds_select(message *dev_m_in, message *dev_m_out) } } - /* check if we can write at least 1 byte */ - bytes = uds_perform_write(minor, dev_m_in->m_source, 1, 1); + /* check if we can write without blocking */ + bytes = uds_perform_write(minor, dev_m_in->m_source, PIPE_BUF, 1); if (bytes > 0) { uds_fd_table[minor].sel_ops_out |= SEL_WR; } @@ -547,6 +560,11 @@ PRIVATE int uds_perform_write(int minor, endpoint_t m_source, break; } } + + if (peer == -1) { + errno = ENOENT; + return -1; + } } /* check if write would overrun buffer. check if message @@ -651,7 +669,8 @@ PUBLIC int uds_read(message *dev_m_in, message *dev_m_out) static int call_count = 0; printf("(uds) [%d] uds_read() call_count=%d\n", uds_minor(dev_m_in), ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, dev_m_in->POSITION); + printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, + dev_m_in->POSITION); #endif minor = uds_minor(dev_m_in); @@ -713,7 +732,8 @@ PUBLIC int uds_write(message *dev_m_in, message *dev_m_out) static int call_count = 0; printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in), ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, dev_m_in->POSITION); + printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, + dev_m_in->POSITION); #endif minor = uds_minor(dev_m_in); @@ -775,7 +795,8 @@ PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out) static int call_count = 0; printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in), ++call_count); - printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, dev_m_in->POSITION); + printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->IO_ENDPT, + dev_m_in->POSITION); #endif minor = uds_minor(dev_m_in); @@ -895,6 +916,16 @@ PUBLIC int uds_ioctl(message *dev_m_in, message *dev_m_out) /* set the send buffer size -- setsockopt(SO_SNDBUF) */ return do_setsockopt_rcvbuf(dev_m_in, dev_m_out); + case NWIOSUDSCTRL: + + /* set the control data -- sendmsg() */ + return do_sendmsg(dev_m_in, dev_m_out); + + case NWIOGUDSCTRL: + + /* set the control data -- recvmsg() */ + return do_recvmsg(dev_m_in, dev_m_out); + default: /* the IOCTL command is not valid for /dev/uds -- diff --git a/servers/pfs/inc.h b/servers/pfs/inc.h index 09755c5e4..93c1edde7 100644 --- a/servers/pfs/inc.h +++ b/servers/pfs/inc.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/servers/pfs/proto.h b/servers/pfs/proto.h index 6e8300d10..e6dedfc99 100644 --- a/servers/pfs/proto.h +++ b/servers/pfs/proto.h @@ -7,6 +7,7 @@ struct buf; struct inode; struct sockaddr_un; +struct ancillary; /* buffer.c */ _PROTOTYPE( struct buf *get_block, (dev_t dev, ino_t inum) ); @@ -90,9 +91,11 @@ _PROTOTYPE( int do_setsockopt_rcvbuf, (message *dev_m_in, message *dev_m_out) ); _PROTOTYPE( int do_sendto, (message *dev_m_in, message *dev_m_out) ); _PROTOTYPE( int do_recvfrom, (message *dev_m_in, message *dev_m_out) ); +_PROTOTYPE( int do_sendmsg, (message *dev_m_in, message *dev_m_out) ); +_PROTOTYPE( int do_recvmsg, (message *dev_m_in, message *dev_m_out) ); _PROTOTYPE( int perform_connection, (message *dev_m_in, message *dev_m_out, struct sockaddr_un *addr, int minorx, int minory) ); - +_PROTOTYPE( int clear_fds, (int minor, struct ancillary *data) ); #endif diff --git a/servers/pfs/uds.c b/servers/pfs/uds.c index 3188cad88..16157c5e4 100644 --- a/servers/pfs/uds.c +++ b/servers/pfs/uds.c @@ -23,7 +23,10 @@ * do_setsockopt_rcvbuf: handles the setsockopt(2) syscall. * do_sendto: handles the sendto(2) syscall. * do_recvfrom: handles the recvfrom(2) syscall. + * do_sendmsg: handles the sendmsg(2) syscall. + * do_recvmsg: handles the recvmsg(2) syscall. * perform_connection: performs the connection of two descriptors. + * clear_fds: calls put_filp for undelivered FDs. * * Also see... * @@ -50,6 +53,187 @@ PUBLIC void uds_init(void) memset(uds_fd_table, '\0', sizeof(uds_fd_t) * NR_FDS); } +/* check the permissions of a socket file */ +PRIVATE int check_perms(int minor, struct sockaddr_un *addr) +{ + int rc; + message vfs_m; + cp_grant_id_t grant_id; + + grant_id = cpf_grant_direct(VFS_PROC_NR, (vir_bytes) addr->sun_path, + UNIX_PATH_MAX, CPF_READ | CPF_WRITE); + + /* ask the VFS to verify the permissions */ + memset(&vfs_m, '\0', sizeof(message)); + + vfs_m.m_type = PFS_REQ_CHECK_PERMS; + vfs_m.IO_ENDPT = uds_fd_table[minor].owner; + vfs_m.IO_GRANT = (char *) grant_id; + vfs_m.COUNT = UNIX_PATH_MAX; + + rc = sendrec(VFS_PROC_NR, &vfs_m); + cpf_revoke(grant_id); + if (OK != rc) { + printf("(uds) sendrec error... req_nr: %d err: %d\n", + vfs_m.m_type, rc); + + return EIO; + } + +#if DEBUG == 1 + printf("(uds) VFS reply => %d\n", vfs_m.m_type); + printf("(uds) Canonical Path => %s\n", addr->sun_path); +#endif + + return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */ +} + +PRIVATE filp_id_t verify_fd(endpoint_t ep, int fd) +{ + int rc; + message vfs_m; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) verify_fd(%d,%d) call_count=%d\n", ep, fd, + ++call_count); +#endif + + memset(&vfs_m, '\0', sizeof(message)); + + vfs_m.m_type = PFS_REQ_VERIFY_FD; + vfs_m.IO_ENDPT = ep; + vfs_m.COUNT = fd; + + rc = sendrec(VFS_PROC_NR, &vfs_m); + if (OK != rc) { + printf("(uds) sendrec error... req_nr: %d err: %d\n", + vfs_m.m_type, rc); + return NULL;; + } + +#if DEBUG == 1 + printf("(uds) VFS reply => %d\n", vfs_m.m_type); +#endif + + return vfs_m.ADDRESS; +} + +PRIVATE int set_filp(filp_id_t sfilp) +{ + int rc; + message vfs_m; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) set_filp(0x%x) call_count=%d\n", sfilp, ++call_count); +#endif + + memset(&vfs_m, '\0', sizeof(message)); + + vfs_m.m_type = PFS_REQ_SET_FILP; + vfs_m.ADDRESS = sfilp; + + rc = sendrec(VFS_PROC_NR, &vfs_m); + if (OK != rc) { + printf("(uds) sendrec error... req_nr: %d err: %d\n", + vfs_m.m_type, rc); + return EIO; + } + +#if DEBUG == 1 + printf("(uds) VFS reply => %d\n", vfs_m.m_type); +#endif + return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */ +} + +PRIVATE int copy_filp(endpoint_t to_ep, filp_id_t cfilp) +{ + int rc; + message vfs_m; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) copy_filp(%d, 0x%x) call_count=%d\n",to_ep, cfilp, + ++call_count); +#endif + + memset(&vfs_m, '\0', sizeof(message)); + + vfs_m.m_type = PFS_REQ_COPY_FILP; + vfs_m.IO_ENDPT = to_ep; + vfs_m.ADDRESS = cfilp; + + rc = sendrec(VFS_PROC_NR, &vfs_m); + if (OK != rc) { + printf("(uds) sendrec error... req_nr: %d err: %d\n", + vfs_m.m_type, rc); + return EIO; + } + +#if DEBUG == 1 + printf("(uds) VFS reply => %d\n", vfs_m.m_type); +#endif + return vfs_m.m_type; +} + +PRIVATE int put_filp(filp_id_t pfilp) +{ + int rc; + message vfs_m; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) put_filp(0x%x) call_count=%d\n", pfilp, ++call_count); +#endif + + memset(&vfs_m, '\0', sizeof(message)); + + vfs_m.m_type = PFS_REQ_PUT_FILP; + vfs_m.ADDRESS = pfilp; + + rc = sendrec(VFS_PROC_NR, &vfs_m); + if (OK != rc) { + printf("(uds) sendrec error... req_nr: %d err: %d\n", + vfs_m.m_type, rc); + return EIO; + } + +#if DEBUG == 1 + printf("(uds) VFS reply => %d\n", vfs_m.m_type); +#endif + return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */ +} + +PRIVATE int cancel_fd(endpoint_t ep, int fd) +{ + int rc; + message vfs_m; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) cancel_fd(%d,%d) call_count=%d\n", ep, fd, ++call_count); +#endif + + memset(&vfs_m, '\0', sizeof(message)); + + vfs_m.m_type = PFS_REQ_CANCEL_FD; + vfs_m.IO_ENDPT = ep; + vfs_m.COUNT = fd; + + rc = sendrec(VFS_PROC_NR, &vfs_m); + if (OK != rc) { + printf("(uds) sendrec error... req_nr: %d err: %d\n", + vfs_m.m_type, rc); + return EIO; + } + +#if DEBUG == 1 + printf("(uds) VFS reply => %d\n", vfs_m.m_type); +#endif + return vfs_m.m_type; /* return reply code OK, ELOOP, etc. */ +} + PUBLIC int perform_connection(message *dev_m_in, message *dev_m_out, struct sockaddr_un *addr, int minorx, int minory) { @@ -152,7 +336,8 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out) if (uds_fd_table[i].addr.sun_family == AF_UNIX && !strncmp(addr.sun_path, uds_fd_table[i].addr.sun_path, - UNIX_PATH_MAX)) { + UNIX_PATH_MAX) && + uds_fd_table[i].listening == 1) { rc = 0; break; @@ -233,7 +418,8 @@ PUBLIC int do_accept(message *dev_m_in, message *dev_m_out) /* if peer is blocked on connect() revive peer */ if (uds_fd_table[minorpeer].suspended) { #if DEBUG == 1 - printf("(uds) [%d] {do_accept} revive %d", minor, minorpeer); + printf("(uds) [%d] {do_accept} revive %d\n", minor, + minorpeer); #endif uds_fd_table[minorpeer].ready_to_revive = 1; notify(dev_m_in->m_source); @@ -298,6 +484,18 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out) return EIO; } + rc = check_perms(minor, &addr); + if (rc != OK) { + + /* permission denied, socket file doesn't exist, etc. */ + uds_fd_table[minor].syscall_done = 1; + + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, rc); + + return rc; + } + /* look for a socket of the same type that is listening on the * address we want to connect to */ @@ -323,7 +521,7 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out) uds_fd_table[i].child = -1; #if DEBUG == 1 - printf("(uds) [%d] {do_connect} revive %d", minor, i); + printf("(uds) [%d] {do_connect} revive %d\n", minor, i); #endif /* wake the parent (server) */ @@ -432,7 +630,7 @@ PUBLIC int do_connect(message *dev_m_in, message *dev_m_out) } #if DEBUG == 1 - printf("(uds) [%d] {do_connect} suspend", minor); + printf("(uds) [%d] {do_connect} suspend\n", minor); #endif /* suspend until the server side completes the connection with accept() @@ -625,7 +823,7 @@ PUBLIC int do_socket(message *dev_m_in, message *dev_m_out) PUBLIC int do_bind(message *dev_m_in, message *dev_m_out) { - int minor; + int minor, strlen; struct sockaddr_un addr; int rc, i; @@ -667,15 +865,39 @@ PUBLIC int do_bind(message *dev_m_in, message *dev_m_out) } /* do some basic sanity checks on the address */ - if (addr.sun_family != AF_UNIX || addr.sun_path[0] == '\0') { + if (addr.sun_family != AF_UNIX) { + + /* bad family */ + uds_fd_table[minor].syscall_done = 1; + + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, + EAFNOSUPPORT); + + return EAFNOSUPPORT; + } + + if (addr.sun_path[0] == '\0') { /* bad address */ uds_fd_table[minor].syscall_done = 1; uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, - (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL); + (cp_grant_id_t) dev_m_in->IO_GRANT, ENOENT); - return EINVAL; + return ENOENT; + } + + rc = check_perms(minor, &addr); + if (rc != OK) { + + /* permission denied, socket file doesn't exist, etc. */ + uds_fd_table[minor].syscall_done = 1; + + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, rc); + + return rc; } /* make sure the address isn't already in use by another socket. */ @@ -939,8 +1161,12 @@ PUBLIC int do_socketpair(message *dev_m_in, message *dev_m_out) minory = (minor(minorin) & BYTE); +#if DEBUG == 1 + printf("socketpair() %d - %d\n", minorx, minory); +#endif + /* security check - both sockets must have the same endpoint (owner) */ - if (uds_fd_table[minorx].endpoint != uds_fd_table[minory].endpoint) { + if (uds_fd_table[minorx].owner != uds_fd_table[minory].owner) { /* we won't allow you to magically connect your socket to * someone elses socket @@ -1307,6 +1533,17 @@ PUBLIC int do_sendto(message *dev_m_in, message *dev_m_out) return EINVAL; } + rc = check_perms(minor, &addr); + if (rc != OK) { + + uds_fd_table[minor].syscall_done = 1; + + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, rc); + + return rc; + } + memcpy(&(uds_fd_table[minor].target), &addr, sizeof(struct sockaddr_un)); @@ -1352,3 +1589,414 @@ PUBLIC int do_recvfrom(message *dev_m_in, message *dev_m_out) return OK; } + +int msg_control_read(struct msg_control *msg_ctrl, struct ancillary *data, + int minor) +{ + int rc; + struct msghdr msghdr; + struct cmsghdr *cmsg = NULL; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) [%d] msg_control_read() call_count=%d\n", minor, + ++call_count); +#endif + + data->nfiledes = 0; + + memset(&msghdr, '\0', sizeof(struct msghdr)); + msghdr.msg_control = msg_ctrl->msg_control; + msghdr.msg_controllen = msg_ctrl->msg_controllen; + + for(cmsg = CMSG_FIRSTHDR(&msghdr); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { + + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + + int i; + int nfds = + MIN((cmsg->cmsg_len-CMSG_LEN(0))/sizeof(int), + OPEN_MAX); + + for (i = 0; i < nfds; i++) { + if (data->nfiledes == OPEN_MAX) { + return EOVERFLOW; + } + + data->fds[data->nfiledes] = + ((int *) CMSG_DATA(cmsg))[i]; +#if DEBUG == 1 + printf("(uds) [%d] fd[%d]=%d\n", minor, + data->nfiledes, data->fds[data->nfiledes]); +#endif + data->nfiledes++; + } + } + } + + /* obtain this socket's credentials */ + rc = getnucred(uds_fd_table[minor].owner, &(data->cred)); + if (rc == -1) { + return errno; + } +#if DEBUG == 1 + printf("(uds) [%d] cred={%d,%d,%d}\n", minor, + data->cred.pid, data->cred.uid, + data->cred.gid); +#endif + return OK; +} + +PRIVATE int send_fds(int minor, struct ancillary *data) +{ + int rc, i, j; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) [%d] send_fds() call_count=%d\n", minor, ++call_count); +#endif + + /* verify the file descriptors and get their filps. */ + for (i = 0; i < data->nfiledes; i++) { + data->filps[i] = verify_fd(uds_fd_table[minor].owner, + data->fds[i]); + + if (data->filps[i] == NULL) { + return EINVAL; + } + } + + /* set them as in-flight */ + for (i = 0; i < data->nfiledes; i++) { + rc = set_filp(data->filps[i]); + if (rc != OK) { + /* revert set_filp() calls */ + for (j = i; j >= 0; j--) { + put_filp(data->filps[j]); + } + return rc; + } + } + + return OK; +} + +PUBLIC int clear_fds(int minor, struct ancillary *data) +{ +/* This function calls put_filp() for all of the FDs in data. + * This is used when a Unix Domain Socket is closed and there + * exists references to file descriptors that haven't been received + * with recvmsg(). + */ + int i; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) [%d] recv_fds() call_count=%d\n", minor, + ++call_count); +#endif + + for (i = 0; i < data->nfiledes; i++) { + put_filp(data->filps[i]); +#if DEBUG == 1 + printf("(uds) clear_fds() => %d\n", data->fds[i]); +#endif + data->fds[i] = -1; + data->filps[i] = NULL; + } + + data->nfiledes = 0; + + return OK; +} + +PRIVATE int recv_fds(int minor, struct ancillary *data, + struct msg_control *msg_ctrl) +{ + int rc, i, j; + struct msghdr msghdr; + struct cmsghdr *cmsg; + endpoint_t to_ep; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) [%d] recv_fds() call_count=%d\n", minor, + ++call_count); +#endif + + msghdr.msg_control = msg_ctrl->msg_control; + msghdr.msg_controllen = msg_ctrl->msg_controllen; + + cmsg = CMSG_FIRSTHDR(&msghdr); + cmsg->cmsg_len = CMSG_LEN(sizeof(int) * data->nfiledes); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + to_ep = uds_fd_table[minor].owner; + + /* copy to the target endpoint */ + for (i = 0; i < data->nfiledes; i++) { + rc = copy_filp(to_ep, data->filps[i]); + if (rc < 0) { + /* revert set_filp() calls */ + for (j = 0; j < data->nfiledes; j++) { + put_filp(data->filps[j]); + } + /* revert copy_filp() calls */ + for (j = i; j >= 0; j--) { + cancel_fd(to_ep, data->fds[j]); + } + return rc; + } + data->fds[i] = rc; /* data->fds[i] now has the new FD */ + } + + for (i = 0; i < data->nfiledes; i++) { + put_filp(data->filps[i]); +#if DEBUG == 1 + printf("(uds) recv_fds() => %d\n", data->fds[i]); +#endif + ((int *)CMSG_DATA(cmsg))[i] = data->fds[i]; + data->fds[i] = -1; + data->filps[i] = NULL; + } + + data->nfiledes = 0; + + return OK; +} + +PRIVATE int recv_cred(int minor, struct ancillary *data, + struct msg_control *msg_ctrl) +{ + int rc, i; + struct msghdr msghdr; + struct cmsghdr *cmsg; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) [%d] recv_cred() call_count=%d\n", minor, + ++call_count); +#endif + + msghdr.msg_control = msg_ctrl->msg_control; + msghdr.msg_controllen = msg_ctrl->msg_controllen; + + cmsg = CMSG_FIRSTHDR(&msghdr); + if (cmsg->cmsg_len > 0) { + cmsg = CMSG_NXTHDR(&msghdr, cmsg); + } + + cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_CREDENTIALS; + memcpy(CMSG_DATA(cmsg), &(data->cred), sizeof(struct ucred)); + + return OK; +} + +PUBLIC int do_sendmsg(message *dev_m_in, message *dev_m_out) +{ + int minor, peer, rc, i; + struct msg_control msg_ctrl; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) [%d] do_sendmsg() call_count=%d\n", + uds_minor(dev_m_in), ++call_count); +#endif + + minor = uds_minor(dev_m_in); + + memset(&msg_ctrl, '\0', sizeof(struct msg_control)); + + rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, + (vir_bytes) 0, (vir_bytes) &msg_ctrl, + sizeof(struct msg_control), D); + + if (rc != OK) { + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, EIO); + return EIO; + } + + /* locate peer */ + peer = -1; + if (uds_fd_table[minor].type == SOCK_DGRAM) { + if (uds_fd_table[minor].target.sun_path[0] == '\0' || + uds_fd_table[minor].target.sun_family != AF_UNIX) { + + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, + dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, + EDESTADDRREQ); + return EDESTADDRREQ; + } + + for (i = 0; i < NR_FDS; i++) { + + /* look for a SOCK_DGRAM socket that is bound on + * the target address + */ + if (uds_fd_table[i].type == SOCK_DGRAM && + uds_fd_table[i].addr.sun_family == AF_UNIX && + !strncmp(uds_fd_table[minor].target.sun_path, + uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)){ + + peer = i; + break; + } + } + + if (peer == -1) { + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, + dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, ENOENT); + return ENOENT; + } + } else { + peer = uds_fd_table[minor].peer; + if (peer == -1) { + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, + dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, ENOTCONN); + return ENOTCONN; + } + } + +#if DEBUG == 1 + printf("(uds) [%d] sendmsg() -- peer=%d\n", minor, peer); +#endif + /* note: it's possible that there is already some file + * descriptors in ancillary_data if the peer didn't call + * recvmsg() yet. That's okay. The receiver will + * get the current file descriptors plus the new ones. + */ + rc = msg_control_read(&msg_ctrl, &uds_fd_table[peer].ancillary_data, + minor); + if (rc != OK) { + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, rc); + return rc; + } + + rc = send_fds(minor, &uds_fd_table[peer].ancillary_data); + if (rc != OK) { + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, rc); + return rc; + } + + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, OK); + return OK; +} + +PUBLIC int do_recvmsg(message *dev_m_in, message *dev_m_out) +{ + int minor; + int rc; + struct msg_control msg_ctrl; + socklen_t controllen_avail = 0; + socklen_t controllen_needed = 0; + socklen_t controllen_desired = 0; + +#if DEBUG == 1 + static int call_count = 0; + printf("(uds) [%d] do_sendmsg() call_count=%d\n", + uds_minor(dev_m_in), ++call_count); +#endif + + minor = uds_minor(dev_m_in); + + +#if DEBUG == 1 + printf("(uds) [%d] CREDENTIALS {pid:%d,uid:%d,gid:%d}\n", minor, + uds_fd_table[minor].ancillary_data.cred.pid, + uds_fd_table[minor].ancillary_data.cred.uid, + uds_fd_table[minor].ancillary_data.cred.gid); +#endif + + memset(&msg_ctrl, '\0', sizeof(struct msg_control)); + + /* get the msg_control from the user, it will include the + * amount of space the user has allocated for control data. + */ + rc = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, + (vir_bytes) 0, (vir_bytes) &msg_ctrl, + sizeof(struct msg_control), D); + + if (rc != OK) { + + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, EIO); + return EIO; + } + + controllen_avail = MIN(msg_ctrl.msg_controllen, MSG_CONTROL_MAX); + + if (uds_fd_table[minor].ancillary_data.nfiledes > 0) { + controllen_needed = CMSG_LEN(sizeof(int) * + (uds_fd_table[minor].ancillary_data.nfiledes)); + } + + /* if there is room we also include credentials */ + controllen_desired = controllen_needed + + CMSG_LEN(sizeof(struct ucred)); + + if (controllen_needed > controllen_avail) { + + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, EOVERFLOW); + return EOVERFLOW; + } + + rc = recv_fds(minor, &uds_fd_table[minor].ancillary_data, &msg_ctrl); + if (rc != OK) { + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, rc); + return rc; + } + + if (controllen_desired <= controllen_avail) { + rc = recv_cred(minor, &uds_fd_table[minor].ancillary_data, + &msg_ctrl); + if (rc != OK) { + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, + dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, rc); + return rc; + } + } + + /* send the user the control data */ + rc = sys_safecopyto(VFS_PROC_NR, (cp_grant_id_t) dev_m_in->IO_GRANT, + (vir_bytes) 0, (vir_bytes) &msg_ctrl, + sizeof(struct msg_control), D); + + if (rc != OK) { + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, EIO); + return EIO; + } + + uds_fd_table[minor].syscall_done = 1; + uds_set_reply(dev_m_out, TASK_REPLY, dev_m_in->IO_ENDPT, + (cp_grant_id_t) dev_m_in->IO_GRANT, OK); + + return OK; +} diff --git a/servers/pfs/uds.h b/servers/pfs/uds.h index 3af2d57e5..cd754e343 100644 --- a/servers/pfs/uds.h +++ b/servers/pfs/uds.h @@ -9,7 +9,9 @@ * dev_uds.c, table.c, uds.c */ +#include #include +#include #include #include @@ -17,8 +19,15 @@ /* max connection backlog for incoming connections */ #define UDS_SOMAXCONN 64 -/* UDS FD state Flags */ -#define UDS_CONNECTING 0x10 +typedef void* filp_id_t; + +/* ancillary data to be sent */ +struct ancillary { + filp_id_t filps[OPEN_MAX]; + int fds[OPEN_MAX]; + int nfiledes; + struct ucred cred; +}; /* * Internal State Information for a socket descriptor. @@ -122,6 +131,11 @@ struct uds_fd { */ 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. -- 2.44.0