I don’t trust spec sheets. When a new industrial IoT gateway or consumer router lands on my bench, I go straight for the hardware. I’m not looking for build quality or chip markings—I’m hunting for the software the vendor forgot to tell you about. The Linux kernel, BusyBox, U‑Boot, maybe a full Debian rootfs crammed inside. A GPL compliance audit isn’t a paperwork drill; it’s a forensic teardown. I trace the boot chain, dump the flash, and compare what I find against what the manufacturer actually released. If they’re hiding something, the silicon will tell me.
Start with the Boot Log: The First Confession
Before I even pick up a soldering iron, I connect a USB‑to‑UART adapter to the board’s serial header. Most embedded Linux devices have one—often unpopulated, sometimes labeled J1 or J2, almost always 3.3V TTL. I set my terminal to 115200 8N1, power on, and watch the boot log scroll. It’s astonishing what spills out. Kernel version, exact SoC, memory map, the init process, sometimes the entire kernel command line. I’ve seen devices print the rootfs partition layout and the bootloader environment before the vendor even thought to disable the console. That’s not a leak; it’s a signed confession.
Next I go after the bootloader itself. If the device uses U‑Boot, I dump the SPI flash with a Pomona clip and a Saleae logic analyzer. The first bytes are usually the boot ROM, then U‑Boot SPL, then U‑Boot proper. I’ve disassembled U‑Boot images and found custom DRAM init code that was never upstreamed or released. The GPL covers bootloaders too. If the vendor modified U‑Boot and shipped the binary, they owe you the source. No source? That’s a violation, plain and simple.
Dumping the Firmware: No Shortcuts
I never rely on vendor‑supplied update files. They’re often encrypted, split into weird chunks, or missing entire partitions. Instead, I desolder the flash chip—SPI NOR, NAND, or eMMC—and read it directly with a programmer. For eMMC, I use a cheap adapter board and a Raspberry Pi running flashrom. For NAND, I use a dedicated reader because bad block management can hide whole filesystems. I’ve pulled complete firmware images from medical devices that the manufacturer swore were “secure” and “unreadable.” The GPL doesn’t care about your obfuscation tricks. If you distributed the binary, you must provide the source.
Once I have the raw dump, I run binwalk -e to extract the filesystem. Binwalk sniffs out magic bytes for SquashFS, JFFS2, UBIFS, and a dozen other embedded formats. I’ve found entire Debian rootfs images inside “proprietary” IoT hubs. The vendor stripped the package manager but left the GPL copyright notices in the binaries. That’s a smoking gun. I mount the filesystem and start cataloging every GPL‑licensed component: the kernel, busybox, glibc, OpenSSL, dropbear, iptables, and often GStreamer or Qt libraries in devices with a display.

Kernel Version and the “Tainted” Flag
I check the kernel version with uname -a if I have shell access, or by reading /proc/version from the extracted rootfs. Then I hunt for the kernel config. The GPL requires the exact configuration used to build the kernel. I’ve requested this from companies and received a generic defconfig that doesn’t match the running kernel. I verify by comparing the config against /proc/config.gz if it’s enabled, or by extracting the IKCONFIG from the kernel image itself. Mismatches are common, especially when vendors enable proprietary kernel modules. I check for those with lsmod or by scanning for .ko files. A proprietary module that links against GPL‑only symbols is a violation. I’ve seen this in video processing pipelines on medical imaging devices—the vendor used a GPL’d V4L2 driver but loaded a closed‑source userspace library that called GPL‑only ioctls. That’s a derivative work, and it must be GPL’d.
Toolchain and Build Scripts: The Missing Pieces
The GPL requires “the scripts used to control compilation and installation of the executable.” That means the build system, the cross‑compiler configuration, and any wrapper scripts. I’ve rarely seen a vendor provide these voluntarily. When I audit a device, I look for remnants of the build environment in the rootfs—often in /usr/lib/build-id or /etc/build. I’ve found hardcoded paths to a developer’s home directory, revealing the exact toolchain used. I then try to reproduce the build. If I can’t, the vendor hasn’t met their obligations. I’ve used this to force a set‑top box manufacturer to release their entire Yocto layer after I demonstrated that their kernel wouldn’t compile without a proprietary driver patch they’d withheld.

