Page MenuHomeFreeBSD

Ensure thread library is initialized in pthread_testcancel().
ClosedPublic

Authored by jhb on Mar 21 2018, 5:52 PM.
Tags
None
Referenced Files
Unknown Object (File)
Sun, Dec 15, 6:15 AM
Unknown Object (File)
Tue, Dec 10, 8:27 AM
Unknown Object (File)
Nov 22 2024, 9:29 AM
Unknown Object (File)
Nov 16 2024, 11:07 AM
Unknown Object (File)
Nov 16 2024, 1:53 AM
Unknown Object (File)
Nov 15 2024, 1:04 PM
Unknown Object (File)
Sep 24 2024, 8:51 AM
Unknown Object (File)
Sep 23 2024, 5:05 AM
Subscribers

Details

Summary

Call _thr_check_init() before reading curthread in pthread_testcancel().

If a constructor in a library creates a semaphore via sem_init() and then
waits for it via sem_wait(), the program can core dump in
_pthread_testcancel() called from sem_wait(). This is because the
semaphore implementation lives in libc, so the library's constructors
can be run before libthr's constructors.

Test Plan
  • Create a simple libsem.so that contains a single C file with a constructor that creates and waits on an anonymous semaphore via sem_init().
  • Link a test program with an empty main as '-lthr -lsem' so that libthr is listed before libsem in DT_NEEDED ensuring rtld will run constructors in libsem first.
  • Run the program and get a segfault.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Hmm, no good way to attach files, so I'll put them inline. sem_lib.c:

#include <err.h>
#include <semaphore.h>

void semtester(void) __attribute__((constructor));

void
semtester(void)
{
	sem_t sem;

	if (sem_init(&sem, 0, 1) == -1)
		err(1, "sem_init");
	if (sem_wait(&sem) == -1)
		err(1, "sem_wait");
	if (sem_destroy(&sem) == -1)
		err(1, "sem_destroy");
}

sem_test.c:

int
main(void)
{

	return (0);
}

Steps to reproduce:

> cc -shared -o libsem.so -fPIC -g sem_lib.c   
> cc -o sem_test sem_test.c -g -lsem -L.
> env LD_LIBRARY_PATH=. ./sem_test_thr
Segmentation fault (core dumped)

Note that sem_open() calls pthread_mutex_lock internally so it already hits a similar check, it is only semaphores created via sem_init() that can trip over this when sem_wait() is invoked. I chose to patch _pthread_testcancel() as that is the thing sem_wait() hits that faults, and it keeps the _thr_init_check() contained in libthr still.

LGTM. This fixes the crash I found when running statically linked QtBase unit tests where one of the C++ constructors happened to block on a QMutex (https://github.com/CTSRD-CHERI/cheribsd/issues/253)

This revision is now accepted and ready to land.Mar 21 2018, 6:43 PM
This revision was automatically updated to reflect the committed changes.