How to Audit an Embedded Device for GPL Compliance — A Hands-On Guide

When you buy a router, a smart camera, or an Android TV box, you’re not just getting a piece of hardware. You’re getting a whole software stack that makes the thing actually work. A big chunk of that stack is open source, often under the GNU General Public License — the GPL. The license says you can run the code, study it, share it, and modify it. But those rights are empty if the vendor never hands over the source. I’ve spent years tearing down firmware, and I can tell you: auditing a device for GPL compliance isn’t about faith. It’s a forensic process. You follow the evidence.

This guide is a step-by-step technical walkthrough. We’ll look at what triggers the GPL, how to find the written offer, how to rip apart firmware images, and how to check if the source you get actually matches the binary running on the device. The point is to see whether a vendor respects copyleft or just pays it lip service.

What Actually Triggers GPL Obligations

Before you even plug the device in, you need to know what flips the GPL switch. The GPL (v2 and v3) kicks in when a company distributes a product containing GPL code. Distribution is the trigger. If they ship you a physical router or put a firmware download on their website, they’ve distributed GPL code. At that moment, they owe you the complete corresponding source. That’s not just the Linux kernel — it’s every GPL or LGPL userspace binary, library, and script baked into the device.

And “corresponding source” is a strict term. It means all the source needed to generate, install, and run the executable on that specific device. Build scripts, toolchain configs, kernel patches — even the compiler itself if it’s not a standard system compiler. A vendor can’t just point you to a random Git repo and call it a day. The GPL demands a written offer, good for three years, to provide source on a physical medium. For firmware downloads, the source has to come with the binary or be available from the same distribution point.

Step 1: Hunt Down the Written Offer

Start with the physical product. Open the box and look for a printed insert. Flip through the quick-start guide and the user manual. The GPL says the offer has to be conspicuous. If you spot a URL, don’t get excited yet. A lot of vendors print a generic link to a corporate “open source” page that hosts nothing but a stale Linux kernel tarball. That’s a red flag. A valid offer is specific to the device model and firmware version you’re holding.

If the box has nothing, boot the device and dig through its web interface or on-screen menus. Look for a “Legal” or “Open Source Licenses” section. Some vendors bury the offer deep in the settings. When you find a URL, screenshot it with a timestamp. Then test the link right away. Does it resolve? Is there an actual source archive? Is it specific to your firmware version? A 404 or a generic kernel dump is a compliance failure, plain and simple.

For headless devices like IoT sensors, the offer might live in the companion mobile app. Check the app’s “About” or “Legal” section. If no offer exists anywhere, the vendor is in direct violation of GPLv2 Section 3 or GPLv3 Section 6. Document that absence carefully — it’s the most common violation I see.

Step 2: Get the Firmware and Fingerprint It

Whether or not you have a source offer, you need the binary firmware. If the vendor provides a downloadable update file, grab it from their support site. If not, you’ll have to pull it from the device itself. That usually means getting a serial console. Open the case, find the UART pins, and hook up a USB-to-TTL adapter. During boot, interrupt the bootloader (U-Boot, most of the time) to drop into a shell. From there, you can dump flash partitions with dd or read straight from /dev/mtdblock*.

Once you have the firmware image, fingerprint it. Run file and binwalk to see the image structure. A typical firmware has a bootloader, a compressed kernel, and a root filesystem — often SquashFS, JFFS2, or UBIFS. Extract the filesystem with unsquashfs or jefferson. Now you’ve got a directory tree that mirrors the device’s rootfs. This is your ground truth.

Close-up of a circuit board with integrated circuits and serial console pins

Step 3: Catalog Every GPL-Licensed Component

With the root filesystem extracted, you need to identify every binary that falls under a copyleft license. Start with the kernel. The kernel image is almost certainly GPLv2. Check for a /proc/version string or pull the kernel config from /proc/config.gz if it’s there. The kernel version tells you which upstream tree to compare against.

Next, scan userspace. Use strings on binaries to search for license references. A lot of GPL tools embed a copyright notice. Look for “GNU General Public License” or “GPL” in the output. Cross-reference the binaries with known open-source packages. BusyBox, iptables, udhcpd, dropbear — these are embedded Linux staples and they’re GPLv2. If you find BusyBox, the vendor has to provide the exact source used to build that binary, including the .config file.

Don’t skip libraries. Shared objects (.so files) like libgcc_s.so (GPLv3 with the GCC Runtime Library Exception) or libstdc++.so have their own license terms. The LGPL requires source for the library itself but allows dynamic linking with proprietary code. But if the vendor statically linked a GPL library into a proprietary binary, the whole binary becomes GPL. Use readelf -d to check dynamic linking. If a binary has no NEEDED entries and you find GPL code inside, the vendor has likely created a derivative work they must release.

Step 4: Verify the Source They Gave You

If the vendor did supply a source archive, your job shifts to validation. Download it and unpack it. The first test is completeness: can you build a working firmware image from this source alone? Try a build. You’ll need the exact toolchain. Check the vendor’s source for a toolchain reference. If it’s missing, the source is incomplete. A common trick is to leave out the cross-compiler, claiming it’s a “standard system component.” But for embedded ARM or MIPS targets, the toolchain is specialized and must be provided.

