#debian #postgresql #psql #auditd #perl

Hiding /etc/shadow from Debian psql wrapper

In the recent note titled "Hiding /etc/shadow from psql", I've mentioned how calling psql was causing auditd to log denied reads of /etc/shadow and have showed one way to deal with this. Here is the continuation of this story, as thanks to insights from @hillu.bsky.social, it's clear that I've missed an important detail.

On Debian /usr/bin/psql is actually a distro specific wrapper over the actual psql binary. I missed that previously:

$ ls -l /usr/bin/psql
lrwxrwxrwx 1 root root 37 Mar 14  2023 /usr/bin/psql -> ../share/postgresql-common/pg_wrapper

This is part of Debian's mechanism for managing multiple PostgreSQL clusters and versions. So the behavior I've observed earlier is Debian specific.

And as @hillu pointed out, /etc/shadow read is ultimately triggered by getpwuid Perl builtin. Which is called by /usr/share/perl5/PgCommon.pm, called from /usr/share/postgresql-common/pg_wrapper by invoking user_cluster_map(). If I understood correctly, the actual read of /etc/shadow is not needed and is only a side effect of triggering getpwuid.

Anyway, the following line of the postgresql-common/pg_wrapper suggests one way to avoid this excessive read attempt:

($version, $cluster, $db) = user_cluster_map() unless ($cluster or $explicit_host or $explicit_port);

Passing explicit connection info to psql will stop the wrapper from entering the code path that ends on shadow file read. But the form of such call is not arbitrary - in the original scenario connection params were in fact passed, but using --dbname CONNSTRING. And Debian wrapper is not trying to extract anything from that. But it does understand psql -h.

And even without resigning from using --dbname CONNSTRING form, we can still escape the issue by adding extra explicit -h HOST. In fact, turns out HOST can be anything then, because as psql docs state, "--dbname [...] can be a connection string. If so, connection string parameters will override any conflicting command line options". At the same time our Perl wrapper will be happy not to call user_cluster_map and leave /etc/shadow alone:

psql --dbname CONNSTRING -h dummy

But that's little hacky. Ideally, PgCommon.pm would not be using getpwuid at all.