If you ship a product that runs Linux or BusyBox, you’re almost certainly shipping GPL-covered code. The obligation to provide corresponding source isn’t optional, and it doesn’t vanish just because your supply chain is a tangled mess. I’ve spent years tearing apart firmware images and chasing incomplete source drops, and I’ve learned that a structured audit is the only way to know you’re actually meeting the license terms. This guide walks through the process I use when I examine a device for GNU General Public License compliance—from the first binary blob to the final source package.
Why a GPL Audit Matters
Compliance isn’t a legal abstraction. When a device boots, it loads a kernel, runs init scripts, and calls userspace binaries. If any of those components are derived from GPL-licensed code, the distributor has to offer the corresponding source. Groups like the Software Freedom Conservancy and gpl-violations.org have spent years enforcing this, and the technical reality is that nearly every embedded Linux product contains GPL components. An audit confirms whether the source code you have matches the binaries on the device—and whether that source is complete and actually buildable.
For engineers, an audit is a forensic exercise. You compare what’s promised against what’s delivered. You check license notices, pick apart binary blobs, and try to rebuild the firmware. The point isn’t to assign blame. It’s to verify that downstream users’ rights are respected. Whether you’re a compliance officer or a curious developer, the steps below give you a repeatable method.
Step 1: Gather the Firmware and Documentation
Start by getting the firmware image exactly as it’s distributed to end users. That might be a downloadable update file, a factory image pulled from flash memory, or a live snapshot from a running device. If the vendor offers source code separately, grab that too. Keep meticulous records: checksums, version strings, download URLs, and dates. These details matter when you later compare what was offered against what’s actually running.
For devices with locked bootloaders, you may need to access the firmware through a software update mechanism or by dumping flash chips directly. Tools like dd, flashrom, or vendor-specific flashing utilities are your entry points. Once you have the binary, use binwalk to scan for embedded filesystems, compressed archives, and kernel images. A typical command is:
binwalk -e firmware.bin
This extracts recognizable components into a directory structure you can start analyzing.

Step 2: Identify All GPL-Licensed Components
Once you have the filesystem contents, search for copyright and license notices. The Linux kernel itself is the most obvious target, but don’t overlook userspace programs, libraries, and even scripts that incorporate GPL code. Common indicators include:
- Kernel modules: Check
/lib/modulesfor.kofiles. Runmodinfoon each to see the license tag. A tag of “GPL” or “GPL v2” is a strong signal, but it’s not definitive; some proprietary modules falsely claim GPL compatibility. - BusyBox: Many embedded devices use BusyBox, which is GPLv2. Look for the BusyBox binary and its applet symlinks. The presence of BusyBox alone triggers the full source requirement.
- Shared libraries: Use
readelf -dorobjdump -pon.sofiles to check for license fields. Libraries likelibc.so(often uClibc or glibc) are LGPL, but their presence still imposes obligations. - Scripts and tools: Shell scripts, Python scripts, and other interpreted code may incorporate GPL snippets. Grep for license headers and copyright statements.
Create a spreadsheet listing every binary, its path, the detected license, and the corresponding source package if the vendor provided one. This inventory becomes your audit baseline.
Step 3: Examine the Offered Source Code
If the manufacturer has provided a source archive, unpack it and map its contents to the binaries you found. The GPL requires “the complete corresponding machine-readable source code,” which means all scripts, Makefiles, and configuration files needed to compile and install the binary. A tarball that contains only a kernel tree without the .config file used for the build is incomplete. A source drop that omits the toolchain, modified libraries, or build scripts is also incomplete.
Check for these common gaps:
- Missing build scripts: The source should include the exact commands and environment used to produce the binary. If the vendor provides a kernel tree but no information on the cross-compiler, linker scripts, or patches, the source is not complete.
- Obfuscated or stripped source: Some vendors ship source that has been deliberately altered to remove comments, meaningful variable names, or build infrastructure. This violates the GPL’s requirement for the “preferred form for modification.”
- Binary-only modules: If the kernel includes proprietary
.kofiles, the vendor must provide either source or a written offer valid for three years. Check the license tags and look for accompanying source.

Step 4: Verify Build Reproducibility
The most rigorous test of a source release is to build it and compare the output to the shipped binaries. This isn’t always straightforward; embedded toolchains, proprietary drivers, and signing keys can complicate the process. Still, even a partial build can reveal missing components.
Set up a build environment that matches the target architecture. For a MIPS or ARM device, you’ll need the appropriate cross-compiler. If the vendor doesn’t specify the exact toolchain, try to infer it from the binary’s ELF notes or the kernel version string. Commands like file and readelf -h give you the target architecture and ABI.
Attempt to build the kernel using the provided .config. If the build fails due to missing drivers or undefined symbols, the source is incomplete. For userspace components, check whether the provided source can produce binaries with matching symbols and sizes. A byte-for-byte match is ideal, but functionally equivalent binaries are acceptable under the GPL as long as the build process is documented and reproducible.
Step 5: Inspect for License Notices and Written Offers
The GPL requires that you “give all recipients a copy of this License along with the Program.” On embedded devices, this often appears in a settings menu, a printed manual, or a text file on the filesystem. Look for a copy of the GPL text and a clear written offer to provide source code. The offer must include contact information and a statement that the offer is valid for three years. If the device has no user interface, the license text and offer should be in the documentation.
Common failures include:
- Missing or buried license text: The GPL text is absent, or it’s hidden in a submenu that users are unlikely to find.
- Expired or invalid offers: The written offer points to a URL that no longer works or an email address that bounces.
- Incomplete offers: The offer promises source code but doesn’t specify which GPL version applies or which components are covered.
Step 6: Check for Derivative Works and Modifications
Many embedded devices use modified versions of GPL software. The kernel may have custom drivers, BusyBox may have added applets, or system libraries may be patched. The GPL requires that these modifications be released under the same license. Your audit must identify any changes and confirm that the corresponding source is available.
To detect modifications, compare the shipped binaries against stock builds of the same version. For the kernel, check the EXTRAVERSION string and look for non-standard modules. For BusyBox, run busybox with no arguments to see the applet list and compare it to the default configuration. Use tools like strings and objdump to find custom symbols or copyright strings that don’t appear in the upstream source.

Step 7: Document and Report Findings
An audit is only as useful as its documentation. For each component, record whether the source is available, whether it builds, and whether the license terms are met. Use a clear classification: compliant, partially compliant, or non-compliant. If you find gaps, note exactly what’s missing and why it matters under the GPL text.
If you’re auditing on behalf of a company, this report becomes the basis for remediation. If you’re an independent researcher, you may choose to share findings with the vendor first. Many compliance issues stem from oversight rather than malice, and vendors often appreciate a detailed technical report that helps them fix the problem. If the vendor is unresponsive, organizations like the Software Freedom Conservancy can provide guidance on next steps.
Common Pitfalls in GPL Audits
Over years of examining devices, I’ve seen patterns that trip up even experienced engineers. Here are a few to watch for:
- Assuming upstream source is enough: A vendor may point you to kernel.org and claim that satisfies their obligations. It doesn’t. The GPL requires the exact source used to build the binary, including patches and configuration.
- Ignoring firmware blobs: Many devices load proprietary firmware onto chips at runtime. While the firmware itself may not be GPL-licensed, the kernel driver that loads it often is. The source for that driver must be provided.
- Overlooking build scripts: A tarball of source files without Makefiles, linker scripts, or instructions is not the “preferred form for modification.” You can’t modify and rebuild the software without them.
- Trusting license tags blindly: Kernel modules can declare any license string. A module that says “GPL” but loads proprietary blobs or uses non-GPL symbols may still be a violation if it creates a derivative work.
FAQ
What is the difference between GPLv2 and GPLv3 in an audit?
GPLv2 is the most common license in embedded Linux systems. GPLv3 adds explicit requirements about “Installation Information” and anti-tivoization clauses. If a device uses GPLv3 code, you must check that the user can install modified versions. This means verifying that the bootloader allows unsigned images or that the vendor provides signing keys. In practice, many vendors avoid GPLv3 components for this reason, but components like coreutils or Samba may be under GPLv3.
How do I handle proprietary kernel modules?
Proprietary kernel modules are a gray area. The kernel’s license allows non-GPL modules if they don’t derive from GPL code, but the boundary is legally contested. For audit purposes, check whether the module uses EXPORT_SYMBOL_GPL functions. If it does, the module likely creates a derivative work and must be GPL-licensed. Also verify that the vendor provides the module’s source if it is GPL-licensed, or a written offer if it is not.
What if the vendor provides source but it does not compile?
Incomplete or non-compilable source is a GPL violation. The license requires the “complete corresponding source code,” which includes all scripts and tools needed to generate the binary. If you can’t build a working image, the source release is insufficient. Document the specific errors and missing components, and request the vendor provide the missing pieces. If they refuse, the source is non-compliant.
How do I audit a device that uses U-Boot?
U-Boot is GPLv2-licensed and often the first code that runs on an embedded device. Check the U-Boot version, look for the GPL notice in the boot messages, and verify that the vendor provides the exact U-Boot source with their board-specific configuration. Many vendors modify U-Boot to add custom boot commands or hardware support. These modifications must be released under GPLv2. If the vendor provides only a stock U-Boot tarball without their patches, that is a violation.
Conclusion
A GPL compliance audit is a technical process rooted in careful binary analysis, source comparison, and build verification. It requires patience and attention to detail, but the methodology is straightforward. By systematically examining firmware, mapping binaries to source, and testing reproducibility, you can determine whether a device respects the rights of its users. The GPL exists to ensure that those who receive software can study, modify, and share it. A proper audit is one of the most effective ways to uphold that principle.