Examine the build scripts. Look for a top-level Makefile or a build.sh. Trace the steps. Does it reference proprietary binary blobs that aren’t included? Wireless drivers often contain a closed-source firmware file that the kernel loads onto the chip. The GPL allows this under the “mere aggregation” clause, but the vendor has to clearly separate the blob from the GPL code. If the build system silently injects a proprietary library into a GPL executable, that’s a violation.

Compare the provided source against the extracted firmware binaries. Build the kernel module for, say, the Wi-Fi driver. Compute the MD5 or SHA256 hash of the resulting .ko file. Strip it (since deployed modules are often stripped) and compare with the one from the device. If the hashes don’t match, the source does not correspond to the binary. That’s a definitive compliance failure. Vendors sometimes release a “similar” source tree from a different commit or with patches omitted. That doesn’t satisfy the GPL’s “corresponding source” requirement.

A developer comparing source code on a monitor with a disassembled device on the desk

Step 5: Dig Into Obfuscation and Linking Tricks

Some vendors actively hide their GPL usage. They rename binaries, strip symbols aggressively, or use packers. To counter that, reach for static analysis tools like radare2 or Ghidra. Disassemble a suspicious binary and look for known GPL function signatures. If you find inflate() or sha1_transform() with instruction patterns identical to zlib or OpenSSL, you’ve spotted GPL code. zlib is under a permissive license, but OpenSSL is not GPL-compatible unless the vendor added an exception. If the binary is GPL and links OpenSSL without an exception, the distribution is unauthorized.

Check for license texts in the firmware. The GPL requires that recipients get a copy of the license. Look in /usr/share/doc or similar paths. If the GPL text is absent, the vendor failed a basic obligation. Also, search for copyright attribution. Many GPL packages require preservation of copyright notices. If the vendor stripped them, they’re infringing.

Step 6: Document Violations and Contact the Vendor

Your audit should produce a structured report. For each GPL component found in the firmware, note the binary path, the identified license, the source status (provided, missing, incomplete), and any linking anomalies. Attach screenshots, hash comparisons, and build logs. This report becomes the basis for enforcement.

Contact the vendor through their official compliance channel. Be precise and technical. State the device model, firmware version, and the specific GPL components you’re requesting. Cite the exact GPL clause they’re violating. Set a reasonable deadline — 30 days is typical. Many vendors have a compliance officer who will respond if the request is legally sound. If they ignore you or send incomplete source again, escalate to the copyright holders of the violated components. Organizations like the Software Freedom Conservancy (SFC) and gpl-violations.org have a track record of successful enforcement actions on behalf of kernel developers and BusyBox authors.

Step 7: Community and Legal Escalation

When a vendor refuses to comply, the open-source community has tools to apply pressure. Publish your audit findings (without proprietary code) on forums and mailing lists. Public pressure often motivates a response. If the violation involves the Linux kernel, the copyright holders can initiate legal proceedings. The GPL is a copyright license, and violation terminates the license, making the distribution an act of copyright infringement. Courts in Germany, the United States, and other jurisdictions have upheld GPL terms.

Remember, compliance isn’t a one-time event. Vendors must maintain source availability for three years after the last distribution. Re-audit new firmware versions. A vendor that was compliant yesterday can become non-compliant tomorrow by adding a new GPL component without updating their source release.

A magnifying glass over a printed circuit board, symbolizing detailed inspection

FAQ: Common Questions on GPL Device Audits

What if the vendor provides source code on a CD only upon request?

That’s perfectly valid under GPLv2 Section 3(b), as long as the written offer is included with the product and the CD contains the complete corresponding source. The offer must be valid for three years. But if the vendor charges more than the cost of physically performing the source distribution, they’re in violation. A nominal fee for media and shipping is acceptable; a $50 “handling” charge is not.

How do I audit a device that uses U-Boot with a proprietary boot script?

U-Boot is GPLv2. The boot script, if it’s a standalone text file loaded by U-Boot, may be considered mere data and not subject to the GPL. But if the vendor modified U-Boot source code to embed the script or to interpret a custom script format, those modifications are derivative works and must be released. Extract the U-Boot binary from the flash, disassemble it, and compare it against the upstream U-Boot for your board. Any added code must be provided in source form.

Can a vendor comply by linking to a third-party repository like GitHub?

No. A link to a public repository does not satisfy the written offer requirement. The GPL requires the distributor to provide the source themselves or through a third party that offers a valid written offer. If the GitHub repository is controlled by the vendor and contains the exact corresponding source for the distributed binary, it may be considered equivalent to a download from the vendor’s own site. But the vendor must still include the written offer in the product. A bare URL in a manual without a specific commit hash or tag that matches the firmware version is insufficient.

What tools are essential for a firmware audit?

You’ll need binwalk for firmware analysis, unsquashfs and jefferson for filesystem extraction, a hex editor like hexdump or xxd, strings for quick license scans, readelf for ELF inspection, and a disassembler like Ghidra or objdump. A USB-to-TTL serial adapter is essential for console access. For build verification, you need the appropriate cross-compiler toolchain, which you may have to construct yourself if the vendor fails to provide it.