diff mbox series

[v6,1/5] linux: Add posix_spawnattr_{get, set}cgroup_np (BZ 26731)

Message ID 20230706134508.422526-2-adhemerval.zanella@linaro.org
State New
Headers show
Series Add pidfd and cgroupv2 support for process creation (resend) | expand

Commit Message

Adhemerval Zanella Netto July 6, 2023, 1:45 p.m. UTC
These function allow to posix_spawn and posix_spawnp to use
CLONE_INTO_CGROUP with clone3, allowing the child process to
be created in a different version 2 cgroup.  They are GNU
extensions that are available only for Linux, and also only
for the architectures that implement clone3 wrapper
(HAVE_CLONE3_WRAPPER).

To create a process on a different cgroupv2, one can use the:

  posix_spawnattr_t attr;
  posix_spawnattr_init (&attr);
  posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETCGROUP);
  posix_spawnattr_setcgroup_np (&attr, cgroup);
  posix_spawn (...)

Similar to other posix_spawn flags, POSIX_SPAWN_SETCGROUP control
whether the cgroup file descriptor will be used or not with
clone3.

There is no fallback is either clone3 does not support the flag
or if the architecture does not provide the clone3 wrapper, in
this case posix_spawn returns ENOTSUP.

Checked on x86_64-linux-gnu.
---
 NEWS                                          |   6 +
 bits/spawn_ext.h                              |  21 ++
 posix/Makefile                                |   1 +
 posix/spawn.h                                 |   6 +-
 posix/spawnattr_setflags.c                    |   3 +-
 sysdeps/unix/sysv/linux/Makefile              |   5 +
 sysdeps/unix/sysv/linux/Versions              |   4 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   2 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   2 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   2 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/bits/spawn_ext.h      |  40 ++++
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist     |   2 +
 .../sysv/linux/loongarch/lp64/libc.abilist    |   2 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |   2 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   2 +
 .../sysv/linux/microblaze/be/libc.abilist     |   2 +
 .../sysv/linux/microblaze/le/libc.abilist     |   2 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   2 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |   2 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   2 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |   2 +
 sysdeps/unix/sysv/linux/or1k/libc.abilist     |   2 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   2 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   2 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   2 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   2 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   2 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   2 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |   2 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |   2 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   2 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   2 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   2 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   2 +
 .../unix/sysv/linux/spawnattr_getcgroup_np.c  |  28 +++
 .../unix/sysv/linux/spawnattr_setcgroup_np.c  |  27 +++
 sysdeps/unix/sysv/linux/spawni.c              |  20 +-
 sysdeps/unix/sysv/linux/tst-spawn-cgroup.c    | 216 ++++++++++++++++++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   2 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   2 +
 46 files changed, 440 insertions(+), 5 deletions(-)
 create mode 100644 bits/spawn_ext.h
 create mode 100644 sysdeps/unix/sysv/linux/bits/spawn_ext.h
 create mode 100644 sysdeps/unix/sysv/linux/spawnattr_getcgroup_np.c
 create mode 100644 sysdeps/unix/sysv/linux/spawnattr_setcgroup_np.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-spawn-cgroup.c
diff mbox series

Patch

diff --git a/NEWS b/NEWS
index f976abccbd..b65f2ef352 100644
--- a/NEWS
+++ b/NEWS
@@ -54,6 +54,12 @@  Major new features:
   explicitly enabled, then fortify source is forcibly disabled so to keep
   original behavior unchanged.
 
+* On Linux, the functions posix_spawnattr_getcgroup_np and
+  posix_spawnattr_setcgroup_np have been added, along with the
+  POSIX_SPAWN_SETCGROUP flag.  They allow posix_spawn and posix_spawnp to
+  set the cgroupv2 in the new process in a race free manner.  These functions
+  are GNU extensions and require a kernel with clone3 support.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * In the Linux kernel for the hppa/parisc architecture some of the
diff --git a/bits/spawn_ext.h b/bits/spawn_ext.h
new file mode 100644
index 0000000000..75b504a768
--- /dev/null
+++ b/bits/spawn_ext.h
@@ -0,0 +1,21 @@ 
+/* POSIX spawn extensions.   Generic version.
+   Copyright (C) 2023 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/>.  */
+
+#ifndef _SPAWN_H
+# error "Never include <bits/spawn-ext.h> directly; use <spawn.h> instead."
+#endif
diff --git a/posix/Makefile b/posix/Makefile
index 3d368b91f6..70faad4b63 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -37,6 +37,7 @@  headers := \
   bits/pthreadtypes-arch.h \
   bits/pthreadtypes.h \
   bits/sched.h \
