diff options
Diffstat (limited to 'nss/tst-cancel-getpwuid_r.c')
-rw-r--r-- | nss/tst-cancel-getpwuid_r.c | 182 |
1 files changed, 0 insertions, 182 deletions
diff --git a/nss/tst-cancel-getpwuid_r.c b/nss/tst-cancel-getpwuid_r.c deleted file mode 100644 index 53de82985c..0000000000 --- a/nss/tst-cancel-getpwuid_r.c +++ /dev/null @@ -1,182 +0,0 @@ -/* Test cancellation of getpwuid_r. - Copyright (C) 2016-2017 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/>. */ - -/* Test if cancellation of getpwuid_r incorrectly leaves internal - function state locked resulting in hang of subsequent calls to - getpwuid_r. The main thread creates a second thread which will do - the calls to getpwuid_r. A semaphore is used by the second thread to - signal to the main thread that it is as close as it can be to the - call site of getpwuid_r. The goal of the semaphore is to avoid any - cancellable function calls between the sem_post and the call to - getpwuid_r. The main thread then attempts to cancel the second - thread. Without the fixes the cancellation happens at any number of - calls to cancellable functions in getpuid_r, but with the fix the - cancellation either does not happen or happens only at expected - points where the internal state is consistent. We use an explicit - pthread_testcancel call to terminate the loop in a timely fashion - if the implementation does not have a cancellation point. */ - -#include <stdio.h> -#include <stdlib.h> -#include <pthread.h> -#include <pwd.h> -#include <nss.h> -#include <sys/types.h> -#include <unistd.h> -#include <semaphore.h> -#include <errno.h> -#include <support/support.h> - -sem_t started; -char *wbuf; -long wbufsz; - -void -worker_free (void *arg) -{ - free (arg); -} - -static void * -worker (void *arg) -{ - int ret; - unsigned int iter = 0; - struct passwd pwbuf, *pw; - uid_t uid; - - uid = geteuid (); - - /* Use a reasonable sized buffer. Note that _SC_GETPW_R_SIZE_MAX is - just a hint and not any kind of maximum value. */ - wbufsz = sysconf (_SC_GETPW_R_SIZE_MAX); - if (wbufsz == -1) - wbufsz = 1024; - wbuf = xmalloc (wbufsz); - - pthread_cleanup_push (worker_free, wbuf); - sem_post (&started); - while (1) - { - iter++; - - ret = getpwuid_r (uid, &pwbuf, wbuf, wbufsz, &pw); - - /* The call to getpwuid_r may not cancel so we need to test - for cancellation after some number of iterations of the - function. Choose an arbitrary 100,000 iterations of running - getpwuid_r in a tight cancellation loop before testing for - cancellation. */ - if (iter > 100000) - pthread_testcancel (); - - if (ret == ERANGE) - { - /* Increase the buffer size. */ - free (wbuf); - wbufsz = wbufsz * 2; - wbuf = xmalloc (wbufsz); - } - - } - pthread_cleanup_pop (1); - - return NULL; -} - -static int -do_test (void) -{ - int ret; - char *buf; - long bufsz; - void *retval; - struct passwd pwbuf, *pw; - pthread_t thread; - - /* Configure the test to only use files. We control the files plugin - as part of glibc so we assert that it should be deferred - cancellation safe. */ - __nss_configure_lookup ("passwd", "files"); - - /* Use a reasonable sized buffer. Note that _SC_GETPW_R_SIZE_MAX is - just a hint and not any kind of maximum value. */ - bufsz = sysconf (_SC_GETPW_R_SIZE_MAX); - if (bufsz == -1) - bufsz = 1024; - buf = xmalloc (bufsz); - - sem_init (&started, 0, 0); - - pthread_create (&thread, NULL, worker, NULL); - - do - { - ret = sem_wait (&started); - if (ret == -1 && errno != EINTR) - { - printf ("FAIL: Failed to wait for second thread to start.\n"); - exit (EXIT_FAILURE); - } - } - while (ret != 0); - - printf ("INFO: Cancelling thread\n"); - if ((ret = pthread_cancel (thread)) != 0) - { - printf ("FAIL: Failed to cancel thread. Returned %d\n", ret); - exit (EXIT_FAILURE); - } - - printf ("INFO: Joining...\n"); - pthread_join (thread, &retval); - if (retval != PTHREAD_CANCELED) - { - printf ("FAIL: Thread was not cancelled.\n"); - exit (EXIT_FAILURE); - } - printf ("INFO: Joined, trying getpwuid_r call\n"); - - /* Before the fix in 312be3f9f5eab1643d7dcc7728c76d413d4f2640 for this - issue the cancellation point could happen in any number of internal - calls, and therefore locks would be left held and the following - call to getpwuid_r would block and the test would time out. */ - do - { - ret = getpwuid_r (geteuid (), &pwbuf, buf, bufsz, &pw); - if (ret == ERANGE) - { - /* Increase the buffer size. */ - free (buf); - bufsz = bufsz * 2; - buf = xmalloc (bufsz); - } - } - while (ret == ERANGE); - - free (buf); - - /* Before the fix we would never get here. */ - printf ("PASS: Canceled getpwuid_r successfully" - " and called it again without blocking.\n"); - - return 0; -} - -#define TIMEOUT 900 -#include <support/test-driver.c> |