ipc: close unauthenticated event-spoofing gap in emit's no-source path
The IPC "emit" method's no-source path took a bare event+data and sent it
straight to emit_tx tagged AdapterSource::System with zero validation of
the event name. Any same-UID process on the socket could send e.g.
{"event":"bread.power.ac.connected",...} and have it delivered to every
Lua subscriber indistinguishable from a real adapter event, since System
is the same tag the daemon uses for its own trusted, Rust-originated
sends (bread.system.startup, bread.profile.activated).
Fix, scoped to the actual threat model (same-UID Unix socket trust means
there's no way to cryptographically distinguish "the real bread-cli
binary" from any other local process, so a generic connection-identity
handshake would be theater):
- New AdapterSource::Manual tag for the no-source emit path. System is
now reserved for daemon-internal, Rust-code-originated sends only and
can never again be produced from data that arrived over the wire.
- The event name is rejected if its top-level dotted segment is one of
the reserved, adapter-owned domains (RESERVED_DOMAINS in
bread-shared/src/apps.rs) -- extended with bluetooth/workspace/window/
monitor, event families the Hyprland and Bluetooth adapters already
publish under but that were missing from that list. Freely-named
custom/test event names are untouched, so `bread emit <name>` and
bread-emit's fire-and-forget single-line-write design keep working
exactly as documented.
Bumped API_VERSION to 1.5.0 and updated Documentation.md's IPC emit
section and Namespaces reserved-domains list accordingly.
Also fixed a subscribe/emit race that surfaced while adding regression
tests for this: events.subscribe's ack is written to the client before
the server task actually registers on the broadcast channel, so a test
that emits immediately after reading the ack can race the registration.
Added a settle delay plus an explicit timeout (instead of an unbounded
read loop) so a future regression fails the test instead of hanging the
whole binary.
This commit is contained in:
parent
96639516b1
commit
7bb6fbb20f
6 changed files with 281 additions and 11 deletions
|
|
@ -45,6 +45,19 @@ impl EventNormalizer {
|
|||
source: raw.source.clone(),
|
||||
data: raw.payload.clone(),
|
||||
}],
|
||||
// `Manual` is never constructed as a `RawEvent::source` in this
|
||||
// codebase — the IPC boundary's unsourced `emit` path builds a
|
||||
// `BreadEvent` directly (see `breadd/src/ipc/mod.rs`), bypassing
|
||||
// this normalizer entirely, exactly as `System` did before it.
|
||||
// This arm exists only so the match stays exhaustive; if that
|
||||
// ever changes, pass-through (like `System`) is the sane default
|
||||
// rather than silently dropping the event.
|
||||
AdapterSource::Manual => vec![BreadEvent {
|
||||
event: raw.kind.clone(),
|
||||
timestamp: raw.timestamp,
|
||||
source: raw.source.clone(),
|
||||
data: raw.payload.clone(),
|
||||
}],
|
||||
};
|
||||
|
||||
out.retain(|ev| self.accept(ev));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue