If you buy a gadget that runs Linux or bundles any GPL-licensed software, you’re entitled to the source code. Paper rights don’t enforce themselves. I’ve spent years peeling back the layers of embedded systems, and I can tell you a real GPL compliance audit is less a legal checkbox and more a deep forensic dig. This guide walks through the exact steps I use to figure out whether a device actually respects the GPL—from pulling firmware off the hardware to picking apart the source release.
Understanding the Scope of GPL Obligations
Before you open a hex editor, get clear on what the GPL actually demands. The GNU General Public License says anyone distributing binaries of GPL-covered software must also make the corresponding source code available. This isn’t just the kernel. It’s every GPL-licensed component baked into the firmware—busybox, uClibc, gstreamer, even proprietary apps that statically link against GPL libraries. The obligation reaches scripts that control compilation and installation, too. If a vendor ships a device with a Linux kernel, they owe you the exact source tree that built that kernel: their modifications, build scripts, and any toolchain pieces that are themselves GPL-licensed.
Plenty of companies treat compliance like a box to tick. They toss a tarball on some obscure FTP server and call it a day. But the GPL is specific: the source must be the exact source used to produce the binary you received. A clean kernel.org tarball with zero vendor patches isn’t compliance if the device runs a modified kernel. A source offer that expires after six months isn’t compliance. A written offer buried on page 200 of a manual nobody reads might technically check a box, but it’s practically useless. Your audit has to verify completeness, accuracy, and genuine accessibility of the source release.
Step 1: Firmware Extraction and Initial Reconnaissance
First job: get the firmware off the device. The approach depends on the hardware. If the device has a web interface that offers firmware updates, grab the update file directly. Often it’s a .bin or .img that’s really a compressed archive. I lean on binwalk to scan for embedded filesystems. My usual first command:
binwalk -e firmware.bin
That pulls out any recognizable filesystems—SquashFS, JFFS2, YAFFS, cramfs—into a directory tree. If the device exposes a serial console or JTAG header, you can go deeper. Solder a header, hook up a USB-to-serial adapter, and watch the bootloader chatter. U-Boot often spills partition layouts and memory addresses. With physical access, you can dump NAND or SPI flash directly using a programmer like the FlashcatUSB or a Raspberry Pi running flashrom. The goal is a complete, byte-for-byte copy of the firmware as it sits on the device’s storage.
Once you’ve got the filesystem mounted, inventory every binary. Use file to spot ELF executables and shared libraries. Run strings on each binary and grep for GPL-related copyright notices. Look for “GNU General Public License” strings—those flag GPL components. But don’t stop there. Plenty of binaries carry no license string yet are still GPL-derived. A static binary with no GPL strings might still be a compiled busybox. You need to fingerprint it.

