mirror of
https://github.com/troglobit/finit.git
synced 2026-10-26 12:14:37 +00:00
Merge pull request #499 from aanderse/docs
docs: cleanup some development work
This commit is contained in:
3 files changed
+1
-125
No files matched your search
+1
-1
@@ -7,6 +7,6 @@ dist_docs_DATA = build.md cmdline.md commands.md conditions.md \
|
|||||||
distro.md example.md features.md index.md initctl.md \
|
distro.md example.md features.md index.md initctl.md \
|
||||||
keventd.md plugins.md requirements.md runlevels.md \
|
keventd.md plugins.md requirements.md runlevels.md \
|
||||||
runparts.md service.md signals.md state-machine.md \
|
runparts.md service.md signals.md state-machine.md \
|
||||||
udev-matching.md watchdog.md
|
watchdog.md
|
||||||
dist_docs_DATA += img/logo.png img/svc-machine.png img/svc-machine.svg \
|
dist_docs_DATA += img/logo.png img/svc-machine.png img/svc-machine.svg \
|
||||||
img/alpine-screenshot2.png
|
img/alpine-screenshot2.png
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
# How udev rules work
|
|
||||||
|
|
||||||
## Summary of the complete fix
|
|
||||||
|
|
||||||
- hardware.c: Write authorized_default=1 on the bus path before nftw
|
|
||||||
runs (just 2 lines added). This exploits the fact that apath already
|
|
||||||
contains path/authorized_default at that point (set by the snprintf on
|
|
||||||
line 71). With authorized_default=1 set on the root hub, any device
|
|
||||||
that appears behind an intermediate hub during hub enumeration gets
|
|
||||||
auto-authorized by the kernel.
|
|
||||||
- 70-usb-authorize.rules: Belt-and-suspenders for the async case. If hub
|
|
||||||
port probing is slow enough that children appear after nftw has
|
|
||||||
already returned, udev sees the add event with authorized=0, walks up
|
|
||||||
the parent chain with ATTRS{authorized_default}=="1", and authorizes
|
|
||||||
the device. Locked buses (authorized_default=0) are correctly skipped.
|
|
||||||
|
|
||||||
```
|
|
||||||
ACTION=="add", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", \
|
|
||||||
ATTR{authorized}=="0", \
|
|
||||||
ATTRS{authorized_default}=="1", \
|
|
||||||
RUN+="/bin/sh -c 'echo 1 > /sys%p/authorized'"
|
|
||||||
```
|
|
||||||
|
|
||||||
This keeps authorized_default=2 (deny by default) fully intact — the
|
|
||||||
security window stays closed. The udev rule only fires when confd has
|
|
||||||
explicitly marked a bus as unlocked.
|
|
||||||
|
|
||||||
## Comment from Undersigned
|
|
||||||
|
|
||||||
Very interesting, I did not know you could do such complex operations
|
|
||||||
with udev rules. Could you explain a bit more in detail how the matching
|
|
||||||
works and how we can guarantee locked buses/ports are not accidentally unlocked?
|
|
||||||
|
|
||||||
> Sure. Let's walk through it step by step.
|
|
||||||
|
|
||||||
## How udev ATTRS{} matching works
|
|
||||||
|
|
||||||
A udev rule matches against a device and its entire parent chain in the
|
|
||||||
sysfs device tree. When a device like 2-1.4 (the keyboard) is added, its
|
|
||||||
sysfs hierarchy looks like:
|
|
||||||
|
|
||||||
```
|
|
||||||
/sys/devices/.../0000:01:00.0/usb2/ ← root hub (usbN)
|
|
||||||
usb2/2-1/ ← VIA Labs hub
|
|
||||||
usb2/2-1/2-1.4/ ← keyboard ← event fires here
|
|
||||||
```
|
|
||||||
|
|
||||||
- ATTR{} (no trailing S) — matches attributes on the device itself only
|
|
||||||
- ATTRS{} (with S) — matches attributes on the device or any of its
|
|
||||||
parents, walking up the tree until it finds a match or runs out of
|
|
||||||
parents
|
|
||||||
|
|
||||||
So ATTRS{authorized_default}=="1" on a keyboard event at 2-1.4 walks:
|
|
||||||
|
|
||||||
1. 2-1.4/authorized_default — doesn't exist (not a hub/controller)
|
|
||||||
2. 2-1/authorized_default — doesn't exist (downstream hubs don't have
|
|
||||||
this attribute, only root hubs do)
|
|
||||||
3. usb2/authorized_default — exists, check its value
|
|
||||||
|
|
||||||
This is exactly the right level: authorized_default only lives on root
|
|
||||||
hubs (usbN), which is precisely where confd writes.
|
|
||||||
|
|
||||||
## Why locked buses can't be accidentally unlocked
|
|
||||||
|
|
||||||
The invariant is: confd owns `authorized_default`. It sets it to 0
|
|
||||||
(locked) or 1 (unlocked). The udev rule only reads it, never writes it.
|
|
||||||
|
|
||||||
Walk through the locked case:
|
|
||||||
|
|
||||||
```
|
|
||||||
confd sets usb2/authorized_default = 0 ← locked
|
|
||||||
```
|
|
||||||
|
|
||||||
A device plugs into usb2. udev fires:
|
|
||||||
|
|
||||||
1. ATTR{authorized}=="0" — matches (device is unauthorized)
|
|
||||||
2. ATTRS{authorized_default}=="1" — walks up to usb2, finds 0 → no match
|
|
||||||
3. Rule doesn't fire. Device stays denied. ✓
|
|
||||||
|
|
||||||
For a device behind an intermediate hub on a locked bus:
|
|
||||||
|
|
||||||
```
|
|
||||||
usb2/authorized_default = 0 ← bus locked
|
|
||||||
usb2/2-1/ ← hub (somehow authorized)
|
|
||||||
usb2/2-1/2-1.4/ ← keyboard
|
|
||||||
```
|
|
||||||
|
|
||||||
Even if the hub itself were authorized somehow, the keyboard's parent
|
|
||||||
chain still reaches `usb2/authorized_default = 0` before finding any
|
|
||||||
`authorized_default = 1`. The rule doesn't fire. ✓
|
|
||||||
|
|
||||||
The only remaining question: what if two buses exist and one is locked?
|
|
||||||
|
|
||||||
Say usb1 is unlocked and usb2 is locked. A device on usb2 fires a udev
|
|
||||||
event. ATTRS walks up: `usb2/authorized_default = 0` — stops there (once
|
|
||||||
it finds the attribute it stops). It does not continue up to PCIe or
|
|
||||||
platform buses looking for usb1's attribute. Each USB device's parent
|
|
||||||
chain only goes through its own root hub.
|
|
||||||
|
|
||||||
This is because authorized_default is found at usb2 — udev stops as soon
|
|
||||||
as it matches the attribute name, regardless of value. If the value
|
|
||||||
doesn't match the condition, the whole rule fails. It doesn't continue
|
|
||||||
looking at other buses.
|
|
||||||
|
|
||||||
## Summary of the guarantee
|
|
||||||
|
|
||||||
```
|
|
||||||
┌───────────────────────┬─────────────────────────┬─────────────────────────┐
|
|
||||||
│ Scenario │ usb2/authorized_default │ Rule fires? │
|
|
||||||
├───────────────────────┼─────────────────────────┼─────────────────────────┤
|
|
||||||
│ Bus unlocked by confd │ 1 │ Yes → device authorized │
|
|
||||||
├───────────────────────┼─────────────────────────┼─────────────────────────┤
|
|
||||||
│ Bus locked by confd │ 0 │ No → device denied │
|
|
||||||
├───────────────────────┼─────────────────────────┼─────────────────────────┤
|
|
||||||
│ Bus at kernel default │ 2 │ No → device denied │
|
|
||||||
├───────────────────────┼─────────────────────────┼─────────────────────────┤
|
|
||||||
│ Bus doesn't exist yet │ — │ No → no match │
|
|
||||||
└───────────────────────┴─────────────────────────┴─────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
The rule is purely reactive: it can only authorize devices on buses that
|
|
||||||
confd has already explicitly declared unlocked. It has no ability to
|
|
||||||
override a lock.
|
|
||||||
@@ -56,7 +56,6 @@ nav:
|
|||||||
- Plugins: plugins.md
|
- Plugins: plugins.md
|
||||||
- Watchdog: watchdog.md
|
- Watchdog: watchdog.md
|
||||||
- keventd: keventd.md
|
- keventd: keventd.md
|
||||||
- udev Rule Matching: udev-matching.md
|
|
||||||
- D-Bus Integration: dbus.md
|
- D-Bus Integration: dbus.md
|
||||||
- Service State Machine: state-machine.md
|
- Service State Machine: state-machine.md
|
||||||
- Distributions: distro.md
|
- Distributions: distro.md
|
||||||
|
|||||||
Reference in new issue
Block a user