Prompted by the discussion on #16110, let's migrate more code to
fd_wait_for_event().
This only leaves 7 places where we call into poll()/poll() directly in
our entire codebase. (one of which is fd_wait_for_event() itself)
poll() sets POLLNVAL inside of the poll structures if an invalid fd is
passed. So far we generally didn't check for that, thus not taking
notice of the error. Given that this specific kind of error is generally
indication of a programming error, and given that our code is embedded
into our projects via NSS or because people link against our library,
let's explicitly check for this and convert it to EBADF.
(I ran into a busy loop because of this missing check when some of my
test code accidentally closed an fd it shouldn't close, so this is a
real thing)
It fully initializes the address structure, so no need for pre-initialization,
and also returns the length of the address, so no need to recalculate using
SOCKADDR_UN_LEN().
socklen_t is unsigned, so let's not use an int for it. (It doesn't matter, but
seems cleaner and more portable to not assume anything about the type.)
This will call json_variant_sensitive() internally while parsing for
each allocated sub-variant. This is better than calling it a posteriori
at the end, because partially parsed variants will always be properly
erased from memory this way.
Use the official glibc API for determining this parameter. In most other
cases in our tree it's better to go directly for RLIMIT_NOFILE since
it's semantically what we want, but for this case it appears more
appropriate to use the friendlier, shorter, explicit API.
We want to use this code in NSS modules, and we never know the execution
environment we are run in there, hence let's move our fds up to ensure
we won't step into dangerous fd territory.
This is similar to how we already do it in sd-bus for client connection
fds.
This call can be useful even if a server object is declared.
(Originally this was not supported, because a server typically needs to
handle multiple connections, and thus a synchronous wait on one would
starve the others out. But in some cases it might make sense to have
varlink point-to-point connections — i.e. where the server only handles
a single connection ever — and there it makes sense to synchronously
wait on the one connection).
This reverts commit 8688c29b5a, but leaves the
reproducer. Structured assignment should be enough to fully initialize the
variable and new0 is not necessary.
Should finally fix oss-fuzz-14688.
8688c29b5a wasn't enough.
The buffer retrieved from memstream has the size that the same as the written
data. When we write do write(f, s, strlen(s)), then no terminating NUL is written,
and the buffer is not (necessarilly) a proper C string.
This adds a minimal Varlink (https://varlink.org/) implementation to our
tree. Given that we already have a JSON logic it's an easy thing to add.
Why bother?
We currently have major problems with IPC before dbus-daemon is up, and
in all components that dbus-daemon itself makes use of (such as various
NSS modules to resolve users as well as the journal which dbus-daemon
logs to). Because of that we so far ended up creating various (usually
crappy) work-arounds either coming up with secondary IPC systems or
sharing data statelessly in /run or similar. Let's clean this up, and
instead use a clean, well-defined, broker-less IPC for cases like that.
This is a minimal implementation of Varlink, i.e. the most basic logic
only. Stuff that's missing is left out on purpose: there's no
introspection/validation and there's no name service. It might make
sense to add that later, but for now let's only do the minimum buy-in we
can get away with. In particular as I'd assume that at least initially
we only use this IPC for our internal communication avoiding
introspection and the name service should be fine.
Specifically, I'd expect that we add IPC interfaces to the following
concepts with this scheme:
1. nss-resolve (so that hostname lookups with resolved work before
resolved is up)
2. journald (so that IPC calls to journald don't have to go through
dbus-daemon thus creating a cyclic dependency between journald and
dbus-daemon)
3. nss-systemd (so that dynamic user lookups via PID 1 work sanely even
inside of dbus-daemon, because otherwise we'd want to use dbus to run
dbus which causes deadlocks)
4. networkd (to make sure one can talk to it in the initrd already,
long before dbus is around)
And there might be other cases similar to this.