[wrong8007] Wrong Boot

docs · activation-triggers(3)

Activation triggers

How the in-tree triggers detect activation, how they are configured and the limitations of each mechanism.

Wrong8007 can be activated through multiple independent trigger mechanisms. Each trigger is configured separately and can be enabled or disabled at module load time.

A trigger is a struct wrong8007_trigger with a name and an init/exit pair, registered in a static array in the core:

struct wrong8007_trigger {
    const char *name;
    int (*init)(void);
    void (*exit)(void);
};

They call wrong8007_activate() and return. Three ship in-tree today:

Built-in triggers

triggerhook & mechanismexecution contextconfigurationmatches on
keyboard register_keyboard_notifier(), matches a configured character sequence keyboard notifier chain (atomic) PHRASE an exact phrase, typed in sequence, US keymap
usb usb_register_notify(), matches configured VID/PID and event USB notifier callback USB_DEVICES, WHITELIST VID:PID:EVENT rules, whitelist or blacklist
network nf_hook_ops at NF_INET_PRE_ROUTING, priority NF_IP_PRI_FIRST softirq (cannot sleep) MATCH_MAC, MATCH_IP, MATCH_PORT, MATCH_PAYLOAD, HEARTBEAT_HOST, HEARTBEAT_INTERVAL, HEARTBEAT_TIMEOUT MAC, IP, magic packet, or heartbeat timeout

Detection latency

triggertypical detection latency
keyboard Effectively immediate on key press; bounded by notifier dispatch
usb typically a few to tens of milliseconds, depending on USB enumeration and hub event delivery
network sub-millisecond for packet matches; heartbeat detection is bounded by the configured polling interval

Detection latency is separate from activation latency. All built-in triggers perform detection only: on a successful match they invoke wrong8007_activate() and return immediately. Any subsequent work occurs outside the trigger callback.

keyboard

Registers a notifier_block via register_keyboard_notifier(). On every keydown, the scancode is mapped through a fixed US-keymap table; if the resulting character equals the next expected character of PHRASE, the match counter advances. A full match calls wrong8007_activate() and resets the counter. A mismatch resets the counter to 0, or to 1 if the mismatched key happens to equal the phrase's first character.

make load PHRASE="nuke" EXEC="/path/to/script"

Limitations:

  • US keymap only: The mapping table is fixed at compile time.
  • Case-sensitive, exact-sequence matching. No typo tolerance: any wrong key resets progress (except where it restarts the match, as above).
  • Only printable single-character keys are matched; modifier keys like Shift or Ctrl do not themselves advance or reset the match, but do affect which character a subsequent key maps to.
  • Does not see input from virtual keyboards or remote sessions, it hooks the kernel's own input notifier chain, which those bypass.

usb

Registers a notifier_block via usb_register_notify(). Rules are supplied as VID:PID:EVENT strings and parsed into a fixed-size array at load time (16 entries maximum); EVENT is one of insert, eject, or any.

# single device, default event (insert or eject)
make load USB_DEVICES="1234:5678" EXEC="/path/to/script"

# trigger only on removal
make load USB_DEVICES="1234:5678:eject" EXEC="/path/to/script"

# multiple devices in one load
make load USB_DEVICES="1234:5678:insert,abcd:ef00:any" EXEC="/path/to/script"

By default the listed devices are treated as a blacklist: any device not in the list matches. Set WHITELIST=1 to invert this, so only listed devices match:

make load USB_DEVICES="1234:5678:any" WHITELIST=1 EXEC="/path/to/script"

Find a device's VID/PID with lsusb.

Rules are validated strictly at load time e.g. malformed VID/PID hex or an unrecognized EVENT string aborts module load with a specific error. If no valid rules are supplied, the USB trigger disables itself (logged, not silent) and does not register for USB notifications at all. The notifier callback schedules work once per matching USB event without deduplication; correctness doesn't require it, since wrong8007_activate()'s latch already absorbs repeated calls.

Limitations:

  • Fixed limit of 16 device rules per load; excess rules are truncated with a warning.
  • Whitelist/blacklist is a single global mode per module load, not per-rule.

network

Registers an nf_hook_ops at NF_INET_PRE_ROUTING, priority NF_IP_PRI_FIRST, IPv4 only.

The hook performs only bounded packet parsing and matching; it does not dynamically allocate or sleep in the softirq context.

Header accesses are guarded by pskb_may_pull() before each dereference; after a successful pull, packet-header pointers are refreshed rather than assumed to remain stable.

Supports four independent matching modes, usable alone or in combination depending on which parameters are set:

MAC address match

make load MATCH_MAC='aa:bb:cc:dd:ee:ff' EXEC="/path/to/script"

Fires on any frame carrying the given source MAC e.g. ARP, broadcast, or simple presence on the segment is enough. No IP-layer traffic is required.

IP address match

make load MATCH_IP='192.168.1.1' EXEC="/path/to/script"

Fires only on a valid IPv4 packet from the given source address. More restrictive than a MAC match: a device that hasn't sent anything at the IP layer yet won't trigger it.

Port + payload (magic packet)

make load MATCH_PORT=1234 MATCH_PAYLOAD='MAGIC' EXEC="/path/to/script"

Matches a TCP or UDP packet on the given source or destination port whose payload contains the given string, found with a bounded linear scan (k_memmem) rather than a general string-search algorithm: payloads are MTU-bounded so the added complexity of KMP or Boyer–Moore buys nothing here.

Send one with the bundled helper:

python3 scripts/whisperer.py 192.168.1.1 1234 "MAGIC"

Heartbeat timeout

make load HEARTBEAT_HOST='192.168.1.1' HEARTBEAT_INTERVAL=10 \
    HEARTBEAT_TIMEOUT=30 EXEC="/path/to/script"

Fires if no packet from the given host is observed within HEARTBEAT_TIMEOUT seconds. A timer_list checks elapsed time every HEARTBEAT_INTERVAL seconds against a spinlock-guarded last_seen_jiffies, updated on every matching packet. Send periodic heartbeats with:

python3 scripts/heartbeat.py 192.168.1.1 1234

MAC- and IP-only triggers can fire immediately on load if the target address is already active on the same network segment including your own machine. No IP traffic is required for a MAC match; even ARP or broadcast traffic is enough. If you're testing on a live network, prefer a magic packet (MATCH_PORT + MATCH_PAYLOAD) for precision, or make sure the trigger source only joins the network when you intend it to.

MAC/IP-only triggers are still useful where the target device is not always connected and you want activation specifically on its appearance e.g. air-gapped or controlled environments, proximity-based activation, or detecting a trusted device joining the network.