[PATCH v2] AArch64: Check kernel version for SVE ifuncs

Florian Weimer fw@deneb.enyo.de
Mon Oct 7 19:33:06 GMT 2024


* Aurelien Jarno:

> Hi
>
> On 2024-03-18 14:14, Wilco Dijkstra wrote:
>> 
>> v2: Add __LINUX_KERNEL_VERSION #ifdefs, improve parser, use 8:8:8 format.
>> 
>> Old Linux kernels disable SVE after every system call.  Calling the
>> SVE-optimized memcpy afterwards will then cause a trap to reenable SVE.
>> As a result, applications with a high use of syscalls may run slower with
>> the SVE memcpy.  This is true for kernels between 4.15.0 and before 6.2.0,
>> except for 5.14.0 which was patched.  Avoid this by checking the kernel
>> version and selecting the SVE ifunc on modern kernels.
>> 
>> Parse the kernel version reported by uname() into a 24-bit kernel.major.minor
>> value without calling any library functions.  If uname() is not supported or
>> if the version format is not recognized, assume the kernel is modern.
>> 
>> Passes regress, OK for commit?
>> 
>
> This commit breaks getpw* functions when using "compat" in nsswitch.conf
> and static binaries. This has been reported in Debian as bug #1083095
> and involving bash. Here is a simple reproducer:
>
> | #include <pwd.h>
> | #include <sys/types.h>
> | #include <unistd.h>
> |
> | int main()
> | {
> |     return getpwuid(getuid()) != NULL;
> | }
>
> When compiled statically against a libc without this patch and executed
> against a libc with this patch, this leads to a segmentation fault with
> the following backtrace (note that libnss_nis.so.2 is not available on
> the system):
>
> | #0  0x0000000000000000 in ?? ()
> | #1  0x0000fffff7dda718 in _dl_open (file=0xfffff7cd0650 "libnss_nis.so.2", mode=-2147483646, caller_dlopen=0xfffff7f32748 <module_load+152>, nsid=-2, argc=1, argv=0xfffffffff3d8, env=0xfffffffff3e8) at ./elf/dl-open.c:830
> | #2  0x0000fffff7f4eca0 in do_dlopen (ptr=ptr@entry=0xffffffffeca8) at ./elf/dl-libc.c:95
> | #3  0x0000fffff7f4e8bc in __GI__dl_catch_exception (exception=exception@entry=0xffffffffec30, operate=0xfffff7f4ec54 <do_dlopen>, args=0xffffffffeca8) at ./elf/dl-error-skeleton.c:208
> | #4  0x0000fffff7f4e980 in __GI__dl_catch_error (objname=0xffffffffec78, errstring=0xffffffffec80, mallocedp=0xffffffffec77, operate=<optimized out>, args=<optimized out>) at ./elf/dl-error-skeleton.c:227
> | #5  0x0000fffff7f4ebf8 in dlerror_run (operate=operate@entry=0xfffff7f4ec54 <do_dlopen>, args=args@entry=0xffffffffeca8) at ./elf/dl-libc.c:45
> | #6  0x0000fffff7f4edf4 in __libc_dlopen_mode (name=<optimized out>, mode=<optimized out>) at ./elf/dl-libc.c:162
> | #7  0x0000fffff7f32748 in module_load (module=0xfffff7cd1fd0) at ./nss/nss_module.c:191
> | #8  0x0000fffff7f32c58 in __nss_module_load (module=0xfffff7cd1fd0) at ./nss/nss_module.c:310
> | #9  __nss_module_get_function (module=0xfffff7cd1fd0, name=0xfffff7fd6780 "setpwent") at ./nss/nss_module.c:336
> | #10 0x0000fffff7fd2834 in init_nss_interface () at nss_compat/compat-pwd.c:95
> | #11 init_nss_interface () at nss_compat/compat-pwd.c:91
> | #12 0x0000fffff7fd40b0 in _nss_compat_getpwuid_r (uid=1000, pwd=0x4b6e58 <resbuf>, buffer=0x4b94d0 "", buflen=1024, errnop=0x4b8770) at nss_compat/compat-pwd.c:1063
> | #13 0x000000000040a2a4 in getpwuid_r ()
> | #14 0x000000000040a098 in getpwuid ()
> | #15 0x00000000004006e4 in main ()
>
> I am fully aware of the "warning: Using 'dlopen' in statically linked
> applications requires at runtime the shared libraries from the glibc
> version used for linking" message displayed when linking statically,
> that said if we can't avoid the breakage, we should probably not
> backport such changes in the stable branches.

This part:

diff --git a/sysdeps/aarch64/cpu-features.h b/sysdeps/aarch64/cpu-features.h
index 77a782422a..5f2da91ebb 100644
--- a/sysdeps/aarch64/cpu-features.h
+++ b/sysdeps/aarch64/cpu-features.h
@@ -71,6 +71,7 @@ struct cpu_features
   /* Currently, the GLIBC memory tagging tunable only defines 8 bits.  */
   uint8_t mte_state;
   bool sve;
+  bool prefer_sve_ifuncs;
   bool mops;
 };

changes the internal GLIBC_PRIVATE ABI.  As far as I can see, the GLRO
struct size increases, and some fields move their addresses.  The bug
report does not show GLRO, only GL.  I suspect that
GLRO(dl_dlfcn_hook) is now zero (taking the place that was formerly
occupied by GLRO(dl_audit).  That's why the loaded libc.so starts
using the loaded ld.so code instead of the statically linked loader.
The loaded ld.so is expected to be dormant, only very partially
initialized, and the statically linked dynamic linker should be used
instead (and that's what GLRO(dl_dlfcn_hook) is for).

It's many many months on the branch, so I'm not sure if we should work
around it at this point.  We can't realistically remain compatible
with both variants at the same time.  I suggest to rebuild bash-static.

We want to provide a way to do static linking while restricting the
use of foreign NSS modules, which would make static linking more
useful.  In the meantime, your statically linked bash could try to use
__nss_configure_lookup to switch most databases to "files", and the
hosts database to "files dns".


More information about the Libc-alpha mailing list