How to Audit a Device for GPL Compliance: A Technical Guide

Free software runs on a deal—code stays open, rights stay clear, expectations go both ways. The GNU General Public License turns that deal into text. When a manufacturer drops Linux, BusyBox, or U-Boot into a box and sells it, they sign up to hand over the matching source. Auditing a device for GPL compliance isn’t a checkbox exercise. It’s methodical evidence collection, binary archaeology, and sometimes a slow argument with a vendor who should know better. Below is a framework I’ve used across routers, IoT gear, and industrial controllers—something you can pick up whether you’re an engineer, a lawyer with a compiler habit, or just someone tired of broken promises.

Embedded system board under inspection with probes and documentation

Understanding the GPL Compliance Baseline

The GPL is a family of licenses, not one dusty document. In embedded gear, you’ll mostly meet GPLv2 and GPLv3. The hinge is “distribution”: ship a binary that contains GPL-covered software, and you owe recipients the complete, corresponding source. Not an upstream tarball. Not a newer release you forked after the product shipped. The exact source that compiled to that binary—Makefiles, patches, configs, the lot.

When things go wrong, laziness usually beats malice. A vendor grabs a Board Support Package from a chipmaker and never checks whether the BSP’s kernel is stock or has been quietly modified. That BSP might carry proprietary kernel modules linked against GPL internals, which means a derivative work they now have to disclose. Tracing that chain backward—from the flash chip on your desk to the build server someone forgot to document—is most of the work.

Legal Triggers and the Derivative Work Problem

“Derivative work” under the GPL is where the shouting starts. The Linux kernel’s module interface is designed so you can load a proprietary driver, provided the driver only uses the standard, public interfaces. The Linus Torvalds exception for user-space programs is widely accepted, but kernel modules that reach for internal symbols—those not sitting behind EXPORT_SYMBOL_GPL—walk into derivative territory fast. During an audit, I pull the kernel’s symbol table, skim the module build scripts, and check which symbols each .ko file actually grabs. A single GPL-only import can flip a module’s licensing obligation.

Software license documents and circuit boards on an engineering desk

Preparing for the Audit: Tools and Access

A GPL audit that matters needs hands on the hardware and eyes on whatever source-delivery mechanism the vendor claims to offer. You need the complete firmware binary set—pulled from flash, grabbed as an OTA update, or read from an eMMC that hasn’t been locked down yet. Here’s the gear I keep nearby:

  • Serial console adapter (UART, JTAG) to catch bootloader chatter and kernel logs before userspace mutes them.
  • Flash memory reader or software extraction tools—dd over a root shell is the calm-day option.
  • Binwalk and Firmware Mod Kit for carving up firmware images.
  • Strings, objdump, and readelf for staring into binaries.
  • Linux kernel source that matches the version the device reports.
  • License scanning tools—FOSSology or Scancode help, but no scanner replaces a person reading build scripts.

Before you unscrew anything, write down the model, hardware revision, and firmware version. That triplet ties the binary you’re holding to the source archive the vendor promised. If they publish a download link or offer a written promise, go get it now and check completeness before you spend hours reverse-engineering something they should have handed over clean.

Phase 1: Firmware Extraction and Preliminary Scan

First real step: pull the entire firmware image off the device’s non-volatile storage. On a Linux box, that often means reading raw MTD partitions or eMMC blocks. If you’ve got a root shell, cat /proc/mtd is your map. On locked-down units, you might need a flash programmer and steady hands.

Once the image is on your drive, let Binwalk chew on it:

binwalk -Me firmware.bin

That gives you a recursive unpack of filesystems, compressed archives, and bootloader blobs. Afterward, you’ve typically got a root filesystem directory—/bin, /lib, /usr—sitting next to a kernel image. A quick strings pass on the kernel and main binaries pulls out GPL breadcrumbs:

strings firmware.bin | grep -i "GNU General Public License"

You’ll usually get multiple hits, which tells you GPL code is definitely inside. Next, grab the kernel version string:

strings vmlinux | grep "Linux version"

That string has to match—letter for letter—the kernel source the vendor gives you. A version mismatch is a quiet alarm that something’s off.

Engineer analyzing firmware code on a laptop with a router board connected

Phase 2: Kernel and Module Verification

The kernel is the spine of almost every compliance audit I’ve done. Start by recovering the configuration. If the device exposes /proc/config.gz, zcat /proc/config.gz on the running system gives you a clean answer. Otherwise, extract it from the kernel image with scripts/extract-ikconfig from the matching kernel source tree.

Take that config, point it at the vendor’s source drop, and rebuild. The resulting kernel binary should be byte-for-byte identical to what’s on the device, assuming you re-create the same toolchain. Build timestamps will differ; debug symbols might wobble. But if code sections don’t match, the vendor handed you source that doesn’t correspond to the binary they shipped.

Analyzing Loadable Kernel Modules

Kernel modules—the .ko files—deserve a long look. modinfo shows you the version magic and symbol dependencies:

modinfo module_name.ko

