By Arjun Mehta, gpl-devices.org
Most engineers I talk to assume the GPL is a checkbox. Release the kernel source, slap a tarball on a website, and you’re done. But when you actually sit down and audit a device — especially a router or IoT gateway running a Linux-based firmware — you quickly realize that compliance is more about traceability, build integrity, and complete corresponding source than it is about intention. I’ve performed dozens of these audits, and I can tell you: the gap between what a company thinks it ships and what the GPL actually requires is often alarmingly wide.
This guide is not a legal opinion. It’s a principled, engineering-level process for verifying whether a device respects the freedoms guaranteed by the GNU General Public License. If you’re a compliance officer, a firmware engineer, or a community auditor, you’ll find a structured method here that you can repeat across any embedded Linux product.
Understanding the Scope of a GPL Audit
A GPL audit is not just about finding the Linux kernel tarball. It’s about validating that every GPL-licensed component — from the bootloader and kernel to user-space libraries and utilities — has its complete and corresponding source code made available. That means the exact source used to produce the binary, plus scripts for controlling compilation and installation. For GPLv3, it also includes installation information that allows modified versions to run on the device.
I break an audit into five phases:
- Firmware acquisition and extraction
- Binary analysis and license identification
- Source offer verification
- Build reproducibility and script checks
- Installation information and anti-tivoization review (for GPLv3)
Each phase demands a different set of tools and a meticulous eye for detail. Let’s walk through them.
Phase 1: Firmware Acquisition and Extraction
You can’t audit what you can’t reach. The first step is getting the complete firmware image that the device runs. For many consumer routers and IoT devices, this is available as a downloadable update from the vendor’s support page. If the device you’re auditing is an older model, check archive.org or community forums — sometimes the only surviving copy is there.
Once you have the binary, you need to identify its format. Common formats for embedded Linux devices include SquashFS, JFFS2, UBIFS, and combined images with a kernel plus rootfs. Use binwalk to scan the file:
binwalk -Me firmware.bin
This command extracts known file systems and recursively scans for embedded data. I also cross-reference with file and hexdump to spot custom headers. Some vendors use proprietary wrappers — if so, document the offset and structure. You’ll need to know whether the source offer covers the exact binary blob you’re inspecting.

Phase 2: Binary Analysis and License Identification
With the root filesystem mounted, the real work begins. You need to catalog every executable, library, and kernel module, then identify which ones are under the GPL (or LGPL, AGPL). This is not as simple as looking for a COPYING file. Many embedded builds strip license headers, and busybox amalgamations can obscure individual tool origins.
I start by building a file list with checksums:
find . -type f -exec sha256sum {} \; > file_manifest.txt
Then I run strings on each binary and grep for GPL-related strings: “GNU General Public License”, “version 2”, “version 3”, “Free Software Foundation”, and common license boilerplate snippets. For kernel modules, modinfo often reveals the license tag:
modinfo ./lib/modules/4.14.0/kernel/drivers/net/wireless/example.ko | grep license
If the module says “Proprietary” but links to GPL-only symbols, you’ve found a violation. In one audit, I discovered a vendor had marked a module “GPL” but refused to release the source, claiming it was a binary-only driver. That’s a clear breach — the GPL doesn’t care about claims; it cares about actual linking.
Don’t forget user-space. Libraries like libc (LGPL), libnl (LGPL), and many others are common. Use readelf -d to check shared library dependencies:
readelf -d /usr/sbin/lighttpd | grep NEEDED
Cross-reference each shared object with its license. The SPDX License List is a reliable reference for standard identifiers.
Phase 3: Source Offer Verification
Now you compare the binary manifest against what the vendor provides as “corresponding source.” The GPL requires that the source be the exact version used, not a close approximation or a stock upstream release. I’ve seen vendors point to kernel.org for their kernel source. That’s insufficient if they applied any patches — and virtually every embedded vendor applies patches.
To verify, you need the vendor’s source archive. Often this is a tarball or a Git repository. For each GPL binary, try to rebuild it from the provided source. Check the version strings:
strings /bin/busybox | grep -i "busybox v"
Then compare with the source version. If the binary says BusyBox v1.31.0 but the source archive contains 1.30.1, that’s a red flag. Even a minor version mismatch suggests the source is incomplete.
For kernel verification, extract the kernel config from the device if possible — /proc/config.gz is a gift when it’s present. Otherwise, you can sometimes recover it from the kernel image using extract-ikconfig. Compare this config with any config file in the source offer. A perfect match indicates the right source; a mismatch means the vendor hasn’t provided the complete build environment.
Phase 4: Build Reproducibility and Script Checks
The GPL’s “scripts used to control compilation and installation” requirement is where many audits fail. It’s not enough to provide the source tree; you must also provide the exact commands, patches, and toolchain information that produce the binary from that source.
I request the vendor’s build scripts — often a Yocto layer, a Buildroot config, or a set of shell scripts. Then I attempt a clean build in a controlled environment (usually a Docker container matching the vendor’s stated build host). If the resulting binary doesn’t match the shipped binary bit-for-bit, I dig into why. Common issues include:
- Missing patches that modify source files
- Undocumented environment variables that affect compilation
- Proprietary toolchains that produce different output than the standard GCC the vendor claims to use
- Binary blobs inserted during the build process that aren’t part of the source offer
Reproducibility is a high bar, but it’s the only objective test. If you can’t rebuild, you can’t confirm the source matches the binary. That’s a failure of the audit, and a likely GPL violation.

