~ruther/guix-local

2194d6e99fdc68e791b63d100bc0eeed649c5b02 — Ludovic Courtès 1 year, 5 months ago e72c26d
gnu: glibc: Update to 2.40.

* gnu/packages/base.scm (glibc): Update to 2.40.
[replacement]: Remove.
(%glibc-patches): Update.
(glibc/fixed): Remove.
(glibc-for-fhs): Update patch name.
* gnu/packages/patches/glibc-hurd64-intr-msg-clobber.patch: Update for 2.40.
* gnu/packages/patches/glibc-hurd64-sgms-context.patch: Remove.
* gnu/local.mk (dist_patch_DATA): Unregister.
* gnu/packages/base.scm (glibc/hurd-headers): Remove it.
* gnu/packages/patches/glibc-2.40-dl-cache.patch,
gnu/packages/patches/glibc-2.40-CVE-2025-0.patch: New files.
* gnu/local.mk (dist_patch_DATA): Register them.

Change-Id: I7f041a6ff9ea11e4b05a75ca704007deb405653b
6 files changed, 186 insertions(+), 575 deletions(-)

M gnu/local.mk
M gnu/packages/base.scm
A gnu/packages/patches/glibc-2.40-CVE-2025-0.patch
A gnu/packages/patches/glibc-2.40-dl-cache.patch
M gnu/packages/patches/glibc-hurd64-intr-msg-clobber.patch
D gnu/packages/patches/glibc-hurd64-sgms-context.patch
M gnu/local.mk => gnu/local.mk +2 -1
@@ 1463,6 1463,8 @@ dist_patch_DATA =						\
  %D%/packages/patches/glibc-2.33-riscv64-miscompilation.patch	\
  %D%/packages/patches/glibc-2.39-git-updates.patch	\
  %D%/packages/patches/glibc-2.39-fmod-libm-a.patch		\
  %D%/packages/patches/glibc-2.40-dl-cache.patch		\
  %D%/packages/patches/glibc-2.40-CVE-2025-0.patch		\
  %D%/packages/patches/glibc-CVE-2019-7309.patch		\
  %D%/packages/patches/glibc-CVE-2019-9169.patch		\
  %D%/packages/patches/glibc-CVE-2019-19126.patch		\


@@ 1493,7 1495,6 @@ dist_patch_DATA =						\
  %D%/packages/patches/glibc-hurd64-gcc-14.2-tls-bug.patch	\
  %D%/packages/patches/glibc-hurd64-fault.patch			\
  %D%/packages/patches/glibc-hurd64-intr-msg-clobber.patch	\
  %D%/packages/patches/glibc-hurd64-sgms-context.patch		\
  %D%/packages/patches/glibc-ldd-powerpc.patch			\
  %D%/packages/patches/glibc-ldd-x86_64.patch			\
  %D%/packages/patches/glibc-locales.patch			\

M gnu/packages/base.scm => gnu/packages/base.scm +7 -31
@@ 1,5 1,5 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2012-2024 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2012-2025 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2014, 2019 Andreas Enge <andreas@enge.fr>
;;; Copyright © 2012 Nikita Karetnikov <nikita@karetnikov.org>
;;; Copyright © 2014, 2015, 2016, 2018 Mark H Weaver <mhw@netris.org>


@@ 893,14 893,14 @@ the store.")
    (license gpl3+)))

