userdb: replace recursion lock
Previously we'd used the existance of a specific AF_UNIX socket in the abstract namespace as lock for disabling lookup recursions. (for breaking out of the loop: userdb synthesized from nss → nss synthesized from userdb → userdb synthesized from nss → …) I did it like that because it promised to work the same both in static and in dynmically linked environments and is accessible easily from any programming language. However, it has a weakness regarding reuse attacks: the socket is securely hashed (siphash) from the thread ID in combination with the AT_RANDOM secret. Thus it should not be guessable from an attacker in advance. That's only true if a thread takes the lock only once and keeps it forever. However, if a thread takes and releases it multiple times an attacker might monitor that and quickly take the lock after the first iteration for follow-up iterations. It's not a big issue given that userdb (as the primary user for this) never released the lock and we never made the concept a public interface, and it was only included in one release so far, but it's something that deserves fixing. (moreover it's a local DoS only, only permitting to disable native userdb lookups) With this rework the libnss_systemd.so.2 module will now export two additional symbols. These symbols are not used by glibc, but can be used by arbitrary programs: one can be used to disable nss-systemd, the other to check if it is currently disabled. The lock is per-thread. It's slightly less pretty, since it requires people to manually link against C code via dlopen()/dlsym(), but it should work safely without the aforementioned weakness.
This commit is contained in:
committed by
Zbigniew Jędrzejewski-Szmek
parent
6e78726e20
commit
037b0a47b0
@@ -659,7 +659,6 @@ static int process_connection(VarlinkServer *server, int fd) {
|
||||
static int run(int argc, char *argv[]) {
|
||||
usec_t start_time, listen_idle_usec, last_busy_usec = USEC_INFINITY;
|
||||
_cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL;
|
||||
_cleanup_close_ int lock = -1;
|
||||
unsigned n_iterations = 0;
|
||||
int m, listen_fd, r;
|
||||
|
||||
@@ -696,8 +695,8 @@ static int run(int argc, char *argv[]) {
|
||||
return log_error_errno(r, "Failed to parse USERDB_FIXED_WORKER: %m");
|
||||
listen_idle_usec = r ? USEC_INFINITY : LISTEN_IDLE_USEC;
|
||||
|
||||
lock = userdb_nss_compat_disable();
|
||||
if (lock < 0)
|
||||
r = userdb_block_nss_systemd(true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to disable userdb NSS compatibility: %m");
|
||||
|
||||
start_time = now(CLOCK_MONOTONIC);
|
||||
|
||||
Reference in New Issue
Block a user