The Binary That Was Just a Shell Script: Unpacking Lenovo's WWAN Unlock Mechanism
Source: lobsters
Vendor lock-in on laptop hardware rarely announces itself clearly. It arrives quietly, in the form of a binary that ships alongside your WWAN modem driver, performs some undocumented initialization ritual, and leaves you entirely dependent on it continuing to exist and run. This is exactly what a recent blog post from hofstede.it documents: Lenovo shipped a closed binary blob to unlock WWAN modem functionality on certain ThinkPad models, and the author replaced it with a 100-line Bash script by tracing what the blob actually did.
The result is instructive not just as a hardware hack, but as a case study in how little work some vendor binaries are actually doing, and how much trust we hand over for nothing.
What WWAN Unlocking Means on ThinkPads
Lenovo ThinkPads have used a variety of embedded WWAN modules over the years: Sierra Wireless EM7455, Fibocom L850-GL, Fibocom FM350-GL, and others. These modules are soldered to M.2 slots and show up as USB composite devices once the machine boots. On Linux, ModemManager handles enumeration and initialization, communicating over AT command ports typically exposed as /dev/ttyACM* or /dev/ttyUSB* interfaces.
The complication on newer hardware is that Lenovo requires an explicit unlock step before the modem will function. Ostensibly this is tied to firmware initialization, regional regulatory compliance, or carrier certification, but in practice it creates a hard dependency on a vendor-supplied tool that runs on startup. Without it, the modem enumerates but refuses to come up properly.
On Windows, this step happens silently through a service. On Linux, Lenovo distributes a binary that you’re expected to invoke at boot via a systemd unit. That binary does its thing, exits, and the modem works. Nobody asks what it actually did.
EFI Variables as a Persistence Mechanism
The key insight in the replacement approach is understanding how UEFI firmware and the operating system exchange state. Linux exposes this through efivarfs, a virtual filesystem typically mounted at /sys/firmware/efi/efivars/. Each variable in this filesystem has a name composed of a GUID and a label, and contains raw bytes that both the firmware and OS can read and write.
The format is simple. The first four bytes are attribute flags: 0x07 means non-volatile, boot-service accessible, and runtime accessible (NV+BS+RT). The remaining bytes are the variable’s payload. Reading is straightforward:
cat /sys/firmware/efi/efivars/{GUID}-VariableName | xxd
Writing requires constructing the attribute prefix:
printf '\x07\x00\x00\x00\x01' > /sys/firmware/efi/efivars/{GUID}-VariableName
The efivar userspace tool wraps this more cleanly, but the filesystem interface is all you need. Variables marked non-volatile survive reboots; the firmware reads them during the next POST and adjusts behavior accordingly. This is how UEFI boot order entries work, how Secure Boot state is stored, and, it turns out, how Lenovo’s modem unlock mechanism works.
What the Blob Was Doing
By strace-ing the binary and monitoring EFI variable changes before and after execution, the author identified the specific variables being written. The blob was reading a set of Lenovo-specific UEFI variables, validating some conditions, then writing an unlock state variable with a GUID and name specific to Lenovo’s firmware interface.
This is a common pattern in OEM firmware tooling. Lenovo’s LVFS-distributed firmware packages use similar mechanisms, writing variables that tell the BIOS how to behave on next boot. The variables themselves are just bytes in NVRAM. The binary adds ceremony but no cryptographic verification, no TPM attestation, no secure channel to the modem. It writes a value; the firmware trusts that value.
The 100-line Bash script replaces the binary by:
- Locating the relevant EFI variables by GUID
- Reading their current state to determine if unlocking is needed
- Writing the unlock payload with the correct attribute flags
- Optionally triggering a ModemManager reprobing to pick up the now-active modem
This is not a bypass or a crack. It is a faithful reimplementation of what the binary was doing, made visible.
Why Vendors Ship Blobs for This
The cynical reading is that blobs create vendor dependency by obscuring a trivial operation. The more charitable reading is that EFI variable manipulation is genuinely dangerous, and vendors want control over which tools do it. Writing the wrong bytes to a non-volatile EFI variable can produce a machine that fails to boot, and recovery requires external UEFI shell access or a BIOS reset. Shipping a tested binary is defensible.
But there is no reason the same caution cannot apply to an open shell script. What the binary provided that the script does not is: opacity. You cannot audit a binary to confirm it only touches what it claims to touch. With a shell script, you can.
This connects to the broader problem of binary blobs in the Linux ecosystem. The Linux kernel’s own stance has shifted over time, with significant effort to document and contain firmware blobs that ship in the kernel tree. Tools like linux-firmware provide a managed registry of known firmware, but vendor tooling that ships outside the kernel gets no such scrutiny.
For users running systems with TPM-backed measured boot or dm-verity protected root filesystems, a closed binary in the boot chain is a trust problem. A shell script is auditable. That matters.
AT Commands and the Modem Side
Some WWAN unlock workflows involve not just EFI variables but also direct AT command exchanges with the modem over its command port. AT commands are the lingua franca of modem control, dating to the Hayes Smartmodem in 1981 and still central to how ModemManager interacts with LTE and 5G modules.
For Fibocom modules specifically, relevant commands include AT+GTUSBMODE to query or set USB composition (which interfaces the modem exposes), and AT+GTFWCFG for firmware configuration. A modem in the wrong USB composition mode may not expose the correct network interfaces, causing ModemManager to fail silently.
Interacting directly:
# Find the AT port
mmcli -m 0 | grep 'primary port'
# Send an AT command directly
microcom -s 115200 /dev/ttyACM2
Or using ModemManager’s own command interface:
mmcli -m 0 --command='AT+GTUSBMODE?'
A complete replacement script would handle both the EFI variable side and, if needed, the modem command side, with readable logic for each step.
The Reproducibility Argument
One underappreciated consequence of replacing blobs with scripts is reproducibility. A binary blob tied to a specific architecture (usually x86_64) breaks under cross-compilation scenarios, container builds, and alternative hardware. A Bash script with standard tool dependencies works anywhere the toolchain works.
For projects that use Lenovo hardware in embedded or edge contexts, this matters concretely. A machine provisioning pipeline that needs to bring up a WWAN modem cannot depend on a vendor binary that requires a GUI login session or ships only as an RPM for a specific distro. A shell script can be vendored, reviewed, and run from an initramfs.
What This Suggests About Hardware Initialization in General
The pattern is not Lenovo-specific. It appears wherever OEM tools mediate between Linux and UEFI firmware state: touchpad gesture configs, fan control tables, keyboard backlight persistence, battery charge thresholds. Many of these are EFI variables or ACPI method calls dressed up as proprietary tooling.
Projects like fw-ectool for Framework laptops and TLP for ThinkPad power management demonstrate that the community can build open equivalents when the underlying protocol is understood. The prerequisite is someone doing the tracing work to figure out what the blob is actually doing, which is precisely what the hofstede.it post documents.
The takeaway from a 100-line Bash script replacing a vendor binary is not that the binary was poorly written. It is that the operation being performed was never complex enough to require a binary in the first place. Once you can read the EFI variables it wrote, reproduce the write operation, and verify the modem comes up, the blob has nothing left to offer.
Transparency and auditability are not abstractions when the alternative is an opaque binary in your boot chain writing bytes to non-volatile firmware storage.