When you buy a router, a smart thermostat, or an Android-based set-top box, you are not just purchasing hardware. You are acquiring a stack of software, much of which is licensed under the GNU General Public License (GPL) and other copyleft licenses. These licenses grant you the right to request, inspect, and modify the source code. Yet, many manufacturers either ignore these obligations or provide incomplete, obfuscated code drops. As an engineer who has spent years reverse-engineering firmware and building cases for compliance enforcement, I have developed a systematic method for auditing a device. This article outlines that process, step by step, so you can determine whether a product truly respects software freedom.
Understanding the Scope of Your Audit
Before you power on the device or download a single file, define the boundaries of your investigation. A GPL compliance audit is not a penetration test; it is a forensic examination of the software supply chain. The goal is to verify that the vendor has provided the “complete corresponding source code” as required by GPLv2 Section 3 or GPLv3 Section 6. This includes not just the kernel and core utilities, but also any scripts used to control compilation and installation. If the device runs Linux, BusyBox, or U-Boot, the GPL almost certainly applies. Start by listing every open-source component you expect to find: the bootloader, the operating system kernel, critical libraries like glibc or uClibc, and user-space daemons. This initial inventory will serve as your checklist.
Step 1: Acquiring the Source Code Offer
Your first practical step is to locate the vendor’s written offer for source code. Check the product packaging, the user manual, and the device’s “About” or “Legal Information” screen. The GPLv2 requires a written offer valid for three years; GPLv3 extends this and clarifies that the offer must be clear and easily accessible. If the vendor provides a URL, download the entire archive immediately. Do not accept a CD-by-mail offer as the sole method unless you are prepared to wait and document the request. A common evasion tactic is to provide a link that 404s or an email address that bounces. Record every attempt to obtain the source: dates, times, and responses. This documentation is essential if you later need to demonstrate non-compliance to a copyright holder or enforcement body.
Step 2: Extracting the Firmware from the Device
If the vendor fails to provide source code, you must extract the binary firmware directly from the hardware. This process varies by device type but follows a logical pattern. For routers and IoT devices, begin with a serial console. Open the enclosure, locate the UART pins (usually a 4-pin header), and connect a USB-to-TTL adapter. Boot the device and interrupt the bootloader to gain a shell. From there, you can dump the flash partitions using commands like cat /dev/mtdblock0 > mtd0.bin. For Android devices, use adb pull to retrieve system partitions. If the bootloader is locked, you may need to exploit known vulnerabilities or use chip-off forensics with a flash programmer. The extracted binaries are your raw evidence. Never rely solely on over-the-air update files, as vendors often strip proprietary blobs from those packages.
Step 3: Deconstructing the Binary Blobs
With the firmware images in hand, the real analysis begins. Use binwalk to scan for embedded filesystems, compressed archives, and executable headers. A typical command is binwalk -e firmware.bin, which will recursively extract known file types. You will often find a SquashFS root filesystem, a JFFS2 partition, or an ext4 image. Mount these read-only and begin cataloging every ELF binary, kernel module, and shared library. Run file on each executable to identify its architecture and format. Then, use strings to search for GPL-licensed copyright notices, version strings, and compilation timestamps. Pay special attention to stripped binaries—vendors often remove symbol tables to hinder analysis, but the GPL requires that the source code be “the preferred form of the work for making modifications,” which includes build scripts and configuration files, not just raw C files.
Step 4: Matching Binaries to Known Open-Source Projects
Your next task is to identify the exact upstream versions of the GPL components. Start with the kernel: run strings zImage | grep "Linux version" to find the kernel version string. For BusyBox, look for the multi-call binary and run it in an emulated environment or check its embedded version string. For libraries like glibc, uClibc, or OpenSSL, extract the .so files and use readelf -p .comment or strings to find version identifiers. Once you have a version number, download the corresponding upstream source tarball. Your goal is to perform a binary-to-source comparison. Compile the upstream source using the vendor’s reported toolchain (often found in the kernel version string or build notes) and compare the resulting binary with the one from the device. If they differ, the vendor has made modifications. The GPL requires that those modifications be released under the same license.
Step 5: Auditing the Vendor’s Source Release
If the vendor does provide a source archive, do not assume it is complete. Unpack it and immediately check for the presence of build scripts. A tarball containing only raw .c and .h files without a Makefile, Kconfig, or a build environment description is non-compliant. The GPL requires “the scripts used to control compilation and installation of the executable.” Next, attempt to build the source. A common trick is to provide source that fails to compile due to missing dependencies, deliberately corrupted files, or absent proprietary toolchains. If you cannot produce a working binary from the provided source, the vendor is in violation. Document every missing file, every compilation error, and every mismatch between the built binary and the one on the device.
Step 6: Checking for License Notices and Derivative Works
Even if the source compiles, the vendor may have violated the GPL’s notice requirements. Inspect the device’s user interface and documentation for the required copyright notices and the GPL text. Many embedded devices bury these in obscure submenus or omit them entirely. Next, examine the source code for signs of derivative works. If the vendor started with a GPL-licensed codebase and added proprietary modules, those modules must also be licensed under the GPL if they are tightly coupled. Look for kernel modules that taint the kernel, user-space daemons that link against GPL libraries, or scripts that incorporate GPL code. The kernel’s MODULE_LICENSE macro is a starting point, but it is not legally binding; actual code linkage determines license obligations.
Step 7: Investigating Obfuscation and Anti-Compliance Techniques
Some vendors actively resist compliance. They may provide source code that is deliberately obfuscated—renamed variables, removed comments, or restructured in ways that make it functionally equivalent but unreadable. The GPL requires the “preferred form for making modifications,” which is the form the original developer would use. If the vendor provides minified JavaScript or preprocessed C code, that is a red flag. Another tactic is the “binary-only kernel module” that claims to be dynamically loaded and therefore not a derivative work. This argument has been rejected by courts and the Free Software Foundation. If a module uses kernel symbols exported under GPL-only, it is a derivative work. Check for modules that call EXPORT_SYMBOL_GPL functions; these are clear indicators of GPL-covered code.
Step 8: Documenting and Reporting Violations
Once you have gathered evidence of non-compliance, organize it into a clear, technical report. Include the device model, firmware version, a list of GPL components identified, the vendor’s source offer (if any), and a detailed account of the discrepancies. Attach logs, screenshots, and binary analysis output. This report can be sent to the vendor directly, but experience shows that individual complaints are often ignored. A more effective path is to submit your findings to the Software Freedom Conservancy or the Free Software Foundation, which have enforcement programs. You can also contact the copyright holders of the specific GPL components; they have legal standing to demand compliance. Remember: the GPL is not a gentleman’s agreement. It is a copyright license with real legal teeth.
Step 9: Verifying Compliance After a Fix
If the vendor responds with an updated source release, do not assume the issue is resolved. Repeat the audit process from scratch. Many vendors release a partial fix to placate complainants while still withholding key components. Rebuild the entire firmware image from the provided source and compare it byte-for-byte with the binary running on the device. Check that all scripts, toolchains, and configuration files are included. Verify that the license notices are now correct. Only when you can independently produce a functionally identical binary from the provided source, and all notices are in place, can you consider the device compliant.
Common Pitfalls and How to Avoid Them
One frequent mistake is focusing only on the Linux kernel. The GPL covers all components, including bootloaders like U-Boot, filesystem tools like e2fsprogs, and cryptographic libraries like OpenSSL. Another pitfall is accepting a source offer that arrives on physical media without verifying its completeness. Always check that the media contains the exact version corresponding to the firmware on your device. A third pitfall is ignoring build dependencies. If the vendor’s source requires a proprietary compiler or links against proprietary libraries, the release is non-compliant because you cannot exercise your freedom to modify and rebuild the software. Finally, do not confuse “open source” with “GPL-compliant.” A vendor may release some code under a permissive license while withholding GPL-covered components. Your audit must be exhaustive.
FAQ: Common Questions About GPL Audits
What if the vendor provides source code but it is for a different version of the firmware?
This is a common evasion. The GPL requires that the source code correspond exactly to the binaries shipped on the device. If the vendor provides source for version 1.0 but your device runs version 1.1 with additional features, that source release is non-compliant. You must demand the source for the exact version you possess. Document the version mismatch by comparing build dates, feature sets, and file sizes.
How do I handle proprietary user-space applications that link to GPL libraries?
If a proprietary application dynamically links to a GPL library, the legal consensus is that the application becomes a derivative work and must be licensed under the GPL. Check the device’s filesystem for proprietary binaries that import GPL symbols. Use ldd or readelf -d to list shared library dependencies. If you find a proprietary binary linked against libcrypto.so (OpenSSL) or libglib.so, the vendor must release its source code under the GPL. Some vendors attempt to circumvent this by using a GPL “wrapper” that communicates over a pipe or socket to a proprietary process. While legally gray, this practice is often challenged by the Free Software Foundation.
Can I audit a device without opening it or voiding the warranty?
In many jurisdictions, “warranty void if removed” stickers are not legally enforceable, especially when the act of opening the device is necessary to exercise your software rights. However, you can often begin an audit without physical disassembly. Check for firmware updates on the vendor’s website; these often contain full filesystem images. You can also use network scanning tools like nmap to identify running services and their versions. For Android devices, adb may provide sufficient access. If these methods fail, you must decide whether the risk of voiding a warranty is acceptable to enforce GPL compliance. In my experience, the information gained from a full firmware dump is indispensable for a thorough audit.
What tools are essential for a firmware audit?
A well-equipped auditor should have: a USB-to-TTL serial adapter for console access, a logic analyzer for debugging boot sequences, and a flash programmer (like a Dediprog or Bus Pirate) for reading flash chips directly. On the software side, binwalk is indispensable for firmware extraction. radare2 or Ghidra can disassemble binaries for deeper analysis. The buildroot and Yocto build systems are useful for recreating embedded environments. Finally, a hex editor and a strong understanding of ELF, PE, and Mach-O binary formats will serve you well. Keep a reference library of common GPL components and their typical version strings to speed up identification.
Conclusion: Vigilance as a Community Responsibility
Auditing a device for GPL compliance is not a trivial task, but it is a necessary one. The GNU General Public License exists to protect the freedom of users to study, share, and modify the software that runs on their devices. When manufacturers ignore these obligations, they undermine the entire ecosystem. By following a rigorous, evidence-based audit process, you can hold vendors accountable and contribute to a culture of compliance. Remember: the source code is not a courtesy; it is a legal requirement. Every audit you perform strengthens the copyleft system and ensures that the next engineer has the freedom to build upon the work of those who came before.



Disclaimer: This article provides technical guidance for auditing GPL compliance and does not constitute legal advice. For specific legal questions regarding the GNU General Public License, consult a qualified attorney experienced in open-source licensing.