Skip to content

09 · Compliance & Open-Source Licensing

A product built on Linux, U-Boot, BusyBox, and a hundred other open source packages inherits a hundred different licenses' obligations — and getting this wrong is a legal and business risk, not a technical inconvenience. GPLv2 (the kernel), GPLv3, LGPL, and permissive licenses (MIT, BSD, Apache) each impose different obligations, and a shipped product is where those obligations become enforceable.

What GPLv2 actually requires for a shipped kernel

The Linux kernel is GPLv2. Shipping a device running it obligates you, on request, to provide the complete corresponding source for the exact kernel you shipped — including your out-of-tree patches — to anyone who receives the binary, not just customers who ask nicely:

$ cat linux-source-offer.txt
This product contains software licensed under the GNU General
Public License v2. To obtain the complete corresponding source
code, including all patches applied to this build, write to:
  Open Source Compliance, Acme Devices Inc, ...
or download it directly at:
  https://opensource.acmedevices.com/product-x/v2.3.1/

A written offer is only compliant if the source you actually provide matches the exact binary shipped — the same kernel version, the same patch stack, the same .config. This is exactly why Module 1's manifest archiving discipline (exact layer pins, exact patch stack per release) isn't just good engineering practice, it's the artifact that makes GPL compliance provable rather than aspirational.

$ tar czf product-x-v2.3.1-gpl-source.tar.gz \
    linux-6.6.35-product-x/ u-boot-2024.01-product-x/ busybox-1.36.1/
$ sha256sum product-x-v2.3.1-gpl-source.tar.gz > product-x-v2.3.1-gpl-source.sha256

GPLv2 vs LGPL vs permissive: what changes obligation-wise

License Distributing binary obligates you to...
GPLv2 (kernel, many GNU tools) Provide complete corresponding source for that exact binary, on request
LGPL (glibc, many libraries) Provide source for the LGPL'd library itself; permits dynamic linking from proprietary code without extending GPL obligations to that code
MIT / BSD / Apache Retain copyright notice and license text; no source-disclosure obligation
GPLv3 Adds anti-Tivoization language in some cases — for locked-down/signed-boot devices, this is the license clause with the most direct interaction with Module 2's secure boot design

GPLv3's anti-Tivoization concern is the one that directly collides with secure boot. GPLv3 (used by some but not all GNU tools — bash, coreutils, modern gcc) requires that if you provide "Installation Information" for a GPLv3-covered work, a user must actually be able to install a modified version and have it run — which is in direct tension with a secure-boot chain (Module 2) that refuses to boot anything not signed by your key. Practically: audit your dependency tree for GPLv3 components specifically, separately from the more common GPLv2 audit, because the compliance answer is genuinely different and harder.

License scanning: automating the audit

$ bitbake -c populate_lic core-image-product
$ cat tmp/deploy/licenses/core-image-product-*/license.manifest | \
    awk -F': ' '{print $2}' | sort | uniq -c | sort -rn | head
    142 MIT
     84 GPLv2
     41 BSD-3-Clause
     12 LGPLv2.1
      3 GPLv3
      2 Apache-2.0

Yocto's populate_lic task, run automatically as part of a normal build when LICENSE_CREATE_PACKAGE_ARCHIVE and related license variables are set, produces exactly this manifest per image — the raw input a compliance review actually needs, generated as a build artifact rather than reconstructed after the fact by manually reading every recipe.

$ scancode --license --json-pp scan-results.json vendor-sdk-blob/

For binary vendor SDK blobs (an NPU delegate library, a proprietary camera ISP tuning tool) with no visible license file, scancode (or an equivalent license-fingerprinting tool) at least surfaces embedded copyright strings and license text fragments worth escalating to the vendor for clarification — silence from a vendor about licensing terms is not the same as "no obligation exists," it's an unresolved compliance gap.

The SBOM: what shipped, in a form auditors and customers can read

A Software Bill of Materials is the modern deliverable a growing number of customers and regulations (in some jurisdictions, increasingly a procurement requirement) expect alongside the product itself:

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.5",
  "components": [
    {"type": "library", "name": "linux", "version": "6.6.35",
     "licenses": [{"license": {"id": "GPL-2.0-only"}}]},
    {"type": "library", "name": "openssl", "version": "3.0.9",
     "licenses": [{"license": {"id": "Apache-2.0"}}]}
  ]
}
$ oe-spdx-creator -i core-image-product
$ ls tmp/deploy/spdx/
core-image-product.spdx.json

