Summary of modules changes for the 5.9 merge window:
 
 - Have modules that use symbols from proprietary modules inherit the
   TAINT_PROPRIETARY_MODULE taint, in an effort to prevent GPL shim modules that
   are used to circumvent _GPL exports. These are modules that claim to be GPL
   licensed while also using symbols from proprietary modules. Such modules will
   be rejected while non-GPL modules will inherit the proprietary taint.
 
 - Module export space cleanup. Unexport symbols that are unused outside of
   module.c or otherwise used in only built-in code.
 
 Signed-off-by: Jessica Yu <jeyu@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCAAuFiEEVrp26glSWYuDNrCUwEV+OM47wXIFAl82YAUQHGpleXVAa2Vy
 bmVsLm9yZwAKCRDARX44zjvBcnlfD/9RFOhmBfk6BUQTbmJSjNUn9ym7sxjVw/yC
 bPEo8DPvZ0FwJ4867fkArPqHQCvOxM41rJkIlDsRycq8jbTsMTZXcfzB0SDyI1ew
 SadQMH5PJqt4lgMDLLk94gM6Oe19Nrq5ICC2WEvif3WLDczjD1tycKERql//WWob
 du7A7wm0IHljUHyTbuM89vZpGO01291Si1UAk9Mzd3HE2yAMCq0KGKbdSZMaQp+O
 2lbn5M8RpQk27gmmmrpHetGkqRlR87/nuw5B4196dBj/eCuHiwFzH+jgV5HPjQHh
 UL1plGa7Bzote7xAPVIkN7vuk4eKHV0ddZ+ATPT6dTqowtX3T0ZnAIp0BdPF8lHK
 5rFSrSSEvDSF+uQ96NQLlaZsUnnfs5vEsWnWTyGk3L+WSGUmyjTCrOi8Ys6Hq7gv
 ZsHFaY+DfHS3DMxqeycDAMNE1mtD96Kc/fTS6JQ2CCS/J8SwdMSOFC5NGynHZnRx
 lwLEgxnu2YjnCWNc5LdhmUOj8jokkWjwczNHDBNSw0bxNGnzu8kZzNbOWUvcPlq3
 DQ6ZfcU2/R443QoiOKIpHplwx07KtOgnpOIpRzj6GELi1mXGLkZR7pESOjvb5qAM
 zFLUgFfRB54is9PzpfyKC+lo63TejcbwjC3wpVXf8MbQiDtnaPB8VazWk17cGJxp
 /vMliSQF5w==
 =Qlem
 -----END PGP SIGNATURE-----

Merge tag 'modules-for-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux

Pull module updates from Jessica Yu:
 "The most important change would be Christoph Hellwig's patch
  implementing proprietary taint inheritance, in an effort to discourage
  the creation of GPL "shim" modules that interface between GPL symbols
  and proprietary symbols.

  Summary:

   - Have modules that use symbols from proprietary modules inherit the
     TAINT_PROPRIETARY_MODULE taint, in an effort to prevent GPL shim
     modules that are used to circumvent _GPL exports. These are modules
     that claim to be GPL licensed while also using symbols from
     proprietary modules. Such modules will be rejected while non-GPL
     modules will inherit the proprietary taint.

   - Module export space cleanup. Unexport symbols that are unused
     outside of module.c or otherwise used in only built-in code"

* tag 'modules-for-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu/linux:
  modules: inherit TAINT_PROPRIETARY_MODULE
  modules: return licensing information from find_symbol
  modules: rename the licence field in struct symsearch to license
  modules: unexport __module_address
  modules: unexport __module_text_address
  modules: mark each_symbol_section static
  modules: mark find_symbol static
  modules: mark ref_module static
  modules: linux/moduleparam.h: drop duplicated word in a comment
This commit is contained in:
Linus Torvalds 2020-08-14 11:07:02 -07:00
Родитель 32b2ee5cea 262e6ae708
Коммит 0fd9cc6b0c
3 изменённых файлов: 47 добавлений и 41 удалений

Просмотреть файл

@ -389,6 +389,7 @@ struct module {
unsigned int num_gpl_syms; unsigned int num_gpl_syms;
const struct kernel_symbol *gpl_syms; const struct kernel_symbol *gpl_syms;
const s32 *gpl_crcs; const s32 *gpl_crcs;
bool using_gplonly_symbols;
#ifdef CONFIG_UNUSED_SYMBOLS #ifdef CONFIG_UNUSED_SYMBOLS
/* unused exported symbols. */ /* unused exported symbols. */
@ -582,34 +583,14 @@ struct module *find_module(const char *name);
struct symsearch { struct symsearch {
const struct kernel_symbol *start, *stop; const struct kernel_symbol *start, *stop;
const s32 *crcs; const s32 *crcs;
enum { enum mod_license {
NOT_GPL_ONLY, NOT_GPL_ONLY,
GPL_ONLY, GPL_ONLY,
WILL_BE_GPL_ONLY, WILL_BE_GPL_ONLY,
} licence; } license;
bool unused; bool unused;
}; };
/*
* Search for an exported symbol by name.
*
* Must be called with module_mutex held or preemption disabled.
*/
const struct kernel_symbol *find_symbol(const char *name,
struct module **owner,
const s32 **crc,
bool gplok,
bool warn);
/*
* Walk the exported symbol table
*
* Must be called with module_mutex held or preemption disabled.
*/
bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
struct module *owner,
void *data), void *data);
/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
symnum out of range. */ symnum out of range. */
int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
@ -657,7 +638,6 @@ static inline void __module_get(struct module *module)
#define symbol_put_addr(p) do { } while (0) #define symbol_put_addr(p) do { } while (0)
#endif /* CONFIG_MODULE_UNLOAD */ #endif /* CONFIG_MODULE_UNLOAD */
int ref_module(struct module *a, struct module *b);
/* This is a #define so the string doesn't get put in every .o file */ /* This is a #define so the string doesn't get put in every .o file */
#define module_name(mod) \ #define module_name(mod) \

Просмотреть файл

@ -108,7 +108,7 @@ struct kparam_array
* ".") the kernel commandline parameter. Note that - is changed to _, so * ".") the kernel commandline parameter. Note that - is changed to _, so
* the user can use "foo-bar=1" even for variable "foo_bar". * the user can use "foo-bar=1" even for variable "foo_bar".
* *
* @perm is 0 if the the variable is not to appear in sysfs, or 0444 * @perm is 0 if the variable is not to appear in sysfs, or 0444
* for world-readable, 0644 for root-writable, etc. Note that if it * for world-readable, 0644 for root-writable, etc. Note that if it
* is writable, you may need to use kernel_param_lock() around * is writable, you may need to use kernel_param_lock() around
* accesses (esp. charp, which can be kfreed when it changes). * accesses (esp. charp, which can be kfreed when it changes).

Просмотреть файл