Step 2: Kernel Verification
The Linux kernel is the heart of most embedded devices, and it’s where vendors cut corners most often. Start by identifying the exact kernel version. If the device gives you a shell, uname -a hands you the version string. Without a shell, extract the kernel image from the firmware. In a U-Boot environment, the kernel is often a uImage with a header you can parse. Use binwalk or dd to strip the header, then run strings on the raw kernel. The version string sits early in the image. Look for “Linux version” followed by a version number and a build timestamp.
Now compare the running kernel against the vendor’s source release. Clone the claimed source tree and check out the tag or commit that matches the version. Build the kernel using the vendor’s provided configuration—if they gave you one. If not, extract the config from the device. On a running system, /proc/config.gz often exists. On static firmware, the config is sometimes embedded in the kernel image itself. Use scripts/extract-ikconfig from the kernel source to pull it out. Build the kernel with the same toolchain version. Then compare the resulting binary against the device’s kernel. A byte-for-byte match is ideal but rarely happens thanks to build timestamps and toolchain quirks. Instead, compare symbol tables using nm or objdump. Look for missing symbols, different function sizes, or extra modules. Any discrepancy means the source doesn’t match the binary.
Pay close attention to kernel modules. Vendors often ship proprietary modules as .ko files while claiming they’re separate works not subject to the GPL. That’s a legal gray area, but technically, a module that uses GPL-only symbols (marked with EXPORT_SYMBOL_GPL) is clearly a derived work. Check the module’s license tag with modinfo. If it says “proprietary” but uses GPL-only symbols, the vendor is violating the kernel’s license. Even if the module uses only non-GPL symbols, the vendor must still provide source for any GPL components they modified in the kernel itself.
Step 3: Auditing Userspace Components
Beyond the kernel, the root filesystem is a goldmine of GPL-licensed code. Start with the obvious: busybox. Almost every embedded device uses it. Extract the busybox binary and run strings to find the version. Busybox embeds its version in the binary. Then check the vendor’s source release for a matching busybox source tree. Build it with the same configuration—busybox’s config is often recoverable from the binary using busybox --help or by pulling out the embedded config data. Compare the binaries. If the vendor modified busybox, those modifications must be in the source release.
Next, inventory shared libraries. Use readelf -d on each binary to list its needed libraries. For each library, identify the upstream project and version. Libraries like libc (uClibc, glibc, musl), libssl, libz, and libgstreamer are common. Check the vendor’s source release for corresponding source packages. Verify that the version matches. If the device uses a patched version of OpenSSL to fix a security hole, that patch must be included. If the vendor statically linked a GPL library into a proprietary application, the entire application becomes subject to the GPL. Look for static linking with ldd—if a binary shows no dynamic links but contains GPL library code (identifiable via strings or function signatures), that’s a red flag.

Step 4: Checking for Obfuscation and Incomplete Releases
Some vendors actively try to hide their GPL violations. They strip symbols from binaries, making it harder to identify functions. They encrypt firmware images, forcing you to extract keys from the hardware. They provide source code that compiles but produces a different binary because they left out critical patches or used a different toolchain. Your audit has to catch these tricks.
For encrypted firmware, look for keys in the bootloader or early-stage initramfs. Often the encryption is symmetric and the key sits in plaintext on the device. Use binwalk with custom magic signatures to spot encrypted blobs. Once decrypted, proceed with normal analysis. For stripped binaries, you can still compare function fingerprints. Extract function bytecode sequences from the device binary and search for them in a compiled version of the vendor’s source. Tools like radare2 or Ghidra help with disassembly and pattern matching. If the vendor’s source produces a binary with different function boundaries or missing code paths, they’ve withheld modifications.
Another common trick is the “partial source drop.” The vendor provides a kernel source tree but omits drivers for key hardware components, claiming they’re proprietary. Check the kernel config for enabled drivers that aren’t in the source tree. If the config references CONFIG_MY_DEVICE=y but the source has no drivers/my_device/ directory, the vendor is violating the GPL. Similarly, look for build scripts that reference external source repositories. If a script tries to fetch a tarball from a private server, the vendor must provide that tarball to you.
Step 5: Verifying the Source Offer Itself
The GPL allows two methods of source distribution: accompanying the device with source on physical media, or a written offer valid for three years. In practice, most vendors use a written offer. Locate it in the device documentation, on the packaging, or in the firmware’s about page. The offer must be prominent. A URL buried in a terms-of-service page that requires account registration isn’t compliant. The URL must be accessible without barriers.
Once you have the URL, download the source archive. Verify its completeness against the components you identified in the firmware. Check file timestamps—a source tarball generated years after the firmware build date is suspicious. It might be a clean upstream release with no vendor changes. Compare the source tree’s .git directory (if present) against the kernel version. Look for vendor-specific branches or tags. If the source is provided as a single giant tarball with no version control history, the vendor is likely hiding their modifications. Demand a proper git repository or at least a patch series against the upstream version.
Test-build the source. Use the vendor’s provided instructions, if any. If the build fails, the source is incomplete. If it succeeds but produces a binary that doesn’t match the device, the source is incomplete. Document every failure meticulously. These are the facts you’ll use when you escalate to the vendor or, if necessary, to the copyright holders.

