diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2015-09-20 20:26:23 +0200 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2015-09-20 20:26:23 +0200 |
commit | cf6fc573a024d6ce3c41fc2bb6e4c02b59721e85 (patch) | |
tree | d98e2d8f42c97b36902450de48c77eaf25067b56 /sysdeps/mach/hurd/recvmsg.c | |
parent | eb5fd84ae0e96d86dec3000f99d05e28faaa4668 (diff) | |
parent | 3ce550bb66517c08cca653a6eeaab71b51bcf719 (diff) |
Merge commit 'refs/top-bases/tschwinge/Roger_Whittaker' into tschwinge/Roger_Whittaker
Diffstat (limited to 'sysdeps/mach/hurd/recvmsg.c')
-rw-r--r-- | sysdeps/mach/hurd/recvmsg.c | 251 |
1 files changed, 188 insertions, 63 deletions
diff --git a/sysdeps/mach/hurd/recvmsg.c b/sysdeps/mach/hurd/recvmsg.c index 93e5e5629c..71ba20e0f6 100644 --- a/sysdeps/mach/hurd/recvmsg.c +++ b/sysdeps/mach/hurd/recvmsg.c @@ -23,6 +23,123 @@ #include <hurd/fd.h> #include <hurd/socket.h> +static unsigned +contains_uid (unsigned int n, __uid_t uids[n], __uid_t uid) +{ + unsigned i; + + for (i = 0; i < n; i++) + if (uids[i] == uid) + return 1; + return 0; +} + +static unsigned +contains_gid (unsigned int n, __gid_t gids[n], __gid_t gid) +{ + unsigned i; + + for (i = 0; i < n; i++) + if (gids[i] == gid) + return 1; + return 0; +} + +/* Check the passed credentials. */ +static error_t +check_auth (mach_port_t rendezvous, + __pid_t pid, + __uid_t uid, __uid_t euid, + __gid_t gid, + int ngroups, __gid_t groups[ngroups]) +{ + error_t err; + size_t neuids = CMGROUP_MAX, nauids = CMGROUP_MAX; + size_t negids = CMGROUP_MAX, nagids = CMGROUP_MAX; + __uid_t euids_buf[neuids], auids_buf[nauids]; + __gid_t egids_buf[negids], agids_buf[nagids]; + __uid_t *euids = euids_buf, *auids = auids_buf; + __gid_t *egids = egids_buf, *agids = agids_buf; + + struct procinfo *pi = NULL; + mach_msg_type_number_t pi_size = 0; + int flags = PI_FETCH_TASKINFO; + char *tw = NULL; + size_t tw_size = 0; + unsigned i; + + err = mach_port_mod_refs (mach_task_self (), rendezvous, + MACH_PORT_RIGHT_SEND, 1); + if (err) + goto out; + + do + err = __USEPORT + (AUTH, __auth_server_authenticate (port, + rendezvous, MACH_MSG_TYPE_COPY_SEND, + MACH_PORT_NULL, 0, + &euids, &neuids, &auids, &nauids, + &egids, &negids, &agids, &nagids)); + while (err == EINTR); + if (err) + goto out; + + /* Check whether this process indeed has these IDs */ + if ( !contains_uid (neuids, euids, uid) + && !contains_uid (nauids, auids, uid) + || !contains_uid (neuids, euids, euid) + && !contains_uid (nauids, auids, euid) + || !contains_gid (negids, egids, gid) + && !contains_gid (nagids, agids, gid) + ) + { + err = EIO; + goto out; + } + + /* Check groups */ + for (i = 0; i < ngroups; i++) + if ( !contains_gid (negids, egids, groups[i]) + && !contains_gid (nagids, agids, groups[i])) + { + err = EIO; + goto out; + } + + /* Check PID */ + /* XXX: Using proc_getprocinfo until + proc_user_authenticate proc_server_authenticate is implemented + */ + /* Get procinfo to check the owner. Maybe he faked the pid, but at least we + check the owner. */ + err = __USEPORT (PROC, __proc_getprocinfo (port, pid, &flags, + (procinfo_t *)&pi, + &pi_size, &tw, &tw_size)); + if (err) + goto out; + + if ( !contains_uid (neuids, euids, pi->owner) + && !contains_uid (nauids, auids, pi->owner)) + err = EIO; + +out: + mach_port_deallocate (mach_task_self (), rendezvous); + if (euids != euids_buf) + __vm_deallocate (__mach_task_self(), (vm_address_t) euids, neuids * sizeof(uid_t)); + if (auids != auids_buf) + __vm_deallocate (__mach_task_self(), (vm_address_t) auids, nauids * sizeof(uid_t)); + if (egids != egids_buf) + __vm_deallocate (__mach_task_self(), (vm_address_t) egids, negids * sizeof(uid_t)); + if (agids != agids_buf) + __vm_deallocate (__mach_task_self(), (vm_address_t) agids, nagids * sizeof(uid_t)); + if (tw_size) + __vm_deallocate (__mach_task_self(), (vm_address_t) tw, tw_size); + if (pi_size) + __vm_deallocate (__mach_task_self(), (vm_address_t) pi, pi_size); + + return err; +} + /* Receive a message as described by MESSAGE from socket FD. Returns the number of bytes read or -1 for errors. */ ssize_t @@ -32,15 +149,15 @@ __libc_recvmsg (int fd, struct msghdr *message, int flags) addr_port_t aport; char *data = NULL; mach_msg_type_number_t len = 0; - mach_port_t *ports, *newports; + mach_port_t *ports, *newports = NULL; mach_msg_type_number_t nports = 0; struct cmsghdr *cmsg; char *cdata = NULL; mach_msg_type_number_t clen = 0; size_t amount; char *buf; - int nfds, *fds; - int i, j; + int nfds, *opened_fds = NULL; + int i, ii, j; error_t reauthenticate (mach_port_t port, mach_port_t *result) { @@ -155,28 +272,71 @@ __libc_recvmsg (int fd, struct msghdr *message, int flags) message->msg_controllen = clen; memcpy (message->msg_control, cdata, message->msg_controllen); - /* SCM_RIGHTS ports. */ if (nports > 0) { newports = __alloca (nports * sizeof (mach_port_t)); + opened_fds = __alloca (nports * sizeof (int)); + } - /* Reauthenticate all ports here. */ - for (i = 0; i < nports; i++) - { - err = reauthenticate (ports[i], &newports[i]); - __mach_port_deallocate (__mach_task_self (), ports[i]); - if (err) - { - for (j = 0; j < i; j++) - __mach_port_deallocate (__mach_task_self (), newports[j]); - for (j = i+1; j < nports; j++) - __mach_port_deallocate (__mach_task_self (), ports[j]); + /* This counts how many ports we processed completely. */ + i = 0; + + for (cmsg = CMSG_FIRSTHDR (message); + cmsg; + cmsg = CMSG_NXTHDR (message, cmsg)) + { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) + { + /* SCM_RIGHTS support. */ + /* The fd's flags are passed in the control data. */ + int *fds = (int *) CMSG_DATA (cmsg); + nfds = (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr))) + / sizeof (int); + + for (j = 0; j < nfds; j++) + { + err = reauthenticate (ports[i], &newports[i]); + if (err) + goto cleanup; + fds[j] = opened_fds[i] = _hurd_intern_fd (newports[i], fds[j], 0); + if (fds[j] == -1) + { + err = errno; + __mach_port_deallocate (__mach_task_self (), newports[i]); + goto cleanup; + } + i++; + } + } + else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDS) + { + /* SCM_CREDS support. */ + /* Check received credentials */ + struct cmsgcred *ucredp = (struct cmsgcred *) CMSG_DATA(cmsg); + + err = check_auth (ports[i], + ucredp->cmcred_pid, + ucredp->cmcred_uid, ucredp->cmcred_euid, + ucredp->cmcred_gid, + ucredp->cmcred_ngroups, ucredp->cmcred_groups); + if (err) + goto cleanup; + i++; + } + } + + for (i = 0; i < nports; i++) + __mach_port_deallocate (mach_task_self (), ports[i]); - __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen); - __hurd_fail (err); - } - } + __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen); + + return (buf - data); +cleanup: + /* Clean up all the file descriptors from port 0 to i-1. */ + if (nports > 0) + { + ii = 0; j = 0; for (cmsg = CMSG_FIRSTHDR (message); cmsg; @@ -184,59 +344,24 @@ __libc_recvmsg (int fd, struct msghdr *message, int flags) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - fds = (int *) CMSG_DATA (cmsg); nfds = (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr))) / sizeof (int); - - for (i = 0; i < nfds && j < nports; i++) - { - /* The fd's flags are passed in the control data. */ - fds[i] = _hurd_intern_fd (newports[j++], fds[i], 0); - if (fds[i] == -1) - { - err = errno; - goto cleanup; - } - } + for (j = 0; j < nfds && ii < i; j++, ii++) + { + _hurd_fd_close (_hurd_fd_get (opened_fds[ii])); + __mach_port_deallocate (__mach_task_self (), newports[ii]); + __mach_port_deallocate (__mach_task_self (), ports[ii]); + } } - } - - if (j != nports) - err = EGRATUITOUS; - - if (err) - cleanup: - { - /* Clean up all the file descriptors. */ - nports = j; - j = 0; - for (cmsg = CMSG_FIRSTHDR (message); - cmsg; - cmsg = CMSG_NXTHDR (message, cmsg)) + else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDS) { - if (cmsg->cmsg_level == SOL_SOCKET - && cmsg->cmsg_type == SCM_RIGHTS) - { - fds = (int *) CMSG_DATA (cmsg); - nfds = (cmsg->cmsg_len - - CMSG_ALIGN (sizeof (struct cmsghdr))) - / sizeof (int); - for (i = 0; i < nfds && j < nports; i++, j++) - _hurd_fd_close (_hurd_fd_get (fds[i])); - } + __mach_port_deallocate (__mach_task_self (), ports[ii]); } - - for (; j < nports; j++) - __mach_port_deallocate (__mach_task_self (), newports[j]); - - __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen); - __hurd_fail (err); } } __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen); - - return (buf - data); + return __hurd_fail (err); } weak_alias (__libc_recvmsg, recvmsg) |