(define %glibc-patches
  (list "glibc-2.39-git-updates.patch"
        "glibc-ldd-powerpc.patch"
  (list "glibc-ldd-powerpc.patch"
        "glibc-2.38-ldd-x86_64.patch"
        "glibc-dl-cache.patch"
        "glibc-2.40-dl-cache.patch"
        "glibc-2.37-versioned-locpath.patch"
        ;; "glibc-allow-kernel-2.6.32.patch"
        "glibc-reinstate-prlimit64-fallback.patch"
        "glibc-supported-locales.patch"
        "glibc-2.40-CVE-2025-0.patch"
        "glibc-2.37-hurd-clock_t_centiseconds.patch"
        "glibc-2.37-hurd-local-clock_gettime_MONOTONIC.patch"
        "glibc-hurd-mach-print.patch"


@@ 912,18 912,17 @@ the store.")
  ;; version 2.28, GNU/Hurd used a different glibc branch.
  (package
   (name "glibc")
   (version "2.39")
   (version "2.40")
   (source (origin
            (method url-fetch)
            (uri (string-append "mirror://gnu/glibc/glibc-" version ".tar.xz"))
            (sha256
             (base32
              "09nrwb0ksbah9k35jchd28xxp2hidilqdgz7b8v5f30pz1yd8yzp"))
              "18h50b0zm8dkpzj81w033v99rbxiykk3v697yr4dfqwjbqbr1a0r"))
            (patches (map search-patch %glibc-patches))))
   (properties `((lint-hidden-cve . ("CVE-2024-2961"
                                     "CVE-2024-33601" "CVE-2024-33602"
                                     "CVE-2024-33600" "CVE-2024-33599"))))
   (replacement glibc/fixed)
   (build-system gnu-build-system)

   ;; Glibc's <limits.h> refers to <linux/limit.h>, for instance, so glibc


@@ 1201,28 1200,6 @@ with the Linux kernel.")
   (license lgpl2.0+)
   (home-page "https://www.gnu.org/software/libc/")))

(define glibc/fixed
  (package
    (inherit glibc)
    (name "glibc")
    (version (package-version glibc))
    (source (origin
              (method git-fetch)
              (uri (git-reference
                    (url "git://sourceware.org/git/glibc.git")
                    ;; This is the latest commit from the
                    ;; 'release/2.39/master' branch, where CVEs and other
                    ;; important bug fixes are cherry picked.
                    (commit "2c882bf9c15d206aaf04766d1b8e3ae5b1002cc2")))
              (file-name (git-file-name name version))
              (sha256
               (base32
                "111yf24g0qcfcxywfzrilmjxysahlbkzxfimcz9rq8p00qzvvf51"))
              (patches (map search-patch
                            (fold (cut delete <...>)
                                  %glibc-patches
                                  '("glibc-2.39-git-updates.patch"))))))))

;; Define a variation of glibc which uses the default /etc/ld.so.cache, useful
;; in FHS containers.
(define-public glibc-for-fhs


@@ 1234,7 1211,7 @@ with the Linux kernel.")
                     ;; directories, re-enabling the default /etc/ld.so.cache
                     ;; behavior.
                     (patches
                      (delete (search-patch "glibc-dl-cache.patch")
                      (delete (search-patch "glibc-2.40-dl-cache.patch")
                              (origin-patches (package-source glibc)))))))))

;; Below are old libc versions, which we use mostly to build locale data in


@@ 1692,7 1669,6 @@ command.")
                (search-patches "glibc-hurd-pthread_setcancelstate.patch"
                                "glibc-hurd64-fault.patch"
                                "glibc-hurd64-intr-msg-clobber.patch"
                                "glibc-hurd64-sgms-context.patch"
                                "glibc-hurd64-gcc-14.2-tls-bug.patch")))))))

(define-public glibc/hurd-headers

A gnu/packages/patches/glibc-2.40-CVE-2025-0.patch => gnu/packages/patches/glibc-2.40-CVE-2025-0.patch +63 -0
@@ 0,0 1,63 @@
From 7d4b6bcae91f29d7b4daf15bab06b66cf1d2217c Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Tue, 21 Jan 2025 16:11:06 -0500
Subject: [PATCH] Fix underallocation of abort_msg_s struct (CVE-2025-0395)

Include the space needed to store the length of the message itself, in
addition to the message string.  This resolves BZ #32582.

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 68ee0f704cb81e9ad0a78c644a83e1e9cd2ee578)
---
 assert/assert.c            | 4 +++-
 sysdeps/posix/libc_fatal.c | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/assert/assert.c b/assert/assert.c
index c29629f5f6..b6e37d694c 100644
--- a/assert/assert.c
+++ b/assert/assert.c
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <atomic.h>
 #include <ldsodefs.h>
+#include <libc-pointer-arith.h>
 #include <libintl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -65,7 +66,8 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file,
       (void) __fxprintf (NULL, "%s", str);
       (void) fflush (stderr);
 
-      total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
+      total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
+			GLRO(dl_pagesize));
       struct abort_msg_s *buf = __mmap (NULL, total, PROT_READ | PROT_WRITE,
 					MAP_ANON | MAP_PRIVATE, -1, 0);
       if (__glibc_likely (buf != MAP_FAILED))
diff --git a/sysdeps/posix/libc_fatal.c b/sysdeps/posix/libc_fatal.c
index f9e3425e04..089c47b04b 100644
--- a/sysdeps/posix/libc_fatal.c
+++ b/sysdeps/posix/libc_fatal.c
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <ldsodefs.h>
+#include <libc-pointer-arith.h>
 #include <paths.h>
 #include <stdarg.h>
 #include <stdbool.h>
@@ -105,7 +106,8 @@ __libc_message_impl (const char *fmt, ...)
     {
       WRITEV_FOR_FATAL (fd, iov, iovcnt, total);
 
-      total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
+      total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
+			GLRO(dl_pagesize));
       struct abort_msg_s *buf = __mmap (NULL, total,
 					PROT_READ | PROT_WRITE,
 					MAP_ANON | MAP_PRIVATE, -1, 0);
-- 
2.46.0


A gnu/packages/patches/glibc-2.40-dl-cache.patch => gnu/packages/patches/glibc-2.40-dl-cache.patch +113 -0
@@ 0,0 1,113 @@
Read the shared library cache relative to $ORIGIN instead of reading
from /etc/ld.so.cache.  Also arrange so that this cache takes
precedence over RUNPATH.

diff --git a/elf/dl-cache.c b/elf/dl-cache.c
index 7c7dc587..19d1d79a 100644
--- a/elf/dl-cache.c
+++ b/elf/dl-cache.c
@@ -374,6 +374,52 @@ _dl_cache_libcmp (const char *p1, const char *p2)
   return *p1 - *p2;
 }
 
+/* Special value representing the lack of an ld.so cache.  */
+static const char ld_so_cache_lacking[] = "/ld.so cache is lacking";
+
+/* Return the per-application ld.so cache, relative to $ORIGIN, or NULL if
+   that fails for some reason.  Do not return the system-wide LD_SO_CACHE
+   since on a foreign distro it would contain invalid information.  */
+static const char *
+ld_so_cache (void)
+{
+  static const char *loader_cache;
+
+  if (loader_cache == NULL)
+    {
+      static const char store[] = @STORE_DIRECTORY@;
+      const char *origin = _dl_get_origin ();
+
+      /* Check whether ORIGIN is something like "/gnu/store/…-foo/bin".  */
+      if (origin != (char *) -1   /* _dl_get_origin reported failure */
+	  && strncmp (store, origin, strlen (store)) == 0
+	  && origin[sizeof store - 1] == '/')
+	{
+	  char *store_item_end = strchr (origin + sizeof store, '/');
+
+	  if (store_item_end != NULL)
+	    {
+	      static const char suffix[] = "/etc/ld.so.cache";
+	      size_t store_item_len = store_item_end - origin;
+
+	      /* Note: We can't use 'malloc' because it can be interposed.
+		 Likewise, 'strncpy' is not available.  */
+	      char *cache = alloca (strlen (origin) + sizeof suffix);
+
+	      strcpy (cache, origin);
+	      strcpy (cache + store_item_len, suffix);
+
+	      loader_cache = __strdup (cache) ?: ld_so_cache_lacking;
+	    }
+	  else
+	    loader_cache = ld_so_cache_lacking;
+	}
+      else
+	loader_cache = ld_so_cache_lacking;
+    }
+
+  return loader_cache;
+}
 
 /* Look up NAME in ld.so.cache and return the file name stored there, or null
    if none is found.  The cache is loaded if it was not already.  If loading
@@ -387,12 +433,15 @@ _dl_load_cache_lookup (const char *name)
 {
   /* Print a message if the loading of libs is traced.  */
   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
-    _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE);
+    _dl_debug_printf (" search cache=%s\n", ld_so_cache ());
+
+  if (__glibc_unlikely (ld_so_cache () == ld_so_cache_lacking))
+    return NULL;
 
   if (cache == NULL)
     {
       /* Read the contents of the file.  */
-      void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
+      void *file = _dl_sysdep_read_whole_file (ld_so_cache (), &cachesize,
 					       PROT_READ);
 
       /* We can handle three different cache file formats here:
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 8a89b710..b8802e74 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -2038,14 +2038,6 @@ _dl_map_object (struct link_map *loader, const char *name,
 			loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
 			LA_SER_LIBPATH, &found_other_class);
 
-      /* Look at the RUNPATH information for this binary.  */
-      if (fd == -1 && loader != NULL
-	  && cache_rpath (loader, &loader->l_runpath_dirs,
-			  DT_RUNPATH, "RUNPATH"))
-	fd = open_path (name, namelen, mode,
-			&loader->l_runpath_dirs, &realname, &fb, loader,
-			LA_SER_RUNPATH, &found_other_class);
-
 #ifdef USE_LDCONFIG
       if (fd == -1
 	  && (__glibc_likely ((mode & __RTLD_SECURE) == 0)
@@ -2104,6 +2096,14 @@ _dl_map_object (struct link_map *loader, const char *name,
 	}
 #endif
 
+      /* Look at the RUNPATH information for this binary.  */
+      if (fd == -1 && loader != NULL
+	  && cache_rpath (loader, &loader->l_runpath_dirs,
+			  DT_RUNPATH, "RUNPATH"))
+	fd = open_path (name, namelen, mode,
+			&loader->l_runpath_dirs, &realname, &fb, loader,
+			LA_SER_RUNPATH, &found_other_class);
+
       /* Finally, try the default path.  */
       if (fd == -1
 	  && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL

M gnu/packages/patches/glibc-hurd64-intr-msg-clobber.patch => gnu/packages/patches/glibc-hurd64-intr-msg-clobber.patch +1 -38
@@ 1,40 1,3 @@
Upstream-status: Taken from <https://salsa.debian.org/glibc-team/glibc/-/blob/c36c87acb1a35d6e06db6cef1e28cf2f405e1a9e/debian/patches/hurd-i386/git-intr-msg-clobber.diff>.

See <https://lists.gnu.org/archive/html/bug-hurd/2024-11/msg00115.html>,
and <https://lists.debian.org/debian-hurd/2024/07/msg00063.html>.

Commited for 2.40

commit c8b4ce0b368115714bd4cce131e1683759471099
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date:   Sat Jul 13 17:00:55 2024 +0200

    hurd: Fix restoring message to be retried
    
    save_data stores the start of the original message to be retried,
    overwritten by the EINTR reply. In 64b builds the overwrite is however
    rounded up to the 64b pointer size, so we have to save more than just
    the 32b err.
    
    Thanks a lot to Luca Dariz for the investigation!

diff --git a/hurd/intr-msg.c b/hurd/intr-msg.c
index 2c2e7dc463..424c1fc700 100644
--- a/hurd/intr-msg.c
+++ b/hurd/intr-msg.c
@@ -42,7 +42,10 @@ _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
   struct clobber
   {
     mach_msg_type_t type;
-    error_t err;
+    union {
+      error_t err;
+      uintptr_t align;
+    };
   };
   union msg
   {

Taken from: <https://salsa.debian.org/glibc-team/glibc/-/blob/027f94215a633cbf53794d4b48675fde36706e35/debian/patches/hurd-i386/local-intr-msg-clobber.diff>

Force putting save_data on the stack rather than in SSE register


@@ 51,7 14,7 @@ Index: glibc-2.38/hurd/intr-msg.c
===================================================================
--- glibc-2.38.orig/hurd/intr-msg.c
+++ glibc-2.38/hurd/intr-msg.c
@@ -79,7 +79,7 @@ _hurd_intr_rpc_mach_msg (mach_msg_header
@@ -66,7 +66,7 @@ _hurd_intr_rpc_mach_msg (mach_msg_header
   mach_msg_bits_t msgh_bits;
   mach_port_t remote_port;
   mach_msg_id_t msgid;

D gnu/packages/patches/glibc-hurd64-sgms-context.patch => gnu/packages/patches/glibc-hurd64-sgms-context.patch +0 -505
@@ 1,505 0,0 @@
Upstream-status: Taken from <https://salsa.debian.org/glibc-team/glibc/-/blob/62c59900cfdf6b9af187f4ae03addcd7cd226bfc/debian/patches/hurd-i386/git-context.diff>.

commit 88b771ab5e1169e746dbf4a990d90cffc5fa54ea
Author: Flavio Cruz <flaviocruz@gmail.com>
Date:   Sat Feb 17 15:25:35 2024 -0500

    Implement setcontext/getcontext/makecontext/swapcontext for Hurd x86_64
    
    Tested with the tests provided by glibc plus some other toy examples.
    Message-ID: <20240217202535.1860803-1-flaviocruz@gmail.com>

diff --git a/sysdeps/mach/hurd/x86_64/Makefile b/sysdeps/mach/hurd/x86_64/Makefile
index 80cf2eb6dc..2b43f5d625 100644
--- a/sysdeps/mach/hurd/x86_64/Makefile
+++ b/sysdeps/mach/hurd/x86_64/Makefile
@@ -3,3 +3,7 @@ ifeq ($(subdir),conform)
 # (missing SA_NOCLDWAIT)
 conformtest-xfail-conds += x86_64-gnu
 endif
+
+ifeq ($(subdir),stdlib)
+sysdep_routines += __start_context
+endif
diff --git a/sysdeps/mach/hurd/x86_64/__start_context.S b/sysdeps/mach/hurd/x86_64/__start_context.S
new file mode 100644
index 0000000000..3cb4c6b5a9
--- /dev/null
+++ b/sysdeps/mach/hurd/x86_64/__start_context.S
@@ -0,0 +1,49 @@
+/* Copyright (C) 2024 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+/* This is the helper code which gets called if a function which is
+   registered with 'makecontext' returns.  In this case we have to
+   install the context listed in the uc_link element of the context
+   'makecontext' manipulated at the time of the 'makecontext' call.
+   If the pointer is NULL the process must terminate.  */
+
+
+ENTRY(__start_context)
+	/* This removes the parameters passed to the function given to
+	   'makecontext' from the stack.  RBX contains the address
+	   on the stack pointer for the next context.  */
+	movq	%rbx, %rsp
+
+	/* Don't use pop here so that stack is aligned to 16 bytes.  */
+	movq	(%rsp), %rdi		/* This is the next context.  */
+	testq	%rdi, %rdi
+	je	2f			/* If it is zero exit.  */
+
+	call	__setcontext
+	/* If this returns (which can happen if __sigprocmask fails) we'll
+	   exit the program with the return error value (-1).  */
+	movq	%rax,%rdi
+
+2:
+	call	HIDDEN_JUMPTARGET(exit)
+	/* The 'exit' call should never return.  In case it does cause
+	   the process to terminate.  */
+L(hlt):
+	hlt
+END(__start_context)
diff --git a/sysdeps/mach/hurd/x86_64/getcontext.S b/sysdeps/mach/hurd/x86_64/getcontext.S
new file mode 100644
index 0000000000..ef431be1a3
--- /dev/null
+++ b/sysdeps/mach/hurd/x86_64/getcontext.S
@@ -0,0 +1,68 @@
+/* Save current context.
+   Copyright (C) 2024 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+
+ENTRY(__getcontext)
+	/* Save the preserved registers, the registers used for passing
+	   args, and the return address.  */
+	movq	%rbx, oRBX(%rdi)
+	movq	%rbp, oRBP(%rdi)
+	movq	%r12, oR12(%rdi)
+	movq	%r13, oR13(%rdi)
+	movq	%r14, oR14(%rdi)
+	movq	%r15, oR15(%rdi)
+
+	movq	%rdi, oRDI(%rdi)
+	movq	%rsi, oRSI(%rdi)
+	movq	%rdx, oRDX(%rdi)
+	movq	%rcx, oRCX(%rdi)
+	movq	%r8, oR8(%rdi)
+	movq	%r9, oR9(%rdi)
+
+	movq	(%rsp), %rcx
+	movq	%rcx, oRIP(%rdi)
+	leaq	8(%rsp), %rcx		/* Exclude the return address.  */
+	movq	%rcx, oRSP(%rdi)
+
+	/* We have separate floating-point register content memory on the
+	   stack.  We use the __fpregs_mem block in the context.  Set the
+	   links up correctly.  */
+
+	leaq	oFPREGSMEM(%rdi), %rcx
+	movq	%rcx, oFPREGS(%rdi)
+	/* Save the floating-point environment.  */
+	fnstenv	(%rcx)
+	fldenv	(%rcx)
+	stmxcsr oMXCSR(%rdi)
+
+	/* Save the current signal mask with
+	 * __sigprocmask(SIG_BLOCK, NULL, oSIGMASK(%rdi)); */
+	leaq	oSIGMASK(%rdi), %rdx
+	movq $0, %rsi
+	movl $SIG_BLOCK, %edi
+	call	HIDDEN_JUMPTARGET (__sigprocmask)
+
+	/* Propagate %rax (and errno, in case).  */
+	ret
+PSEUDO_END(__getcontext)
+
+weak_alias (__getcontext, getcontext)
diff --git a/sysdeps/mach/hurd/x86_64/makecontext.c b/sysdeps/mach/hurd/x86_64/makecontext.c
new file mode 100644
index 0000000000..6990a7775c
--- /dev/null
+++ b/sysdeps/mach/hurd/x86_64/makecontext.c
@@ -0,0 +1,119 @@
+/* Create new context.
+   Copyright (C) 2024 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <ucontext.h>
+
+#include "ucontext_i.h"
+
+/* This implementation can handle any ARGC value but only
+   normal integer parameters.
+   makecontext sets up a stack and the registers for the
+   user context. The stack looks like this:
+               +-----------------------+
+               | next context          |
+               +-----------------------+
+               | parameter 7-n         |
+	       +-----------------------+
+	       | trampoline address    |
+    %rsp ->    +-----------------------+
+
+   The registers are set up like this:
+     %rdi,%rsi,%rdx,%rcx,%r8,%r9: parameter 1 to 6
+     %rbx   : address of next context
+     %rsp   : stack pointer.
+*/
+
+/* XXX: This implementation currently only handles integer arguments.
+   To handle long int and pointer arguments the va_arg arguments needs
+   to be changed to long and also the stdlib/tst-setcontext.c file needs
+   to be changed to pass long arguments to makecontext.  */
+
+
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+  extern void __start_context (void) attribute_hidden;
+  greg_t *sp;
+  unsigned int idx_uc_link;
+  va_list ap;
+  int i;
+
+  /* Generate room on stack for parameter if needed and uc_link.  */
+  sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp
+		   + ucp->uc_stack.ss_size);
+  sp -= (argc > 6 ? argc - 6 : 0) + 1;
+  /* Align stack and make space for trampoline address.  */
+  sp = (greg_t *) ((((uintptr_t) sp) & -16L) - 8);
+
+  idx_uc_link = (argc > 6 ? argc - 6 : 0) + 1;
+
+  /* Setup context ucp.  */
+  /* Address to jump to.  */
+  ucp->uc_mcontext.gregs[REG_RIP] = (uintptr_t) func;
+  /* Setup rbx.*/
+  ucp->uc_mcontext.gregs[REG_RBX] = (uintptr_t) &sp[idx_uc_link];
+  ucp->uc_mcontext.gregs[REG_RSP] = (uintptr_t) sp;
+
+  /* Setup stack.  */
+  sp[0] = (uintptr_t) &__start_context;
+  sp[idx_uc_link] = (uintptr_t) ucp->uc_link;
+
+  va_start (ap, argc);
+  /* Handle arguments.
+
+     The standard says the parameters must all be int values.  This is
+     an historic accident and would be done differently today.  For
+     x86-64 all integer values are passed as 64-bit values and
+     therefore extending the API to copy 64-bit values instead of
+     32-bit ints makes sense.  It does not break existing
+     functionality and it does not violate the standard which says
+     that passing non-int values means undefined behavior.  */
+  for (i = 0; i < argc; ++i)
+    switch (i)
+      {
+      case 0:
+	ucp->uc_mcontext.gregs[REG_RDI] = va_arg (ap, greg_t);
+	break;
+      case 1:
+	ucp->uc_mcontext.gregs[REG_RSI] = va_arg (ap, greg_t);
+	break;
+      case 2:
+	ucp->uc_mcontext.gregs[REG_RDX] = va_arg (ap, greg_t);
+	break;
+      case 3:
+	ucp->uc_mcontext.gregs[REG_RCX] = va_arg (ap, greg_t);
+	break;
+      case 4:
+	ucp->uc_mcontext.gregs[REG_R8] = va_arg (ap, greg_t);
+	break;
+      case 5:
+	ucp->uc_mcontext.gregs[REG_R9] = va_arg (ap, greg_t);
+	break;
+      default:
+	/* Put value on stack.  */
+	sp[i - 5] = va_arg (ap, greg_t);
+	break;
+      }
+  va_end (ap);
+}
+
+
+weak_alias (__makecontext, makecontext)
diff --git a/sysdeps/mach/hurd/x86_64/setcontext.S b/sysdeps/mach/hurd/x86_64/setcontext.S
new file mode 100644
index 0000000000..99919ee2a8
--- /dev/null
+++ b/sysdeps/mach/hurd/x86_64/setcontext.S
@@ -0,0 +1,96 @@
+/* Install given context.
+   Copyright (C) 2024 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+
+ENTRY(__setcontext)
+	/* Save argument since call will destroy it.  */
+	pushq	%rdi
+	cfi_adjust_cfa_offset(8)
+
+	/* Set the signal mask with
+	   __sigprocmask (SIG_SETMASK, mask, NULL).  */
+	xorl	%edx, %edx
+	leaq	oSIGMASK(%rdi), %rsi
+	movl	$SIG_SETMASK, %edi
+	call	HIDDEN_JUMPTARGET (__sigprocmask)
+	/* Pop the pointer into RDX. The choice is arbitrary, but
+	   leaving RDI and RSI available for use later can avoid
+	   shuffling values.  */
+	popq	%rdx
+
+	test	%rax, %rax
+	jne	L(pseudo_end)
+
+	/* Restore the floating-point context.  Not the registers, only the
+	   rest.  */
+	movq	oFPREGS(%rdx), %rcx
+	fldenv	(%rcx)
+	ldmxcsr oMXCSR(%rdx)
+
+	/* Load the new stack pointer, the preserved registers and
+	   registers used for passing args.  */
+	cfi_def_cfa(%rdx, 0)
+	cfi_offset(%rbx,oRBX)
+	cfi_offset(%rbp,oRBP)
+	cfi_offset(%r12,oR12)
+	cfi_offset(%r13,oR13)
+	cfi_offset(%r14,oR14)
+	cfi_offset(%r15,oR15)
+	cfi_offset(%rsp,oRSP)
+	cfi_offset(%rip,oRIP)
+
+	movq	oRSP(%rdx), %rsp
+	movq	oRBX(%rdx), %rbx
+	movq	oRBP(%rdx), %rbp
+	movq	oR12(%rdx), %r12
+	movq	oR13(%rdx), %r13
+	movq	oR14(%rdx), %r14
+	movq	oR15(%rdx), %r15
+
+	/* The following ret should return to the address set with
+	getcontext.  Therefore push the address on the stack.  */
+	movq	oRIP(%rdx), %rcx
+	pushq	%rcx
+
+	movq	oRSI(%rdx), %rsi
+	movq	oRDI(%rdx), %rdi
+	movq	oRCX(%rdx), %rcx
+	movq	oR8(%rdx), %r8
+	movq	oR9(%rdx), %r9
+
+	/* Setup finally %rdx.  */
+	movq	oRDX(%rdx), %rdx
+
+	/* End FDE here, we fall into another context.  */
+	cfi_endproc
+	cfi_startproc
+
+	/* Clear rax to indicate success.  */
+	xorl	%eax, %eax
+L(pseudo_end):
+	/* The following 'ret' will pop the address of the code and jump
+	   to it.  */
+	ret
+PSEUDO_END(__setcontext)
+libc_hidden_def (__setcontext)
+
+weak_alias (__setcontext, setcontext)
diff --git a/sysdeps/mach/hurd/x86_64/swapcontext.S b/sysdeps/mach/hurd/x86_64/swapcontext.S
new file mode 100644
index 0000000000..79718a1fdd
--- /dev/null
+++ b/sysdeps/mach/hurd/x86_64/swapcontext.S
@@ -0,0 +1,120 @@
+/* Save current context and install the given one.
+   Copyright (C) 2024 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+
+/* int __swapcontext (ucontext_t *oucp, const ucontext_t *ucp);
+
+  Saves the machine context in oucp such that when it is activated,
+  it appears as if __swapcontextt() returned again, restores the
+  machine context in ucp and thereby resumes execution in that
+  context.
+
+  This implementation is intended to be used for *synchronous* context
+  switches only.  Therefore, it does not have to save anything
+  other than the PRESERVED state.  */
+
+ENTRY(__swapcontext)
+	/* Save the preserved registers, the registers used for passing args,
+	   and the return address.  */
+	movq	%rbx, oRBX(%rdi)
+	movq	%rbp, oRBP(%rdi)
+	movq	%r12, oR12(%rdi)
+	movq	%r13, oR13(%rdi)
+	movq	%r14, oR14(%rdi)
+	movq	%r15, oR15(%rdi)
+
+	movq	%rdi, oRDI(%rdi)
+	movq	%rsi, oRSI(%rdi)
+	movq	%rdx, oRDX(%rdi)
+	movq	%rcx, oRCX(%rdi)
+	movq	%r8, oR8(%rdi)
+	movq	%r9, oR9(%rdi)
+
+	movq	(%rsp), %rcx
+	movq	%rcx, oRIP(%rdi)
+	leaq	8(%rsp), %rcx		/* Exclude the return address.  */
+	movq	%rcx, oRSP(%rdi)
+
+	/* We have separate floating-point register content memory on the
+	   stack.  We use the __fpregs_mem block in the context.  Set the
+	   links up correctly.  */
+	leaq	oFPREGSMEM(%rdi), %rcx
+	movq	%rcx, oFPREGS(%rdi)
+	/* Save the floating-point environment.  */
+	fnstenv	(%rcx)
+	stmxcsr oMXCSR(%rdi)
+
+
+	/* The function call destroys some registers, save ucp.  */
+	movq	%rsi, %r12
+
+	/* Save the current signal mask and install the new one with
+	   __sigprocmask (SIG_BLOCK, newset, oldset).  */
+	leaq	oSIGMASK(%rdi), %rdx
+	leaq	oSIGMASK(%rsi), %rsi
+	movl	$SIG_SETMASK, %edi
+	call	HIDDEN_JUMPTARGET (__sigprocmask)
+	test	%rax, %rax
+	jne	L(pseudo_end)
+
+	/* Restore destroyed register into RDX. The choice is arbitrary,
+	   but leaving RDI and RSI available for use later can avoid
+	   shuffling values.  */
+	movq	%r12, %rdx
+
+	/* Restore the floating-point context.  Not the registers, only the
+	   rest.  */
+	movq	oFPREGS(%rdx), %rcx
+	fldenv	(%rcx)
+	ldmxcsr oMXCSR(%rdx)
+
+	/* Load the new stack pointer and the preserved registers.  */
+	movq	oRSP(%rdx), %rsp
+	movq	oRBX(%rdx), %rbx
+	movq	oRBP(%rdx), %rbp
+	movq	oR12(%rdx), %r12
+	movq	oR13(%rdx), %r13
+	movq	oR14(%rdx), %r14
+	movq	oR15(%rdx), %r15
+
+	/* The following ret should return to the address set with
+	getcontext.  Therefore push the address on the stack.  */
+	movq	oRIP(%rdx), %rcx
+	pushq	%rcx
+
+	/* Setup registers used for passing args.  */
+	movq	oRDI(%rdx), %rdi
+	movq	oRSI(%rdx), %rsi
+	movq	oRCX(%rdx), %rcx
+	movq	oR8(%rdx), %r8
+	movq	oR9(%rdx), %r9
+
+	/* Setup finally %rdx.  */
+	movq	oRDX(%rdx), %rdx
+
+	/* Clear rax to indicate success.  */
+	xorl	%eax, %eax
+L(pseudo_end):
+	ret
+PSEUDO_END(__swapcontext)
+
+weak_alias (__swapcontext, swapcontext)