An SBOM is also exactly the artifact that makes Module 1's CVE-tracking obligation and this module's license-tracking obligation the same underlying data viewed two ways — the component list that tells you what to scan for known vulnerabilities is the same list that tells you what license obligations apply. Building one pipeline that produces both views is far less effort than maintaining them as separate manual processes.

Traps

  • A written GPL source offer whose actual downloadable archive doesn't match the shipped binary — a mismatched patch stack or wrong kernel version in the offered source, discovered by anyone who actually exercises the offer, converts a compliance program into evidence of non-compliance.
  • Treating "it's open source, so it's automatically fine" as a blanket answer. Every license has different obligations; a GPLv3 component buried in a dependency tree can create genuine tension with a secure boot design that nobody flagged until legal review, late in a program.
  • No process for vendor SDK blobs with unclear licensing — silence is not clearance; unresolved license status on a shipped binary component is a real, open risk that a scan will surface but won't resolve on its own.
  • License compliance treated as a one-time pre-launch checklist instead of a per-release artifact — every dependency bump (Module 1's ongoing maintenance work) can introduce a new license into the tree, and the SBOM/manifest needs regenerating every release, not once at launch.

Cheat sheet

Obligation Practice
GPLv2 kernel/tools Written offer + archive matching the exact shipped source, per release
LGPL libraries Dynamic linking preserves proprietary-code exemption; confirm linking mode
GPLv3 components Audit separately — direct tension with secure boot (Module 2)
Unclear-license vendor blobs Scan (scancode), escalate to vendor, don't assume clearance
Ongoing tracking Generate license manifest + SBOM per release, same pipeline as CVE data

On verification

License obligations summarized here reflect the commonly understood terms of GPLv2/LGPL/MIT/BSD/GPLv3 as documented by their respective license texts and standard OSS compliance practice, and the Yocto populate_lic/SPDX tooling described follows documented BitBake conventions; this module is not legal advice — a real product's compliance program should involve counsel, and no license scan was actually run on this machine.

How It Actually Works

GPLv2's "distribution" trigger is a legal event tied to what leaves your premises, and the kernel's own build mechanics are what make "corresponding source" a precise, checkable artifact. GPLv2 §3 requires that anyone you convey the binary to also receive (or be offered, in writing, for at least three years) the exact source corresponding to that binary — which for a Yocto/Buildroot build means the specific recipe/patch set and .config that produced the shipped zImage/modules, not "the kernel.org tree" in general, because the kernel's own Kconfig-driven build (module 3) means two different .configs from identical source produce meaningfully different binaries. This is precisely why reproducible builds (module 1) and license compliance intersect in practice: proving "this is the exact source for this exact binary" is a build-reproducibility claim as much as a legal one.

License scanning tools work by matching license text/SPDX identifiers against every source file BitBake actually pulled in, not by inspecting your own code. Tools like oe-core's LICENSE/LIC_FILES_CHKSUM mechanism checksum each recipe's declared license file at parse time and fail the build if it changes unexpectedly (catching an upstream license change silently flowing into your product), while broader scanners (FOSSology-style) walk the fetched source tree file-by-file, pattern- matching against a known corpus of license texts to catch code that carries a different license than its containing package declares — which happens more often than expected, since a single upstream tarball can bundle vendored code under a different license than the project's own top-level LICENSE file states.

An SBOM is a machine-readable dependency graph the same package- manager metadata Yocto already tracks internally can generate almost for free. create-spdx/similar Yocto classes walk the same RDEPENDS/DEPENDS graph BitBake's task scheduler already built to order the build (module 1's dependency DAG, again) and emit it as an SPDX or CycloneDX document — package name, version, license, and hash per component — because that dependency graph already is a complete bill of materials; the SBOM tooling's job is serializing existing build metadata into a standard auditor-readable format, not independently re-discovering what's in the image.

Exercise

(1) Write the written GPL source-offer text your product would ship (printed manual, or a settings-menu string) and describe exactly what archive you'd need to keep on hand to honor a request against it a year after that specific release shipped. (2) Given a Yocto license.manifest showing 3 GPLv3 packages in an image for a device with a closed secure boot chain, describe the compliance question you'd raise and to whom. (3) One paragraph: explain why an SBOM built as a side effect of the same pipeline that runs cve_check is a better process than maintaining license and vulnerability tracking as two separate manual spreadsheets.