
Where Linux Kernel GPLv2 Licensing Is Defined
Read the COPYING file at the root of the kernel tree and you have the official answer: it declares GPL-2.0 WITH Linux-syscall-note, which means the GNU General Public License version 2 only, per the text in LICENSES/preferred/GPL-2.0. Everything else people argue about is narrower. Per-file SPDX tags, exported UAPI headers, and the MODULE_LICENSE kernel strings that decide GPL versus proprietary symbol access are classifications inside that license, not exits from it.
Last updated: 2026-08-02
Where is the Linux kernel's GPLv2 license officially documented?
In the source tree, in three places, and I read them in this order. First COPYING at the top level, which carries the SPDX expression above. Second the LICENSES/ directory, which holds the full text of each license the tree uses, including LICENSES/preferred/GPL-2.0. Third Documentation/process/license-rules.rst, which is where the project spells out how files are tagged.
The exception that people quote out of context has its own file: LICENSES/exceptions/Linux-syscall-note. Read that file before you repeat what someone told you it says. It is short, and it is specific about the syscall boundary.
Blog summaries, including this one, are secondary. If a claim about kernel licensing matters to you legally or commercially, the tree is the evidence and a lawyer is the interpreter.
GPL-2.0-only is not the same as GPL-2.0-or-later
The kernel is version 2 only. That is the whole point of the "only" in the identifier, and LICENSES/preferred/GPL-2.0 is the text it points at. An "or later" grant would let a downstream recipient take the code under a newer version of the GPL instead. The kernel does not offer that choice, so do not assume it.
This matters when you write your own file headers. If you tag a file GPL-2.0-or-later because you copied the tag from somewhere, you granted something you may not have meant to grant. Pick the identifier from the official SPDX license list and mean it.
What COPYING covers, and what it does not
The license in COPYING applies to the kernel source as a whole. Individual source files may carry a different license, as long as it is GPL-2.0 compatible. That is stated in the kernel's own licensing rules, and it is the single most misread sentence in this whole subject.
So a file tagged (GPL-2.0 OR BSD-3-Clause) is not a hole in the kernel's copyleft. It is a file the author chose to offer under two sets of terms, one of which is compatible with the rest of the tree. Reuse under the permissive arm is a question about that file, and only that file.
When COPYING and a file tag appear to disagree, they usually are not disagreeing. The top-level file describes the distribution; the tag describes one file. Read both, then read the license text in LICENSES/ that the tag names.
The syscall note covers userspace, and nothing more
Linux-syscall-note exists so that normal userspace programs calling into the kernel are not treated as derived works of it. That is why the top-level SPDX expression reads GPL-2.0 WITH Linux-syscall-note. Your shell, your database, your closed-source trading app: all fine, none affected by the kernel's license because they talk to it through system calls.
It is not a general exception for anything that touches kernel code. A loadable module is not on the userspace side of that boundary. It links against kernel symbols, runs in kernel address space, and is analyzed on its own facts.
Why UAPI headers read differently
Headers under include/uapi/ get shipped to userspace and compiled into userspace programs. That is the reason they carry their own SPDX expressions, and why the syscall note shows up on them. Without a narrow exception, including a kernel header to get a struct definition would drag a licensing argument into every program on the system.
Check the actual header you care about rather than assuming. Internal headers elsewhere in the tree do not get the same treatment, and the difference is visible in one line of each file:
grep -m1 "SPDX-License-Identifier" include/uapi/linux/stat.h
grep -m1 "SPDX-License-Identifier" include/linux/sched.h
That comparison tells you more in two seconds than an afternoon of forum reading.
MODULE_LICENSE kernel strings: GPL vs proprietary symbols
MODULE_LICENSE is a runtime declaration the loader parses, and the match is exact. It writes a string into the .modinfo section of your .ko, and insmod compares it against a fixed list. Get the string right and you keep access to symbols exported with EXPORT_SYMBOL_GPL. Get it wrong and the kernel treats you as proprietary.
The idents the kernel accepts as indicating free software modules are "GPL", "GPL v2", "GPL and additional rights", "Dual BSD/GPL", "Dual MIT/GPL", and "Dual MPL/GPL". The other available ident is "Proprietary".
| MODULE_LICENSE string | What it declares | GPL-only symbols | Taints |
|---|---|---|---|
GPL | Documented in include/linux/module.h as GNU Public License v2 | Yes | No |
GPL v2 | GPL v2, same as above without the "only or later" distinction | Yes | No |
GPL and additional rights | GPL plus extra permissions | Yes | No |
Dual BSD/GPL | Recipient may take BSD or GPL | Yes | No |
Dual MIT/GPL | Recipient may take MIT or GPL | Yes | No |
Dual MPL/GPL | Recipient may take Mozilla or GPL | Yes | No |
Proprietary | Closed source, no GPL claim | No | Yes |
| Macro omitted | Loader sees no license at all | No | Yes |
One correction worth making, because plenty of older writing on this gets it backwards. In current mainline include/linux/module.h, "GPL" is documented as GNU Public License v2, not "v2 or later". Both "GPL" and "GPL v2" state the module is under GPL v2 without indicating only versus or-later. So neither string encodes the distinction your SPDX tag encodes, and neither one silently upgrades you.
My rule: pick the ident that matches your file's SPDX tag in meaning, then let the tag carry the precision. If your headers say GPL-2.0-only, "GPL v2" is the string I would write, because it reads unambiguously to the next human who opens the file.
What breaks when the string is wrong