+  bits/spawn_ext.h \
   bits/thread-shared-types.h \
   bits/types.h \
   bits/types/idtype_t.h \
diff --git a/posix/spawn.h b/posix/spawn.h
index 04cc525fa5..731862cc5a 100644
--- a/posix/spawn.h
+++ b/posix/spawn.h
@@ -34,7 +34,8 @@  typedef struct
   sigset_t __ss;
   struct sched_param __sp;
   int __policy;
-  int __pad[16];
+  int __cgroup;
+  int __pad[15];
 } posix_spawnattr_t;
 
 
@@ -59,6 +60,7 @@  typedef struct
 #ifdef __USE_GNU
 # define POSIX_SPAWN_USEVFORK		0x40
 # define POSIX_SPAWN_SETSID		0x80
+# define POSIX_SPAWN_SETCGROUP         0x100
 #endif
 
 
@@ -231,4 +233,6 @@  posix_spawn_file_actions_addtcsetpgrp_np (posix_spawn_file_actions_t *,
 
 __END_DECLS
 
+#include <bits/spawn_ext.h>
+
 #endif /* spawn.h */
diff --git a/posix/spawnattr_setflags.c b/posix/spawnattr_setflags.c
index 97153948e4..e7bb217c6a 100644
--- a/posix/spawnattr_setflags.c
+++ b/posix/spawnattr_setflags.c
@@ -26,7 +26,8 @@ 
 		   | POSIX_SPAWN_SETSCHEDPARAM				      \
 		   | POSIX_SPAWN_SETSCHEDULER				      \
 		   | POSIX_SPAWN_SETSID					      \
-		   | POSIX_SPAWN_USEVFORK)
+		   | POSIX_SPAWN_USEVFORK				      \
+		   | POSIX_SPAWN_SETCGROUP)
 
 /* Store flags in the attribute structure.  */
 int
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index be801e3be4..d7b020154a 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -493,11 +493,14 @@  sysdep_routines += \
   getcpu \
   oldglob \
   sched_getcpu \
+  spawnattr_getcgroup_np \
+  spawnattr_setcgroup_np \
   # sysdep_routines
 
 tests += \
   tst-affinity \
   tst-affinity-pid \
+  tst-spawn-cgroup \
   # tests
 
 tests-static += \
@@ -511,6 +514,8 @@  tests += \
 CFLAGS-fork.c = $(libio-mtsafe)
 CFLAGS-getpid.o = -fomit-frame-pointer
 CFLAGS-getpid.os = -fomit-frame-pointer
+
+tst-spawn-cgroup-ARGS = -- $(host-test-program-cmd)
 endif
 
 ifeq ($(subdir),inet)
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index bc59bce42f..c912370cde 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -321,6 +321,10 @@  libc {
     __ppoll64_chk;
 %endif
   }
