From cdf38fbfcba4c87777d7ba2175f08e877dafe86a Mon Sep 17 00:00:00 2001 From: Maxime Devos 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 . 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 diff --git a/gnu/local.mk b/gnu/local.mk index a7255e8df7..abad3ad777 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -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 \ diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm index ea2e102c15..ab6f13ec88 100644 --- a/gnu/packages/base.scm +++ b/gnu/packages/base.scm @@ -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.) diff --git a/gnu/packages/patches/glibc-hurd-proc-reauth.patch b/gnu/packages/patches/glibc-hurd-proc-reauth.patch new file mode 100644 index 0000000000..fa3b0f1403 --- /dev/null +++ b/gnu/packages/patches/glibc-hurd-proc-reauth.patch @@ -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); diff --git a/gnu/packages/patches/glibc-hurd-sendmsg-SCM_CREDS.patch b/gnu/packages/patches/glibc-hurd-sendmsg-SCM_CREDS.patch new file mode 100644 index 0000000000..67de2e1829 --- /dev/null +++ b/gnu/packages/patches/glibc-hurd-sendmsg-SCM_CREDS.patch @@ -0,0 +1,261 @@ +Subject: [PATCH] hurd: SCM_CREDS support + +Adjusted for use in Guix by removing #include . + + +Svante Signell +Samuel Thibault + + * 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 + #include + ++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 + #include + #include ++#include + + #include + #include + #include + #include ++#include + #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