Two failures, and both are visible in logs. The first is taint. The second is a symbol that will not resolve.
When nf_reject_ipv4 omits the macro, the kernel says so in plain language: module license 'unspecified' taints kernel. That line sits in dmesg right after the load, so look there before you theorize. The symbol failure is the one that wastes people's evenings. EXPORT_SYMBOL is available to any module, while EXPORT_SYMBOL_GPL is not usable by modules without a GPL-compatible license.
The symptom is Unknown symbol on insert, right after you added one function call. The symbol is in /proc/kallsyms and the header is fine. The real problem is your license string, so check it before you touch the build system.
Read the taint bitmask instead of guessing
cat /proc/sys/kernel/tainted gives you a number, and the number is a bitmask. Two bits matter for licensing questions. Bit 0 has value 1 and shows as the log character 'P': a proprietary module was loaded. Bit 12 has value 4096 and shows as 'O': an externally built, out-of-tree module was loaded.
Decoding by hand gets old, so use the script that ships with the kernel. tools/debugging/kernel-chktaint prints the proprietary module taint as "(#0)" and the out-of-tree module taint as "(#12)". That output is evidence you can paste into a bug report.
For the module in front of you, start here:
modinfo -F license ./mymodule.ko
dmesg | grep -iE "taint|unknown symbol"
cat /proc/sys/kernel/tainted
The first command tells you what you actually shipped, which is not always what you think you wrote.
How to verify a licensing question in the tree
Work from the file outward. Naming the exact path first saves you from answering a question about a different file than the one that matters.
- Read
COPYINGfor the distribution-level license. - Find the SPDX tag in the specific file you care about.
- Read the matching text under
LICENSES/, including any exception file the tag names. - Confirm the macro and the tag agree in meaning, not in spelling.
- Load the module and read
dmesgand the taint value to see what the kernel concluded.
Step five is the one people skip. Static reading tells you what you intended; the loader tells you what you produced. If those disagree, trust the loader and fix the source.
The kernel requires precise SPDX identifiers in its source files, with valid identifiers taken from the official SPDX list rather than invented. Comment style differs by file type, and the placement rules live in the licensing rules document. Read that document once instead of copying a tag from whatever file you had open.
The NVIDIA installer question, answered plainly
Take the open modules. NVIDIA's open kernel modules are kernel modules with full MIT/GPLv2 source code, and no functional difference is expected against the proprietary flavor. Same hardware support, source you can read when a load fails.
Be clear about the scope of that word "open", though. The user space components and the GPU firmware remain proprietary. So the open modules improve your debugging life and your GPL story at the module boundary; they do not turn the driver stack into free software.
"Linux" the system versus the Linux kernel
These are different licensing questions and mixing them causes most of the confusion I see. The kernel's license is the one declared in COPYING. A distribution is thousands of separate packages, each with its own license, shipped together.
Compilers, shells, desktop environments, libraries, and redistributable firmware blobs all carry their own terms. Some are copyleft, many are permissive, and a few are not free software at all. The kernel's version-2-only licensing says nothing about any of them.
For compliance work, that means your obligations are per component. If you are choosing terms for your own code that sits next to the kernel, my writeup on Apache and GPL compatibility for drivers covers the wrinkle people hit first, and the LGPL's linking rules explain why library code is treated differently. If you are starting from scratch, read how to choose an open source license before you write a line.
FAQ
Can I license a kernel module under GPL version 3?
The loader has no ident for it. Your string has to match one of the accepted values exactly, and a version 3 declaration is not among them, so the module gets treated as not GPL-compatible and loses the restricted symbols. The legal analysis of a version 3 module against a version 2 only kernel is a separate question, and one for a lawyer reading the GNU General Public License version 2 text itself.
Do the SPDX tag and the MODULE_LICENSE string have to match word for word?
No, and they cannot. They draw from different vocabularies: SPDX identifiers come from the official SPDX list, while the macro accepts a short fixed set the loader knows. What they must do is agree in meaning. A scanner reading one thing and insmod reading the opposite is a defect a reviewer should catch.
Where does the SPDX tag go in a Makefile or a shell script?
Use the comment leader that file type understands, which is # for Makefiles and scripts rather than the // you use in C. The kernel's licensing rules document specifies the exact form for each file type. Read it there instead of copying from a neighboring file, because plenty of older files predate the current convention.
Does built-in code still need MODULE_LICENSE?
Keep the macro. When the code is compiled into the kernel image, there is no .ko for the loader to inspect, so nothing consults the string at boot. The moment someone builds that same source as a module, though, the string is what governs symbol access and taint. Either way, the file's SPDX tag is what states the license.