License Texts and Copyright Notices: The Paper Trail
I always check for the GPL license text. The GPL requires that the license be included with the distribution. I’ve found devices where the license file was present but the source code was not. That’s an admission of guilt. I also look for copyright notices in the binaries. The strings command often reveals embedded copyright statements. If a binary contains “Copyright (C) 2000‑2020 The BusyBox Authors” but the vendor’s source package doesn’t include BusyBox, I know they’ve stripped it. I’ve used this to confront a consumer electronics company that shipped a smart display with a BusyBox shell accessible via a hidden debug menu. They’d removed all BusyBox documentation but left the binary and its copyright strings intact.
Dynamic Linking and LGPL Components
Not all open‑source components are GPL; many are LGPL. The LGPL allows dynamic linking without requiring the entire application to be open‑sourced. But I still check compliance. I use readelf -d to list the shared libraries a binary links against. If I find an LGPL library like glibc or FFmpeg, the vendor must provide the source for that library and any modifications. They must also allow the user to replace the library with a modified version. I’ve tested this by cross‑compiling a patched glibc and swapping it in on a device. If the device refuses to boot or the application crashes because of a signature check, that’s a violation. I’ve seen this on a medical IoT gateway that used secure boot to lock down the rootfs, preventing any library replacement. The vendor claimed security, but the GPL doesn’t grant exceptions for that.
U‑Boot and the SPL: The Hidden GPL Code
U‑Boot is GPLv2+, and many vendors modify it heavily for their boards. I’ve extracted U‑Boot from SPI flash and found custom board init code that was never upstreamed or released. The GPL requires that the source be provided for any binary distributed. If the device ships with U‑Boot in flash, that’s distribution. I’ve used this to get a Chinese tablet manufacturer to release their U‑Boot source after I proved their bootloader was a modified version with a proprietary fastboot implementation. They had stripped all GPL notices from the binary, but the code structure was unmistakable when I disassembled it with Ghidra.
Practical Steps for Your Own Audit
If you want to audit a device yourself, here’s my workflow:
- Identify the SoC and memory layout. Check the boot log or open the device and read chip markings. This tells you what architecture you’re dealing with.
- Dump the firmware. Use a programmer or a software method like reading /dev/mtd if you have root access. Never trust a vendor‑provided update file alone.
- Extract the filesystem. Binwalk, unsquashfs, and jefferson are your friends. Mount the rootfs and start cataloging binaries.
- Identify GPL components. Run
stringson binaries, check for copyright notices, and compare against known open‑source projects. Tools like Trivy or cve‑bin‑tool can help identify known packages. - Request source code. Contact the vendor and ask for the complete corresponding source for each GPL component. Be specific. If they refuse or provide incomplete source, you have evidence of a violation.

What to Do When You Find a Violation
I don’t just blog about it. I document everything: the device model, firmware version, the specific GPL components, and the steps to reproduce the finding. Then I contact the vendor’s legal or compliance department. I give them a reasonable deadline to respond. If they ignore me, I escalate to the Software Freedom Conservancy or the gpl‑violations.org project. These organizations have legal resources to enforce the GPL. I’ve also filed complaints with the US Federal Trade Commission for deceptive trade practices when a vendor claims their device is “open source” but hides proprietary blobs. The GPL isn’t a suggestion; it’s a license with real obligations.
FAQ: Common Questions About GPL Audits
What if the vendor provides source code but it’s incomplete?
Incomplete source is a violation. The GPL requires the “complete corresponding source code,” which includes all build scripts, configuration files, and any other material necessary to compile and install the binary. If you can’t reproduce the exact binary from the provided source, the vendor hasn’t complied. I’ve seen vendors provide kernel source but omit the toolchain or the initramfs build scripts. That’s not enough.
Can a vendor charge for providing the source code?
Yes, but only a reasonable fee to cover the cost of physical media and shipping. They cannot charge for the source code itself. If they distribute the binary online, they must also provide the source online at no charge. I’ve seen vendors try to charge hundreds of dollars for a CD‑R; that’s not reasonable and is a violation.
What if the device uses a proprietary kernel module?
Proprietary kernel modules are a gray area, but if they use GPL‑only symbols, they are considered derivative works and must be GPL’d. The Linux kernel community has been clear on this. I check for this by looking at the module’s license tag with modinfo and by checking which symbols it imports. If it imports GPL‑only symbols and claims a proprietary license, that’s a red flag.
Auditing a device for GPL compliance is a technical process that requires direct access to the hardware and a methodical approach. I’ve found violations in everything from $20 Wi‑Fi plugs to $50,000 medical imaging systems. The GPL exists to protect user freedom, and as engineers, we have the skills to enforce it. Next time you’re curious about a device, don’t just read the spec sheet—open it up and see what’s really inside.