+  GLIBC_2.38 {
+    posix_spawnattr_getcgroup_np;
+    posix_spawnattr_setcgroup_np;
+  }
   GLIBC_PRIVATE {
     # functions used in other libraries
     __syscall_rt_sigqueueinfo;
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index c49363e70e..cbc8387131 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2669,6 +2669,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index d6b1dcaae6..6d31a565d2 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2778,6 +2778,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index dfe0c3f7b6..8c604659c4 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2430,6 +2430,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 6c75e5aa76..7936ed59f8 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -550,6 +550,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 03d6f7ae2d..2893783e3d 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -547,6 +547,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/bits/spawn_ext.h b/sysdeps/unix/sysv/linux/bits/spawn_ext.h
new file mode 100644
index 0000000000..3bc10ab477
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/bits/spawn_ext.h
@@ -0,0 +1,40 @@ 
+/* POSIX spawn extensions.   Linux version.
+   Copyright (C) 2023 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/>.  */
+
+#ifndef _SPAWN_H
+# error "Never include <bits/spawn-ext.h> directly; use <spawn.h> instead."
+#endif
+
+__BEGIN_DECLS
+
+#ifdef __USE_MISC
+
+/* Get the cgroupsv2 the attribute structure.  */
+extern int posix_spawnattr_getcgroup_np (const posix_spawnattr_t *
+					 __restrict __attr,
+					 int *__cgroup)
+     __THROW __nonnull ((1, 2));
+
+/* Store scheduling parameters in the attribute structure.  */
+extern int posix_spawnattr_setcgroup_np (posix_spawnattr_t *__restrict __attr,
+					 int __cgroup)
+     __THROW __nonnull ((1));
+
+#endif /* __USE_MISC */
+
+__END_DECLS
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index d858c108c6..dc1b885b5a 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2706,6 +2706,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 82a14f8ace..c967612203 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2655,6 +2655,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 1950b15d5d..c7b921f392 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2839,6 +2839,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index d0b9cb279b..a0e4bd3ab9 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2604,6 +2604,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
index e760a631dd..bb8b895a37 100644
--- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
@@ -2190,6 +2190,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 35785a3d5f..0c28b1bd74 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -551,6 +551,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 4ab2426e0a..59badcaf6b 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2782,6 +2782,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 38faa16232..18da382fc2 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2755,6 +2755,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 374d658988..3f54fb325f 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2752,6 +2752,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index fcc5e88e91..4ce0ca4955 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2747,6 +2747,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 01eb96cd93..dc6e322b77 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2745,6 +2745,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index a2748b7b74..b4ce7b5c82 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2753,6 +2753,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 0ae7ba499d..311800f6ca 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2655,6 +2655,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 947495a0e2..756f3cce1d 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2794,6 +2794,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index 115f1039e7..9b59c148a1 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2176,6 +2176,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 19c4c325b0..022c9d5907 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2821,6 +2821,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 3e043c4044..5eabe69671 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2854,6 +2854,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index e4f3a766bb..a66243cb1b 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2575,6 +2575,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index dafe1c4a59..8904138f0b 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2889,6 +2889,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index b9740a1afc..c90aeb6bbf 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2432,6 +2432,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index e3b4656aa2..dea9d8e7fc 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2632,6 +2632,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 84cb7a50ed..475f5a991f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2819,6 +2819,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 33df3b1646..228525449e 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2612,6 +2612,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 94cbccd715..f8ffa32087 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2662,6 +2662,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 3bb316a787..ab4fecdc3e 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2659,6 +2659,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 6341b491b4..79b5353355 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2814,6 +2814,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 8ed1ea2926..479637e24d 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2627,6 +2627,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/spawnattr_getcgroup_np.c b/sysdeps/unix/sysv/linux/spawnattr_getcgroup_np.c
new file mode 100644
index 0000000000..82fd8f4b71
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/spawnattr_getcgroup_np.c
@@ -0,0 +1,28 @@ 
+/* Copyright (C) 2000-2023 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 <spawn.h>
+
+/* Get scheduling policy from the attribute structure.  */
+int
+posix_spawnattr_getcgroup_np (const posix_spawnattr_t *attr,
+			      int *cgroup)
+{
+  *cgroup = attr->__cgroup;
+
+  return 0;
+}
diff --git a/sysdeps/unix/sysv/linux/spawnattr_setcgroup_np.c b/sysdeps/unix/sysv/linux/spawnattr_setcgroup_np.c
new file mode 100644
index 0000000000..74d60bb5ea
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/spawnattr_setcgroup_np.c
@@ -0,0 +1,27 @@ 
+/* Copyright (C) 2000-2023 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 <spawn.h>
+
+/* Store scheduling policy in the attribute structure.  */
+int
+posix_spawnattr_setcgroup_np (posix_spawnattr_t *attr, int cgroup)
+{
+  attr->__cgroup = cgroup;
+
+  return 0;
+}
diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
index ec687cb423..da748679c1 100644
--- a/sysdeps/unix/sysv/linux/spawni.c
+++ b/sysdeps/unix/sysv/linux/spawni.c
@@ -380,14 +380,19 @@  __spawnix (pid_t * pid, const char *file,
      need for CLONE_SETTLS.  Although parent and child share the same TLS
      namespace, there will be no concurrent access for TLS variables (errno
      for instance).  */
+  bool set_cgroup = attrp ? (attrp->__flags & POSIX_SPAWN_SETCGROUP) : false;
   struct clone_args clone_args =
     {
       /* Unsupported flags like CLONE_CLEAR_SIGHAND will be cleared up by
 	 __clone_internal_fallback.  */
-      .flags = CLONE_CLEAR_SIGHAND | CLONE_VM | CLONE_VFORK,
+      .flags = (set_cgroup ? CLONE_INTO_CGROUP : 0)
+	       | CLONE_CLEAR_SIGHAND
+	       | CLONE_VM
+	       | CLONE_VFORK,
       .exit_signal = SIGCHLD,
       .stack = (uintptr_t) stack,
       .stack_size = stack_size,
+      .cgroup = (set_cgroup ? attrp->__cgroup : 0)
     };
 #ifdef HAVE_CLONE3_WRAPPER
   args.use_clone3 = true;
@@ -398,8 +403,17 @@  __spawnix (pid_t * pid, const char *file,
 #endif
     {
       args.use_clone3 = false;
-      new_pid = __clone_internal_fallback (&clone_args, __spawni_child,
-					   &args);
+      if (!set_cgroup)
+	new_pid = __clone_internal_fallback (&clone_args, __spawni_child,
+					     &args);
+      else
+	{
+	  /* No fallback for POSIX_SPAWN_SETCGROUP if clone3 is not
+	     supported.  */
+	  new_pid = -1;
+	  if (errno == ENOSYS)
+	    errno = ENOTSUP;
+	}
     }
 
   /* It needs to collect the case where the auxiliary process was created
diff --git a/sysdeps/unix/sysv/linux/tst-spawn-cgroup.c b/sysdeps/unix/sysv/linux/tst-spawn-cgroup.c
new file mode 100644
index 0000000000..6dba30ab29
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-spawn-cgroup.c
@@ -0,0 +1,216 @@ 
+/* Tests for posix_spawn cgroup extension.
+   Copyright (C) 2023 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <spawn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+#include <support/temp_file.h>
+#include <sys/vfs.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define CGROUPFS "/sys/fs/cgroup/"
+#ifndef CGROUP2_SUPER_MAGIC
+# define CGROUP2_SUPER_MAGIC 0x63677270
+#endif
+
+#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
+
+#define CGROUP_TEST "test-spawn-cgroup"
+
+/* Nonzero if the program gets called via `exec'.  */
+#define CMDLINE_OPTIONS \
+  { "restart", no_argument, &restart, 1 },
+static int restart;
+
+/* Hold the four initial argument used to respawn the process, plus the extra
+   '--direct', '--restart', the check type ('SIG_IGN' or 'SIG_DFL'), and a
+   final NULL.  */
+static char *spargs[8];
+
+static inline char *
+startswith (const char *s, const char *prefix)
+{
+  size_t l = strlen (prefix);
+  if (strncmp (s, prefix, l) == 0)
+    return (char *) s + l;
+  return NULL;
+}
+
+static char *
+get_cgroup (void)
+{
+  FILE *f = fopen ("/proc/self/cgroup", "re");
+  if (f == NULL)
+    FAIL_UNSUPPORTED ("no cgroup defined for the process");
+
+  char *cgroup = NULL;
+
+  char *line = NULL;
+  size_t linesiz = 0;
+  while (xgetline (&line, &linesiz, f) > 0)
+    {
+      char *entry = startswith (line, "0:");
+      if (entry == NULL)
+	continue;
+
+      entry = strchr (entry, ':');
+      if (entry == NULL)
+	continue;
+
+      cgroup = entry + 1;
+      size_t l = strlen (cgroup);
+      if (cgroup[l - 1] == '\n')
+	cgroup[l - 1] = '\0';
+
+      cgroup = xstrdup (entry + 1);
+      break;
+    }
+
+  xfclose (f);
+  free (line);
+
+  return cgroup;
+}
+
+
+/* Called on process re-execution.  */
+_Noreturn static void
+handle_restart (int argc, char *argv[])
+{
+  assert (argc == 1);
+  char *newcgroup = argv[0];
+
+  char *current_cgroup = get_cgroup ();
+  TEST_VERIFY_EXIT (current_cgroup != NULL);
+  TEST_COMPARE_STRING (newcgroup, current_cgroup);
+  exit (EXIT_SUCCESS);
+}
+
+static int
+do_test_cgroup_failure (pid_t *pid, int cgroup)
+{
+  posix_spawnattr_t attr;
+  TEST_COMPARE (posix_spawnattr_init (&attr), 0);
+  TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETCGROUP), 0);
+  TEST_COMPARE (posix_spawnattr_setcgroup_np (&attr, cgroup), 0);
+
+  int cgetgroup;
+  TEST_COMPARE (posix_spawnattr_getcgroup_np (&attr, &cgetgroup), 0);
+  TEST_COMPARE (cgroup, cgetgroup);
+
+  return posix_spawn (pid, spargs[0], NULL, &attr, spargs, environ);
+}
+
+static int
+create_new_cgroup (char **newcgroup)
+{
+  struct statfs fs;
+  if (statfs (CGROUPFS, &fs) < 0)
+    {
+      if (errno == ENOENT)
+	FAIL_UNSUPPORTED ("not cgroupv2 mount found");
+      FAIL_EXIT1 ("statfs (%s): %m\n", CGROUPFS);
+    }
+
+  if (!F_TYPE_EQUAL (fs.f_type, CGROUP2_SUPER_MAGIC))
+    FAIL_UNSUPPORTED ("%s is not a cgroupv2", CGROUPFS);
+
+  char *cgroup = get_cgroup ();
+  TEST_VERIFY_EXIT (cgroup != NULL);
+  *newcgroup = xasprintf ("%s/%s", cgroup, CGROUP_TEST);
+  char *cgpath = xasprintf ("%s%s/%s", CGROUPFS, cgroup, CGROUP_TEST);
+  free (cgroup);
+
+  if (mkdir (cgpath, 0755) == -1 && errno != EEXIST)
+    {
+      if (errno == EACCES || errno == EPERM)
+	FAIL_UNSUPPORTED ("can not create a new cgroupv2 group");
+      FAIL_EXIT1 ("mkdir (%s): %m", cgpath);
+    }
+  add_temp_file (cgpath);
+
+  return xopen (cgpath, O_DIRECTORY | O_RDONLY | O_CLOEXEC, 0666);
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+  /* We must have either:
+
+     - one or four parameters if called initially:
+       + argv[1]: path for ld.so        optional
+       + argv[2]: "--library-path"      optional
+       + argv[3]: the library path      optional
+       + argv[4]: the application name
+
+     - six parameters left if called through re-execution:
+       + argv[4/1]: the application name
+       + argv[5/2]: the created cgroup
+
+     * When built with --enable-hardcoded-path-in-tests or issued without
+       using the loader directly.  */
+
+  if (restart)
+    handle_restart (argc - 1, &argv[1]);
+
+  TEST_VERIFY_EXIT (argc == 2 || argc == 5);
+
+  char *newcgroup;
+  int cgroup = create_new_cgroup (&newcgroup);
+
+  int i;
+  for (i = 0; i < argc - 1; i++)
+    spargs[i] = argv[i + 1];
+  spargs[i++] = (char *) "--direct";
+  spargs[i++] = (char *) "--restart";
+  spargs[i++] = (char *) newcgroup;
+  spargs[i] = NULL;
+
+  /* Check if invalid cgroups returns an error.  */
+  {
+    TEST_COMPARE (do_test_cgroup_failure (NULL, -1), EINVAL);
+  }
+
+  {
+    pid_t pid;
+    TEST_COMPARE (do_test_cgroup_failure (&pid, cgroup), 0);
+
+    siginfo_t sinfo;
+    TEST_COMPARE (waitid (P_PID, pid, &sinfo, WEXITED), 0);
+    TEST_COMPARE (sinfo.si_signo, SIGCHLD);
+    TEST_COMPARE (sinfo.si_code, CLD_EXITED);
+    TEST_COMPARE (sinfo.si_status, 0);
+  }
+
+  xclose (cgroup);
+  free (newcgroup);
+
+  return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 57cfcc2086..ea8539447c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2578,6 +2578,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 3f0a9f6d82..f15ac7c33f 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2684,6 +2684,8 @@  GLIBC_2.38 __strlcat_chk F
 GLIBC_2.38 __strlcpy_chk F
 GLIBC_2.38 __wcslcat_chk F
 GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 posix_spawnattr_getcgroup_np F
+GLIBC_2.38 posix_spawnattr_setcgroup_np F
 GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F