From cdf38fbfcba4c87777d7ba2175f08e877dafe86a Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Mon, 13 Sep 2021 11:23:21 +0200
Subject: [PATCH] WIP gnu: glibc: New security patches.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The existence of the vulnerabilities was noted at
<https://lists.gnu.org/archive/html/bug-hurd/2021-08/msg00007.html>.
TODO: check if these are all necessary packages for glibc.
TODO: why does the glibc tarball build for --system=x86_64-linux but not
for --system=i586-gnu?
Build error:
‘patching file hurd/hurdinit.c
Hunk #1 FAILED at 177.
1 out of 1 hunk FAILED -- saving rejects to file hurd/hurdinit.c.rej’
but this file isn't modified by the new patches!
* gnu/local.mk (dist_patch_DATA): Register new patches.
* gnu/packages/base.scm (glibc)[replacement]: Register replacement.
(glibc/fixed): New variable.
* gnu/packages/patches/glibc-hurd-proc-reauth.patch: New file.
* gnu/packages/patches/glibc-hurd-sendmsg-SCM_CREDS.patch.
---
gnu/local.mk | 2 +
gnu/packages/base.scm | 7 +
.../patches/glibc-hurd-proc-reauth.patch | 114 ++++++++
.../glibc-hurd-sendmsg-SCM_CREDS.patch | 261 ++++++++++++++++++
4 files changed, 384 insertions(+)
create mode 100644 gnu/packages/patches/glibc-hurd-proc-reauth.patch
create mode 100644 gnu/packages/patches/glibc-hurd-sendmsg-SCM_CREDS.patch
@@ -1150,9 +1150,11 @@ dist_patch_DATA = \
%D%/packages/patches/glibc-hurd-clock_gettime_monotonic.patch \
%D%/packages/patches/glibc-hurd-clock_t_centiseconds.patch \
%D%/packages/patches/glibc-hurd-gettyent.patch \
+ %D%/packages/patches/glibc-hurd-proc-reauth.patch \
%D%/packages/patches/glibc-hurd-mach-print.patch \
%D%/packages/patches/glibc-hurd-magic-pid.patch \
%D%/packages/patches/glibc-hurd-signal-sa-siginfo.patch \
+ %D%/packages/patches/glibc-hurd-sendmsg-SCM_CREDS.patch \
%D%/packages/patches/glibc-ldd-powerpc.patch \
%D%/packages/patches/glibc-ldd-x86_64.patch \
%D%/packages/patches/glibc-locales.patch \
@@ -706,6 +706,7 @@ the store.")
(package
(name "glibc")
(version "2.31")
+ (replacement glibc/fixed)
(source (origin
(method url-fetch)
(uri (string-append "mirror://gnu/glibc/glibc-" version ".tar.xz"))
@@ -966,6 +967,12 @@ with the Linux kernel.")
(license lgpl2.0+)
(home-page "https://www.gnu.org/software/libc/")))
+(define glibc/fixed
+ (package-with-extra-patches
+ glibc
+ (search-patches "glibc-hurd-sendmsg-SCM_CREDS.patch"
+ "glibc-hurd-proc-reauth.patch")))
+
;; Below are old libc versions, which we use mostly to build locale data in
;; the old format (which the new libc cannot cope with.)
new file mode 100644
@@ -0,0 +1,114 @@
+Index: glibc-2.31/hurd/hurdsig.c
+===================================================================
+--- glibc-2.31.orig/hurd/hurdsig.c
++++ glibc-2.31/hurd/hurdsig.c
+@@ -1580,28 +1580,53 @@ _hurdsig_init (const int *intarray, size
+ static void
+ reauth_proc (mach_port_t new)
+ {
+- mach_port_t ref, ignore;
++ error_t err;
++ mach_port_t ref, newproc;
+
+ ref = __mach_reply_port ();
+- if (! HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
++ err = HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
+ __proc_reauthenticate (port, ref,
+- MACH_MSG_TYPE_MAKE_SEND)
+- || __auth_user_authenticate (new, ref,
+- MACH_MSG_TYPE_MAKE_SEND,
+- &ignore))
+- && ignore != MACH_PORT_NULL)
+- __mach_port_deallocate (__mach_task_self (), ignore);
++ MACH_MSG_TYPE_MAKE_SEND));
++ if (err)
++ {
++ __mach_port_destroy (__mach_task_self (), ref);
++ return;
++ }
++
++ err = __auth_user_authenticate (new, ref,
++ MACH_MSG_TYPE_MAKE_SEND,
++ &newproc);
+ __mach_port_destroy (__mach_task_self (), ref);
++ if (err)
++ return;
++
++ if (newproc == MACH_PORT_NULL)
++ {
++ /* Old versions of the proc server did not recreate the process
++ port when reauthenticating, and passed MACH_PORT_NULL through
++ the auth server. That must be what we're dealing with. */
++
++ /* Set the owner of the process here too. */
++ __mutex_lock (&_hurd_id.lock);
++ if (!_hurd_check_ids ())
++ HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
++ __proc_setowner (port,
++ (_hurd_id.gen.nuids
++ ? _hurd_id.gen.uids[0] : 0),
++ !_hurd_id.gen.nuids));
++ __mutex_unlock (&_hurd_id.lock);
++
++ return;
++ }
++
++ err = __proc_reauthenticate_complete (newproc);
++ if (err)
++ {
++ __mach_port_deallocate (__mach_task_self (), newproc);
++ return;
++ }
+
+- /* Set the owner of the process here too. */
+- __mutex_lock (&_hurd_id.lock);
+- if (!_hurd_check_ids ())
+- HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
+- __proc_setowner (port,
+- (_hurd_id.gen.nuids
+- ? _hurd_id.gen.uids[0] : 0),
+- !_hurd_id.gen.nuids));
+- __mutex_unlock (&_hurd_id.lock);
++ _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], newproc);
+
+ (void) &reauth_proc; /* Silence compiler warning. */
+ }
+Index: glibc-2.31/sysdeps/mach/hurd/spawni.c
+===================================================================
+--- glibc-2.31.orig/sysdeps/mach/hurd/spawni.c
++++ glibc-2.31/sysdeps/mach/hurd/spawni.c
+@@ -651,11 +651,29 @@ retry:
+ ref, MACH_MSG_TYPE_MAKE_SEND,
+ &newproc);
+ __mach_port_destroy (__mach_task_self (), ref);
+- if (!err)
+- {
+- __mach_port_deallocate (__mach_task_self (), proc);
+- proc = newproc;
+- }
++ if (err)
++ goto out;
++ if (newproc == MACH_PORT_NULL)
++ {
++ /* Old versions of the proc server did not recreate the process
++ port when reauthenticating, and passed MACH_PORT_NULL through
++ the auth server. That must be what we're dealing with. Just
++ keep the existing proc port in this case. */
++ }
++ else
++ {
++ err = __proc_reauthenticate_complete (newproc);
++ if (err)
++ {
++ __mach_port_deallocate (__mach_task_self (), newproc);
++ goto out;
++ }
++ else
++ {
++ __mach_port_deallocate (__mach_task_self (), proc);
++ proc = newproc;
++ }
++ }
+
+ if (!err)
+ err = reauthenticate (INIT_PORT_CRDIR, &rcrdir);
new file mode 100644
@@ -0,0 +1,261 @@
+Subject: [PATCH] hurd: SCM_CREDS support
+
+Adjusted for use in Guix by removing #include <sysdep-cancel.h>.
+
+
+Svante Signell <svante.signell@gmail.com>
+Samuel Thibault <samuel.thibault@ens-lyon.org>
+
+ * sysdeps/mach/hurd/sendmsg.c (__libc_sendmsg): On SCM_CREDS
+ control messages, record uids, pass a rendez-vous port in the
+ control message, and call __auth_user_authenticate_request to
+ make auth send credentials on that port. Do not wait for a
+ reply.
+ * sysdeps/mach/hurd/recvmsg.c (contains_uid, contains_gid,
+ check_auth): New functions.
+ (__libc_recvmsg): On SCM_CREDS control messages, call check_auth
+ to check the passed credentials thanks to the answer from the
+ auth server.
+ * hurd/Makefile (user-interfaces): Add auth_request and
+ auth_reply.
+
+---
+ hurd/Makefile | 2
+ sysdeps/mach/hurd/recvmsg.c | 137 ++++++++++++++++++++++++++++++++++++++++++++
+ sysdeps/mach/hurd/sendmsg.c | 36 +++++++++++
+ 3 files changed, 174 insertions(+), 1 deletion(-)
+
+--- a/sysdeps/mach/hurd/recvmsg.c
++++ b/sysdeps/mach/hurd/recvmsg.c
+@@ -24,6 +24,123 @@
+ #include <hurd/socket.h>
+ #include <sysdep-cancel.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
+@@ -211,6 +328,21 @@
+ newfds++;
+ }
+ }
++ 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++)
+@@ -241,6 +373,11 @@
+ __mach_port_deallocate (__mach_task_self (), ports[ii]);
+ }
+ }
++ else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDS)
++ {
++ __mach_port_deallocate (__mach_task_self (), ports[ii]);
++ ii++;
++ }
+ }
+ }
+
+--- a/sysdeps/mach/hurd/sendmsg.c
++++ b/sysdeps/mach/hurd/sendmsg.c
+@@ -19,10 +19,12 @@
+ #include <string.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
++#include <unistd.h>
+
+ #include <hurd.h>
+ #include <hurd/fd.h>
+ #include <hurd/ifsock.h>
+ #include <hurd/socket.h>
++#include <hurd/auth_request.h>
+ #include "hurd/hurdsocket.h"
+
+@@ -113,6 +115,8 @@
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+ nports += (cmsg->cmsg_len - CMSG_ALIGN (sizeof (struct cmsghdr)))
+ / sizeof (int);
++ else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDS)
++ nports++;
+
+ if (nports)
+ ports = __alloca (nports * sizeof (mach_port_t));
+@@ -147,6 +151,38 @@
+ goto out;
+ }
+ }
++ else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDS)
++ {
++ /* SCM_CREDS support: send credentials. */
++ mach_port_t rendezvous = __mach_reply_port (), reply;
++ struct cmsgcred *ucredp;
++
++ err = __mach_port_insert_right (mach_task_self (), rendezvous,
++ rendezvous, MACH_MSG_TYPE_MAKE_SEND);
++ ports[nports++] = rendezvous;
++ if (err)
++ goto out;
++
++ ucredp = (struct cmsgcred *) CMSG_DATA(cmsg);
++ /* Fill in credentials data */
++ ucredp->cmcred_pid = __getpid();
++ ucredp->cmcred_uid = __getuid();
++ ucredp->cmcred_euid = __geteuid();
++ ucredp->cmcred_gid = __getgid();
++ ucredp->cmcred_ngroups =
++ __getgroups (sizeof (ucredp->cmcred_groups) / sizeof (gid_t),
++ ucredp->cmcred_groups);
++
++ /* And make auth server authenticate us. */
++ reply = __mach_reply_port();
++ err = __USEPORT
++ (AUTH, __auth_user_authenticate_request (port,
++ reply, MACH_MSG_TYPE_MAKE_SEND_ONCE,
++ rendezvous, MACH_MSG_TYPE_MAKE_SEND));
++ __mach_port_deallocate (__mach_task_self (), reply);
++ if (err)
++ goto out;
++ }
+ }
+
+ if (addr)
+--- a/hurd/Makefile
++++ b/hurd/Makefile
+@@ -29,7 +29,7 @@
+ # The RPC interfaces go in a separate library.
+ interface-library := libhurduser
+ user-interfaces := $(addprefix hurd/,\
+- auth startup \
++ auth auth_request auth_reply startup \
+ process process_request \
+ msg msg_reply msg_request \
+ exec exec_startup crash interrupt \
--
2.33.0