Phase 5: Installation Information and Anti-Tivoization
If the device contains GPLv3 code — which is common in modern routers via packages like bash, wget, or grub2 — then the vendor must provide “Installation Information.” This means you must be able to take a modified GPLv3 binary and install it on the device, and the device must accept and run it.
Testing this is straightforward: build a modified busybox or kernel module with a non-functional change (like a custom version string), and attempt to flash it onto the device. If the bootloader rejects unsigned images and there’s no documented way to disable signature checks, the vendor is in violation. I’ve encountered this repeatedly with locked-down Android-based set-top boxes. The vendor ships GPLv3 components but uses secure boot to prevent any user modification. That’s precisely what GPLv3’s anti-tivoization clause forbids.
Document the exact steps you took, the error messages, and the vendor’s response (or lack thereof). This evidence is critical for enforcement actions.
Common Pitfalls in GPL Audits
Over the years, I’ve cataloged recurring patterns that trip up auditors — and vendors:
1. Incomplete “Corresponding Source”
Vendors often omit the toolchain, assuming that specifying “GCC 4.8” is enough. But the GPL requires all scripts and tools that are not generally available. If the vendor used a custom linker script or a patched binutils, that must be included.
2. Dynamic Linking Blind Spots
Auditors sometimes focus only on the kernel. But user-space applications dynamically link to libraries that may be GPL or LGPL. A proprietary daemon that links against libreadline (GPLv3) is a derivative work and must be licensed under GPL-compatible terms. Check all shared library dependencies with ldd (run on the target or a compatible emulator).
3. Firmware Blobs in the Kernel
The kernel itself can contain binary firmware blobs. While many are redistributable under permissive licenses, some are not. The GPL requires that the source offer include the preferred form of modification for those blobs, if any. If the blob is just a hex dump with no source, and it’s not under a free license, its inclusion can be a separate licensing issue.
4. Time-Boxed Source Offers
Some vendors provide a source download link that expires, or they require a written request and then never respond. The GPL says the offer must be valid for at least three years and accessible to any third party. If you can’t download the source today, the device is non-compliant.
Tools I Rely On
An effective audit requires the right instruments. Here’s my standard toolkit:
- Binwalk: Firmware extraction and analysis
- FOSSology: License scanning and identification, great for bulk analysis
- scancode-toolkit: Detailed license and copyright detection
- Buildroot/Yocto: For recreating build environments and testing reproducibility
- QEMU: User-mode emulation to run target binaries and check dynamic linking
- diffoscope: Deep comparison of binaries to identify differences between builds
- Git: For tracking patches and version history

Documenting Your Findings
An audit without a report is just a personal exercise. Your documentation should be precise enough that another engineer can replicate your results. I structure my reports with:
- Executive summary: Clear compliance status (compliant, non-compliant, or inconclusive)
- Device details: Model, firmware version, acquisition method
- Methodology: Tools used, build environment, and key commands
- Binary list with license tags: Table of all binaries and their identified licenses
- Source comparison results: Differences found, build reproducibility outcome
- Installation information test: Steps and results, especially for GPLv3
- Evidence: Logs, screenshots, and checksums
This format has held up in discussions with vendors and in community enforcement efforts. It leaves no room for ambiguity.
Why This Matters Beyond the Checklist
I approach GPL compliance as an engineer who believes in the four freedoms. When a vendor ships a Linux-based device without complete source, they’re not just breaking a license; they’re denying users the right to study, modify, and share the software they own. That’s a fundamental breach of trust. Audits are the mechanism that keeps the ecosystem honest.
Every time I find a missing patch or a locked bootloader, I think of the developers who wrote that code with the expectation that their work would remain free. Compliance isn’t a burden — it’s the price of benefiting from a commons that thousands of engineers have built.
If you’re auditing a device for the first time, start with something simple: a router you have at home. Extract the firmware, catalog the binaries, and compare against the vendor’s source offer. You’ll learn more from that exercise than from any whitepaper. And if you find a violation, report it. The GPL is only as strong as the people who enforce it.
Frequently Asked Questions
What if the vendor provides source code but it’s incomplete or modified?
An incomplete source offer is a violation. The GPL requires the exact corresponding source. If patches are missing or the source tree has been altered after the build, you cannot verify the binary. Document the discrepancies with checksums and file comparisons, and request the complete source under the GPL’s written offer provision.
How do I handle devices that use secure boot and GPLv3 code?
GPLv3 requires that the device allow user-modified software to run. If secure boot prevents this and the vendor does not provide signing keys or a documented unlock procedure, the device is non-compliant. Test this by attempting to boot a modified binary. If it fails, capture the error and include it in your audit report.
Is it enough to check only the kernel for GPL compliance?
No. The kernel is the most visible GPL component, but many embedded devices use GPL-licensed bootloaders (U-Boot, GRUB2), libraries (libgcc, libstdc++), and user-space tools (busybox, bash). A complete audit must cover the entire root filesystem. Ignoring user-space is the most common mistake in compliance audits.
Can I rely on the vendor’s own compliance statement?
A self-declaration is a starting point, not a conclusion. Vendors often misunderstand the GPL’s requirements or rely on outdated compliance processes. Independent verification through binary analysis and rebuild testing is the only way to confirm compliance. Trust, but verify — with tools and scripts.