libselinux: fix thread safety issues with lookup_common()
There are two problems with lookup_common() and therefore
selabel_lookup() and related functions that this patch fixes:
1) A race with the lazy compilation of regexes. Since the struct
regex_data is allocated and assigned immediately to the parent struct
spec, it's possible for a second thread to see that this pointer is
non-NULL before the regex compilation has finished. This typically
results in a -1 return from selabel_lookup() with ENOENT as errno.
This is fixed by adding synchronization in compile_regex().
2) A race with PCRE2 regex_match(). A struct pcre2_match_data is
created once and used for all regex matches for a given regex. This
is problematic if two threads are attempting to evaluate the same
regex simultaneously. This typically results in a successful return
from selabel_lookup() but with an erroneous selabel.
This is fixed by adding a pthread_mutex within regex_match() for
PCRE2. Note, on my system, creating new matchdata takes roughly an
order of magnitude more time than locking a non-contended
pthread_mutex. I don't believe programs will have enough contention
on this lock to justify that cost.
Bug: 63861738
Test: ueventd unit tests
Change-Id: I13bf782d81d0a0b896d444e396f307ad0dbacb6a
5 files changed