guix-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[bug#50698] [PATCH] WIP patches for recently-known hurd security vulnera


From: Maxime Devos
Subject: [bug#50698] [PATCH] WIP patches for recently-known hurd security vulnerabilities
Date: Mon, 20 Sep 2021 12:40:48 +0200
User-agent: Evolution 3.34.2

Hi,

I've tried to patch the glibc package for the problems noted at
<https://lists.gnu.org/archive/html/bug-hurd/2021-08/msg00007.html>;.

I've found two recent patches (glibc-hurd-proc-reauth.patch and
glibc-hurd-sendmsg-SCM_CREDS.patch) that appeared relevant.  I tried
to patch our glibc package with those patches.

The modified tarball builds fine for --system=x86_64-linux, but not
for --system=i586-gnu (tested with ./pre-inst-env guix build hello
--system=i586-gnu).  Any idea what's happening here?

Greetings,
Maxime.
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

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 <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

Attachment: signature.asc
Description: This is a digitally signed message part


reply via email to

[Prev in Thread] Current Thread [Next in Thread]