How to Audit a Device for GPL Compliance: A Practical Field Guide

What a GPL Compliance Audit Actually Means

Let’s cut through the noise. A GPL compliance audit isn’t some abstract legal exercise—it’s a hands-on forensic dig into the software a device ships with. You’re checking whether the manufacturer respected the GNU General Public License. For embedded Linux engineers, this means pulling apart firmware, examining bootloaders, and sifting through whatever source code the vendor bothered to release. The GPL gives users the right to run, study, share, and modify the software on their own hardware. When a company slaps GPL code—like the Linux kernel, BusyBox, or U-Boot—into a product and then locks it down, they’re breaking that agreement. That’s not just a legal misstep; it’s a direct attack on the open hardware ecosystem. This guide is about gathering hard evidence, not just complaining. It’s a skill every embedded developer should have in their back pocket.

We’ll walk through a practical, evidence-first audit method. You’ll learn to dissect firmware images, track kernel changes, and demand source code with surgical precision. The focus is GPLv2—the workhorse license in embedded Linux—but the approach works for LGPL and other copyleft licenses too. By the time you’re done, you’ll have a repeatable process to hold manufacturers’ feet to the fire, and to keep your own projects from stumbling into accidental violations.

Close-up of a circuit board with embedded components

Step 1: Map the Device and Its Software Stack

First, take stock of every piece of software on that device. Bootloader, kernel, root filesystem, any proprietary apps—list them all. Most embedded gadgets lean on U-Boot or Barebox, a Linux kernel, and a BusyBox-based userland. Poke around the device’s UI, its manual, or firmware update files for copyright notices. GPLv2 says those notices need to be “conspicuously and appropriately published” on the device. If they’re nowhere to be found, that’s your first warning sign.

Grab the firmware image if you can. For devices with accessible storage—eMMC, SPI flash, an SD card—use dd or a hardware programmer to dump the contents. For locked-down hardware, intercept OTA updates by sniffing network traffic or reverse-engineering the update client. Once you’ve got the image, let binwalk tear it apart to find filesystem signatures and extract the guts. A typical command:

binwalk -e firmware.bin

You’ll end up with a directory of extracted filesystems. Hunt for the kernel image (often zImage or uImage) and the rootfs (SquashFS, JFFS2, or initramfs). Grab the kernel version string with strings kernel.img | grep "Linux version". That gives you the exact upstream release—you’ll need it later to check against whatever source the vendor hands over.

Building a Software Bill of Materials

Put together a software Bill of Materials (SBOM) for the device. List every GPL-licensed binary you spot: the kernel, kernel modules, BusyBox, glibc, wireless drivers, you name it. For each one, note the binary’s path, the license type, and the version if you can sniff it out. Tools like readelf and strings help pull version strings from binaries. This SBOM becomes your checklist when you go asking the manufacturer for source code.

Engineer inspecting a circuit board with a multimeter

Step 2: Demand Source Code and Size Up the Response

GPLv2 says complete corresponding source code has to be offered to anyone who gets the binary. That offer must be good for at least three years, and it can come as physical media, a download link, or a written promise. Start by hunting for the manufacturer’s open source compliance page. A lot of companies hide it under “Legal” or “Developer Resources.” If you can’t find it, fire off a formal request to their support or legal team. Be specific: name the device model, firmware version, and the GPL components you’ve already identified. Demand the complete corresponding source—that means build scripts and installation instructions, not just a tarball of untouched upstream code.

When the source shows up, hold it against your SBOM. Make sure the kernel source matches the version string you pulled earlier. Look for a .config file that lines up with the running kernel’s configuration (you can yank this from /proc/config.gz on a rooted device or by analyzing the kernel image). Check that any kernel modules actually build from the provided source. A classic dirty trick: shipping a binary kernel module with no source, or handing over a source tarball that doesn’t even include the module’s code.

Red Flags in Source Offerings

Manufacturers often try to skate by with the bare minimum. Watch for these games:

  • Incomplete source: Build scripts, toolchain details, or modified files are missing.
  • Wrong version: They give you source for Linux 4.1, but the device runs 4.1.15 with custom patches.
  • Obfuscated code: Source that’s been deliberately scrambled and won’t compile to the shipped binary.
  • Proprietary blobs: Kernel modules or libraries statically linked to GPL code, but handed over only as binaries.

If the source is incomplete, ask for the missing pieces in writing. Point to the specific GPLv2 sections (Section 3 on source code provision is your friend). Keep a record of every email and letter—this paper trail is gold if the case ever lands in front of a copyright holder or a courtroom.

Step 3: Deep Binary Analysis to Catch Hidden Violations

Even when source is provided, you’ve got to verify it actually matches the binaries on the device. This is where static and dynamic analysis earn their keep. Start with the kernel configuration. Extract the config from the running kernel (if you’ve got shell access) or from the kernel image using scripts/extract-ikconfig from the kernel source tree. Diff it against the provided .config. Any mismatches scream that the source doesn’t match the binary.