That vermagic string needs to align with the running kernel’s version, SMP/preempt settings, and compiler fingerprint. Then dig into the module’s symbol table with objdump -t or readelf -s. I’m hunting for any symbol that isn’t in the kernel’s Module.symvers file—or worse, one marked EXPORT_SYMBOL_GPL. That’s a strong signal the module is a derivative work. Vendors sometimes strip symbols to blur things, but the dynamic symbol table that the loader needs can’t be completely hidden without breaking the module.

Phase 3: Userspace and Library Licensing

Past the kernel, the filesystem is a thicket of binaries and libraries under different licenses. The GPL’s copyleft reaches any program that includes GPL code. I go through every ELF binary and .so library and figure out what license governs it.

For each binary, a quick scan helps:

strings /usr/bin/suspicious_app | grep -i "license\|gpl\|copyright"

Dynamic linking to a GPL library usually creates a derivative work, which means the whole program needs to ship under GPL terms. The FSF is unambiguous about this, even if a few legal readings differ by region. I flag any proprietary app that links to libreadline (GPLv3) or libgmp (LGPLv3/GPLv2) without corresponding source. Static linking leaves zero wiggle room: a static binary that pulls in GPL object code must itself be under the GPL.

Interpreted Languages and Scripts

Scripts don’t get a pass. Shell scripts, Python, Lua—if they’re distributed inside a GPL-covered work and carry GPL code themselves, the obligations apply. I mount the full filesystem and search for scripts that borrow from GPL projects. A common slip-up: a vendor drops OpenWrt utility scripts into proprietary firmware without ever publishing the source.

Phase 4: Verifying the Source Code Offer

The GPL says source must be offered “in the customary way for software interchange.” Today, that means a downloadable archive or a public repository that doesn’t demand a scavenger hunt. The auditor’s job is to judge whether the offer is complete and actually works.

A source package that passes muster includes:

  • The exact source of every GPL component, down to patches and local modifications.
  • Build scripts, Makefiles, and configuration files used to generate the binary.
  • A plain explanation of the build environment—compiler version, toolchain, dependencies.
  • Instructions that let a competent developer reproduce the binary from that source.

To test the offer, I follow the vendor’s instructions in a clean build environment. If the build breaks, the source is incomplete. If it finishes but the output doesn’t match the device binary, the source isn’t corresponding. Both outcomes are violations. Plain as that.

Phase 5: Documenting Findings and Compliance Reporting

The last phase is writing it down so others can act on it. Every finding should pin:

  • The specific GPL-covered component and its version.
  • The binary file on the device that includes it.
  • Evidence that the source is missing, partial, or mismatched.
  • A pointer to the relevant GPL clause—GPLv2 Section 3, GPLv3 Section 6.
  • Screenshots, logs, and file hashes that back up the claim.

Write reports for engineers and lawyers who need facts, not adjectives. If the vendor tried in good faith but missed a component, suggest a fix path. If non-compliance looks deliberate—obfuscated source, build scripts rigged to fail—say so directly. The community deserves to know what happened.

FAQ: GPL Device Auditing

What is the most common GPL violation found in embedded devices?

The one I see over and over is incomplete Linux kernel source. Vendors post a stock tarball from kernel.org and leave out their own board-specific patches, drivers, and the exact .config that built the running kernel. BusyBox is another repeat offender—nearly every embedded Linux device uses it, and many vendors “forget” to publish the source they modified.

Can I audit a device without opening it?

You can get partway with network probes and firmware update files pulled from the vendor’s support page. Nmap will show service banners that hint at GPL components. But a serious audit almost always needs filesystem access—through a root shell or by extracting flash directly. Without that, you can’t check kernel modules or confirm the filesystem isn’t hiding something.

What should I do if I discover a GPL violation?

Document it cold. Then contact the vendor’s legal or compliance contact—many companies have a gpl-compliance@ address. Send a short summary of the missing source, the device model, and the firmware version. If they go silent or push back, groups like the Software Freedom Conservancy or the Free Software Foundation can help you figure out next enforcement steps.

Does the GPL require the vendor to provide the toolchain as well?

The GPL requires “scripts used to control compilation and installation,” which can include the toolchain if it’s not generally available. GPLv3 is explicit: “Corresponding Source” covers compilers, linkers, and other tools needed to install and run modified versions. GPLv2 is quieter on this, but the FSF’s reading is that a proprietary toolchain required to build the source must be provided. In practice, most embedded builds use GCC or similar free toolchains, so toolchain withholding is rarer than kernel-source withholding.

How long does a typical GPL audit take?

Depends on the box and the vendor. A straightforward Wi-Fi router with a single-core SoC and a mostly-stock BSP might take 8 to 16 hours of focused work. A multi-processor industrial controller with proprietary DSP firmware and a heavily patched kernel can stretch across days or weeks. The longest phase is usually the build verification—debugging toolchain skew and missing dependencies can turn into a deep rabbit hole.

GPL compliance auditing is a craft that protects the free software ecosystem from slow erosion. It takes precision, patience, and a refusal to accept half-measures. A structured methodology turns scattered observations into a report that holds up—actionable for lawyers, useful for engineers, and honest toward the community that builds the software we all rely on.