
MODULE_LICENSE Kernel Strings: GPL vs Proprietary Symbols
MODULE_LICENSE is not paperwork you paste and forget. It's a string the kernel parses at load time to decide two things: whether your module taints the kernel, and whether it can resolve GPL-only exported symbols. Use "GPL" only when the code really is GPL-2.0 compatible, and match one of the exact strings the loader recognizes, like Dual BSD/GPL or Proprietary. Get the identifier wrong, or mismatch it against the SPDX header, and you fail EXPORT_SYMBOL_GPL lookups, get silently tainted, or ship something that isn't legally what you think it is. Verify with modinfo and dmesg. Do not copy a snippet and hope.
Last updated: 2026-07-17
What does the MODULE_LICENSE macro actually do?
It writes a string into a .modinfo section of your .ko file, and the module loader reads that string when you insmod or modprobe. That's the whole mechanism. The macro itself is trivial:
MODULE_LICENSE("GPL");
Here is what happens at load time. The kernel compares your string against a fixed list it knows about. If the string means "this is free software the kernel accepts as GPL-compatible," you get full access to symbols exported with EXPORT_SYMBOL_GPL. If the string is unknown or proprietary, the loader sets a taint flag and denies those symbols.
The comparison is exact-match, not fuzzy. "GPL" works. "gpl" does not. "GPLv2" does not. A typo here fails quietly, so the module loads tainted and you spend an hour wondering why a symbol won't resolve. Check the string first.
Which MODULE_LICENSE string should you use?
Match the string to what your code actually is, not what you wish it were. The kernel recognizes a specific set, and each one carries meaning:
| String | Use it when | GPL-only symbols |
|---|---|---|
GPL | Code is GPL-2.0 or later, GPL-compatible | Yes |
GPL v2 | You mean GPL-2.0 specifically | Yes |
Dual BSD/GPL | Dual-licensed BSD and GPL | Yes |
Dual MIT/GPL | Dual-licensed MIT and GPL | Yes |
Dual MPL/GPL | Dual-licensed Mozilla and GPL | Yes |
Proprietary | Closed source, no GPL claim | No, taints kernel |
The GPL versus GPL v2 distinction trips people up. Both grant symbol access. GPL covers GPL-2.0-or-later, while GPL v2 pins to version 2 only. If your source header says one thing and your macro says another, you've created a contradiction a reviewer will bounce.
One rule I hold to: the MODULE_LICENSE string is a runtime declaration, not your legal license. It tells the loader how to treat you. Your SPDX tag and LICENSE file are what actually govern the code. Keep them consistent or you're lying to one of the two systems.
What breaks if you pick the wrong string or omit it
Two failures show up, and both are diagnosable. The first is a taint flag. The second is a symbol lookup that returns nothing.
Omit MODULE_LICENSE entirely and the kernel treats the module as proprietary. You'll see a line in dmesg like module xyz: loading out-of-tree module taints kernel followed by a note about it having no license. Run dmesg | grep -i taint right after load and the message is sitting there.
The symbol failure is nastier because it looks like a build problem. EXPORT_SYMBOL and EXPORT_SYMBOL_GPL export symbols differently: the former are available to any kernel module, while the latter cannot be used by any modules which do not carry a GPL-compatible license. A mislabeled module hits Unknown symbol in dmesg and refuses to insert. People chase missing headers for an hour. The real problem is the license string denied access to a symbol that's right there in /proc/kallsyms.
Check the taint state directly with cat /proc/sys/kernel/tainted. A nonzero value means something tainted the running kernel, and the bitmask tells you what. A proprietary module sets bit zero. That number is your evidence, not a guess.
How does MODULE_LICENSE relate to the kernel's own license?
The Linux kernel is released under GNU General Public License version 2 only, written as GPL-2.0-only. That single fact drives everything downstream. Your module runs inside GPL-2.0 code and calls into it, so the kernel enforces a boundary on what non-GPL modules may touch.
MODULE_LICENSE is how you declare which side of that boundary you're on. Say GPL and the kernel treats your module as part of the free-software commons and hands over the GPL-only symbols. Say Proprietary and it fences you off from those symbols and marks the kernel as tainted so bug reports carry that context.
This is not the kernel deciding your legal status. It's the kernel enforcing a technical policy that reflects the license. If you distribute a derivative work of GPL-2.0 code, GPL-2.0 terms apply whether or not your string says so. The string just controls runtime behavior. For the deeper obligations, I've written separately on how to ensure GPL compliance in kernel code.
Where the kernel's license is officially declared
Stop trusting secondhand claims about kernel licensing and read the source tree. The authoritative statement lives in the COPYING file at the root of the kernel source. Modern trees point that file at the LICENSES/ directory, which holds the full text of every license used and its SPDX identifier.
The kernel's official position is GPL-2.0-only with a syscall exception for user-space. That's in the documentation under Documentation/process/license-rules.rst, and it's the file I send people to when they argue about whether the kernel is "GPL v2 or later." It is not. It is version 2 only. The kernel licensing rules documentation is the primary source, and it settles the argument.
Every new source file now carries an SPDX tag on line one, so you can read a single file's license without hunting through COPYING. That convention is what the next section is about.
How SPDX identifiers relate to the MODULE_LICENSE macro
They solve different problems and you need both. The SPDX-License-Identifier goes on the first line of every source file as a single-line comment, and it declares the file's actual license to compliance tools and humans. The format is strict:
// SPDX-License-Identifier: GPL-2.0
For C headers or scripts the comment leader changes, but the tag stays on line one. That placement is not decoration. Tooling like checkpatch.pl reads that exact position, so a tag on line three might as well not exist.
Here is the split that matters. The SPDX tag is compile-time metadata for tools. MODULE_LICENSE is runtime metadata for the kernel loader. One does not replace the other. You write the SPDX tag so license scanners understand your source, and you write MODULE_LICENSE so the running kernel knows how to treat your loaded module.
When they disagree, you have a bug. An SPDX tag of GPL-2.0 with a MODULE_LICENSE of Proprietary says one thing to scancode and the opposite to insmod. Keep the pair aligned across every file.
Can you dual-license a module, and which combinations work?
Yes, and the kernel gives you named strings for the common cases: Dual BSD/GPL, Dual MIT/GPL, and Dual MPL/GPL. All three grant GPL-only symbol access because one arm of the dual license is GPL-2.0 compatible. That compatible arm is the whole point.
Dual licensing means a downstream user may take your code under either license. Someone building a proprietary product picks the BSD or MIT arm. Meanwhile, someone in the GPL world picks GPL. Your module still loads with full symbol access because the kernel sees the GPL arm and is satisfied.
In your source headers, express the same thing with SPDX OR syntax:
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
Compatibility is the catch. Dual-licensing only works when both arms are licenses you actually hold the rights to grant, and when the non-GPL arm is genuinely permissive. Dual BSD/GPL is well-trodden. Bolting GPL onto a license with conflicting terms is not dual licensing, it's a legal mess. If patents are in play, read my comparison of Apache versus GPL for Linux drivers first, because Apache-2.0 and GPL-2.0 have a known compatibility wrinkle.
Why UAPI headers don't make your user-space code GPL
Because the kernel carves out an explicit exception, and without it every program that made a syscall would arguably be a GPL derivative. That would be absurd, so the kernel says so in writing.
User-space API headers, the ones under include/uapi/, carry the tag GPL-2.0 WITH Linux-syscall-note. That WITH clause is the syscall exception. It means using those headers to talk to the kernel does not drag your program under GPL-2.0. Your closed-source application can call open() and ioctl() all day and stay closed.
The boundary is the syscall interface. Code that runs in kernel space and links against kernel symbols is bound by GPL-2.0. Code that runs in user space and only crosses the syscall boundary is not. Keep those two straight. The exception protects normal applications, not out-of-tree modules trying to dodge copyleft by claiming they only "use an interface."
Should you add MODULE_DESCRIPTION and MODULE_AUTHOR?
Add MODULE_DESCRIPTION, always. Recent kernels emit a build warning when it's missing, and some trees are moving toward failing the build outright. It's one line and it saves you a W=1 warning:
MODULE_DESCRIPTION("Example character driver for widget hardware");
MODULE_AUTHOR("Your Name <[email protected]>");
MODULE_AUTHOR is optional and I still write it, because modinfo shows it and it tells the next maintainer who to blame. Neither macro affects taint or symbol access. They're metadata, pure and simple.
MODULE_DESCRIPTION is getting mandatory because the kernel team wants every module self-documenting. A .ko file with no description is a black box in a bug report. Write the line. It costs nothing and stops the warning.
The NVIDIA installer asks: proprietary or MIT/GPL kernel modules?
Pick MIT/GPL if your GPU supports it, which covers most recent NVIDIA hardware. When the installer prints "multiple kernel module types are available for this system, which would you like to use, NVIDIA proprietary or MIT/GPL," it's asking which flavor of the driver's kernel-space component to build.
The MIT/GPL modules ship an open kernel-space part that carries a Dual MIT/GPL license string. As a result, it resolves GPL-only symbols, taints the kernel less aggressively, and gives you readable stack traces when something breaks. The proprietary variant is the older closed blob. It still loads and runs, but it sets the taint flag and hands you worse debugging context.
There's a hardware line, though. The open MIT/GPL modules need a recent enough GPU, roughly Turing and later. On older cards the proprietary blob is your only working option, so the installer may not even offer the choice. When both appear, treat MIT/GPL as the default and only fall back to proprietary if your card is too old or a specific feature regresses.
One caveat worth stating: "MIT/GPL" here labels the open kernel module, not the whole driver. The user-space libraries stay closed either way. So this choice changes taint and symbol behavior in the kernel, not the licensing of the parts running in your desktop session.
How to check a module's license without guessing
Run modinfo first. It reads the .modinfo section straight out of the .ko and prints the declared license:
modinfo mymodule.ko | grep license
That tells you exactly what the loader will see. For a module that's already loaded, look under /sys/module/, though the license field there depends on kernel version, so modinfo on the file is the reliable read.
For taint, the two commands I keep in muscle memory are dmesg | grep -i taint and cat /proc/sys/kernel/tainted. The first gives you the human-readable reason a module tainted the kernel. The second gives you the bitmask, which is the machine-readable truth. A proprietary module flips the low bit and the message names the module.
To check the source before you build, grep for both declarations:
grep -rn "MODULE_LICENSE\|SPDX-License-Identifier" .
If the SPDX tag and the MODULE_LICENSE string disagree, you found your inconsistency before the loader did. That's the whole workflow: read the string, read the tag, confirm they match, confirm the taint state is what you expect.
What built-in modules change about license visibility
A module compiled into the kernel with =y instead of =m has no .ko file, so modinfo has nothing to read. The license metadata is still in the source, but the runtime picture changes.
Check modules.builtin in your kernel's module directory to see what got compiled in. Anything listed there is part of the kernel image, not a loadable file. Its MODULE_LICENSE string doesn't gate symbol access the same way, because a built-in module isn't loaded through the path that checks taint.
So when someone asks why modinfo returns nothing for a driver they know exists, the answer is usually that it's built-in. Look in the source tree or modules.builtin instead of hunting for a .ko that was never produced. Built-in code inherits the kernel's own GPL-2.0-only status by virtue of being part of the image.
FAQ
Does MODULE_LICENSE change the legal license of my code?
No. It's a runtime declaration the kernel loader reads, not a legal grant. Your real license comes from the SPDX tag, the LICENSE file, and the copyright headers. The macro only controls whether the kernel taints itself and whether you can resolve GPL-only symbols. Set it to match your actual license, but don't mistake the string for the license itself.
Can I keep an out-of-tree module closed source?
You can build and distribute a proprietary module, but expect two costs. It taints the kernel, and it loses access to every symbol exported with EXPORT_SYMBOL_GPL. Because many core interfaces are GPL-only, a closed module is fenced off from large parts of the kernel. Whether that's legally clean for a derivative work is a separate and contested question. The technical fence is real regardless.
Why does my module fail with "Unknown symbol" only after I added a call?
Because the symbol you're calling was exported GPL-only, and your MODULE_LICENSE string isn't recognized as GPL. Run modinfo on the .ko and confirm the license string is exact. A typo like GPLv2 instead of GPL v2 reads as unknown, denies GPL-only symbols, and produces exactly that Unknown symbol line in dmesg. Fix the string and rebuild.
Where do I put the SPDX tag in a Makefile or shell script?
On the first line, as a # comment. The SPDX-License-Identifier convention requires a single-line comment at the top of the file, and tools read that exact position. In C use // or a /* */ comment on line one; in scripts and Makefiles use #. A tag buried lower won't be picked up by license scanners.
Do I need to keep the SPDX tag and MODULE_LICENSE identical word for word?
No, they use different vocabularies. The SPDX side uses formal identifiers like GPL-2.0 or (GPL-2.0 OR MIT), while MODULE_LICENSE uses the loader's short strings like GPL or Dual MIT/GPL. What matters is that they describe the same license. For example, an SPDX tag of (GPL-2.0 OR MIT) pairs with a MODULE_LICENSE of Dual MIT/GPL, not Proprietary.
