libink: take the match keys clients send without asking

A rule carrying sender, destination, or eavesdrop was refused whole,
and a peer whose AddMatch fails gets no signals at all.  That is a
poor trade for keys clients attach as a matter of course: better a
filter wider than asked for than a subscription that never happened.

They are accepted and ignored rather than honoured.  Widening costs
nothing here since Finit is the only sender on this bus, and what it
emits through the match table is state any peer that got this far may
already read.

argN and argNpath still take the whole rule down.  Honouring them
means parsing message bodies, and nothing asks for them yet.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2026-08-13 10:15:19 +02:00
parent f3c73f1192
commit 5cc41b3ba4
2 changed files with 40 additions and 1 deletions
+20 -1
View File
@@ -7,6 +7,14 @@
* keys cause the whole rule to be rejected so a peer learns its
* filter didn't take, rather than silently receiving everything.
*
* The exceptions are sender, destination, and eavesdrop, which are
* accepted and then ignored. Clients send them as a matter of
* course, and refusing the rule leaves such a peer with no signals at
* all, which serves it far worse than a filter wider than it asked
* for. Widening is safe here: Finit is the only sender on this bus,
* and everything it emits through the match table is state any peer
* that reached the bus may already read.
*
* Copyright (c) 2026 Joachim Wiberg <troglobit@gmail.com>
* SPDX-License-Identifier: MIT
*/
@@ -103,7 +111,18 @@ struct link_match *__match_parse(const char *rule)
else if (!strcmp(key, "interface")) slot = &m->interface;
else if (!strcmp(key, "member")) slot = &m->member;
else if (!strcmp(key, "path")) slot = &m->path;
else {
else if (!strcmp(key, "sender") ||
!strcmp(key, "destination") ||
!strcmp(key, "eavesdrop")) {
/* Understood well enough to accept, see above. */
free(key);
free(value);
continue;
} else {
/* XXX: argN and argNpath land here, so a rule
* using them takes nothing rather than too
* much. They narrow on body contents, which
* means parsing the body to honour them. */
free(key);
free(value);
goto bad;
+20
View File
@@ -54,6 +54,26 @@ case "$(cat /tmp/dbus-match.out)" in
*) fail "Unexpected reply: $(cat /tmp/dbus-match.out)" ;;
esac
# A client that sends these must still get its signals: refusing the
# rule would leave it with none at all. The sender here is deliberately
# wrong, so a delivered signal proves the key was ignored and not
# quietly honoured.
say "AddMatch accepts, and ignores, sender/destination/eavesdrop"
rm -f /tmp/dbus-ignored.out
( texec "$CLIENT" monitor-signal "$BUS" \
"type='signal',sender='org.freedesktop.DBus',destination=':1.99',eavesdrop='false',interface='org.finit.Cond1',member='ConditionChanged'" \
5000 > /tmp/dbus-ignored.out 2>&1 ) &
ign_pid=$!
sleep 0.5
texec "$CLIENT" call-s "$BUS" /org/finit/cond \
org.finit.Cond1 Set "dbus-ignored-keys" >/dev/null \
|| fail "Cond1.Set returned non-zero"
set +e
wait "$ign_pid"
ign_rc=$?
set -e
assert "Signal still delivered through the wider rule (rc=$ign_rc)" "$ign_rc" -eq 0
say "Unknown method on a Finit interface gets an org.freedesktop.DBus.Error.* reply"
set +e
texec "$CLIENT" unknown "$BUS"