From owner-freebsd-bugs@FreeBSD.ORG Thu Aug 30 15:40:02 2007 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 054D216A469 for ; Thu, 30 Aug 2007 15:40:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id D6F3213C483 for ; Thu, 30 Aug 2007 15:40:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.1/8.14.1) with ESMTP id l7UFe1fQ043202 for ; Thu, 30 Aug 2007 15:40:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.1/8.14.1/Submit) id l7UFe1RZ043201; Thu, 30 Aug 2007 15:40:01 GMT (envelope-from gnats) Resent-Date: Thu, 30 Aug 2007 15:40:01 GMT Resent-Message-Id: <200708301540.l7UFe1RZ043201@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Oleg Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 0CB6016A41A for ; Thu, 30 Aug 2007 15:37:42 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21]) by mx1.freebsd.org (Postfix) with ESMTP id F0E6413C4B3 for ; Thu, 30 Aug 2007 15:37:41 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.14.1/8.14.1) with ESMTP id l7UFbfW2038615 for ; Thu, 30 Aug 2007 15:37:41 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.14.1/8.14.1/Submit) id l7UFbfYj038614; Thu, 30 Aug 2007 15:37:41 GMT (envelope-from nobody) Message-Id: <200708301537.l7UFbfYj038614@www.freebsd.org> Date: Thu, 30 Aug 2007 15:37:41 GMT From: Oleg To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: bin/115946: [libpam] not thread-safe X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 30 Aug 2007 15:40:02 -0000 >Number: 115946 >Category: bin >Synopsis: [libpam] not thread-safe >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Thu Aug 30 15:40:01 GMT 2007 >Closed-Date: >Last-Modified: >Originator: Oleg >Release: 6.2-RELEASE 7-CURRENT >Organization: Sunbay >Environment: FreeBSD netsnapper.domain.com 6.2-RELEASE FreeBSD 6.2-RELEASE #0: Tue Aug 14 15:14:19 EEST 2007 root@netsnapper.domain.com:/usr/src/sys/i386/compile/NETSNAPPER i386 (SMP + SCHED_ULE) >Description: openpam_load_module/openpam_release_module (/usr/src/contrib/openpam/lib/openpam_load.c) called from pam_start/pam_end not thread safe. They use global static variable for list of previously found modules. Easly reproduceable with attached program (only on true 2-x CPU machine). >How-To-Repeat: Steps: # cc -Wall -D_UNIX -D_DEBUG -std=c99 -I/usr/local/include -I/usr/include/security -O0 -g -fno-inline -L/usr/local/lib -o pthreads_and_pam main.c -Xlinker -Bdynamic -lpam -lpthread # echo "auth required pam_permit.so" >/usr/local/etc/pam.d/pthreads_and_pam # ./pthreads_and_pam .................... (after 4 sec - 5 min) pthreads_and_pam in free(): error: chunk is already free Abort trap: 6 (core dumped) # grep openpam /var/log/messages Aug 30 17:33:57 netsnapper pthreads_and_pam: in openpam_release_module(): module (null) has negative refcount >Fix: Add synchronization code around access to global variable 'modules' in /usr/src/contrib/openpam/lib/openpam_load.c. Can take from /usr/src/libexec/rtld-elf/rtld_lock.c or add new library depend from libpthread and use their function (ugly?) Patch attached with submission follows: #include #include #include #include #include #include #include #include typedef struct _auth_subject_t { const char *username; const char *password; const char *service; } auth_subject_t; #define NUM_THREADS 50 volatile int num_threads; pthread_mutex_t num_thr_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t last_thread_fini; int pam_auth_conv(int NumOfMsgs, const struct pam_message **pMsgs, struct pam_response **pResponces, void *pContext) { int i = 0; *pResponces = (struct pam_response *) malloc(NumOfMsgs * sizeof(struct pam_response)); if (*pResponces == NULL) { return 0; } bzero(*pResponces, NumOfMsgs * sizeof(struct pam_response)); for (i = 0; i < NumOfMsgs; i++) { switch(pMsgs[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: (*pResponces)[i].resp = strdup(((auth_subject_t*)pContext)->password); (*pResponces)[i].resp_retcode = 0; break; case PAM_PROMPT_ECHO_ON: (*pResponces)[i].resp = strdup(((auth_subject_t*)pContext)->username); (*pResponces)[i].resp_retcode = 0; break; case PAM_ERROR_MSG: break; case PAM_TEXT_INFO: break; default: break; } } return PAM_SUCCESS; } void* test(void* arg) { struct pam_conv conv = {0}; auth_subject_t auth_subject = { /*login*/"agile", /*password*/"agile", "pthreads_and_pam" }; conv.conv = pam_auth_conv; conv.appdata_ptr = &auth_subject; int result = 0; pam_handle_t *pam_handle = NULL; const char *pam_service_name = auth_subject.service; result = pam_start(pam_service_name, NULL, &conv, &pam_handle); if (result != PAM_SUCCESS) { fprintf(stderr, "pam_start failed, %s\n", pam_strerror(pam_handle, result)); goto failed; } result = pam_authenticate(pam_handle, 0); if (result != PAM_SUCCESS) { fprintf(stderr, "* %s\n", pam_strerror(pam_handle, result)); goto failed; } putc('.', stderr); failed: if (pam_handle) { pam_end(pam_handle, 0); } pthread_mutex_lock(&num_thr_mutex); num_threads--; // last thread? if (num_threads == 0) { pthread_cond_signal(&last_thread_fini); } pthread_mutex_unlock(&num_thr_mutex); return NULL; } int main(int argc, char *argv[]) { pthread_cond_init(&last_thread_fini, NULL); pthread_t thr; //for(int x=0; x<1; x++) while(1) { pthread_mutex_lock(&num_thr_mutex); num_threads = NUM_THREADS; for (int i=0; iRelease-Note: >Audit-Trail: >Unformatted: