Article: Are non-GPL loadable Linux drivers really u not /u a problem?
Sep 28, 2002 — by LinuxDevices Staff — from the LinuxDevices Archive — 70 viewsThis article by Kevin Dankwardt explores the issue of whether non-GPL loadable Linux drivers are really not a problem. While many Linux developers assume that binary-only drivers are acceptable, there are growing technical reasons to avoid them. New features in tools and in the Linux kernel hamper the acceptability of non-GPL loadable modules. Also, the widely held belief that non-GPL loadable modules do not violate the Linux kernel's GPL license, due to an exception authorized by Linus Torvalds, is called into question.
by Kevin Dankwardt
Linux drivers and the GPL
Some Linux kernel developers do not like non-GPL code to make use of the Linux kernel interface. To discourage such non-GPL code, the Linux kernel provides two mechanisms: a 'tainted' flag and GPL-use-only exported symbols. The interface to which we refer is the use of exported symbols for code linked, statically, or dynamically to the kernel. It appears clear that applications in user-space, that simply make system calls, are not affected by the GPL licensing of the Linux kernel.
It is generally accepted that code directly linked into a Linux kernel, via what is commonly known as 'statically linking', must be licensed under the GPL. Further, it is also commonly believed that code working with the Linux kernel via what is known as the dynamically loadable module method need not be GPL licensed.
Many Linux aficionados take 'need not be GPL licensed' to mean that there is no legal nor Linux technical requirement to do so. We will discuss the Linux technical reasons to do so in this article. We also note, that any capabilities that the Linux kernel, or utilities like BusyBox or modutils, employ to restrict usage by non-GPL licensed software, can, of course, be defeated by modifying such software. We do not discuss the legality nor the ethicality of such modifications.
Belief that loadable modules need not be GPL licensed seems to come from two sources. One source is consistent interpretation as such in the industry. That is, many developers believe, because they hear others say so, that loadable modules need not be GPL licensed and they act accordingly. This belief has been communicated to me personally by numerous CTOs, corporate counsels, and VPs of Engineering.
LinuxDevices.com published an earlier article by Jerry Epplin which details issues and circumstances concerning the GPL and loadable modules. In the article, Epplin cautions developers to GPL their loadable modules, points out that the issue can be a bit complicated, and mentions that some developers feel justified in releasing binary-only drivers.
Epplin writes “And the kernel developers have consistently supported this interpretation [non-GPL loadable modules are acceptable] by tolerating, albeit reluctantly, the presence of proprietary hardware drivers. This tolerance of proprietary drivers has held for a very long time, and numerous hardware manufacturers are currently depending on it.” “But,” Epplin goes on to say “some kernel developers have questioned Linus' authority to issue this GPL exception.”
Matt Asay, in a paper about the GPL and Linux wrote “This reading of the GPL [that it is OK to have non-GPL loadable modules] has become so prevalent in the past year that Stallman's opinion on the matter is largely irrelevant.” Richard Stallman is a primary proponent of the GPL.
Recent additions to the Linux kernel and the utilities that manage loadable modules are efforts by Linux kernel developers, and others, to discourage non-GPL loadable modules. Perhaps the prior lack of such efforts was because those so inclined were not yet sufficiently motivated to do so because they had other work they considered more important.
The second source is Linus Torvalds. Remarks by Linus Torvalds, inventor of Linux and copyright holder on only some of the Linux kernel, do address this issue. In an email, Torvalds describes his position . . .
I personally consider anything a “derived work” that needs special hooks in the kernel to function with Linux (ie it is _not_ acceptable to make a small piece of GPL-code as a hook for the larger piece), as that obviously implies that the bigger module needs “help” from the main kernel.
Similarly, I consider anything that has intimate knowledge about kernel internals to be a derived work.
What is left in the gray area tends to be clearly separate modules: code that had a life outside Linux from the beginning, and that do something self-containted [SIC] that doesn't really have any impact on the rest of the kernel. A device driver that was originally written for something else, and that doesn't need any but the standard UNIX read/write kind of interfaces, for example.
These statements seem to clearly say that, in Torvalds', opinion, merely being a dynamically loaded module is not sufficient justification for not GPLing code.
Loadable Kernel Modules
The Linux kernel allows kernel level code to be added at run-time. That is, after Linux has booted, additional functionality, such as device drivers, can be loaded into the kernel from object files from a file system. While loadable modules are most commonly used to add device drivers, such as network or sound card support, it is a general mechanism where other functionality, for example, real-time operating system APIs, new system calls, or file system support can be added.
When a loadable module is inserted into the kernel it must go through what is essentially a link step. Any external names it references, such as kernel functions and data structures, must be resolved.
Loadable modules are normally inserted into the kernel via the commands insmod or modprobe — which make the system call create_module().
Developing and inserting a kernel loadable module is a simple process. A kernel loadable module skeleton can simply be . . .
#include linux/module.h
#include linux/kernel.h
int init_module(void) {
printk("hello, loadable module worldn");
return 0;
}
void cleanup_module(void) {
printk("Goodbye kind worldn");
}
This can be compiled with: gcc -c -O -D__KERNEL__ -DMODULE testmodule.c -Isource code include directory
. Where source code include directory
is the path name to the include directory that goes with the kernel source for which the module is to be compiled.
While running the appropriate kernel, the module could be inserted with 'insmod testmodule.o'. Modules that are inserted can be listed with the command lsmod and removed with the command rmmod.
Since kernel data structures may change from kernel release to kernel release, modules must be compiled for the exact kernel release for which they are to be inserted. The insmod command option '-f' can be used to force module insertion by overriding version checking. A forced module still must have all of its external names resolved so a module written for another kernel version may still fail to load. A forced module taints the kernel with newer kernels and modutils.
Tainting
In order to have a running Linux kernel remember whether modules have been force inserted or had non-GPL (or dual BSD/GPL) licensed modules loaded, the Linux kernel maintains a write-once flag: /proc/sys/kernel/tainted. This tainted flag is non-zero if a module has been force loaded or a module that has not declared itself to be acceptably licensed is loaded. A third value for the tainted flag is set when an unacceptable combination of AMD processors is chosen for SMP.
The setting of the tainted flag for non-GPL or forced load is done by the commands insmod and modprobe from the modutils package as of release 2.4.9. In a recent release of BusyBox (September, 2002, version 0.60.4), the tainting is set, in its version of insmod. The BusyBox version of insmod is commonly used in embedded Linux systems.
The tainted flag was added to the Linux kernel as of release 2.4.9-ac9. The reason for the creation of this flag and having non-GPL module loading set it is seen in a quote from Alan Cox: “Unfortunately I get so many bug reports caused by the nvidia modules and people lying when asked if they have them loaded that some kind of action has to occur, otherwise I'm going to have to stop reading bug reports from anyone I don't know personally.”
The main problem thus seems to be that kernel maintainers such as Alan Cox are hampered by kernel level code whose source they cannot examine when investigating bug reports. Thus, the setting of the tainted flag is reported in kernel panics and OOPSes.
A module is declared to be GPL licensed by the inclusion of the statement MODULE_LICENSE(“GPL”) in the source code. Often as the last line in the file. For example . . .
#include linux/module.h
#include linux/kernel.h
int init_module(void) {
printk("hello, loadable module worldn");
return 0;
}
void cleanup_module(void) {
printk("Goodbye kind worldn");
}
MODULE_LICENSE("GPL");
Inserting a non-GPL module in a recent kernel, and suitable version of insmod, results in an error message that says: “Warning: loading testmodule will taint the kernel: no license…” Note that this is more than a warning, the kernel has been tainted and will remain so until it is rebooted.
GPL-only symbols
A related issue is that of exporting kernel symbols for use with only GPL licensed code. Code written as part of a statically linked kernel or as part of a dynamically loadable module can export symbols. These symbols are for use of other parts of the statically linked kernel or for modules to be inserted afterward.
In the latest development version of the Linux kernel, 2.5.38, there are four symbols (out of 437) in kernel/ksyms.c that are exported as EXPORT_SYMBOL_GPL. Thus, it appears that exporting of symbols as restricted to GPL is not common. One can grep /proc/ksyms for GPLONLY to see if your running kernel exports any GPLONLY symbols.
The FAQ entry about GPLONLY symbols says: “Note that Linus has stated that existing symbols will not be switched to GPL-only.”
As an example . . .
#define EXPORT_SYMTAB
#include linux/config.h
#if defined(CONFIG_MODVERSIONS) &&!defined(MODVERSIONS)
#define MODVERSIONS
#endif
#ifdef MODVERSIONS
#include linux/modversions.h
#endif
#include linux/module.h
#include linux/kernel.h
int init_module()
{
return 0;
}
void module_exit()
{}
void testmodule_print_message()
{
printk("Hello, in testmodule_print_messagen");
}
EXPORT_SYMBOL_GPL(testmodule_print_message);
MODULE_LICENSE("GPL");
The function testmodule_print_message() can be called from a GPL licensed module like the following . . .
#define EXPORT_SYMTAB
#include linux/config.h
#if defined(CONFIG_MODVERSIONS) &&!defined(MODVERSIONS)
#define MODVERSIONS
#endif
#ifdef MODVERSIONS
#include linux/modversions.h
#endif
#include linux/module.h
#include linux/kernel.h
MODULE_LICENSE("GPL");
extern void testmodule_print_message(void);
int init_module()
{
testmodule_print_message();
return 0;
}
void module_exit()
{}
The function testmodule_print_message() is callable only from GPL-licensed modules that are loaded after the module that defines it. The file /proc/ksyms will report the symbol as GPLONLY_testmodule_print_message. Attempting to call the function from non-GPL code results in an error message like the following from a suitable version of insmod . . .
# insmod ./call_non_gpl.o
./call_non_gpl.o: unresolved symbol testmodule_print_message
./call_non_gpl.o:
Hint: You are trying to load a module without a GPL compatible
license and it has unresolved symbols. The module may be
trying to access GPLONLY symbols but the problem is more
likely to be a coding or user error. Contact the module
supplier for assistance, only they can help you.
Conclusion
While it is generally believed that non-GPLed Linux kernel loadable modules are acceptable, there are two mechanisms in Linux that hamper them. The tainted flag is used to record, among other things, that a non-GPL module has been loaded. Any subsequent dumps from the kernel will be marked as tainted and therefore may not be accepted in bug reports to some kernel developers.
Symbols exported as EXPORT_SYMBOL_GPL() may not be linked to via non-GPL code. This explicitly prevents non-GPL code from using some symbols in the Linux kernel.
About the author: Kevin Dankwardt is founder and President of K Computing, a training and consulting firm. He has spent most of the last 9 years designing, developing, and delivering technical training for such subjects as Unix system programming, Linux device drivers, real- time programming, and parallel-programming for various organizations world-wide. He received his Ph.D. in Computer Science, in 1988.
This article was originally published on LinuxDevices.com and has been donated to the open source community by QuinStreet Inc. Please visit LinuxToday.com for up-to-date news and articles about Linux and open source.