@ -422,7 +422,7 @@ static bool each_symbol_in_section(const struct symsearch *arr,
} }
/* Returns true as soon as fn returns true, otherwise false. */ /* Returns true as soon as fn returns true, otherwise false. */
bool each_symbol_section(bool (*fn)(const struct symsearch *arr, static bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
struct module *owner, struct module *owner,
void *data), void *data),
void *data) void *data)
@ -484,7 +484,6 @@ bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
} }
return false; return false;
} }
EXPORT_SYMBOL_GPL(each_symbol_section);
struct find_symbol_arg { struct find_symbol_arg {
/* Input */ /* Input */
@ -496,6 +495,7 @@ struct find_symbol_arg {
struct module *owner; struct module *owner;
const s32 *crc; const s32 *crc;
const struct kernel_symbol *sym; const struct kernel_symbol *sym;
enum mod_license license;
}; };
static bool check_exported_symbol(const struct symsearch *syms, static bool check_exported_symbol(const struct symsearch *syms,
@ -505,9 +505,9 @@ static bool check_exported_symbol(const struct symsearch *syms,
struct find_symbol_arg *fsa = data; struct find_symbol_arg *fsa = data;
if (!fsa->gplok) { if (!fsa->gplok) {
if (syms->licence == GPL_ONLY) if (syms->license == GPL_ONLY)
return false; return false;
if (syms->licence == WILL_BE_GPL_ONLY && fsa->warn) { if (syms->license == WILL_BE_GPL_ONLY && fsa->warn) {
pr_warn("Symbol %s is being used by a non-GPL module, " pr_warn("Symbol %s is being used by a non-GPL module, "
"which will not be allowed in the future\n", "which will not be allowed in the future\n",
fsa->name); fsa->name);
@ -529,6 +529,7 @@ static bool check_exported_symbol(const struct symsearch *syms,
fsa->owner = owner; fsa->owner = owner;
fsa->crc = symversion(syms->crcs, symnum); fsa->crc = symversion(syms->crcs, symnum);
fsa->sym = &syms->start[symnum]; fsa->sym = &syms->start[symnum];
fsa->license = syms->license;
return true; return true;
} }
@ -585,9 +586,10 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms,
/* Find an exported symbol and return it, along with, (optional) crc and /* Find an exported symbol and return it, along with, (optional) crc and
* (optional) module which owns it. Needs preempt disabled or module_mutex. */ * (optional) module which owns it. Needs preempt disabled or module_mutex. */
const struct kernel_symbol *find_symbol(const char *name, static const struct kernel_symbol *find_symbol(const char *name,
struct module **owner, struct module **owner,
const s32 **crc, const s32 **crc,
enum mod_license *license,
bool gplok, bool gplok,
bool warn) bool warn)
{ {
@ -602,13 +604,14 @@ const struct kernel_symbol *find_symbol(const char *name,
*owner = fsa.owner; *owner = fsa.owner;
if (crc) if (crc)
*crc = fsa.crc; *crc = fsa.crc;
if (license)
*license = fsa.license;
return fsa.sym; return fsa.sym;
} }
pr_debug("Failed to find symbol %s\n", name); pr_debug("Failed to find symbol %s\n", name);
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(find_symbol);
/* /*
* Search for module by name: must hold module_mutex (or preempt disabled * Search for module by name: must hold module_mutex (or preempt disabled
@ -869,7 +872,7 @@ static int add_module_usage(struct module *a, struct module *b)
} }
/* Module a uses b: caller needs module_mutex() */ /* Module a uses b: caller needs module_mutex() */
int ref_module(struct module *a, struct module *b) static int ref_module(struct module *a, struct module *b)
{ {
int err; int err;
@ -888,7 +891,6 @@ int ref_module(struct module *a, struct module *b)
} }
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ref_module);
/* Clear the unload stuff of the module. */ /* Clear the unload stuff of the module. */
static void module_unload_free(struct module *mod) static void module_unload_free(struct module *mod)
@ -1077,7 +1079,7 @@ void __symbol_put(const char *symbol)
struct module *owner; struct module *owner;
preempt_disable(); preempt_disable();
if (!find_symbol(symbol, &owner, NULL, true, false)) if (!find_symbol(symbol, &owner, NULL, NULL, true, false))
BUG(); BUG();
module_put(owner); module_put(owner);
preempt_enable(); preempt_enable();
@ -1169,11 +1171,10 @@ static inline void module_unload_free(struct module *mod)
{ {
} }
int ref_module(struct module *a, struct module *b) static int ref_module(struct module *a, struct module *b)
{ {
return strong_try_module_get(b); return strong_try_module_get(b);
} }
EXPORT_SYMBOL_GPL(ref_module);
static inline int module_unload_init(struct module *mod) static inline int module_unload_init(struct module *mod)
{ {
@ -1356,7 +1357,7 @@ static inline int check_modstruct_version(const struct load_info *info,
* locking is necessary -- use preempt_disable() to placate lockdep. * locking is necessary -- use preempt_disable() to placate lockdep.
*/ */
preempt_disable(); preempt_disable();
if (!find_symbol("module_layout", NULL, &crc, true, false)) { if (!find_symbol("module_layout", NULL, &crc, NULL, true, false)) {
preempt_enable(); preempt_enable();
BUG(); BUG();
} }
@ -1430,6 +1431,24 @@ static int verify_namespace_is_imported(const struct load_info *info,
return 0; return 0;
} }
static bool inherit_taint(struct module *mod, struct module *owner)
{
if (!owner || !test_bit(TAINT_PROPRIETARY_MODULE, &owner->taints))
return true;
if (mod->using_gplonly_symbols) {
pr_err("%s: module using GPL-only symbols uses symbols from proprietary module %s.\n",
mod->name, owner->name);
return false;
}
if (!test_bit(TAINT_PROPRIETARY_MODULE, &mod->taints)) {
pr_warn("%s: module uses symbols from proprietary module %s, inheriting taint.\n",
mod->name, owner->name);
set_bit(TAINT_PROPRIETARY_MODULE, &mod->taints);
}
return true;
}
/* Resolve a symbol for this module. I.e. if we find one, record usage. */ /* Resolve a symbol for this module. I.e. if we find one, record usage. */
static const struct kernel_symbol *resolve_symbol(struct module *mod, static const struct kernel_symbol *resolve_symbol(struct module *mod,
@ -1440,6 +1459,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
struct module *owner; struct module *owner;
const struct kernel_symbol *sym; const struct kernel_symbol *sym;
const s32 *crc; const s32 *crc;
enum mod_license license;
int err; int err;
/* /*
@ -1449,11 +1469,19 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
*/ */
sched_annotate_sleep(); sched_annotate_sleep();
mutex_lock(&module_mutex); mutex_lock(&module_mutex);
sym = find_symbol(name, &owner, &crc, sym = find_symbol(name, &owner, &crc, &license,
!(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true); !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
if (!sym) if (!sym)
goto unlock; goto unlock;
if (license == GPL_ONLY)
mod->using_gplonly_symbols = true;
if (!inherit_taint(mod, owner)) {
sym = NULL;
goto getname;
}
if (!check_version(info, name, mod, crc)) { if (!check_version(info, name, mod, crc)) {
sym = ERR_PTR(-EINVAL); sym = ERR_PTR(-EINVAL);
goto getname; goto getname;
@ -2236,7 +2264,7 @@ void *__symbol_get(const char *symbol)
const struct kernel_symbol *sym; const struct kernel_symbol *sym;
preempt_disable(); preempt_disable();
sym = find_symbol(symbol, &owner, NULL, true, true); sym = find_symbol(symbol, &owner, NULL, NULL, true, true);
if (sym && strong_try_module_get(owner)) if (sym && strong_try_module_get(owner))
sym = NULL; sym = NULL;
preempt_enable(); preempt_enable();
@ -2272,7 +2300,7 @@ static int verify_exported_symbols(struct module *mod)
for (i = 0; i < ARRAY_SIZE(arr); i++) { for (i = 0; i < ARRAY_SIZE(arr); i++) {
for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
if (find_symbol(kernel_symbol_name(s), &owner, NULL, if (find_symbol(kernel_symbol_name(s), &owner, NULL,
true, false)) { NULL, true, false)) {
pr_err("%s: exports duplicate symbol %s" pr_err("%s: exports duplicate symbol %s"
" (owned by %s)\n", " (owned by %s)\n",
mod->name, kernel_symbol_name(s), mod->name, kernel_symbol_name(s),
@ -4489,7 +4517,6 @@ struct module *__module_address(unsigned long addr)
} }
return mod; return mod;
} }
EXPORT_SYMBOL_GPL(__module_address);
/* /*
* is_module_text_address - is this address inside module code? * is_module_text_address - is this address inside module code?
@ -4528,7 +4555,6 @@ struct module *__module_text_address(unsigned long addr)
} }
return mod; return mod;
} }
EXPORT_SYMBOL_GPL(__module_text_address);
/* Don't grab lock, we're oopsing. */ /* Don't grab lock, we're oopsing. */
void print_modules(void) void print_modules(void)