Step 6: Documenting and Reporting Violations
An audit is only as good as its documentation. For each component, create a report entry: the binary name, the claimed source version, the actual version found, discrepancies, and build comparison results. Include hashes of binaries and source files. This builds a chain of evidence that’s hard to dispute. If you find violations, your first step is to contact the vendor. Be specific. Don’t just say “you’re violating the GPL.” Say “your kernel binary contains function X at offset Y, but your source release does not include the file that defines function X. Please provide the missing source.” Give them a reasonable deadline—30 days is standard.
If the vendor ignores you or refuses to comply, you have options. The GPL is a copyright license. Only the copyright holders of the violated code can enforce it in court. You can contact the Software Freedom Conservancy or the Free Software Foundation, which do GPL enforcement work. You can also contact the individual copyright holders of the components you found violated—kernel developers, busybox authors, etc. Provide them with your audit report. They have legal standing to demand compliance. In many cases, the threat of enforcement from a known copyright holder is enough to make a vendor release the source.
Remember: this isn’t about punishment. It’s about keeping the free software ecosystem healthy. When a vendor violates the GPL, they gain an unfair advantage over competitors who do comply. They also deprive users of the ability to fix bugs, improve security, and extend the life of their devices. Your audit is a service to the community.
FAQ: Common Questions About GPL Device Audits
What if the device uses a proprietary bootloader? Does that affect GPL compliance?
The bootloader itself isn’t necessarily subject to the GPL. Many devices use proprietary bootloaders like U-Boot (which is GPL-licensed, but vendors sometimes use proprietary forks) or completely custom boot code. The GPL covers the operating system and applications, not the boot firmware, unless that boot firmware incorporates GPL code. However, if the bootloader is derived from GPL-licensed code (like a modified U-Boot), the vendor must provide its source. Check the bootloader strings for GPL references. If the bootloader is proprietary but the kernel is GPL, the vendor must still provide the kernel source and any scripts used to interface the bootloader with the kernel.
Verifying Bootloader Components
To audit the bootloader, dump the first few megabytes of flash. U-Boot leaves a distinctive header. Use mkimage -l to parse it. If the bootloader is U-Boot, the vendor must provide the exact U-Boot source used, including board support files. Many vendors modify U-Boot to add splash screens or custom boot commands. Those modifications are GPL-covered. If the vendor claims their bootloader is proprietary but it contains U-Boot strings, they are likely violating the GPL.
How do I handle devices that use signed or encrypted firmware updates?
Signed firmware is a security measure, not necessarily a compliance issue. The GPL does not require vendors to give you the ability to install modified firmware. It only requires them to give you the source code. However, if the signing mechanism prevents you from exercising your right to modify and run the software on the device, that’s a separate issue often called “tivoization.” The GPL version 3 explicitly prohibits tivoization, but many devices use GPL version 2 software, which does not. Check the license version of each component. For GPLv3 components, the vendor must provide signing keys or a way to bypass the signature check. For GPLv2 components, they don’t. In either case, you can still audit the source code itself. Extract the firmware before it’s flashed, or dump it from flash after installation. The encryption or signing doesn’t prevent you from verifying the source code’s completeness.
What tools are essential for a thorough GPL audit?
My core toolkit includes binwalk for firmware extraction, hexdump and strings for binary inspection, readelf and objdump for ELF analysis, and a cross-compilation toolchain matching the device’s architecture (ARM, MIPS, etc.). For disassembly, radare2 or Ghidra are invaluable. For kernel config extraction, the kernel source’s scripts/extract-ikconfig. A good JTAG/SWD debugger like a J-Link or FT2232H board helps with flash dumping. A logic analyzer can decode SPI traffic to extract firmware from chips that aren’t easily socketed. And patience—lots of it. Some devices fight you every step of the way.
Conclusion: The Principle of the Audit
Auditing a device for GPL compliance is a technical challenge, but it’s grounded in a simple principle: the code you run should be the code you can inspect, modify, and share. Every binary on that device is a promise made by the vendor. Your job is to verify that promise. When you find a broken promise, you’re not just a tinkerer—you’re an advocate for the users who don’t have the skills to look under the hood. The process I’ve outlined here is methodical and evidence-based. It leaves no room for hand-waving. Vendors can argue about legal interpretations, but they can’t argue with a hex dump that shows their source code doesn’t match their binary. That’s the power of a proper audit.