This is a downstream rework of this upstream patch: [PATCH v2 2/2] nss: Protect against errno changes in function lookup (bug 28953) The NSS module loading code has been rewritten upstream, which is why only the test can be reused. NSS_DECLARE_MODULE_FUNCTIONS does not yet exist downstream, so this part had to be skipped. diff --git a/nss/Makefile b/nss/Makefile index d5c28a6b5ed3661c..e8a7d9c7b3cefcdf 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -59,7 +59,8 @@ tests = test-netdb test-digits-dots tst-nss-getpwent bug17079 \ tst-nss-test2 \ tst-nss-test3 \ tst-nss-test4 \ - tst-nss-test5 + tst-nss-test5 \ + tst-nss-test_errno xtests = bug-erange tests-container = \ @@ -130,7 +131,7 @@ routines += $(libnss_files-routines) static-only-routines += $(libnss_files-routines) tests-static += tst-nss-static endif -extra-test-objs += nss_test1.os nss_test2.os +extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os include ../Rules @@ -166,10 +167,13 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver libof-nss_test1 = extramodules libof-nss_test2 = extramodules +libof-nss_test_errno = extramodules $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps) $(build-module) $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps) $(build-module) +$(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps) + $(build-module) $(objpfx)nss_test2.os : nss_test1.c ifdef libnss_test1.so-version $(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so @@ -179,9 +183,13 @@ ifdef libnss_test2.so-version $(objpfx)/libnss_test2.so$(libnss_test2.so-version): $(objpfx)/libnss_test2.so $(make-link) endif +$(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \ + $(objpfx)/libnss_test_errno.so + $(make-link) $(patsubst %,$(objpfx)%.out,$(tests)) : \ $(objpfx)/libnss_test1.so$(libnss_test1.so-version) \ - $(objpfx)/libnss_test2.so$(libnss_test2.so-version) + $(objpfx)/libnss_test2.so$(libnss_test2.so-version) \ + $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) ifeq (yes,$(have-thread-library)) $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) diff --git a/nss/nss_test_errno.c b/nss/nss_test_errno.c new file mode 100644 index 0000000000000000..ca75c890aa057869 --- /dev/null +++ b/nss/nss_test_errno.c @@ -0,0 +1,53 @@ +/* NSS service provider with errno clobber. + Copyright (C) 2022 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 + . */ + +#include +#include +#include +#include + +static void __attribute__ ((constructor)) +init (void) +{ + /* An arbitrary error code which is otherwise not used. */ + errno = ELIBBAD; +} + +/* Lookup functions for pwd follow that do not return any data. */ + +enum nss_status +_nss_test_errno_setpwent (int stayopen) +{ + setenv ("_nss_test_errno_setpwent", "yes", 1); + return NSS_STATUS_SUCCESS; +} + +enum nss_status +_nss_test_errno_getpwent_r (struct passwd *result, + char *buffer, size_t size, int *errnop) +{ + setenv ("_nss_test_errno_getpwent_r", "yes", 1); + return NSS_STATUS_NOTFOUND; +} + +enum nss_status +_nss_test_errno_endpwent (void) +{ + setenv ("_nss_test_errno_endpwent", "yes", 1); + return NSS_STATUS_SUCCESS; +} diff --git a/nss/nsswitch.c b/nss/nsswitch.c index 17adf1ef03f93d60..e59ab674e0426b26 100644 --- a/nss/nsswitch.c +++ b/nss/nsswitch.c @@ -401,6 +401,7 @@ void * __nss_lookup_function (service_user *ni, const char *fct_name) { void **found, *result; + int saved_errno = errno; /* We now modify global data. Protect it. */ __libc_lock_lock (lock); @@ -523,6 +524,8 @@ __nss_lookup_function (service_user *ni, const char *fct_name) /* Remove the lock. */ __libc_lock_unlock (lock); + __set_errno (saved_errno); + return result; } libc_hidden_def (__nss_lookup_function) diff --git a/nss/tst-nss-test_errno.c b/nss/tst-nss-test_errno.c new file mode 100644 index 0000000000000000..d2c42dd363a38b0e --- /dev/null +++ b/nss/tst-nss-test_errno.c @@ -0,0 +1,61 @@ +/* getpwent failure when dlopen clobbers errno (bug 28953). + Copyright (C) 2022 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 + . */ + +#include +#include +#include +#include +#include +#include +#include + +static int +do_test (void) +{ + __nss_configure_lookup ("passwd", "files test_errno"); + + errno = 0; + setpwent (); + TEST_COMPARE (errno, 0); + + bool root_seen = false; + while (true) + { + errno = 0; + struct passwd *e = getpwent (); + if (e == NULL) + break; + if (strcmp (e->pw_name, "root")) + root_seen = true; + } + + TEST_COMPARE (errno, 0); + TEST_VERIFY (root_seen); + + errno = 0; + endpwent (); + TEST_COMPARE (errno, 0); + + TEST_COMPARE_STRING (getenv ("_nss_test_errno_setpwent"), "yes"); + TEST_COMPARE_STRING (getenv ("_nss_test_errno_getpwent_r"), "yes"); + TEST_COMPARE_STRING (getenv ("_nss_test_errno_endpwent"), "yes"); + + return 0; +} + +#include