From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 68971 invoked by alias); 5 Dec 2016 15:42:44 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Received: (qmail 68962 invoked by uid 89); 5 Dec 2016 15:42:44 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.4 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_NONE,RCVD_IN_SORBS_SPAM autolearn=no version=3.3.2 spammy=semaphore, held, cancel, services X-HELO: mail-qt0-f177.google.com X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:to:from:subject:organization:cc:message-id:date :user-agent:mime-version:content-transfer-encoding; bh=FactuwyZXaX8Ykf2j2fsNRQAPb/hl8hC/JM+dKBMGPk=; b=c3DVUO50xEI3acPVvY1U/fGkwxt4eLkzpkx3WNQ0WxN3eMmiyEAyZupvwPxvPqZjDg q0xpRMzFwI3I1B9iLiAYs/MnxpHtZ8ZCJCqdofyZFlcbj+KN7cozsT1Q45+DXfhn6oIX n2h5qsdfreryCVYPxoXJoizPykrb1lQ/pYgZUAQFu20dnxmXtJcMiEfiXDXWJ+mKSziK t2DOSaBdNGi/x+qdeIdLVCgKnCwYh77b+m3f7CbWvttNyuMt4K6xxJAUeKjVQpYBhXnt NwI3cgmvJskyTuI+ddh4nY++Am5jmpB2Ihub4UkpXhOGBAo8nVTfzMAWIOg1/9s4Jsse ohHg== X-Gm-Message-State: AKaTC001gTv4DggpG2jj/fZwDNyYA0fJhlXEFkl08GR6DtQ6cmdVVGlHGX5Rak2FhKL6eKbe X-Received: by 10.200.40.175 with SMTP id i44mr50437095qti.258.1480952552156; Mon, 05 Dec 2016 07:42:32 -0800 (PST) To: GNU C Library From: Carlos O'Donell Subject: [PATCH] Add cancellation test for getpwuid_r. Cc: Florian Weimer Message-ID: <4a4fbbe6-073e-0127-cd8c-5ab6531c7c5f@redhat.com> Date: Mon, 05 Dec 2016 15:42:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-SW-Source: 2016-12/txt/msg00098.txt.bz2 Add a regression test for the fix in 312be3f9f5eab1643d7dcc7728c76d413d4f2640 which corrects cancellation problems around getpwuid_r. No regressions on x86_64. Test hangs without the aformentioned fix, but passes after the fix. OK to checkin? 2016-12-05 Carlos O'Donell * nss/tst-cancel-getpwuid_r.c: New file. diff --git a/nss/Makefile b/nss/Makefile index 1f016d9..9132e17 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -54,6 +54,12 @@ tests = test-netdb tst-nss-test1 test-digits-dots \ $(tests-static) xtests = bug-erange +# If we have a thread library then we can test cancellation against +# some routines like getpwuid_r. +ifeq (yes,$(have-thread-library)) +tests += tst-cancel-getpwuid_r +endif + # Specify rules for the nss_* modules. We have some services. services := files db @@ -125,3 +131,7 @@ $(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so $(make-link) endif $(objpfx)tst-nss-test1.out: $(objpfx)/libnss_test1.so$(libnss_test1.so-version) + +ifeq (yes,$(have-thread-library)) +$(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) +endif diff --git a/nss/tst-cancel-getpwuid_r.c b/nss/tst-cancel-getpwuid_r.c new file mode 100644 index 0000000..3570394 --- /dev/null +++ b/nss/tst-cancel-getpwuid_r.c @@ -0,0 +1,120 @@ +/* Test cancellation of getpwuid_r. + Copyright (C) 2016 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 + . */ + +/* 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 happens only at expected points where the internal state + is consistent. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int do_test (void); +#define TEST_FUNCTION do_test () + +#include "../test-skeleton.c" + +sem_t started; +char *wbuf; +long wbufsz; + +void +worker_free (void *arg) +{ + free (arg); +} + +static void * +worker( void *arg ) +{ + struct passwd pwbuf, *pw; + uid_t uid; + uid = geteuid(); + wbufsz = sysconf(_SC_GETPW_R_SIZE_MAX); + wbuf = xmalloc (wbufsz); + pthread_cleanup_push (worker_free, wbuf); + sem_post (&started); + while (1) + getpwuid_r(uid, &pwbuf, wbuf, wbufsz, &pw); + 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; + bufsz = sysconf(_SC_GETPW_R_SIZE_MAX); + 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. */ + getpwuid_r (geteuid(), &pwbuf, buf, sizeof(buf), &pw); + free (buf); + printf ("INFO: Previoulsy we would never get here\n"); + printf ("PASS: Cancelled getpwuid_r successfully" + " and called it again without blocking.\n"); + return 0; +} --- Cheers, Carlos.