--- a/sysdeps/mach/hurd/recvmsg.c +++ b/sysdeps/mach/hurd/recvmsg.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001, 2002, 2010 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2002, 2010, 2013 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -18,10 +18,12 @@ #include #include #include +#include #include #include #include +#include /* Receive a message as described by MESSAGE from socket FD. Returns the number of bytes read or -1 for errors. */ @@ -155,6 +157,104 @@ message->msg_controllen = clen; memcpy (message->msg_control, cdata, message->msg_controllen); + error_t check_auth (process_t proc, auth_t auth, __pid_t pid, + __uid_t euid, __uid_t auid, + __gid_t egid, __gid_t agid, + int ngroups, __gid_t *groups) + { + error_t err; + pid_t rpid, rppid; + int orphaned; + uid_t euids_buf[CMGROUP_MAX], auids_buf[CMGROUP_MAX]; + uid_t *euids = euids_buf, *auids = auids_buf; + gid_t egids_buf[CMGROUP_MAX], agids_buf[CMGROUP_MAX]; + gid_t *egids = egids_buf, *agids = agids_buf; + size_t neuids = CMGROUP_MAX, nauids = CMGROUP_MAX; + size_t negids = CMGROUP_MAX, nagids = CMGROUP_MAX; + + /* FIXME: In this the right lock? */ + /* FIXME: EPERM and/or EACCESS? */ + HURD_CRITICAL_BEGIN; + __mutex_lock (&_hurd_id.lock); + err = _hurd_check_ids(); + if (err) + goto finish; + + err = __USEPORT (PROC, __proc_getpids (proc, &rpid, &rppid, &orphaned)); + if (err) + goto finish; + if (rpid != pid ) + { + err = EPERM; + goto finish; + } + + err = __USEPORT (AUTH, __auth_getids + (auth, + &euids, &neuids, &auids, &nauids, + &egids, &negids, &agids, &nagids)); + if (err) + goto finish; + + /* Check ids */ + if (euid != euids_buf[0] || auid != auids_buf[0] || + egid != egids_buf[0] || agid != agids_buf[0]) + { + err = EPERM; + goto finish; + } + /* Check groups */ + for (int i = 0; i < negids; i++) + { + /* FIXME: is sorted check needed? */ + if (groups[i] != egids_buf[i]) + { + err = EPERM; + goto finish; + } + } + + finish: + __mutex_unlock (&_hurd_id.lock); + HURD_CRITICAL_END; + return err; + } + + /* SCM_CREDS support: Fill in the credentials data */ + struct cmsgcred *ucredp = NULL; + __pid_t pid = 0; + __uid_t euid = 0, auid = 0; + __gid_t egid = 0, agid = 0; + int ngroups; + __gid_t groups[CMGROUP_MAX]; + + cmsg = CMSG_FIRSTHDR (message); + /* Read received credentials */ + if (cmsg != NULL && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDS) + { + for (; cmsg; cmsg = CMSG_NXTHDR (message, cmsg)) + { + ucredp = (struct cmsgcred *) CMSG_DATA(cmsg); + pid = ucredp->cmcred_pid; + auid = ucredp->cmcred_uid; + euid = ucredp->cmcred_euid; + agid = ucredp->cmcred_gid; + egid = agid; /* Not in struct cmsgcred */ + ngroups = ucredp->cmcred_ngroups; + for (int i = 0; i < ngroups ; i++) + groups[i] = ucredp->cmcred_groups[i]; + } + + /* Check recieved credentials */ + err = check_auth (ports[0], ports[1], pid, + euid, auid, egid, agid, ngroups, groups); + __mach_port_deallocate (mach_task_self (), ports[0]); + __mach_port_deallocate (mach_task_self (), ports[1]); + if (err) + return __hurd_fail (err); + goto label; + } + /* SCM_RIGHTS ports. */ if (nports > 0) { @@ -234,6 +334,7 @@ } } + label: __vm_deallocate (__mach_task_self (), (vm_address_t) cdata, clen); return (buf - data);