Next, hunt for proprietary kernel modules. On a rooted device, lsmod lists loaded modules. For each one, check the MODULE_LICENSE tag with modinfo module.ko. If the tag says “Proprietary” but the module uses GPL-only symbols (marked with EXPORT_SYMBOL_GPL in the kernel), that’s a violation. The kernel community calls this a clear infringement, as laid out in the Linux kernel licensing rules. You can spot GPL-only symbol usage by checking /proc/kallsyms on a running system or by disassembling the module with objdump.

Picking Apart User-Space Binaries

User-space programs can break the GPL too. If a binary is statically linked against a GPL library (like glibc or BusyBox), the whole program has to be GPL-licensed and its source provided. Use ldd to check dynamic linking. For static binaries, readelf -s will show you library symbols. Find GPL library code baked into a proprietary binary? That’s a violation. BusyBox is a repeat offender here because it’s often statically linked into a single binary to save space. The Software Freedom Conservancy’s Copyleft Compliance Guide has detailed examples of these cases.

Close-up of a microchip on a green circuit board

Step 4: Build the Source and Compare Binaries

The real test of compliance is a reproducible build. Set up a build environment that mirrors the device’s toolchain as closely as you can. The provided source should spell out the cross-compiler version and build flags. If it doesn’t, you can often guess the toolchain from strings in the binary (like the GCC version). Compile the kernel and user-space pieces, then compare the resulting binaries against what you pulled from the device.

Use diffoscope for a deep dive into the two filesystems. It recursively unpacks archives and compares individual files, flagging any differences. Even if the binaries aren’t bit-for-bit identical—timestamps or build paths can cause that—diffoscope shows you which files differ and how. If the provided source spits out a kernel with different features or a BusyBox with different applets, the manufacturer hasn’t given you the true corresponding source.

When Reproducibility Falls Apart

Reproducible builds are tricky, and some differences are harmless. But if you can’t build a functional equivalent, the source is insufficient. Write down exactly what you did, the toolchain you used, and the differences you saw. This evidence hits hard when you confront a manufacturer or file a compliance complaint with groups like the Software Freedom Conservancy or gpl-violations.org.

Step 5: Escalating and Reporting Violations

If the manufacturer ignores your requests or hands over non-compliant source, you’ve got options. First, reach out to the copyright holders of the GPL components. A lot of kernel developers and projects like BusyBox actively enforce their copyrights. Hand them your audit evidence—the SBOM, correspondence, and binary analysis. They have standing to demand compliance or take legal action. The gpl-violations.org project has a solid track record of enforcement in Europe, while the Software Freedom Conservancy handles cases in the US.

You can also go public with your findings. A detailed technical report on a mailing list or your blog puts pressure on the manufacturer and warns other engineers. Stick to the facts and the GPL text; avoid legal conclusions. This approach has pushed plenty of companies to quietly release source code to dodge a reputation hit.

FAQ

What’s the difference between GPLv2 and GPLv3 compliance?

GPLv2 centers on source code provision and notice requirements. GPLv3 adds explicit terms about anti-tivoization (hardware restrictions on modified software) and patent retaliation. In embedded devices, GPLv2 is more common, but if you spot GPLv3 code (like some GNU tools), the device must not block installation of modified versions. Check for locked bootloaders or signed firmware requirements that stop user-modified software.

How can I tell if a binary is statically linked to a GPL library?

Run ldd on the target binary. If it says “not a dynamic executable” or lists no shared libraries, it’s statically linked. Then use readelf -s or objdump -T to look for symbols from known GPL libraries (like glibc functions). If you find them, the binary likely includes GPL code and must be distributed with source under a GPL-compatible license.

What if the manufacturer claims the source code is a trade secret?

The GPL doesn’t allow trade secret claims on GPL-licensed code. If they’ve modified GPL-covered software and distributed the binaries, they have to provide the corresponding source. A refusal based on trade secrets is a clear violation. Document the claim and escalate to the copyright holders or enforcement organizations.

How do I audit a device without physical access?

If you can’t get the hardware, download firmware updates from the manufacturer’s website. Use binwalk to extract filesystems and analyze them as described. You can also scan for GPL components by searching for copyright strings in the firmware image. It won’t catch everything, but it’s a start. For network-connected devices, you might probe for GPL binaries using tools like nmap and banner grabbing.

Building a Compliance Toolkit

Auditing GPL compliance is a skill that sharpens with practice. Put together a toolkit of open-source forensic tools: binwalk, diffoscope, readelf, objdump, and a cross-compiler toolchain. Get comfortable with the GPL text and the Software Freedom Law Center’s compliance guides. Start with devices you own—routers, IoT gadgets, Android phones—and document what you find. Each audit makes you better at spotting violations and strengthens the open hardware community against proprietary lock-in.

Remember, compliance isn’t just about catching violators. It’s about keeping the embedded Linux ecosystem open so engineers have the freedom to innovate on the devices they own. When you demand source code, you’re not just enforcing a license—you’re defending the principle that hardware should serve its user, not its manufacturer.