File ulp-prologue-into-asm-functions.patch of Package glibc.38381
From 9c671100fdae958780cd5addb4a1681d4d652711 Mon Sep 17 00:00:00 2001
From: Giuliano Belinassi <gbelinassi@suse.de>
Date: Thu, 2 Jan 2025 22:40:22 +0100
Subject: [PATCH] Add Userspace Livepatch prologue into ASM functions
Userspace Live Patching (ULP) refers to the process of applying
patches to the libraries used by a running process, without
interrupting it. In order to archive this, functions must have
the NOP prologue. This prologue is included automatically when
compiled with -fpatchable-function-entry, but for ASM functions
this have to be included manually. This patch does this.
Signed-off-by: Giuliano Belinassi <gbelinassi@suse.de>
---
config.h.in | 3 ++
config.make.in | 2 +
configure | 45 +++++++++++++++++++
configure.ac | 20 +++++++++
sysdeps/powerpc/powerpc64/le/Makefile | 5 +++
sysdeps/powerpc/powerpc64/sysdep.h | 55 ++++++++++++++++++++++--
sysdeps/x86/sysdep.h | 22 ++++++++--
sysdeps/x86_64/Makefile | 5 +++
sysdeps/x86_64/multiarch/strcmp-avx2.S | 5 +--
sysdeps/x86_64/multiarch/strcmp-evex.S | 5 +--
sysdeps/x86_64/multiarch/strcmp-sse4_2.S | 5 +--
sysdeps/x86_64/sysdep.h | 40 +++++++++++++++++
12 files changed, 192 insertions(+), 20 deletions(-)
diff --git a/config.h.in b/config.h.in
index 0dedc124f7..08b1868002 100644
--- a/config.h.in
+++ b/config.h.in
@@ -204,6 +204,9 @@
/* Define to 1 if libpthread actually resides in libc. */
#define PTHREAD_IN_LIBC 0
+/* Define to 1 if support for userspace livepatching is enabled. */
+#define ENABLE_USERSPACE_LIVEPATCH 0
+
/* An integer used to scale the timeout of test programs. */
#define TIMEOUTFACTOR 1
diff --git a/config.make.in b/config.make.in
index d487a4f4e9..222fd22c76 100644
--- a/config.make.in
+++ b/config.make.in
@@ -74,6 +74,7 @@ bind-now = @bindnow@
have-cxx-thread_local = @libc_cv_cxx_thread_local@
have-loop-to-function = @libc_cv_cc_loop_to_function@
have-textrel_ifunc = @libc_cv_textrel_ifunc@
+split-patch-nops = @libc_cv_split_patch_nops@
multi-arch = @multi_arch@
@@ -85,6 +86,7 @@ nss-crypt = @libc_cv_nss_crypt@
static-nss-crypt = @libc_cv_static_nss_crypt@
# Configuration options.
+enable-userspace-livepatch = @enable_userspace_livepatch@
build-shared = @shared@
build-profile = @profile@
build-static-nss = @static_nss@
diff --git a/configure b/configure
index 4ef387146d..dce8c1961d 100755
--- a/configure
+++ b/configure
@@ -622,6 +622,8 @@ LIBOBJS
pthread_in_libc
RELEASE
VERSION
+libc_cv_split_patch_nops
+enable_userspace_livepatch
mach_interface_list
DEFINES
static_nss
@@ -819,6 +821,7 @@ enable_cet
enable_scv
enable_fortify_source
with_cpu
+enable_userspace_livepatch
'
ac_precious_vars='build_alias
host_alias
@@ -1501,6 +1504,8 @@ Optional Features:
Use -D_FORTIFY_SOURCE=[1|2|3] to control code
hardening, defaults to highest possible value
supported by the build compiler.
+ --enable-userspace-livepatch
+ build with userspace livepatch support [default=no]
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@@ -8000,6 +8005,46 @@ libc_cv_multidir=`${CC-cc} $CFLAGS $CPPFLAGS -print-multi-directory`
+# Check whether --enable-userspace-livepatch was given.
+if test ${enable_userspace_livepatch+y}
+then :
+ enableval=$enable_userspace_livepatch; enable_userspace_livepatch=$enableval
+else $as_nop
+ enable_userspace_livepatch=no
+fi
+
+
+# Libpulp uses -fpatchable-function-entry to add padding NOPS to the
+# prologue of all functions.
+if test "x$enable_userspace_livepatch" = xyes; then
+ printf "%s\n" "#define ENABLE_USERSPACE_LIVEPATCH 1" >>confdefs.h
+
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -msplit-patch-nops" >&5
+printf %s "checking for -msplit-patch-nops... " >&6; }
+if test ${libc_cv_split_patch_nops+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if { ac_try='${CC-cc} -msplit-patch-nops -xc /dev/null -S -o /dev/null'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+then :
+ libc_cv_split_patch_nops=-msplit-patch-nops
+else $as_nop
+ libc_cv_split_patch_nops=
+fi
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_split_patch_nops" >&5
+printf "%s\n" "$libc_cv_split_patch_nops" >&6; }
+
+
VERSION=`sed -n -e 's/^#define VERSION "\([^"]*\)"/\1/p' < $srcdir/version.h`
RELEASE=`sed -n -e 's/^#define RELEASE "\([^"]*\)"/\1/p' < $srcdir/version.h`
diff --git a/configure.ac b/configure.ac
index 12d1f50b14..3724b3dce7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1828,6 +1828,26 @@ AC_SUBST(DEFINES)
dnl See sysdeps/mach/configure.ac for this variable.
AC_SUBST(mach_interface_list)
+AC_ARG_ENABLE([userspace-livepatch],
+ AS_HELP_STRING([--enable-userspace-livepatch],
+ [build with userspace livepatch support @<:@default=no@:>@]),
+ [enable_userspace_livepatch=$enableval],
+ [enable_userspace_livepatch=no])
+
+# Libpulp uses -fpatchable-function-entry to add padding NOPS to the
+# prologue of all functions.
+if test "x$enable_userspace_livepatch" = xyes; then
+ AC_DEFINE(ENABLE_USERSPACE_LIVEPATCH)
+fi
+AC_SUBST(enable_userspace_livepatch)
+
+AC_CACHE_CHECK([for -msplit-patch-nops], libc_cv_split_patch_nops, [dnl
+LIBC_TRY_CC_OPTION([-msplit-patch-nops],
+ [libc_cv_split_patch_nops=-msplit-patch-nops],
+ [libc_cv_split_patch_nops=])
+])
+AC_SUBST(libc_cv_split_patch_nops)
+
VERSION=`sed -n -e 's/^#define VERSION "\([^"]*\)"/\1/p' < $srcdir/version.h`
RELEASE=`sed -n -e 's/^#define RELEASE "\([^"]*\)"/\1/p' < $srcdir/version.h`
AC_SUBST(VERSION)
diff --git a/sysdeps/powerpc/powerpc64/le/Makefile b/sysdeps/powerpc/powerpc64/le/Makefile
index 5214eb40ad..9706132216 100644
--- a/sysdeps/powerpc/powerpc64/le/Makefile
+++ b/sysdeps/powerpc/powerpc64/le/Makefile
@@ -1,3 +1,8 @@
+# Add flags for Userspace Livepatching support.
+ifeq (yes,$(enable-userspace-livepatch))
++cflags += -fpatchable-function-entry=14,13 $(split-patch-nops)
+endif
+
# When building float128 we need to ensure -mfloat128 is
# passed to all such object files.
type-float128-CFLAGS := -mfloat128
diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h
index ce92d8b3d2..1463f6f44c 100644
--- a/sysdeps/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/powerpc/powerpc64/sysdep.h
@@ -162,6 +162,46 @@
BODY_LABEL(\name):
.endm
+/* Libpulp uses -fpatchable-function-entry to add padding NOPS to the
+ prologue of all functions. This works for C functions. For functions
+ written in ASM, the way we do this is by adding this prologue manually. */
+
+#if ENABLE_USERSPACE_LIVEPATCH
+
+/* Instructions to be inserted before the function label. */
+# define ULP_NOPS_PRE_PROLOGUE .rept 13; nop; .endr
+
+/* Instruction to be inserted after the function label. */
+# define ULP_NOPS_POST_PROLOGUE .rept 1; nop; .endr
+
+
+/* this macro expands according to the following condition:
+ * if name = _start, then the prologue is not inserted.
+ * if name = _dl_relocate_static_pie, then the prologue is not inserted.
+ * if name = anything else, then the prologue is inserted.
+ **/
+# define __ULP_PRE_PROLOGUE_dl_relocate_static_pie ,
+# define __ULP_PRE_PROLOGUE_start ,
+# define __ULP_PRE_PROLOGUE(x, y,...) y
+# define _ULP_PRE_PROLOGUE(x, ...) __ULP_PRE_PROLOGUE(x, __VA_ARGS__)
+# define ULP_PRE_PROLOGUE(name) _ULP_PRE_PROLOGUE(__ULP_PRE_PROLOGUE##name, ULP_NOPS_PRE_PROLOGUE,)
+
+/* this macro expands according to the following condition:
+ * if name = _start, then the postlogue is not inserted.
+ * if name = _dl_relocate_static_pie, then the postlogue is not inserted.
+ * if name = anything else, then the postlogue is inserted.
+ **/
+# define __ULP_POST_PROLOGUE_dl_relocate_static_pie ,
+# define __ULP_POST_PROLOGUE_start ,
+# define __ULP_POST_PROLOGUE(x, y,...) y
+# define _ULP_POST_PROLOGUE(x, ...) __ULP_POST_PROLOGUE(x, __VA_ARGS__)
+# define ULP_POST_PROLOGUE(name) _ULP_POST_PROLOGUE(__ULP_POST_PROLOGUE##name, ULP_NOPS_POST_PROLOGUE,)
+
+#else
+# define ULP_PRE_PROLOGUE(name)
+# define ULP_POST_PROLOGUE(name)
+#endif
+
/* Use ENTRY_TOCLESS for functions that make no use of r2 and
guarantee r2 is unchanged on exit. Any function that has @toc or
@got relocs uses r2. Functions that call other functions via the
@@ -174,19 +214,26 @@ BODY_LABEL(\name):
before the start of the function's code. */
#ifndef PROF
#define ENTRY_TOCLESS(name, ...) \
+ ULP_PRE_PROLOGUE(name); \
ENTRY_3 name, ## __VA_ARGS__; \
- cfi_startproc
+ cfi_startproc; \
+ ULP_POST_PROLOGUE(name)
#define ENTRY(name, ...) \
- ENTRY_TOCLESS(name, ## __VA_ARGS__); \
- LOCALENTRY(name)
+ ULP_PRE_PROLOGUE(name); \
+ ENTRY_3 name, ## __VA_ARGS__; \
+ cfi_startproc; \
+ LOCALENTRY(name); \
+ ULP_POST_PROLOGUE(name)
#else
/* The call to _mcount is potentially via the plt, so profiling code
is never free of an r2 use. */
#define ENTRY_TOCLESS(name, ...) \
+ ULP_PRE_PROLOGUE(name); \
ENTRY_3 name, ## __VA_ARGS__; \
cfi_startproc; \
- LOCALENTRY(name)
+ LOCALENTRY(name); \
+ ULP_POST_PROLOGUE(name)
#define ENTRY(name, ...) \
ENTRY_TOCLESS(name, ## __VA_ARGS__)
diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h
index 0b3483a77a..f5aba094fd 100644
--- a/sysdeps/x86/sysdep.h
+++ b/sysdeps/x86/sysdep.h
@@ -77,15 +77,29 @@ enum cf_protection_level
#define ALIGNARG(log2) 1<<log2
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name;
+/* For 32-bit glibc then define those macros as empty. */
+#ifndef ULP_PRE_PROLOGUE
+# define ULP_PRE_PROLOGUE(name)
+#endif
+#ifndef ULP_POST_PROLOGUE
+# define ULP_POST_PROLOGUE(name)
+#endif
+
+/* Define the first instructions of a function. */
+#define FUNCTION_START(name) \
+ ULP_PRE_PROLOGUE(name); \
+ C_LABEL(name); \
+ cfi_startproc; \
+ _CET_ENDBR; \
+ ULP_POST_PROLOGUE(name); \
+ CALL_MCOUNT;
+
/* Define an entry point visible from C. */
#define ENTRY_P2ALIGN(name, alignment) \
.globl C_SYMBOL_NAME(name); \
.type C_SYMBOL_NAME(name),@function; \
.align ALIGNARG(alignment); \
- C_LABEL(name) \
- cfi_startproc; \
- _CET_ENDBR; \
- CALL_MCOUNT
+ FUNCTION_START(name)
/* Common entry 16 byte aligns. */
#define ENTRY(name) ENTRY_P2ALIGN (name, 4)
diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
index 00120ca9ca..f0713dcbe3 100644
--- a/sysdeps/x86_64/Makefile
+++ b/sysdeps/x86_64/Makefile
@@ -1,3 +1,8 @@
+# Add flags for Userspace Livepatching support.
+ifeq (yes,$(enable-userspace-livepatch))
++cflags += -fpatchable-function-entry=16,14
+endif
+
# The i387 `long double' is a distinct type we support.
long-double-fcts = yes
diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S
index 8804338d75..d3584b2c5d 100644
--- a/sysdeps/x86_64/multiarch/strcmp-avx2.S
+++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S
@@ -201,10 +201,7 @@ END (STRCASECMP)
# endif
.p2align 4
-STRCMP:
- cfi_startproc
- _CET_ENDBR
- CALL_MCOUNT
+FUNCTION_START(STRCMP)
# if defined USE_AS_STRCASECMP_L
/* We have to fall back on the C implementation for locales with
diff --git a/sysdeps/x86_64/multiarch/strcmp-evex.S b/sysdeps/x86_64/multiarch/strcmp-evex.S
index 6a7fec669e..5710d74aa3 100644
--- a/sysdeps/x86_64/multiarch/strcmp-evex.S
+++ b/sysdeps/x86_64/multiarch/strcmp-evex.S
@@ -226,10 +226,7 @@ END (STRCASECMP)
# endif
.p2align 4
-STRCMP:
- cfi_startproc
- _CET_ENDBR
- CALL_MCOUNT
+FUNCTION_START(STRCMP)
# if defined USE_AS_STRCASECMP_L
/* We have to fall back on the C implementation for locales with
diff --git a/sysdeps/x86_64/multiarch/strcmp-sse4_2.S b/sysdeps/x86_64/multiarch/strcmp-sse4_2.S
index cbb22884eb..327377daa6 100644
--- a/sysdeps/x86_64/multiarch/strcmp-sse4_2.S
+++ b/sysdeps/x86_64/multiarch/strcmp-sse4_2.S
@@ -103,10 +103,7 @@ END (STRCASECMP)
# define arg arg
-STRCMP:
- cfi_startproc
- _CET_ENDBR
- CALL_MCOUNT
+FUNCTION_START(STRCMP)
/*
* This implementation uses SSE to compare up to 16 bytes at a time.
diff --git a/sysdeps/x86_64/sysdep.h b/sysdeps/x86_64/sysdep.h
index 6ca169573d..9754508f2d 100644
--- a/sysdeps/x86_64/sysdep.h
+++ b/sysdeps/x86_64/sysdep.h
@@ -24,6 +24,46 @@
#ifdef __ASSEMBLER__
+/* Libpulp uses -fpatchable-function-entry to add padding NOPS to the
+ prologue of all functions. This works for C functions. For functions
+ written in ASM, the way we do this is by adding this prologue manually. */
+
+#if ENABLE_USERSPACE_LIVEPATCH
+
+/* Instructions to be inserted before the function label. */
+# define ULP_NOPS_PRE_PROLOGUE .rept 14; nop; .endr
+
+/* Instruction to be inserted after the function label. */
+# define ULP_NOPS_POST_PROLOGUE .rept 2; nop; .endr
+
+
+/* this macro expands according to the following condition:
+ * if name = _start, then the prologue is not inserted.
+ * if name = _dl_relocate_static_pie, then the prologue is not inserted.
+ * if name = anything else, then the prologue is inserted.
+ **/
+# define __ULP_POST_PROLOGUE_dl_relocate_static_pie ,
+# define __ULP_PRE_PROLOGUE_start ,
+# define __ULP_PRE_PROLOGUE(x, y,...) y
+# define _ULP_PRE_PROLOGUE(x, ...) __ULP_PRE_PROLOGUE(x, __VA_ARGS__)
+# define ULP_PRE_PROLOGUE(name) _ULP_PRE_PROLOGUE(__ULP_PRE_PROLOGUE##name, ULP_NOPS_PRE_PROLOGUE,)
+
+/* this macro expands according to the following condition:
+ * if name = _start, then the postlogue is not inserted.
+ * if name = _dl_relocate_static_pie, then the postlogue is not inserted.
+ * if name = anything else, then the postlogue is inserted.
+ **/
+# define __ULP_POST_PROLOGUE_dl_relocate_static_pie ,
+# define __ULP_POST_PROLOGUE_start ,
+# define __ULP_POST_PROLOGUE(x, y,...) y
+# define _ULP_POST_PROLOGUE(x, ...) __ULP_POST_PROLOGUE(x, __VA_ARGS__)
+# define ULP_POST_PROLOGUE(name) _ULP_POST_PROLOGUE(__ULP_POST_PROLOGUE##name, ULP_NOPS_POST_PROLOGUE,)
+
+#else
+# define ULP_PRE_PROLOGUE(name)
+# define ULP_POST_PROLOGUE(name)
+#endif
+
/* Syntactic details of assembler. */
/* This macro is for setting proper CFI with DW_CFA_expression describing
--
2.49.0