Retry USB approval delivery when notifications become available
This commit is contained in:
1 parent
79db1a1826
commit
9e20c2a185
2 files changed
+76
-43
No files matched your search
@@ -16,7 +16,7 @@ IPC.Connected)
|
|||||||
USBGUARD_DEVICE_ID="${BASH_REMATCH[1]}" \
|
USBGUARD_DEVICE_ID="${BASH_REMATCH[1]}" \
|
||||||
USBGUARD_DEVICE_TARGET_NEW=block \
|
USBGUARD_DEVICE_TARGET_NEW=block \
|
||||||
USBGUARD_DEVICE_RULE="${BASH_REMATCH[2]}" \
|
USBGUARD_DEVICE_RULE="${BASH_REMATCH[2]}" \
|
||||||
"$OMARCHY_PATH/bin/omarchy-usb-authorization-event"
|
"$OMARCHY_PATH/bin/omarchy-usb-authorization-event" || true
|
||||||
fi
|
fi
|
||||||
done <<<"$blocked"
|
done <<<"$blocked"
|
||||||
exit 0
|
exit 0
|
||||||
@@ -44,40 +44,52 @@ request="$requests/$token.json"
|
|||||||
# watch executes handlers concurrently. A reconnect scan and a policy event
|
# watch executes handlers concurrently. A reconnect scan and a policy event
|
||||||
# can refer to the same device; publish only one pending request.
|
# can refer to the same device; publish only one pending request.
|
||||||
exec 9>"$requests/.lock"
|
exec 9>"$requests/.lock"
|
||||||
flock 9
|
# Keep retrying without needing another USB event. Handlers belong to the
|
||||||
[[ ! -e $request ]] || exit 0
|
# watcher service and are stopped with the graphical session.
|
||||||
|
while true; do
|
||||||
|
flock 9
|
||||||
|
[[ ! -e $request ]] || exit 0
|
||||||
|
|
||||||
# Discard events overtaken by another policy decision or device replacement.
|
# Discard events overtaken by another policy decision or device replacement.
|
||||||
blocked=$(usbguard list-devices --blocked) || exit 1
|
blocked=$(usbguard list-devices --blocked) || exit 1
|
||||||
current=0
|
current=0
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
if [[ $line == "$USBGUARD_DEVICE_ID: $USBGUARD_DEVICE_RULE" ]]; then
|
if [[ $line == "$USBGUARD_DEVICE_ID: $USBGUARD_DEVICE_RULE" ]]; then
|
||||||
current=1
|
current=1
|
||||||
break
|
break
|
||||||
|
fi
|
||||||
|
done <<<"$blocked"
|
||||||
|
(( current )) || exit 0
|
||||||
|
|
||||||
|
# Login and shell restarts can leave D-Bus alive before notifications are ready.
|
||||||
|
# Bound each wait so disappeared devices are rechecked between attempts.
|
||||||
|
if ! omarchy-notification-wait 1; then
|
||||||
|
flock -u 9
|
||||||
|
sleep 1
|
||||||
|
continue
|
||||||
fi
|
fi
|
||||||
done <<<"$blocked"
|
|
||||||
(( current )) || exit 0
|
|
||||||
|
|
||||||
temporary=$(mktemp "$requests/.request.XXXXXXXXXX")
|
temporary=$(mktemp "$requests/.request.XXXXXXXXXX")
|
||||||
trap 'rm -f "$temporary"' EXIT
|
trap 'rm -f "$temporary"' EXIT
|
||||||
|
|
||||||
jq -n \
|
jq -n \
|
||||||
--arg id "$USBGUARD_DEVICE_ID" \
|
--arg id "$USBGUARD_DEVICE_ID" \
|
||||||
--arg rule "$USBGUARD_DEVICE_RULE" \
|
--arg rule "$USBGUARD_DEVICE_RULE" \
|
||||||
'{id: $id, rule: $rule}' >"$temporary"
|
'{id: $id, rule: $rule}' >"$temporary"
|
||||||
chmod 600 "$temporary"
|
chmod 600 "$temporary"
|
||||||
mv -f "$temporary" "$request"
|
mv -f "$temporary" "$request"
|
||||||
|
|
||||||
if ! omarchy-notification-send \
|
if omarchy-notification-send \
|
||||||
--app-name omarchy-action \
|
--app-name omarchy-action \
|
||||||
--urgency critical \
|
--urgency critical \
|
||||||
--glyph \
|
--glyph \
|
||||||
"USB accessory blocked" \
|
"USB accessory blocked" \
|
||||||
"Click to review it. Keep it blocked unless you recognize the device." \
|
"Click to review it. Keep it blocked unless you recognize the device." \
|
||||||
--exec omarchy-launch-floating-terminal-with-presentation \
|
--exec omarchy-launch-floating-terminal-with-presentation \
|
||||||
omarchy-usb-authorization-review "$token"; then
|
omarchy-usb-authorization-review "$token"; then
|
||||||
# Only a delivered notification may suppress subsequent attempts. Keep the
|
exit 0
|
||||||
# lock until failure cleanup so another event cannot skip an unsent request.
|
fi
|
||||||
rm -f "$request"
|
rm -f "$request"
|
||||||
exit 1
|
flock -u 9
|
||||||
fi
|
sleep 1
|
||||||
|
done
|
||||||
@@ -67,6 +67,7 @@ generate-policy)
|
|||||||
;;
|
;;
|
||||||
list-devices)
|
list-devices)
|
||||||
if [[ ${2:-} == "--blocked" ]]; then
|
if [[ ${2:-} == "--blocked" ]]; then
|
||||||
|
if [[ -n ${BLOCKED_DEVICES_FILE:-} ]]; then cat "$BLOCKED_DEVICES_FILE"; exit 0; fi
|
||||||
if [[ ${BLOCKED_DEVICE_PRESENT:-1} == 1 ]]; then
|
if [[ ${BLOCKED_DEVICE_PRESENT:-1} == 1 ]]; then
|
||||||
rule="${BLOCKED_DEVICE_RULE:?}"
|
rule="${BLOCKED_DEVICE_RULE:?}"
|
||||||
if [[ -n ${BLOCKED_DEVICE_RULE_FILE:-} && -f $BLOCKED_DEVICE_RULE_FILE ]]; then
|
if [[ -n ${BLOCKED_DEVICE_RULE_FILE:-} && -f $BLOCKED_DEVICE_RULE_FILE ]]; then
|
||||||
@@ -126,7 +127,17 @@ cat >"$stub_bin/omarchy-notification-send" <<'STUB'
|
|||||||
printf 'notification' >>"$CALLS"
|
printf 'notification' >>"$CALLS"
|
||||||
printf ' <%s>' "$@" >>"$CALLS"
|
printf ' <%s>' "$@" >>"$CALLS"
|
||||||
printf '\n' >>"$CALLS"
|
printf '\n' >>"$CALLS"
|
||||||
exit "${NOTIFICATION_FAIL:-0}"
|
if [[ -n ${NOTIFICATION_FAILURE_MARKER:-} && ! -e $NOTIFICATION_FAILURE_MARKER ]]; then
|
||||||
|
touch "$NOTIFICATION_FAILURE_MARKER"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
STUB
|
||||||
|
cat >"$stub_bin/omarchy-notification-wait" <<'STUB'
|
||||||
|
#!/bin/bash
|
||||||
|
if [[ -n ${NOTIFICATION_READY_FILE:-} ]]; then
|
||||||
|
touch "$NOTIFICATION_READY_FILE.waited"
|
||||||
|
[[ -e $NOTIFICATION_READY_FILE ]]
|
||||||
|
fi
|
||||||
STUB
|
STUB
|
||||||
chmod +x "$stub_bin"/*
|
chmod +x "$stub_bin"/*
|
||||||
|
|
||||||
@@ -515,16 +526,26 @@ fi
|
|||||||
pass "USB review binds approval to the device snapshot"
|
pass "USB review binds approval to the device snapshot"
|
||||||
|
|
||||||
notification_count=$(grep -c '^notification' "$calls")
|
notification_count=$(grep -c '^notification' "$calls")
|
||||||
if NOTIFICATION_FAIL=1 USBGUARD_IPC_SIGNAL=IPC.Connected \
|
printf '17: %s\n18: %s\n' "$malicious_rule" 'block id 1234:5678 name "Second blocked device" hash "second"' >"$scratch/two-blocked"
|
||||||
"$ROOT/bin/omarchy-usb-authorization-event"; then
|
NOTIFICATION_READY_FILE="$scratch/notification-ready" \
|
||||||
fail "a failed notification must report failure"
|
NOTIFICATION_FAILURE_MARKER="$scratch/first-send-failed" \
|
||||||
fi
|
BLOCKED_DEVICES_FILE="$scratch/two-blocked" \
|
||||||
[[ ! -e $request ]] || fail "a failed notification must not suppress retries"
|
USBGUARD_IPC_SIGNAL=IPC.Connected \
|
||||||
USBGUARD_IPC_SIGNAL=IPC.Connected "$ROOT/bin/omarchy-usb-authorization-event"
|
timeout 10 "$ROOT/bin/omarchy-usb-authorization-event" &
|
||||||
[[ -f $request ]] || fail "reconnection retries a failed notification"
|
scan_pid=$!
|
||||||
[[ $(grep -c '^notification' "$calls") == $((notification_count + 2)) ]] ||
|
for ((attempt=0; attempt<50; attempt++)); do
|
||||||
fail "reconnection must attempt delivery after an earlier send failure"
|
[[ -e $scratch/notification-ready.waited ]] && break
|
||||||
pass "failed USB notifications can be retried on reconnection"
|
sleep 0.02
|
||||||
|
done
|
||||||
|
[[ -e $scratch/notification-ready.waited ]] || fail "startup waits for notification readiness"
|
||||||
|
[[ $(grep -c '^notification' "$calls") == "$notification_count" ]] ||
|
||||||
|
fail "startup does not send before the notification server is ready"
|
||||||
|
touch "$scratch/notification-ready"
|
||||||
|
wait "$scan_pid" || fail "startup scan must retry and finish without another USB event"
|
||||||
|
[[ $(grep -c '^notification' "$calls") == $((notification_count + 3)) ]] ||
|
||||||
|
fail "two blocked devices must be notified despite a failed first send"
|
||||||
|
[[ -f $request ]] || fail "successful retry leaves a reviewable request"
|
||||||
|
pass "USB startup waits for notifications and automatically retries delivery for all devices"
|
||||||
|
|
||||||
sysfs="$scratch/sys/bus/usb/devices"
|
sysfs="$scratch/sys/bus/usb/devices"
|
||||||
mkdir -p "$sysfs/usb1" "$sysfs/1-2"
|
mkdir -p "$sysfs/usb1" "$sysfs/1-2"
|
||||||
|
|||||||
Reference in new issue
Block a user