cregit-Linux how code gets into the kernel

Release 4.9 kernel/module.c

Directory: kernel
/*
   Copyright (C) 2002 Richard Henderson
   Copyright (C) 2001 Rusty Russell, 2002, 2010 Rusty Russell IBM.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#include <linux/export.h>
#include <linux/moduleloader.h>
#include <linux/trace_events.h>
#include <linux/init.h>
#include <linux/kallsyms.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/elf.h>
#include <linux/proc_fs.h>
#include <linux/security.h>
#include <linux/seq_file.h>
#include <linux/syscalls.h>
#include <linux/fcntl.h>
#include <linux/rcupdate.h>
#include <linux/capability.h>
#include <linux/cpu.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/vermagic.h>
#include <linux/notifier.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/rculist.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
#include <asm/mmu_context.h>
#include <linux/license.h>
#include <asm/sections.h>
#include <linux/tracepoint.h>
#include <linux/ftrace.h>
#include <linux/livepatch.h>
#include <linux/async.h>
#include <linux/percpu.h>
#include <linux/kmemleak.h>
#include <linux/jump_label.h>
#include <linux/pfn.h>
#include <linux/bsearch.h>
#include <linux/dynamic_debug.h>
#include <uapi/linux/module.h>
#include "module-internal.h"


#define CREATE_TRACE_POINTS
#include <trace/events/module.h>

#ifndef ARCH_SHF_SMALL

#define ARCH_SHF_SMALL 0
#endif

/*
 * Modules' sections will be aligned on page boundaries
 * to ensure complete separation of code and data, but
 * only when CONFIG_DEBUG_SET_MODULE_RONX=y
 */
#ifdef CONFIG_DEBUG_SET_MODULE_RONX

# define debug_align(X) ALIGN(X, PAGE_SIZE)
#else

# define debug_align(X) (X)
#endif

/* If this is set, the section belongs in the init part of the module */

#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))

/*
 * Mutex protects:
 * 1) List of modules (also safely readable with preempt_disable),
 * 2) module_use links,
 * 3) module_addr_min/module_addr_max.
 * (delete and add uses RCU list operations). */

DEFINE_MUTEX(module_mutex);

EXPORT_SYMBOL_GPL(module_mutex);
static LIST_HEAD(modules);

#ifdef CONFIG_MODULES_TREE_LOOKUP

/*
 * Use a latched RB-tree for __module_address(); this allows us to use
 * RCU-sched lookups of the address from any context.
 *
 * This is conditional on PERF_EVENTS || TRACING because those can really hit
 * __module_address() hard by doing a lot of stack unwinding; potentially from
 * NMI context.
 */


static __always_inline unsigned long __mod_tree_val(struct latch_tree_node *n) { struct module_layout *layout = container_of(n, struct module_layout, mtn.node); return (unsigned long)layout->base; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra2871.79%133.33%
rusty russellrusty russell717.95%133.33%
jason wesseljason wessel410.26%133.33%
Total39100.00%3100.00%


static __always_inline unsigned long __mod_tree_size(struct latch_tree_node *n) { struct module_layout *layout = container_of(n, struct module_layout, mtn.node); return (unsigned long)layout->size; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra2974.36%133.33%
rusty russellrusty russell1025.64%266.67%
Total39100.00%3100.00%


static __always_inline bool mod_tree_less(struct latch_tree_node *a, struct latch_tree_node *b) { return __mod_tree_val(a) < __mod_tree_val(b); }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra2071.43%150.00%
rusty russellrusty russell828.57%150.00%
Total28100.00%2100.00%


static __always_inline int mod_tree_comp(void *key, struct latch_tree_node *n) { unsigned long val = (unsigned long)key; unsigned long start, end; start = __mod_tree_val(n); if (val < start) return -1; end = start + __mod_tree_size(n); if (val >= end) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra4868.57%150.00%
rusty russellrusty russell2231.43%150.00%
Total70100.00%2100.00%

static const struct latch_tree_ops mod_tree_ops = { .less = mod_tree_less, .comp = mod_tree_comp, }; static struct mod_tree_root { struct latch_tree_root root; unsigned long addr_min; unsigned long addr_max; } mod_tree __cacheline_aligned = { .addr_min = -1UL, }; #define module_addr_min mod_tree.addr_min #define module_addr_max mod_tree.addr_max
static noinline void __mod_tree_insert(struct mod_tree_node *node) { latch_tree_insert(&node->node, &mod_tree.root, &mod_tree_ops); }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra28100.00%1100.00%
Total28100.00%1100.00%


static void __mod_tree_remove(struct mod_tree_node *node) { latch_tree_erase(&node->node, &mod_tree.root, &mod_tree_ops); }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra27100.00%1100.00%
Total27100.00%1100.00%

/* * These modifications: insert, remove_init and remove; are serialized by the * module_mutex. */
static void mod_tree_insert(struct module *mod) { mod->core_layout.mtn.mod = mod; mod->init_layout.mtn.mod = mod; __mod_tree_insert(&mod->core_layout.mtn); if (mod->init_layout.size) __mod_tree_insert(&mod->init_layout.mtn); }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra4474.58%266.67%
rusty russellrusty russell1525.42%133.33%
Total59100.00%3100.00%


static void mod_tree_remove_init(struct module *mod) { if (mod->init_layout.size) __mod_tree_remove(&mod->init_layout.mtn); }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra2379.31%266.67%
rusty russellrusty russell620.69%133.33%
Total29100.00%3100.00%


static void mod_tree_remove(struct module *mod) { __mod_tree_remove(&mod->core_layout.mtn); mod_tree_remove_init(mod); }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra2388.46%266.67%
rusty russellrusty russell311.54%133.33%
Total26100.00%3100.00%


static struct module *mod_find(unsigned long addr) { struct latch_tree_node *ltn; ltn = latch_tree_find((void *)addr, &mod_tree.root, &mod_tree_ops); if (!ltn) return NULL; return container_of(ltn, struct mod_tree_node, node)->mod; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra57100.00%3100.00%
Total57100.00%3100.00%

#else /* MODULES_TREE_LOOKUP */ static unsigned long module_addr_min = -1UL, module_addr_max = 0;
static void mod_tree_insert(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra10100.00%1100.00%
Total10100.00%1100.00%


static void mod_tree_remove_init(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra10100.00%1100.00%
Total10100.00%1100.00%


static void mod_tree_remove(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra10100.00%1100.00%
Total10100.00%1100.00%


static struct module *mod_find(unsigned long addr) { struct module *mod; list_for_each_entry_rcu(mod, &modules, list) { if (within_module(addr, mod)) return mod; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra42100.00%1100.00%
Total42100.00%1100.00%

#endif /* MODULES_TREE_LOOKUP */ /* * Bounds of module text, for speeding up __module_address. * Protected by module_mutex. */
static void __mod_update_bounds(void *base, unsigned int size) { unsigned long min = (unsigned long)base; unsigned long max = min + size; if (min < module_addr_min) module_addr_min = min; if (max > module_addr_max) module_addr_max = max; }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra52100.00%1100.00%
Total52100.00%1100.00%


static void mod_update_bounds(struct module *mod) { __mod_update_bounds(mod->core_layout.base, mod->core_layout.size); if (mod->init_layout.size) __mod_update_bounds(mod->init_layout.base, mod->init_layout.size); }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra3469.39%150.00%
rusty russellrusty russell1530.61%150.00%
Total49100.00%2100.00%

#ifdef CONFIG_KGDB_KDB struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ #endif /* CONFIG_KGDB_KDB */
static void module_assert_mutex(void) { lockdep_assert_held(&module_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra14100.00%1100.00%
Total14100.00%1100.00%


static void module_assert_mutex_or_preempt(void) { #ifdef CONFIG_LOCKDEP if (unlikely(!debug_locks)) return; WARN_ON_ONCE(!rcu_read_lock_sched_held() && !lockdep_is_held(&module_mutex)); #endif }

Contributors

PersonTokensPropCommitsCommitProp
peter zijlstrapeter zijlstra3597.22%150.00%
steven rostedtsteven rostedt12.78%150.00%
Total36100.00%2100.00%

static bool sig_enforce = IS_ENABLED(CONFIG_MODULE_SIG_FORCE); #ifndef CONFIG_MODULE_SIG_FORCE module_param(sig_enforce, bool_enable_only, 0644); #endif /* !CONFIG_MODULE_SIG_FORCE */ /* Block module loading/unloading? */ int modules_disabled = 0; core_param(nomodule, modules_disabled, bint, 0); /* Waiting for a module to finish initializing? */ static DECLARE_WAIT_QUEUE_HEAD(module_wq); static BLOCKING_NOTIFIER_HEAD(module_notify_list);
int register_module_notifier(struct notifier_block *nb) { return blocking_notifier_chain_register(&module_notify_list, nb); }

Contributors

PersonTokensPropCommitsCommitProp
john levonjohn levon1789.47%150.00%
alan sternalan stern210.53%150.00%
Total19100.00%2100.00%

EXPORT_SYMBOL(register_module_notifier);
int unregister_module_notifier(struct notifier_block *nb) { return blocking_notifier_chain_unregister(&module_notify_list, nb); }

Contributors

PersonTokensPropCommitsCommitProp
john levonjohn levon1789.47%150.00%
alan sternalan stern210.53%150.00%
Total19100.00%2100.00%

EXPORT_SYMBOL(unregister_module_notifier); struct load_info { Elf_Ehdr *hdr; unsigned long len; Elf_Shdr *sechdrs; char *secstrings, *strtab; unsigned long symoffs, stroffs; struct _ddebug *debug; unsigned int num_debug; bool sig_ok; #ifdef CONFIG_KALLSYMS unsigned long mod_kallsyms_init_off; #endif struct { unsigned int sym, str, mod, vers, info, pcpu; } index; }; /* We require a truly strong try_module_get(): 0 means failure due to ongoing or failed initialization etc. */
static inline int strong_try_module_get(struct module *mod) { BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED); if (mod && mod->state == MODULE_STATE_COMING) return -EBUSY; if (try_module_get(mod)) return 0; else return -ENOENT; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell52100.00%3100.00%
Total52100.00%3100.00%


static inline void add_taint_module(struct module *mod, unsigned flag, enum lockdep_ok lockdep_ok) { add_taint(flag, lockdep_ok); mod->taints |= (1U << flag); }

Contributors

PersonTokensPropCommitsCommitProp
florin malitaflorin malita2672.22%133.33%
rusty russellrusty russell616.67%133.33%
andi kleenandi kleen411.11%133.33%
Total36100.00%3100.00%

/* * A thread that wants to hold a reference to a module only while it * is running can call this to safely exit. nfsd and lockd use this. */
void __noreturn __module_put_and_exit(struct module *mod, long code) { module_put(mod); do_exit(code); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell2395.83%150.00%
jiri kosinajiri kosina14.17%150.00%
Total24100.00%2100.00%

EXPORT_SYMBOL(__module_put_and_exit); /* Find a module section: 0 means not found. */
static unsigned int find_sec(const struct load_info *info, const char *name) { unsigned int i; for (i = 1; i < info->hdr->e_shnum; i++) { Elf_Shdr *shdr = &info->sechdrs[i]; /* Alloc bit cleared means "ignore it." */ if ((shdr->sh_flags & SHF_ALLOC) && strcmp(info->secstrings + shdr->sh_name, name) == 0) return i; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell85100.00%2100.00%
Total85100.00%2100.00%

/* Find a module section, or NULL. */
static void *section_addr(const struct load_info *info, const char *name) { /* Section 0 has sh_addr 0. */ return (void *)info->sechdrs[find_sec(info, name)].sh_addr; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell38100.00%2100.00%
Total38100.00%2100.00%

/* Find a module section, or NULL. Fill in number of "objects" in section. */
static void *section_objs(const struct load_info *info, const char *name, size_t object_size, unsigned int *num) { unsigned int sec = find_sec(info, name); /* Section 0 has sh_addr 0 and sh_size 0. */ *num = info->sechdrs[sec].sh_size / object_size; return (void *)info->sechdrs[sec].sh_addr; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell66100.00%2100.00%
Total66100.00%2100.00%

/* Provided by the linker */ extern const struct kernel_symbol __start___ksymtab[]; extern const struct kernel_symbol __stop___ksymtab[]; extern const struct kernel_symbol __start___ksymtab_gpl[]; extern const struct kernel_symbol __stop___ksymtab_gpl[]; extern const struct kernel_symbol __start___ksymtab_gpl_future[]; extern const struct kernel_symbol __stop___ksymtab_gpl_future[]; extern const unsigned long __start___kcrctab[]; extern const unsigned long __start___kcrctab_gpl[]; extern const unsigned long __start___kcrctab_gpl_future[]; #ifdef CONFIG_UNUSED_SYMBOLS extern const struct kernel_symbol __start___ksymtab_unused[]; extern const struct kernel_symbol __stop___ksymtab_unused[]; extern const struct kernel_symbol __start___ksymtab_unused_gpl[]; extern const struct kernel_symbol __stop___ksymtab_unused_gpl[]; extern const unsigned long __start___kcrctab_unused[]; extern const unsigned long __start___kcrctab_unused_gpl[]; #endif #ifndef CONFIG_MODVERSIONS #define symversion(base, idx) NULL #else #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL) #endif
static bool each_symbol_in_section(const struct symsearch *arr, unsigned int arrsize, struct module *owner, bool (*fn)(const struct symsearch *syms, struct module *owner, void *data), void *data) { unsigned int j; for (j = 0; j < arrsize; j++) { if (fn(&arr[j], owner, data)) return true; } return false; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell6068.97%150.00%
sam ravnborgsam ravnborg2731.03%150.00%
Total87100.00%2100.00%

/* Returns true as soon as fn returns true, otherwise false. */
bool each_symbol_section(bool (*fn)(const struct symsearch *arr, struct module *owner, void *data), void *data) { struct module *mod; static const struct symsearch arr[] = { { __start___ksymtab, __stop___ksymtab, __start___kcrctab, NOT_GPL_ONLY, false }, { __start___ksymtab_gpl, __stop___ksymtab_gpl, __start___kcrctab_gpl, GPL_ONLY, false }, { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future, __start___kcrctab_gpl_future, WILL_BE_GPL_ONLY, false }, #ifdef CONFIG_UNUSED_SYMBOLS { __start___ksymtab_unused, __stop___ksymtab_unused, __start___kcrctab_unused, NOT_GPL_ONLY, true }, { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl, __start___kcrctab_unused_gpl, GPL_ONLY, true }, #endif }; module_assert_mutex_or_preempt(); if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data)) return true; list_for_each_entry_rcu(mod, &modules, list) { struct symsearch arr[] = { { mod->syms, mod->syms + mod->num_syms, mod->crcs, NOT_GPL_ONLY, false }, { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, mod->gpl_crcs, GPL_ONLY, false }, { mod->gpl_future_syms, mod->gpl_future_syms + mod->num_gpl_future_syms, mod->gpl_future_crcs, WILL_BE_GPL_ONLY, false }, #ifdef CONFIG_UNUSED_SYMBOLS { mod->unused_syms, mod->unused_syms + mod->num_unused_syms, mod->unused_crcs, NOT_GPL_ONLY, true }, { mod->unused_gpl_syms, mod->unused_gpl_syms + mod->num_unused_gpl_syms, mod->unused_gpl_crcs, GPL_ONLY, true }, #endif }; if (mod->state == MODULE_STATE_UNFORMED) continue; if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data)) return true; } return false; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell25183.39%743.75%
sam ravnborgsam ravnborg185.98%16.25%
denys vlasenkodenys vlasenko144.65%16.25%
arjan van de venarjan van de ven92.99%16.25%
peter zijlstrapeter zijlstra31.00%16.25%
pre-gitpre-git20.66%16.25%
linus torvaldslinus torvalds10.33%16.25%
andi kleenandi kleen10.33%16.25%
david mosbergerdavid mosberger10.33%16.25%
kai germaschewskikai germaschewski10.33%16.25%
Total301100.00%16100.00%

EXPORT_SYMBOL_GPL(each_symbol_section); struct find_symbol_arg { /* Input */ const char *name; bool gplok; bool warn; /* Output */ struct module *owner; const unsigned long *crc; const struct kernel_symbol *sym; };
static bool check_symbol(const struct symsearch *syms, struct module *owner, unsigned int symnum, void *data) { struct find_symbol_arg *fsa = data; if (!fsa->gplok) { if (syms->licence == GPL_ONLY) return false; if (syms->licence == WILL_BE_GPL_ONLY && fsa->warn) { pr_warn("Symbol %s is being used by a non-GPL module, " "which will not be allowed in the future\n", fsa->name); } } #ifdef CONFIG_UNUSED_SYMBOLS if (syms->unused && fsa->warn) { pr_warn("Symbol %s is marked as UNUSED, however this module is " "using it.\n", fsa->name); pr_warn("This symbol will go away in the future.\n"); pr_warn("Please evaluate if this is the right api to use and " "if it really is, submit a report to the linux kernel " "mailing list together with submitting your code for " "inclusion.\n"); } #endif fsa->owner = owner; fsa->crc = symversion(syms->crcs, symnum); fsa->sym = &syms->start[symnum]; return true; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell12281.33%225.00%
arjan van de venarjan van de ven96.00%112.50%
andrew mortonandrew morton85.33%112.50%
denys vlasenkodenys vlasenko53.33%112.50%
yannick guerriniyannick guerrini32.00%112.50%
tim abbotttim abbott21.33%112.50%
greg kroah-hartmangreg kroah-hartman10.67%112.50%
Total150100.00%8100.00%


static int cmp_name(const void *va, const void *vb) { const char *a; const struct kernel_symbol *b; a = va; b = vb; return strcmp(a, b->name); }

Contributors

PersonTokensPropCommitsCommitProp
alessio igor boganialessio igor bogani45100.00%1100.00%
Total45100.00%1100.00%


static bool find_symbol_in_section(const struct symsearch *syms, struct module *owner, void *data) { struct find_symbol_arg *fsa = data; struct kernel_symbol *sym; sym = bsearch(fsa->name, syms->start, syms->stop - syms->start, sizeof(struct kernel_symbol), cmp_name); if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data)) return true; return false; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell5359.55%150.00%
alessio igor boganialessio igor bogani3640.45%150.00%
Total89100.00%2100.00%

/* Find a symbol and return it, along with, (optional) crc and * (optional) module which owns it. Needs preempt disabled or module_mutex. */
const struct kernel_symbol *find_symbol(const char *name, struct module **owner, const unsigned long **crc, bool gplok, bool warn) { struct find_symbol_arg fsa; fsa.name = name; fsa.gplok = gplok; fsa.warn = warn; if (each_symbol_section(find_symbol_in_section, &fsa)) { if (owner) *owner = fsa.owner; if (crc) *crc = fsa.crc; return fsa.sym; } pr_debug("Failed to find symbol %s\n", name); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell7673.79%444.44%
greg kroah-hartmangreg kroah-hartman1413.59%111.11%
tim abbotttim abbott65.83%111.11%
pre-gitpre-git43.88%111.11%
arjan van de venarjan van de ven21.94%111.11%
jim cromiejim cromie10.97%111.11%
Total103100.00%9100.00%

EXPORT_SYMBOL_GPL(find_symbol); /* * Search for module by name: must hold module_mutex (or preempt disabled * for read-only access). */
static struct module *find_module_all(const char *name, size_t len, bool even_unformed) { struct module *mod; module_assert_mutex_or_preempt(); list_for_each_entry(mod, &modules, list) { if (!even_unformed && mod->state == MODULE_STATE_UNFORMED) continue; if (strlen(mod->name) == len && !memcmp(mod->name, name, len)) return mod; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell4051.28%350.00%
pre-gitpre-git2025.64%116.67%
mathias krausemathias krause1620.51%116.67%
peter zijlstrapeter zijlstra22.56%116.67%
Total78100.00%6100.00%


struct module *find_module(const char *name) { module_assert_mutex(); return find_module_all(name, strlen(name), false); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell2382.14%266.67%
mathias krausemathias krause517.86%133.33%
Total28100.00%3100.00%

EXPORT_SYMBOL_GPL(find_module); #ifdef CONFIG_SMP
static inline void __percpu *mod_percpu(struct module *mod) { return mod->percpu; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo19100.00%2100.00%
Total19100.00%2100.00%


static int percpu_modalloc(struct module *mod, struct load_info *info) { Elf_Shdr *pcpusec = &info->sechdrs[info->index.pcpu]; unsigned long align = pcpusec->sh_addralign; if (!pcpusec->sh_size) return 0; if (align > PAGE_SIZE) { pr_warn("%s: per-cpu alignment %li > %li\n", mod->name, align, PAGE_SIZE); align = PAGE_SIZE; } mod->percpu = __alloc_reserved_percpu(pcpusec->sh_size, align); if (!mod->percpu) { pr_warn("%s: Could not allocate %lu bytes percpu data\n", mod->name, (unsigned long)pcpusec->sh_size); return -ENOMEM; } mod->percpu_size = pcpusec->sh_size; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo7255.81%350.00%
rusty russellrusty russell5542.64%233.33%
andrew mortonandrew morton21.55%116.67%
Total129100.00%6100.00%


static void percpu_modfree(struct module *mod) { free_percpu(mod->percpu); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo18100.00%2100.00%
Total18100.00%2100.00%


static unsigned int find_pcpusec(struct load_info *info) { return find_sec(info, ".data..percpu"); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo1575.00%133.33%
rusty russellrusty russell420.00%133.33%
denys vlasenkodenys vlasenko15.00%133.33%
Total20100.00%3100.00%


static void percpu_modcopy(struct module *mod, const void *from, unsigned long size) { int cpu; for_each_possible_cpu(cpu) memcpy(per_cpu_ptr(mod->percpu, cpu), from, size); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo43100.00%2100.00%
Total43100.00%2100.00%

/** * is_module_percpu_address - test whether address is from module static percpu * @addr: address to test * * Test whether @addr belongs to module static percpu area. * * RETURNS: * %true if @addr is from module static percpu area */
bool is_module_percpu_address(unsigned long addr) { struct module *mod; unsigned int cpu; preempt_disable(); list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) continue; if (!mod->percpu_size) continue; for_each_possible_cpu(cpu) { void *start = per_cpu_ptr(mod->percpu, cpu); if ((void *)addr >= start && (void *)addr < start + mod->percpu_size) { preempt_enable(); return true; } } } preempt_enable(); return false; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo9491.26%150.00%
rusty russellrusty russell98.74%150.00%
Total103100.00%2100.00%

#else /* ... !CONFIG_SMP */
static inline void __percpu *mod_percpu(struct module *mod) { return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo1376.47%150.00%
andrew mortonandrew morton423.53%150.00%
Total17100.00%2100.00%


static int percpu_modalloc(struct module *mod, struct load_info *info) { /* UP modules shouldn't have this section: ENOMEM isn't quite right */ if (info->sechdrs[info->index.pcpu].sh_size != 0) return -ENOMEM; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell2560.98%133.33%
tejun heotejun heo921.95%133.33%
andrew mortonandrew morton717.07%133.33%
Total41100.00%3100.00%


static inline void percpu_modfree(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton763.64%150.00%
tejun heotejun heo436.36%150.00%
Total11100.00%2100.00%


static unsigned int find_pcpusec(struct load_info *info) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton1280.00%150.00%
rusty russellrusty russell320.00%150.00%
Total15100.00%2100.00%


static inline void percpu_modcopy(struct module *mod, const void *from, unsigned long size) { /* pcpusec should be 0, and size of that section should be 0. */ BUG_ON(size != 0); }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton2586.21%150.00%
tejun heotejun heo413.79%150.00%
Total29100.00%2100.00%


bool is_module_percpu_address(unsigned long addr) { return false; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo12100.00%1100.00%
Total12100.00%1100.00%

#endif /* CONFIG_SMP */ #define MODINFO_ATTR(field) \ static void setup_modinfo_##field(struct module *mod, const char *s) \ { \ mod->field = kstrdup(s, GFP_KERNEL); \ } \ static ssize_t show_modinfo_##field(struct module_attribute *mattr, \ struct module_kobject *mk, char *buffer) \ { \ return scnprintf(buffer, PAGE_SIZE, "%s\n", mk->mod->field); \ } \ static int modinfo_##field##_exists(struct module *mod) \ { \ return mod->field != NULL; \ } \ static void free_modinfo_##field(struct module *mod) \ { \ kfree(mod->field); \ mod->field = NULL; \ } \ static struct module_attribute modinfo_##field = { \ .attr = { .name = __stringify(field), .mode = 0444 }, \ .show = show_modinfo_##field, \ .setup = setup_modinfo_##field, \ .test = modinfo_##field##_exists, \ .free = free_modinfo_##field, \ }; MODINFO_ATTR(version); MODINFO_ATTR(srcversion); static char last_unloaded_module[MODULE_NAME_LEN+1]; #ifdef CONFIG_MODULE_UNLOAD EXPORT_TRACEPOINT_SYMBOL(module_get); /* MODULE_REF_BASE is the base reference count by kmodule loader. */ #define MODULE_REF_BASE 1 /* Init the unload section of the module. */
static int module_unload_init(struct module *mod) { /* * Initialize reference counter to MODULE_REF_BASE. * refcnt == 0 means module is going. */ atomic_set(&mod->refcnt, MODULE_REF_BASE); INIT_LIST_HEAD(&mod->source_list); INIT_LIST_HEAD(&mod->target_list); /* Hold reference count during initialization. */ atomic_inc(&mod->refcnt); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell1836.00%222.22%
masami hiramatsumasami hiramatsu1020.00%222.22%
linus torvaldslinus torvalds918.00%111.11%
pre-gitpre-git714.00%111.11%
andrew mortonandrew morton48.00%111.11%
eric dumazeteric dumazet12.00%111.11%
christoph lameterchristoph lameter12.00%111.11%
Total50100.00%9100.00%

/* Does a already use b? */
static int already_uses(struct module *a, struct module *b) { struct module_use *use; list_for_each_entry(use, &b->source_list, source_list) { if (use->source == a) { pr_debug("%s uses %s!\n", a->name, b->name); return 1; } } pr_debug("%s does not use %s!\n", a->name, b->name); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell4460.27%125.00%
pre-gitpre-git2432.88%125.00%
linus torvaldslinus torvalds34.11%125.00%
jim cromiejim cromie22.74%125.00%
Total73100.00%4100.00%

/* * Module a uses b * - we add 'a' as a "source", 'b' as a "target" of module use * - the module_use is added to the list of 'b' sources (so * 'b' can walk the list to see who sourced them), and of 'a' * targets (so 'a' can see what modules it targets). */
static int add_module_usage(struct module *a, struct module *b) { struct module_use *use; pr_debug("Allocating new usage for %s.\n", a->name); use = kmalloc(sizeof(*use), GFP_ATOMIC); if (!use) { pr_warn("%s: out of memory loading\n", a->name); return -ENOMEM; } use->source = a; use->target = b; list_add(&use->source_list, &b->source_list); list_add(&use->target_list, &a->target_list); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds10298.08%133.33%
jim cromiejim cromie10.96%133.33%
andrew mortonandrew morton10.96%133.33%
Total104100.00%3100.00%

/* Module a uses b: caller needs module_mutex() */
int ref_module(struct module *a, struct module *b) { int err; if (b == NULL || already_uses(a, b)) return 0; /* If module isn't available, we fail. */ err = strong_try_module_get(b); if (err) return err; err = add_module_usage(a, b); if (err) { module_put(b); return err; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell5370.67%457.14%
pre-gitpre-git1520.00%114.29%
linus torvaldslinus torvalds56.67%114.29%
kay sieverskay sievers22.67%114.29%
Total75100.00%7100.00%

EXPORT_SYMBOL_GPL(ref_module); /* Clear the unload stuff of the module. */
static void module_unload_free(struct module *mod) { struct module_use *use, *tmp; mutex_lock(&module_mutex); list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) { struct module *i = use->target; pr_debug("%s unusing %s\n", mod->name, i->name); module_put(i); list_del(&use->source_list); list_del(&use->target_list); kfree(use); } mutex_unlock(&module_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell4043.96%240.00%
pre-gitpre-git2628.57%120.00%
linus torvaldslinus torvalds2426.37%120.00%
jim cromiejim cromie11.10%120.00%
Total91100.00%5100.00%

#ifdef CONFIG_MODULE_FORCE_UNLOAD
static inline int try_force_unload(unsigned int flags) { int ret = (flags & O_TRUNC); if (ret) add_taint(TAINT_FORCED_RMMOD, LOCKDEP_NOW_UNRELIABLE); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton2779.41%125.00%
randy dunlaprandy dunlap38.82%125.00%
akinobu mitaakinobu mita25.88%125.00%
rusty russellrusty russell25.88%125.00%
Total34100.00%4100.00%

#else
static inline int try_force_unload(unsigned int flags) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton1392.86%150.00%
akinobu mitaakinobu mita17.14%150.00%
Total14100.00%2100.00%

#endif /* CONFIG_MODULE_FORCE_UNLOAD */ /* Try to release refcount of module, 0 means success. */
static int try_release_module_ref(struct module *mod) { int ret; /* Try to decrement refcnt which we set at loading */ ret = atomic_sub_return(MODULE_REF_BASE, &mod->refcnt); BUG_ON(ret < 0); if (ret) /* Someone can put this right now, recover with checking */ ret = atomic_add_unless(&mod->refcnt, MODULE_REF_BASE, 0); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
masami hiramatsumasami hiramatsu3562.50%133.33%
andrew mortonandrew morton1628.57%133.33%
rusty russellrusty russell58.93%133.33%
Total56100.00%3100.00%


static int try_stop_module(struct module *mod, int flags, int *forced) { /* If it's not unused, quit unless we're forcing. */ if (try_release_module_ref(mod) != 0) { *forced = try_force_unload(flags); if (!(*forced)) return -EWOULDBLOCK; } /* Mark it as dying. */ mod->state = MODULE_STATE_GOING; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
masami hiramatsumasami hiramatsu3660.00%116.67%
andrew mortonandrew morton1321.67%116.67%
rusty russellrusty russell711.67%233.33%
pre-gitpre-git46.67%233.33%
Total60100.00%6100.00%

/** * module_refcount - return the refcount or -1 if unloading * * @mod: the module we're checking * * Returns: * -1 if the module is in the process of unloading * otherwise the number of references in the kernel to the module */
int module_refcount(struct module *mod) { return atomic_read(&mod->refcnt) - MODULE_REF_BASE; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell1152.38%240.00%
masami hiramatsumasami hiramatsu523.81%240.00%
nick pigginnick piggin523.81%120.00%
Total21100.00%5100.00%

EXPORT_SYMBOL(module_refcount); /* This exists whether we can unload or not */ static void free_module(struct module *mod); SYSCALL_DEFINE2(delete_module, const char __user *, name_user, unsigned int, flags) { struct module *mod; char name[MODULE_NAME_LEN]; int ret, forced = 0; if (!capable(CAP_SYS_MODULE) || modules_disabled) return -EPERM; if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) return -EFAULT; name[MODULE_NAME_LEN-1] = '\0'; if (mutex_lock_interruptible(&module_mutex) != 0) return -EINTR; mod = find_module(name); if (!mod) { ret = -ENOENT; goto out; } if (!list_empty(&mod->source_list)) { /* Other modules depend on us: get rid of them first. */ ret = -EWOULDBLOCK; goto out; } /* Doing init or already dying? */ if (mod->state != MODULE_STATE_LIVE) { /* FIXME: if (force), slam module count damn the torpedoes */ pr_debug("%s already dying\n", mod->name); ret = -EBUSY; goto out; } /* If it has an init func, it must have an exit func to unload */ if (mod->init && !mod->exit) { forced = try_force_unload(flags); if (!forced) { /* This module can't be removed */ ret = -EBUSY; goto out; } } /* Stop the machine so refcounts can't move and disable module. */ ret = try_stop_module(mod, flags, &forced); if (ret != 0) goto out; mutex_unlock(&module_mutex); /* Final destruction now no one is using it. */ if (mod->exit != NULL) mod->exit(); blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GOING, mod); klp_module_going(mod); ftrace_release_mod(mod); async_synchronize_full(); /* Store the name of the last unloaded module for diagnostic purposes */ strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module)); free_module(mod); return 0; out: mutex_unlock(&module_mutex); return ret; }
static inline void print_unload_info(struct seq_file *m, struct module *mod) { struct module_use *use; int printed_something = 0; seq_printf(m, " %i ", module_refcount(mod)); /* * Always include a trailing , so userspace can differentiate * between this and the old multi-field proc format. */ list_for_each_entry(use, &mod->source_list, source_list) { printed_something = 1; seq_printf(m, "%s,", use->source->name); } if (mod->init != NULL && mod->exit == NULL) { printed_something = 1; seq_puts(m, "[permanent],"); } if (!printed_something) seq_puts(m, "-"); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell6864.15%529.41%
pre-gitpre-git2927.36%847.06%
linus torvaldslinus torvalds32.83%15.88%
ionut alexaionut alexa32.83%15.88%
brian gerstbrian gerst21.89%15.88%
jianjun kongjianjun kong10.94%15.88%
Total106100.00%17100.00%


void __symbol_put(const char *symbol) { struct module *owner; preempt_disable(); if (!find_symbol(symbol, &owner, NULL, true, false)) BUG(); module_put(owner); preempt_enable(); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell3371.74%555.56%
pre-gitpre-git1123.91%222.22%
kai germaschewskikai germaschewski12.17%111.11%
tim abbotttim abbott12.17%111.11%
Total46100.00%9100.00%

EXPORT_SYMBOL(__symbol_put); /* Note this assumes addr is a function, which it currently always is. */
void symbol_put_addr(void *addr) { struct module *modaddr; unsigned long a = (unsigned long)dereference_function_descriptor(addr); if (core_kernel_text(a)) return; /* * Even though we hold a reference on the module; we still need to * disable preemption in order to safely traverse the data structure. */ preempt_disable(); modaddr = __module_text_address(a); BUG_ON(!modaddr); module_put(modaddr); preempt_enable(); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell4473.33%466.67%
trent piephotrent piepho915.00%116.67%
peter zijlstrapeter zijlstra711.67%116.67%
Total60100.00%6100.00%

EXPORT_SYMBOL_GPL(symbol_put_addr);
static ssize_t show_refcnt(struct module_attribute *mattr, struct module_kobject *mk, char *buffer) { return sprintf(buffer, "%i\n", module_refcount(mk->mod)); }

Contributors

PersonTokensPropCommitsCommitProp
greg kroah-hartmangreg kroah-hartman2057.14%116.67%
tejun heotejun heo514.29%116.67%
rusty russellrusty russell514.29%233.33%
kay sieverskay sievers411.43%116.67%
christoph hellwigchristoph hellwig12.86%116.67%
Total35100.00%6100.00%

static struct module_attribute modinfo_refcnt = __ATTR(refcnt, 0444, show_refcnt, NULL);
void __module_get(struct module *module) { if (module) { preempt_disable(); atomic_inc(&module->refcnt); trace_module_get(module, _RET_IP_); preempt_enable(); } }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt3491.89%150.00%
masami hiramatsumasami hiramatsu38.11%150.00%
Total37100.00%2100.00%

EXPORT_SYMBOL(__module_get);
bool try_module_get(struct module *module) { bool ret = true; if (module) { preempt_disable(); /* Note: here, we can fail to get a reference */ if (likely(module_is_live(module) && atomic_inc_not_zero(&module->refcnt) != 0)) trace_module_get(module, _RET_IP_); else ret = false; preempt_enable(); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
steven rostedtsteven rostedt5485.71%133.33%
masami hiramatsumasami hiramatsu914.29%266.67%
Total63100.00%3100.00%

EXPORT_SYMBOL(try_module_get);
void module_put(struct module *module) { int ret; if (module) { preempt_disable(); ret = atomic_dec_if_positive(&module->refcnt); WARN_ON(ret < 0); /* Failed to put refcount */ trace_module_put(module, _RET_IP_); preempt_enable(); } }

Contributors

PersonTokensPropCommitsCommitProp
al viroal viro2244.00%116.67%
masami hiramatsumasami hiramatsu1632.00%233.33%
li zefanli zefan714.00%116.67%
christoph lameterchristoph lameter48.00%116.67%
eric dumazeteric dumazet12.00%116.67%
Total50100.00%6100.00%

EXPORT_SYMBOL(module_put); #else /* !CONFIG_MODULE_UNLOAD */
static inline void print_unload_info(struct seq_file *m, struct module *mod) { /* We don't know the usage count, or what modules are using. */ seq_puts(m, " - -"); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell2392.00%250.00%
ionut alexaionut alexa14.00%125.00%
jianjun kongjianjun kong14.00%125.00%
Total25100.00%4100.00%


static inline void module_unload_free(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell11100.00%2100.00%
Total11100.00%2100.00%


int ref_module(struct module *a, struct module *b) { return strong_try_module_get(b); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell21100.00%3100.00%
Total21100.00%3100.00%

EXPORT_SYMBOL_GPL(ref_module);
static inline int module_unload_init(struct module *mod) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell15100.00%2100.00%
Total15100.00%2100.00%

#endif /* CONFIG_MODULE_UNLOAD */
static size_t module_flags_taint(struct module *mod, char *buf) { size_t l = 0; if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE)) buf[l++] = 'P'; if (mod->taints & (1 << TAINT_OOT_MODULE)) buf[l++] = 'O'; if (mod->taints & (1 << TAINT_FORCED_MODULE)) buf[l++] = 'F'; if (mod->taints & (1 << TAINT_CRAP)) buf[l++] = 'C'; if (mod->taints & (1 << TAINT_UNSIGNED_MODULE)) buf[l++] = 'E'; if (mod->taints & (1 << TAINT_LIVEPATCH)) buf[l++] = 'K'; /* * TAINT_FORCED_RMMOD: could be added. * TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't * apply to modules. */ return l; }

Contributors

PersonTokensPropCommitsCommitProp
kevin winchesterkevin winchester10371.53%120.00%
josh poimboeufjosh poimboeuf2013.89%120.00%
mathieu desnoyersmathieu desnoyers1913.19%120.00%
rusty russellrusty russell10.69%120.00%
dave jonesdave jones10.69%120.00%
Total144100.00%5100.00%


static ssize_t show_initstate(struct module_attribute *mattr, struct module_kobject *mk, char *buffer) { const char *state = "unknown"; switch (mk->mod->state) { case MODULE_STATE_LIVE: state = "live"; break; case MODULE_STATE_COMING: state = "coming"; break; case MODULE_STATE_GOING: state = "going"; break; default: BUG(); } return sprintf(buffer, "%s\n", state); }

Contributors

PersonTokensPropCommitsCommitProp
kay sieverskay sievers7194.67%266.67%
rusty russellrusty russell45.33%133.33%
Total75100.00%3100.00%

static struct module_attribute modinfo_initstate = __ATTR(initstate, 0444, show_initstate, NULL);
static ssize_t store_uevent(struct module_attribute *mattr, struct module_kobject *mk, const char *buffer, size_t count) { enum kobject_action action; if (kobject_action_type(buffer, count, &action) == 0) kobject_uevent(&mk->kobj, action); return count; }

Contributors

PersonTokensPropCommitsCommitProp
kay sieverskay sievers55100.00%1100.00%
Total55100.00%1100.00%

struct module_attribute module_uevent = __ATTR(uevent, 0200, NULL, store_uevent);
static ssize_t show_coresize(struct module_attribute *mattr, struct module_kobject *mk, char *buffer) { return sprintf(buffer, "%u\n", mk->mod->core_layout.size); }

Contributors

PersonTokensPropCommitsCommitProp
kay sieverskay sievers3391.67%266.67%
rusty russellrusty russell38.33%133.33%
Total36100.00%3100.00%

static struct module_attribute modinfo_coresize = __ATTR(coresize, 0444, show_coresize, NULL);
static ssize_t show_initsize(struct module_attribute *mattr, struct module_kobject *mk, char *buffer) { return sprintf(buffer, "%u\n", mk->mod->init_layout.size); }

Contributors

PersonTokensPropCommitsCommitProp
kay sieverskay sievers3391.67%266.67%
rusty russellrusty russell38.33%133.33%
Total36100.00%3100.00%

static struct module_attribute modinfo_initsize = __ATTR(initsize, 0444, show_initsize, NULL);
static ssize_t show_taint(struct module_attribute *mattr, struct module_kobject *mk, char *buffer) { size_t l; l = module_flags_taint(mk->mod, buffer); buffer[l++] = '\n'; return l; }

Contributors

PersonTokensPropCommitsCommitProp
kay sieverskay sievers45100.00%2100.00%
Total45100.00%2100.00%

static struct module_attribute modinfo_taint = __ATTR(taint, 0444, show_taint, NULL); static struct module_attribute *modinfo_attrs[] = { &module_uevent, &modinfo_version, &modinfo_srcversion, &modinfo_initstate, &modinfo_coresize, &modinfo_initsize, &modinfo_taint, #ifdef CONFIG_MODULE_UNLOAD &modinfo_refcnt, #endif NULL, }; static const char vermagic[] = VERMAGIC_STRING;
static int try_to_force_load(struct module *mod, const char *reason) { #ifdef CONFIG_MODULE_FORCE_LOAD if (!test_taint(TAINT_FORCED_MODULE)) pr_warn("%s: %s: kernel tainted.\n", mod->name, reason); add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_NOW_UNRELIABLE); return 0; #else return -ENOEXEC; #endif }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds4984.48%120.00%
rusty russellrusty russell58.62%240.00%
andi kleenandi kleen35.17%120.00%
andrew mortonandrew morton11.72%120.00%
Total58100.00%5100.00%

#ifdef CONFIG_MODVERSIONS /* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */
static unsigned long maybe_relocated(unsigned long crc, const struct module *crc_owner) { #ifdef ARCH_RELOCATES_KCRCTAB if (crc_owner == NULL) return crc - (unsigned long)reloc_start; #endif return crc; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell40100.00%1100.00%
Total40100.00%1100.00%


static int check_version(Elf_Shdr *sechdrs, unsigned int versindex, const char *symname, struct module *mod, const unsigned long *crc, const struct module *crc_owner) { unsigned int i, num_versions; struct modversion_info *versions; /* Exporting module didn't supply crcs? OK, we're already tainted. */ if (!crc) return 1; /* No versions at all? modprobe --force does this. */ if (versindex == 0) return try_to_force_load(mod, symname) == 0; versions = (void *) sechdrs[versindex].sh_addr; num_versions = sechdrs[versindex].sh_size / sizeof(struct modversion_info); for (i = 0; i < num_versions; i++) { if (strcmp(versions[i].name, symname) != 0) continue; if (versions[i].crc == maybe_relocated(*crc, crc_owner)) return 1; pr_debug("Found checksum %lX vs module %lX\n", maybe_relocated(*crc, crc_owner), versions[i].crc); goto bad_version; } /* Broken toolchain. Warn once, then let it go.. */ pr_warn_once("%s: no symbol version for %s\n", mod->name, symname); return 1; bad_version: pr_warn("%s: disagrees about version of symbol %s\n", mod->name, symname); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
kai germaschewskikai germaschewski13967.15%111.11%
rusty russellrusty russell4923.67%444.44%
linus torvaldslinus torvalds178.21%222.22%
ionut alexaionut alexa10.48%111.11%
jim cromiejim cromie10.48%111.11%
Total207100.00%9100.00%


static inline int check_modstruct_version(Elf_Shdr *sechdrs, unsigned int versindex, struct module *mod) { const unsigned long *crc; /* * Since this should be found in kernel (which can't be removed), no * locking is necessary -- use preempt_disable() to placate lockdep. */ preempt_disable(); if (!find_symbol(VMLINUX_SYMBOL_STR(module_layout), NULL, &crc, true, false)) { preempt_enable(); BUG(); } preempt_enable(); return check_version(sechdrs, versindex, VMLINUX_SYMBOL_STR(module_layout), mod, crc, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell5771.25%450.00%
peter zijlstrapeter zijlstra1215.00%112.50%
kai germaschewskikai germaschewski67.50%112.50%
james hoganjames hogan45.00%112.50%
tim abbotttim abbott11.25%112.50%
Total80100.00%8100.00%

/* First part is kernel version, which we ignore if module has crcs. */
static inline int same_magic(const char *amagic, const char *bmagic, bool has_crcs) { if (has_crcs) { amagic += strcspn(amagic, " "); bmagic += strcspn(bmagic, " "); } return strcmp(amagic, bmagic) == 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell54100.00%2100.00%
Total54100.00%2100.00%

#else
static inline int check_version(Elf_Shdr *sechdrs, unsigned int versindex, const char *symname, struct module *mod, const unsigned long *crc, const struct module *crc_owner) { return 1; }

Contributors

PersonTokensPropCommitsCommitProp
kai germaschewskikai germaschewski3075.00%133.33%
rusty russellrusty russell1025.00%266.67%
Total40100.00%3100.00%


static inline int check_modstruct_version(Elf_Shdr *sechdrs, unsigned int versindex, struct module *mod) { return 1; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell23100.00%1100.00%
Total23100.00%1100.00%


static inline int same_magic(const char *amagic, const char *bmagic, bool has_crcs) { return strcmp(amagic, bmagic) == 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell30100.00%2100.00%
Total30100.00%2100.00%

#endif /* CONFIG_MODVERSIONS */ /* Resolve a symbol for this module. I.e. if we find one, record usage. */
static const struct kernel_symbol *resolve_symbol(struct module *mod, const struct load_info *info, const char *name, char ownername[]) { struct module *owner; const struct kernel_symbol *sym; const unsigned long *crc; int err; /* * The module_mutex should not be a heavily contended lock; * if we get the occasional sleep here, we'll go an extra iteration * in the wait_event_interruptible(), which is harmless. */ sched_annotate_sleep(); mutex_lock(&module_mutex); sym = find_symbol(name, &owner, &crc, !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true); if (!sym) goto unlock; if (!check_version(info->sechdrs, info->index.vers, name, mod, crc, owner)) { sym = ERR_PTR(-EINVAL); goto getname; } err = ref_module(mod, owner); if (err) { sym = ERR_PTR(err); goto getname; } getname: /* We must make copy under the lock if we failed to get ref. */ strncpy(ownername, module_name(owner), MODULE_NAME_LEN); unlock: mutex_unlock(&module_mutex); return sym; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell10657.92%746.67%
greg kroah-hartmangreg kroah-hartman4222.95%16.67%
tim abbotttim abbott126.56%16.67%
florin malitaflorin malita63.28%16.67%
richard hendersonrichard henderson52.73%16.67%
peter zijlstrapeter zijlstra42.19%16.67%
andi kleenandi kleen42.19%16.67%
linus torvaldslinus torvalds21.09%16.67%
kai germaschewskikai germaschewski21.09%16.67%
Total183100.00%15100.00%


static const struct kernel_symbol * resolve_symbol_wait(struct module *mod, const struct load_info *info, const char *name) { const struct kernel_symbol *ksym; char owner[MODULE_NAME_LEN]; if (wait_event_interruptible_timeout(module_wq, !IS_ERR(ksym = resolve_symbol(mod, info, name, owner)) || PTR_ERR(ksym) != -EBUSY, 30 * HZ) <= 0) { pr_warn("%s: gave up waiting for init of module %s.\n", mod->name, owner); } return ksym; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell9098.90%266.67%
andrew mortonandrew morton11.10%133.33%
Total91100.00%3100.00%

/* * /sys/module/foo/sections stuff * J. Corbet <corbet@lwn.net> */ #ifdef CONFIG_SYSFS #ifdef CONFIG_KALLSYMS
static inline bool sect_empty(const Elf_Shdr *sect) { return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0; }

Contributors

PersonTokensPropCommitsCommitProp
ben hutchingsben hutchings28100.00%1100.00%
Total28100.00%1100.00%

struct module_sect_attr { struct module_attribute mattr; char *name; unsigned long address; }; struct module_sect_attrs { struct attribute_group grp; unsigned int nsections; struct module_sect_attr attrs[0]; };
static ssize_t module_sect_show(struct module_attribute *mattr, struct module_kobject *mk, char *buf) { struct module_sect_attr *sattr = container_of(mattr, struct module_sect_attr, mattr); return sprintf(buf, "0x%pK\n", (void *)sattr->address); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet4078.43%125.00%
kees cookkees cook59.80%125.00%
tejun heotejun heo47.84%125.00%
kay sieverskay sievers23.92%125.00%
Total51100.00%4100.00%


static void free_sect_attrs(struct module_sect_attrs *sect_attrs) { unsigned int section; for (section = 0; section < sect_attrs->nsections; section++) kfree(sect_attrs->attrs[section].name); kfree(sect_attrs); }

Contributors

PersonTokensPropCommitsCommitProp
ian s. nelsonian s. nelson4697.87%150.00%
rusty russellrusty russell12.13%150.00%
Total47100.00%2100.00%


static void add_sect_attrs(struct module *mod, const struct load_info *info) { unsigned int nloaded = 0, i, size[2]; struct module_sect_attrs *sect_attrs; struct module_sect_attr *sattr; struct attribute **gattr; /* Count loaded sections and allocate structures */ for (i = 0; i < info->hdr->e_shnum; i++) if (!sect_empty(&info->sechdrs[i])) nloaded++; size[0] = ALIGN(sizeof(*sect_attrs) + nloaded * sizeof(sect_attrs->attrs[0]), sizeof(sect_attrs->grp.attrs[0])); size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]); sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL); if (sect_attrs == NULL) return; /* Setup section attributes. */ sect_attrs->grp.name = "sections"; sect_attrs->grp.attrs = (void *)sect_attrs + size[0]; sect_attrs->nsections = 0; sattr = &sect_attrs->attrs[0]; gattr = &sect_attrs->grp.attrs[0]; for (i = 0; i < info->hdr->e_shnum; i++) { Elf_Shdr *sec = &info->sechdrs[i]; if (sect_empty(sec)) continue; sattr->address = sec->sh_addr; sattr->name = kstrdup(info->secstrings + sec->sh_name, GFP_KERNEL); if (sattr->name == NULL) goto out; sect_attrs->nsections++; sysfs_attr_init(&sattr->mattr.attr); sattr->mattr.show = module_sect_show; sattr->mattr.store = NULL; sattr->mattr.attr.name = sattr->name; sattr->mattr.attr.mode = S_IRUGO; *(gattr++) = &(sattr++)->mattr.attr; } *gattr = NULL; if (sysfs_create_group(&mod->mkobj.kobj, &sect_attrs->grp)) goto out; mod->sect_attrs = sect_attrs; return; out: free_sect_attrs(sect_attrs); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet16340.45%114.29%
tejun heotejun heo14736.48%114.29%
rusty russellrusty russell348.44%114.29%
ian s. nelsonian s. nelson348.44%114.29%
eric w. biedermaneric w. biederman102.48%114.29%
helge dellerhelge deller102.48%114.29%
ben hutchingsben hutchings51.24%114.29%
Total403100.00%7100.00%


static void remove_sect_attrs(struct module *mod) { if (mod->sect_attrs) { sysfs_remove_group(&mod->mkobj.kobj, &mod->sect_attrs->grp); /* We are positive that no one is using any sect attrs * at this point. Deallocate immediately. */ free_sect_attrs(mod->sect_attrs); mod->sect_attrs = NULL; } }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet3366.00%133.33%
tejun heotejun heo1632.00%133.33%
ian s. nelsonian s. nelson12.00%133.33%
Total50100.00%3100.00%

/* * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections. */ struct module_notes_attrs { struct kobject *dir; unsigned int notes; struct bin_attribute attrs[0]; };
static ssize_t module_notes_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count) { /* * The caller checked the pos and count against our size. */ memcpy(buf, bin_attr->private + pos, count); return count; }

Contributors

PersonTokensPropCommitsCommitProp
roland mcgrathroland mcgrath4389.58%150.00%
chris wrightchris wright510.42%150.00%
Total48100.00%2100.00%


static void free_notes_attrs(struct module_notes_attrs *notes_attrs, unsigned int i) { if (notes_attrs->dir) { while (i-- > 0) sysfs_remove_bin_file(notes_attrs->dir, &notes_attrs->attrs[i]); kobject_put(notes_attrs->dir); } kfree(notes_attrs); }

Contributors

PersonTokensPropCommitsCommitProp
roland mcgrathroland mcgrath5698.25%150.00%
alexey dobriyanalexey dobriyan11.75%150.00%
Total57100.00%2100.00%


static void add_notes_attrs(struct module *mod, const struct load_info *info) { unsigned int notes, loaded, i; struct module_notes_attrs *notes_attrs; struct bin_attribute *nattr; /* failed to create section attributes, so can't create notes */ if (!mod->sect_attrs) return; /* Count notes sections and allocate structures. */ notes = 0; for (i = 0; i < info->hdr->e_shnum; i++) if (!sect_empty(&info->sechdrs[i]) && (info->sechdrs[i].sh_type == SHT_NOTE)) ++notes; if (notes == 0) return; notes_attrs = kzalloc(sizeof(*notes_attrs) + notes * sizeof(notes_attrs->attrs[0]), GFP_KERNEL); if (notes_attrs == NULL) return; notes_attrs->notes = notes; nattr = &notes_attrs->attrs[0]; for (loaded = i = 0; i < info->hdr->e_shnum; ++i) { if (sect_empty(&info->sechdrs[i])) continue; if (info->sechdrs[i].sh_type == SHT_NOTE) { sysfs_bin_attr_init(nattr); nattr->attr.name = mod->sect_attrs->attrs[loaded].name; nattr->attr.mode = S_IRUGO; nattr->size = info->sechdrs[i].sh_size; nattr->private = (void *) info->sechdrs[i].sh_addr; nattr->read = module_notes_read; ++nattr; } ++loaded; } notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj); if (!notes_attrs->dir) goto out; for (i = 0; i < notes; ++i) if (sysfs_create_bin_file(notes_attrs->dir, &notes_attrs->attrs[i])) goto out; mod->notes_attrs = notes_attrs; return; out: free_notes_attrs(notes_attrs, i); }

Contributors

PersonTokensPropCommitsCommitProp
roland mcgrathroland mcgrath29685.06%116.67%
rusty russellrusty russell267.47%116.67%
ingo molnaringo molnar92.59%116.67%
ben hutchingsben hutchings92.59%116.67%
eric w. biedermaneric w. biederman51.44%116.67%
greg kroah-hartmangreg kroah-hartman30.86%116.67%
Total348100.00%6100.00%


static void remove_notes_attrs(struct module *mod) { if (mod->notes_attrs) free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes); }

Contributors

PersonTokensPropCommitsCommitProp
roland mcgrathroland mcgrath30100.00%1100.00%
Total30100.00%1100.00%

#else
static inline void add_sect_attrs(struct module *mod, const struct load_info *info) { }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet1376.47%150.00%
rusty russellrusty russell423.53%150.00%
Total17100.00%2100.00%


static inline void remove_sect_attrs(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet11100.00%1100.00%
Total11100.00%1100.00%


static inline void add_notes_attrs(struct module *mod, const struct load_info *info) { }

Contributors

PersonTokensPropCommitsCommitProp
roland mcgrathroland mcgrath1376.47%150.00%
rusty russellrusty russell423.53%150.00%
Total17100.00%2100.00%


static inline void remove_notes_attrs(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
roland mcgrathroland mcgrath11100.00%1100.00%
Total11100.00%1100.00%

#endif /* CONFIG_KALLSYMS */
static void add_usage_links(struct module *mod) { #ifdef CONFIG_MODULE_UNLOAD struct module_use *use; int nowarn; mutex_lock(&module_mutex); list_for_each_entry(use, &mod->target_list, target_list) { nowarn = sysfs_create_link(use->target->holders_dir, &mod->mkobj.kobj, mod->name); } mutex_unlock(&module_mutex); #endif }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell68100.00%2100.00%
Total68100.00%2100.00%


static void del_usage_links(struct module *mod) { #ifdef CONFIG_MODULE_UNLOAD struct module_use *use; mutex_lock(&module_mutex); list_for_each_entry(use, &mod->target_list, target_list) sysfs_remove_link(use->target->holders_dir, mod->name); mutex_unlock(&module_mutex); #endif }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell54100.00%2100.00%
Total54100.00%2100.00%


static int module_add_modinfo_attrs(struct module *mod) { struct module_attribute *attr; struct module_attribute *temp_attr; int error = 0; int i; mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) * (ARRAY_SIZE(modinfo_attrs) + 1)), GFP_KERNEL); if (!mod->modinfo_attrs) return -ENOMEM; temp_attr = mod->modinfo_attrs; for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { if (!attr->test || attr->test(mod)) { memcpy(temp_attr, attr, sizeof(*temp_attr)); sysfs_attr_init(&temp_attr->attr); error = sysfs_create_file(&mod->mkobj.kobj, &temp_attr->attr); ++temp_attr; } } return error; }

Contributors

PersonTokensPropCommitsCommitProp
matt domschmatt domsch7950.97%125.00%
greg kroah-hartmangreg kroah-hartman6743.23%125.00%
eric w. biedermaneric w. biederman85.16%125.00%
rusty russellrusty russell10.65%125.00%
Total155100.00%4100.00%


static void module_remove_modinfo_attrs(struct module *mod) { struct module_attribute *attr; int i; for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) { /* pick a field to test for end of list */ if (!attr->attr.name) break; sysfs_remove_file(&mod->mkobj.kobj, &attr->attr); if (attr->free) attr->free(mod); } kfree(mod->modinfo_attrs); }

Contributors

PersonTokensPropCommitsCommitProp
matt domschmatt domsch6068.18%133.33%
greg kroah-hartmangreg kroah-hartman2730.68%133.33%
rusty russellrusty russell11.14%133.33%
Total88100.00%3100.00%


static void mod_kobject_put(struct module *mod) { DECLARE_COMPLETION_ONSTACK(c); mod->mkobj.kobj_completion = &c; kobject_put(&mod->mkobj.kobj); wait_for_completion(&c); }

Contributors

PersonTokensPropCommitsCommitProp
li zhongli zhong41100.00%1100.00%
Total41100.00%1100.00%


static int mod_sysfs_init(struct module *mod) { int err; struct kobject *kobj; if (!module_sysfs_initialized) { pr_err("%s: module sysfs not initialized\n", mod->name); err = -EINVAL; goto out; } kobj = kset_find_obj(module_kset, mod->name); if (kobj) { pr_err("%s: module is already loaded\n", mod->name); kobject_put(kobj); err = -EINVAL; goto out; } mod->mkobj.mod = mod; memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); mod->mkobj.kobj.kset = module_kset; err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL, "%s", mod->name); if (err) mod_kobject_put(mod); /* delay uevent until full sysfs population */ out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
greg kroah-hartmangreg kroah-hartman11169.81%640.00%
ed swierked swierk2113.21%16.67%
kay sieverskay sievers1710.69%320.00%
rusty russellrusty russell42.52%213.33%
tejun heotejun heo31.89%16.67%
andrew mortonandrew morton21.26%16.67%
li zhongli zhong10.63%16.67%
Total159100.00%15100.00%


static int mod_sysfs_setup(struct module *mod, const struct load_info *info, struct kernel_param *kparam, unsigned int num_params) { int err; err = mod_sysfs_init(mod); if (err) goto out; mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj); if (!mod->holders_dir) { err = -ENOMEM; goto out_unreg; } err = module_param_sysfs_setup(mod, kparam, num_params); if (err) goto out_unreg_holders; err = module_add_modinfo_attrs(mod); if (err) goto out_unreg_param; add_usage_links(mod); add_sect_attrs(mod, info); add_notes_attrs(mod, info); kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD); return 0; out_unreg_param: module_param_sysfs_remove(mod); out_unreg_holders: kobject_put(mod->holders_dir); out_unreg: mod_kobject_put(mod); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
kay sieverskay sievers7443.53%318.75%
rusty russellrusty russell5029.41%531.25%
greg kroah-hartmangreg kroah-hartman1911.18%318.75%
matt domschmatt domsch137.65%16.25%
akinobu mitaakinobu mita74.12%16.25%
pre-gitpre-git63.53%212.50%
li zhongli zhong10.59%16.25%
Total170100.00%16100.00%


static void mod_sysfs_fini(struct module *mod) { remove_notes_attrs(mod); remove_sect_attrs(mod); mod_kobject_put(mod); }

Contributors

PersonTokensPropCommitsCommitProp
denis v. lunevdenis v. lunev1557.69%133.33%
rusty russellrusty russell1038.46%133.33%
li zhongli zhong13.85%133.33%
Total26100.00%3100.00%


static void init_param_lock(struct module *mod) { mutex_init(&mod->param_lock); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell19100.00%1100.00%
Total19100.00%1100.00%

#else /* !CONFIG_SYSFS */
static int mod_sysfs_setup(struct module *mod, const struct load_info *info, struct kernel_param *kparam, unsigned int num_params) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell29100.00%2100.00%
Total29100.00%2100.00%


static void mod_sysfs_fini(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
denis v. lunevdenis v. lunev10100.00%1100.00%
Total10100.00%1100.00%


static void module_remove_modinfo_attrs(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell10100.00%1100.00%
Total10100.00%1100.00%


static void del_usage_links(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell10100.00%1100.00%
Total10100.00%1100.00%


static void init_param_lock(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell10100.00%1100.00%
Total10100.00%1100.00%

#endif /* CONFIG_SYSFS */
static void mod_sysfs_teardown(struct module *mod) { del_usage_links(mod); module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); kobject_put(mod->mkobj.drivers_dir); kobject_put(mod->holders_dir); mod_sysfs_fini(mod); }

Contributors

PersonTokensPropCommitsCommitProp
greg kroah-hartmangreg kroah-hartman1940.43%220.00%
kay sieverskay sievers1429.79%330.00%
rusty russellrusty russell817.02%330.00%
matt domschmatt domsch510.64%110.00%
denis v. lunevdenis v. lunev12.13%110.00%
Total47100.00%10100.00%

#ifdef CONFIG_DEBUG_SET_MODULE_RONX /* * LKM RO/NX protection: protect module's text/ro-data * from modification and any data from execution. * * General layout of module is: * [text] [read-only-data] [ro-after-init] [writable data] * text_size -----^ ^ ^ ^ * ro_size ------------------------| | | * ro_after_init_size -----------------------------| | * size -----------------------------------------------------------| * * These values are always page-aligned (as is base) */
static void frob_text(const struct module_layout *layout, int (*set_memory)(unsigned long start, int num_pages)) { BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1)); BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1)); set_memory((unsigned long)layout->base, layout->text_size >> PAGE_SHIFT); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell4761.04%350.00%
matthieu castetmatthieu castet2329.87%116.67%
david howellsdavid howells56.49%116.67%
li zefanli zefan22.60%116.67%
Total77100.00%6100.00%


static void frob_rodata(const struct module_layout *layout, int (*set_memory)(unsigned long start, int num_pages)) { BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1)); BUG_ON((unsigned long)layout->text_size & (PAGE_SIZE-1)); BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1)); set_memory((unsigned long)layout->base + layout->text_size, (layout->ro_size - layout->text_size) >> PAGE_SHIFT); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell5855.77%440.00%
matthieu castetmatthieu castet2625.00%110.00%
josh poimboeufjosh poimboeuf98.65%110.00%
greg kroah-hartmangreg kroah-hartman32.88%110.00%
andrew mortonandrew morton32.88%110.00%
jason baronjason baron32.88%110.00%
jan glauberjan glauber21.92%110.00%
Total104100.00%10100.00%


static void frob_ro_after_init(const struct module_layout *layout, int (*set_memory)(unsigned long start, int num_pages)) { BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1)); BUG_ON((unsigned long)layout->ro_size & (PAGE_SIZE-1)); BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1)); set_memory((unsigned long)layout->base + layout->ro_size, (layout->ro_after_init_size - layout->ro_size) >> PAGE_SHIFT); }

Contributors

PersonTokensPropCommitsCommitProp
jessica yujessica yu104100.00%1100.00%
Total104100.00%1100.00%


static void frob_writable_data(const struct module_layout *layout, int (*set_memory)(unsigned long start, int num_pages)) { BUG_ON((unsigned long)layout->base & (PAGE_SIZE-1)); BUG_ON((unsigned long)layout->ro_after_init_size & (PAGE_SIZE-1)); BUG_ON((unsigned long)layout->size & (PAGE_SIZE-1)); set_memory((unsigned long)layout->base + layout->ro_after_init_size, (layout->size - layout->ro_after_init_size) >> PAGE_SHIFT); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell9389.42%337.50%
josh poimboeufjosh poimboeuf43.85%112.50%
jessica yujessica yu32.88%112.50%
matthieu castetmatthieu castet21.92%112.50%
pre-gitpre-git10.96%112.50%
jan glauberjan glauber10.96%112.50%
Total104100.00%8100.00%

/* livepatching wants to disable read-only so it can frob module. */
void module_disable_ro(const struct module *mod) { frob_text(&mod->core_layout, set_memory_rw); frob_rodata(&mod->core_layout, set_memory_rw); frob_ro_after_init(&mod->core_layout, set_memory_rw); frob_text(&mod->init_layout, set_memory_rw); frob_rodata(&mod->init_layout, set_memory_rw); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell3862.30%450.00%
jessica yujessica yu1016.39%112.50%
matthieu castetmatthieu castet69.84%112.50%
jan glauberjan glauber69.84%112.50%
josh poimboeufjosh poimboeuf11.64%112.50%
Total61100.00%8100.00%


void module_enable_ro(const struct module *mod, bool after_init) { frob_text(&mod->core_layout, set_memory_ro); frob_rodata(&mod->core_layout, set_memory_ro); frob_text(&mod->init_layout, set_memory_ro); frob_rodata(&mod->init_layout, set_memory_ro); if (after_init) frob_ro_after_init(&mod->core_layout, set_memory_ro); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell3145.59%430.77%
jessica yujessica yu1725.00%17.69%
jan glauberjan glauber1116.18%215.38%
matthieu castetmatthieu castet45.88%17.69%
pre-gitpre-git22.94%215.38%
andrew mortonandrew morton11.47%17.69%
josh poimboeufjosh poimboeuf11.47%17.69%
ingo molnaringo molnar11.47%17.69%
Total68100.00%13100.00%


static void module_enable_nx(const struct module *mod) { frob_rodata(&mod->core_layout, set_memory_nx); frob_ro_after_init(&mod->core_layout, set_memory_nx); frob_writable_data(&mod->core_layout, set_memory_nx); frob_rodata(&mod->init_layout, set_memory_nx); frob_writable_data(&mod->init_layout, set_memory_nx); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell3048.39%225.00%
jessica yujessica yu1016.13%112.50%
jan glauberjan glauber914.52%225.00%
ingo molnaringo molnar69.68%112.50%
matthieu castetmatthieu castet69.68%112.50%
andrew mortonandrew morton11.61%112.50%
Total62100.00%8100.00%


static void module_disable_nx(const struct module *mod) { frob_rodata(&mod->core_layout, set_memory_x); frob_ro_after_init(&mod->core_layout, set_memory_x); frob_writable_data(&mod->core_layout, set_memory_x); frob_rodata(&mod->init_layout, set_memory_x); frob_writable_data(&mod->init_layout, set_memory_x); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell3251.61%233.33%
matthieu castetmatthieu castet1219.35%116.67%
jessica yujessica yu1016.13%116.67%
jan glauberjan glauber69.68%116.67%
josh poimboeufjosh poimboeuf23.23%116.67%
Total62100.00%6100.00%

/* Iterate through all modules and set each module's text as RW */
void set_all_modules_text_rw(void) { struct module *mod; mutex_lock(&module_mutex); list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) continue; frob_text(&mod->core_layout, set_memory_rw); frob_text(&mod->init_layout, set_memory_rw); } mutex_unlock(&module_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
matthieu castetmatthieu castet4774.60%120.00%
rusty russellrusty russell1320.63%360.00%
daniel bluemandaniel blueman34.76%120.00%
Total63100.00%5100.00%

/* Iterate through all modules and set each module's text as RO */
void set_all_modules_text_ro(void) { struct module *mod; mutex_lock(&module_mutex); list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) continue; frob_text(&mod->core_layout, set_memory_ro); frob_text(&mod->init_layout, set_memory_ro); } mutex_unlock(&module_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
matthieu castetmatthieu castet4774.60%120.00%
rusty russellrusty russell1320.63%360.00%
daniel bluemandaniel blueman34.76%120.00%
Total63100.00%5100.00%


static void disable_ro_nx(const struct module_layout *layout) { frob_text(layout, set_memory_rw); frob_rodata(layout, set_memory_rw); frob_rodata(layout, set_memory_x); frob_ro_after_init(layout, set_memory_rw); frob_ro_after_init(layout, set_memory_x); frob_writable_data(layout, set_memory_x); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell2444.44%125.00%
jessica yujessica yu1425.93%125.00%
matthieu castetmatthieu castet1324.07%125.00%
josh poimboeufjosh poimboeuf35.56%125.00%
Total54100.00%4100.00%

#else
static void disable_ro_nx(const struct module_layout *layout) { }

Contributors

PersonTokensPropCommitsCommitProp
matthieu castetmatthieu castet654.55%133.33%
rusty russellrusty russell436.36%133.33%
josh poimboeufjosh poimboeuf19.09%133.33%
Total11100.00%3100.00%


static void module_enable_nx(const struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
matthieu castetmatthieu castet763.64%133.33%
jan glauberjan glauber218.18%133.33%
rusty russellrusty russell218.18%133.33%
Total11100.00%3100.00%


static void module_disable_nx(const struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
jan glauberjan glauber545.45%133.33%
matthieu castetmatthieu castet436.36%133.33%
rusty russellrusty russell218.18%133.33%
Total11100.00%3100.00%

#endif #ifdef CONFIG_LIVEPATCH /* * Persist Elf information about a module. Copy the Elf header, * section header table, section string table, and symtab section * index from info to mod->klp_info. */
static int copy_module_elf(struct module *mod, struct load_info *info) { unsigned int size, symndx; int ret; size = sizeof(*mod->klp_info); mod->klp_info = kmalloc(size, GFP_KERNEL); if (mod->klp_info == NULL) return -ENOMEM; /* Elf header */ size = sizeof(mod->klp_info->hdr); memcpy(&mod->klp_info->hdr, info->hdr, size); /* Elf section header table */ size = sizeof(*info->sechdrs) * info->hdr->e_shnum; mod->klp_info->sechdrs = kmalloc(size, GFP_KERNEL); if (mod->klp_info->sechdrs == NULL) { ret = -ENOMEM; goto free_info; } memcpy(mod->klp_info->sechdrs, info->sechdrs, size); /* Elf section name string table */ size = info->sechdrs[info->hdr->e_shstrndx].sh_size; mod->klp_info->secstrings = kmalloc(size, GFP_KERNEL); if (mod->klp_info->secstrings == NULL) { ret = -ENOMEM; goto free_sechdrs; } memcpy(mod->klp_info->secstrings, info->secstrings, size); /* Elf symbol section index */ symndx = info->index.sym; mod->klp_info->symndx = symndx; /* * For livepatch modules, core_kallsyms.symtab is a complete * copy of the original symbol table. Adjust sh_addr to point * to core_kallsyms.symtab since the copy of the symtab in module * init memory is freed at the end of do_init_module(). */ mod->klp_info->sechdrs[symndx].sh_addr = \ (unsigned long) mod->core_kallsyms.symtab; return 0; free_sechdrs: kfree(mod->klp_info->sechdrs); free_info: kfree(mod->klp_info); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
jessica yujessica yu281100.00%1100.00%
Total281100.00%1100.00%


static void free_module_elf(struct module *mod) { kfree(mod->klp_info->sechdrs); kfree(mod->klp_info->secstrings); kfree(mod->klp_info); }

Contributors

PersonTokensPropCommitsCommitProp
jessica yujessica yu36100.00%1100.00%
Total36100.00%1100.00%

#else /* !CONFIG_LIVEPATCH */
static int copy_module_elf(struct module *mod, struct load_info *info) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jessica yujessica yu19100.00%1100.00%
Total19100.00%1100.00%


static void free_module_elf(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
jessica yujessica yu10100.00%1100.00%
Total10100.00%1100.00%

#endif /* CONFIG_LIVEPATCH */
void __weak module_memfree(void *module_region) { vfree(module_region); }

Contributors

PersonTokensPropCommitsCommitProp
jonas bonnjonas bonn1493.33%150.00%
rusty russellrusty russell16.67%150.00%
Total15100.00%2100.00%


void __weak module_arch_cleanup(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
jonas bonnjonas bonn10100.00%1100.00%
Total10100.00%1100.00%


void __weak module_arch_freeing_init(struct module *mod) { }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell10100.00%1100.00%
Total10100.00%1100.00%

/* Free a module, remove from lists, etc. */
static void free_module(struct module *mod) { trace_module_free(mod); mod_sysfs_teardown(mod); /* We leave it in list to prevent duplicate loads, but make sure * that noone uses it while it's being deconstructed. */ mutex_lock(&module_mutex); mod->state = MODULE_STATE_UNFORMED; mutex_unlock(&module_mutex); /* Remove dynamic debug info */ ddebug_remove_module(mod->name); /* Arch-specific cleanup. */ module_arch_cleanup(mod); /* Module unload stuff */ module_unload_free(mod); /* Free any allocated parameters. */ destroy_params(mod->kp, mod->num_kp); if (is_livepatch_module(mod)) free_module_elf(mod); /* Now we can delete it from the lists */ mutex_lock(&module_mutex); /* Unlink carefully: kallsyms could be walking list. */ list_del_rcu(&mod->list); mod_tree_remove(mod); /* Remove this module from bug list, this uses list_del_rcu */ module_bug_cleanup(mod); /* Wait for RCU-sched synchronizing before releasing mod->list and buglist. */ synchronize_sched(); mutex_unlock(&module_mutex); /* This may be empty, but that's OK */ disable_ro_nx(&mod->init_layout); module_arch_freeing_init(mod); module_memfree(mod->init_layout.base); kfree(mod->args); percpu_modfree(mod); /* Free lock-classes; relies on the preceding sync_rcu(). */ lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size); /* Finally, free the core (containing the module structure) */ disable_ro_nx(&mod->core_layout); module_memfree(mod->core_layout.base); #ifdef CONFIG_MPU update_protections(current->mm); #endif }

Contributors

PersonTokensPropCommitsCommitProp
matthieu castetmatthieu castet8542.08%15.88%
rusty russellrusty russell5828.71%741.18%
masami hiramatsumasami hiramatsu136.44%211.76%
bernd schmidtbernd schmidt125.94%15.88%
jessica yujessica yu125.94%15.88%
prarit bhargavaprarit bhargava125.94%15.88%
peter zijlstrapeter zijlstra83.96%317.65%
ingo molnaringo molnar20.99%15.88%
Total202100.00%17100.00%


void *__symbol_get(const char *symbol) { struct module *owner; const struct kernel_symbol *sym; preempt_disable(); sym = find_symbol(symbol, &owner, NULL, true, true); if (sym && strong_try_module_get(owner)) sym = NULL; preempt_enable(); return sym ? (void *)sym->value : NULL; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell4158.57%650.00%
tim abbotttim abbott1622.86%18.33%
pre-gitpre-git1217.14%433.33%
kai germaschewskikai germaschewski11.43%18.33%
Total70100.00%12100.00%

EXPORT_SYMBOL_GPL(__symbol_get); /* * Ensure that an exported symbol [global namespace] does not already exist * in the kernel or in some other module's exported symbol table. * * You must hold the module_mutex. */
static int verify_export_symbols(struct module *mod) { unsigned int i; struct module *owner; const struct kernel_symbol *s; struct { const struct kernel_symbol *sym; unsigned int num; } arr[] = { { mod->syms, mod->num_syms }, { mod->gpl_syms, mod->num_gpl_syms }, { mod->gpl_future_syms, mod->num_gpl_future_syms }, #ifdef CONFIG_UNUSED_SYMBOLS { mod->unused_syms, mod->num_unused_syms }, { mod->unused_gpl_syms, mod->num_unused_gpl_syms }, #endif }; for (i = 0; i < ARRAY_SIZE(arr); i++) { for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) { if (find_symbol(s->name, &owner, NULL, true, false)) { pr_err("%s: exports duplicate symbol %s" " (owned by %s)\n", mod->name, s->name, module_name(owner)); return -ENOEXEC; } } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell11558.67%350.00%
ashutosh naikashutosh naik7337.24%116.67%
denys vlasenkodenys vlasenko73.57%116.67%
andrew mortonandrew morton10.51%116.67%
Total196100.00%6100.00%

/* Change all symbols so that st_value encodes the pointer directly. */
static int simplify_symbols(struct module *mod, const struct load_info *info) { Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; Elf_Sym *sym = (void *)symsec->sh_addr; unsigned long secbase; unsigned int i; int ret = 0; const struct kernel_symbol *ksym; for (i = 1; i < symsec->sh_size / sizeof(Elf_Sym); i++) { const char *name = info->strtab + sym[i].st_name; switch (sym[i].st_shndx) { case SHN_COMMON: /* Ignore common symbols */ if (!strncmp(name, "__gnu_lto", 9)) break; /* We compiled with -fno-common. These are not supposed to happen. */ pr_debug("Common symbol: %s\n", name); pr_warn("%s: please compile with -fno-common\n", mod->name); ret = -ENOEXEC; break; case SHN_ABS: /* Don't need to do anything */ pr_debug("Absolute symbol: 0x%08lx\n", (long)sym[i].st_value); break; case SHN_LIVEPATCH: /* Livepatch symbols are resolved by livepatch */ break; case SHN_UNDEF: ksym = resolve_symbol_wait(mod, info, name); /* Ok if resolved. */ if (ksym && !IS_ERR(ksym)) { sym[i].st_value = ksym->value; break; } /* Ok if weak. */ if (!ksym && ELF_ST_BIND(sym[i].st_info) == STB_WEAK) break; pr_warn("%s: Unknown symbol %s (err %li)\n", mod->name, name, PTR_ERR(ksym)); ret = PTR_ERR(ksym) ?: -ENOENT; break; default: /* Divert to percpu allocation if a percpu var. */ if (sym[i].st_shndx == info->index.pcpu) secbase = (unsigned long)mod_percpu(mod); else secbase = info->sechdrs[sym[i].st_shndx].sh_addr; sym[i].st_value += secbase; break; } } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell24174.84%526.32%
andrew mortonandrew morton309.32%315.79%
tim abbotttim abbott164.97%15.26%
joe mariojoe mario144.35%15.26%
pre-gitpre-git103.11%526.32%
jessica yujessica yu51.55%15.26%
tejun heotejun heo30.93%15.26%
jim cromiejim cromie20.62%15.26%
ionut alexaionut alexa10.31%15.26%
Total322100.00%19100.00%


static int apply_relocations(struct module *mod, const struct load_info *info) { unsigned int i; int err = 0; /* Now do relocations. */ for (i = 1; i < info->hdr->e_shnum; i++) { unsigned int infosec = info->sechdrs[i].sh_info; /* Not a valid relocation section? */ if (infosec >= info->hdr->e_shnum) continue; /* Don't bother with non-allocated sections */ if (!(info->sechdrs[infosec].sh_flags & SHF_ALLOC)) continue; /* Livepatch relocation sections are applied by livepatch */ if (info->sechdrs[i].sh_flags & SHF_RELA_LIVEPATCH) continue; if (info->sechdrs[i].sh_type == SHT_REL) err = apply_relocate(info->sechdrs, info->strtab, info->index.sym, i, mod); else if (info->sechdrs[i].sh_type == SHT_RELA) err = apply_relocate_add(info->sechdrs, info->strtab, info->index.sym, i, mod); if (err < 0) break; } return err; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell17291.98%266.67%
jessica yujessica yu158.02%133.33%
Total187100.00%3100.00%

/* Additional bytes needed by arch in front of individual sections */
unsigned int __weak arch_mod_section_prepend(struct module *mod, unsigned int section) { /* default implementation just returns zero */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
helge dellerhelge deller20100.00%1100.00%
Total20100.00%1100.00%

/* Update size with this section: return offset. */
static long get_offset(struct module *mod, unsigned int *size, Elf_Shdr *sechdr, unsigned int section) { long ret; *size += arch_mod_section_prepend(mod, section); ret = ALIGN(*size, sechdr->sh_addralign ?: 1); *size = ret + sechdr->sh_size; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell3960.94%228.57%
helge dellerhelge deller1929.69%114.29%
pre-gitpre-git57.81%342.86%
denys vlasenkodenys vlasenko11.56%114.29%
Total64100.00%7100.00%

/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld might -- code, read-only data, read-write data, small data. Tally sizes, and place the offsets into sh_entsize fields: high bit means it belongs in init. */
static void layout_sections(struct module *mod, struct load_info *info) { static unsigned long const masks[][2] = { /* NOTE: all executable code must be the first section * in this array; otherwise modify the text_size * finder in the two loops below */ { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL }, { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL }, { SHF_RO_AFTER_INIT | SHF_ALLOC, ARCH_SHF_SMALL }, { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL }, { ARCH_SHF_SMALL | SHF_ALLOC, 0 } }; unsigned int m, i; for (i = 0; i < info->hdr->e_shnum; i++) info->sechdrs[i].sh_entsize = ~0UL; pr_debug("Core section allocation order:\n"); for (m = 0; m < ARRAY_SIZE(masks); ++m) { for (i = 0; i < info->hdr->e_shnum; ++i) { Elf_Shdr *s = &info->sechdrs[i]; const char *sname = info->secstrings + s->sh_name; if ((s->sh_flags & masks[m][0]) != masks[m][0] || (s->sh_flags & masks[m][1]) || s->sh_entsize != ~0UL || strstarts(sname, ".init")) continue; s->sh_entsize = get_offset(mod, &mod->core_layout.size, s, i); pr_debug("\t%s\n", sname); } switch (m) { case 0: /* executable */ mod->core_layout.size = debug_align(mod->core_layout.size); mod->core_layout.text_size = mod->core_layout.size; break; case 1: /* RO: text and ro-data */ mod->core_layout.size = debug_align(mod->core_layout.size); mod->core_layout.ro_size = mod->core_layout.size; break; case 2: /* RO after init */ mod->core_layout.size = debug_align(mod->core_layout.size); mod->core_layout.ro_after_init_size = mod->core_layout.size; break; case 4: /* whole core */ mod->core_layout.size = debug_align(mod->core_layout.size); break; } } pr_debug("Init section allocation order:\n"); for (m = 0; m < ARRAY_SIZE(masks); ++m) { for (i = 0; i < info->hdr->e_shnum; ++i) { Elf_Shdr *s = &info->sechdrs[i]; const char *sname = info->secstrings + s->sh_name; if ((s->sh_flags & masks[m][0]) != masks[m][0] || (s->sh_flags & masks[m][1]) || s->sh_entsize != ~0UL || !strstarts(sname, ".init")) continue; s->sh_entsize = (get_offset(mod, &mod->init_layout.size, s, i) | INIT_OFFSET_MASK); pr_debug("\t%s\n", sname); } switch (m) { case 0: /* executable */ mod->init_layout.size = debug_align(mod->init_layout.size); mod->init_layout.text_size = mod->init_layout.size; break; case 1: /* RO: text and ro-data */ mod->init_layout.size = debug_align(mod->init_layout.size); mod->init_layout.ro_size = mod->init_layout.size; break; case 2: /* * RO after init doesn't apply to init_layout (only * core_layout), so it just takes the value of ro_size. */ mod->init_layout.ro_after_init_size = mod->init_layout.ro_size; break; case 4: /* whole init */ mod->init_layout.size = debug_align(mod->init_layout.size); break; } } }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell42767.56%853.33%
matthieu castetmatthieu castet10015.82%16.67%
jessica yujessica yu599.34%16.67%
richard hendersonrichard henderson182.85%16.67%
pre-gitpre-git152.37%213.33%
helge dellerhelge deller81.27%16.67%
jim cromiejim cromie50.79%16.67%
Total632100.00%15100.00%


static void set_license(struct module *mod, const char *license) { if (!license) license = "unspecified"; if (!license_is_gpl_compatible(license)) { if (!test_taint(TAINT_PROPRIETARY_MODULE)) pr_warn("%s: module license '%s' taints kernel.\n", mod->name, license); add_taint_module(mod, TAINT_PROPRIETARY_MODULE, LOCKDEP_NOW_UNRELIABLE); } }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell4571.43%333.33%
florin malitaflorin malita812.70%111.11%
randy dunlaprandy dunlap46.35%222.22%
andrew mortonandrew morton34.76%222.22%
andi kleenandi kleen34.76%111.11%
Total63100.00%9100.00%

/* Parse tag=value strings from .modinfo section */
static char *next_string(char *string, unsigned long *secsize) { /* Skip non-zero chars */ while (string[0]) { string++; if ((*secsize)-- <= 1) return NULL; } /* Skip any zero padding. */ while (!string[0]) { string++; if ((*secsize)-- <= 1) return NULL; } return string; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell72100.00%1100.00%
Total72100.00%1100.00%


static char *get_modinfo(struct load_info *info, const char *tag) { char *p; unsigned int taglen = strlen(tag); Elf_Shdr *infosec = &info->sechdrs[info->index.info]; unsigned long size = infosec->sh_size; for (p = (char *)infosec->sh_addr; p; p = next_string(p, &size)) { if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') return p + taglen + 1; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell110100.00%2100.00%
Total110100.00%2100.00%


static void setup_modinfo(struct module *mod, struct load_info *info) { struct module_attribute *attr; int i; for (i = 0; (attr = modinfo_attrs[i]); i++) { if (attr->setup) attr->setup(mod, get_modinfo(info, attr->attr.name)); } }

Contributors

PersonTokensPropCommitsCommitProp
matt domschmatt domsch6494.12%150.00%
rusty russellrusty russell45.88%150.00%
Total68100.00%2100.00%


static void free_modinfo(struct module *mod) { struct module_attribute *attr; int i; for (i = 0; (attr = modinfo_attrs[i]); i++) { if (attr->free) attr->free(mod); } }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell52100.00%1100.00%
Total52100.00%1100.00%

#ifdef CONFIG_KALLSYMS /* lookup symbol in given range of kernel_symbols */
static const struct kernel_symbol *lookup_symbol(const char *name, const struct kernel_symbol *start, const struct kernel_symbol *stop) { return bsearch(name, start, stop - start, sizeof(struct kernel_symbol), cmp_name); }

Contributors

PersonTokensPropCommitsCommitProp
americo wangamerico wang3269.57%150.00%
alessio igor boganialessio igor bogani1430.43%150.00%
Total46100.00%2100.00%


static int is_exported(const char *name, unsigned long value, const struct module *mod) { const struct kernel_symbol *ks; if (!mod) ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab); else ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); return ks != NULL && ks->value == value; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell3243.24%125.00%
tim abbotttim abbott2736.49%125.00%
sam ravnborgsam ravnborg1418.92%125.00%
alexey dobriyanalexey dobriyan11.35%125.00%
Total74100.00%4100.00%

/* As per nm */
static char elf_type(const Elf_Sym *sym, const struct load_info *info) { const Elf_Shdr *sechdrs = info->sechdrs; if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT) return 'v'; else return 'w'; } if (sym->st_shndx == SHN_UNDEF) return 'U'; if (sym->st_shndx == SHN_ABS || sym->st_shndx == info->index.pcpu) return 'a'; if (sym->st_shndx >= SHN_LORESERVE) return '?'; if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR) return 't'; if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC && sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) { if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE)) return 'r'; else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL) return 'g'; else return 'd'; } if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) { if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL) return 's'; else return 'b'; } if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name, ".debug")) { return 'n'; } return '?'; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell23595.92%375.00%
miroslav benesmiroslav benes104.08%125.00%
Total245100.00%4100.00%


static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs, unsigned int shnum, unsigned int pcpundx) { const Elf_Shdr *sec; if (src->st_shndx == SHN_UNDEF || src->st_shndx >= shnum || !src->st_name) return false; #ifdef CONFIG_KALLSYMS_ALL if (src->st_shndx == pcpundx) return true; #endif sec = sechdrs + src->st_shndx; if (!(sec->sh_flags & SHF_ALLOC) #ifndef CONFIG_KALLSYMS_ALL || !(sec->sh_flags & SHF_EXECINSTR) #endif || (sec->sh_entsize & INIT_OFFSET_MASK)) return false; return true; }

Contributors

PersonTokensPropCommitsCommitProp
jan beulichjan beulich9482.46%150.00%
miroslav benesmiroslav benes2017.54%150.00%
Total114100.00%2100.00%

/* * We only allocate and copy the strings needed by the parts of symtab * we keep. This is simple, but has the effect of making multiple * copies of duplicates. We could be more sophisticated, see * linux-kernel thread starting with * <73defb5e4bca04a6431392cc341112b1@localhost>. */
static void layout_symtab(struct module *mod, struct load_info *info) { Elf_Shdr *symsect = info->sechdrs + info->index.sym; Elf_Shdr *strsect = info->sechdrs + info->index.str; const Elf_Sym *src; unsigned int i, nsrc, ndst, strtab_size = 0; /* Put symbol section at end of init part of module. */ symsect->sh_flags |= SHF_ALLOC; symsect->sh_entsize = get_offset(mod, &mod->init_layout.size, symsect, info->index.sym) | INIT_OFFSET_MASK; pr_debug("\t%s\n", info->secstrings + symsect->sh_name); src = (void *)info->hdr + symsect->sh_offset; nsrc = symsect->sh_size / sizeof(*src); /* Compute total space required for the core symbols' strtab. */ for (ndst = i = 0; i < nsrc; i++) { if (i == 0 || is_livepatch_module(mod) || is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum, info->index.pcpu)) { strtab_size += strlen(&info->strtab[src[i].st_name])+1; ndst++; } } /* Append room for core symbols at end of core part. */ info->symoffs = ALIGN(mod->core_layout.size, symsect->sh_addralign ?: 1); info->stroffs = mod->core_layout.size = info->symoffs + ndst * sizeof(Elf_Sym); mod->core_layout.size += strtab_size; mod->core_layout.size = debug_align(mod->core_layout.size); /* Put string table section at end of init part of module. */ strsect->sh_flags |= SHF_ALLOC; strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect, info->index.str) | INIT_OFFSET_MASK; pr_debug("\t%s\n", info->secstrings + strsect->sh_name); /* We'll tack temporary mod_kallsyms on the end. */ mod->init_layout.size = ALIGN(mod->init_layout.size, __alignof__(struct mod_kallsyms)); info->mod_kallsyms_init_off = mod->init_layout.size; mod->init_layout.size += sizeof(struct mod_kallsyms); mod->init_layout.size = debug_align(mod->init_layout.size); }

Contributors

PersonTokensPropCommitsCommitProp
jan beulichjan beulich18749.21%216.67%
rusty russellrusty russell14036.84%433.33%
kevin cernekeekevin cernekee225.79%18.33%
laura abbottlaura abbott174.47%18.33%
miroslav benesmiroslav benes61.58%18.33%
jessica yujessica yu51.32%18.33%
satoru takeuchisatoru takeuchi20.53%18.33%
jim cromiejim cromie10.26%18.33%
Total380100.00%12100.00%

/* * We use the full symtab and strtab which layout_symtab arranged to * be appended to the init section. Later we switch to the cut-down * core-only ones. */
static void add_kallsyms(struct module *mod, const struct load_info *info) { unsigned int i, ndst; const Elf_Sym *src; Elf_Sym *dst; char *s; Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; /* Set up to point into init section. */ mod->kallsyms = mod->init_layout.base + info->mod_kallsyms_init_off; mod->kallsyms->symtab = (void *)symsec->sh_addr; mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym); /* Make sure we get permanent strtab: don't use info->strtab. */ mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr; /* Set types up while we still have access to sections. */ for (i = 0; i < mod->kallsyms->num_symtab; i++) mod->kallsyms->symtab[i].st_info = elf_type(&mod->kallsyms->symtab[i], info); /* Now populate the cut down core kallsyms for after init. */ mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs; mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs; src = mod->kallsyms->symtab; for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) { if (i == 0 || is_livepatch_module(mod) || is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum, info->index.pcpu)) { dst[ndst] = src[i]; dst[ndst++].st_name = s - mod->core_kallsyms.strtab; s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name], KSYM_NAME_LEN) + 1; } } mod->core_kallsyms.num_symtab = ndst; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell20061.35%861.54%
jan beulichjan beulich8425.77%215.38%
kevin cernekeekevin cernekee319.51%17.69%
miroslav benesmiroslav benes61.84%17.69%
jessica yujessica yu51.53%17.69%
Total326100.00%13100.00%

#else
static inline void layout_symtab(struct module *mod, struct load_info *info) { }

Contributors

PersonTokensPropCommitsCommitProp
jan beulichjan beulich1168.75%266.67%
rusty russellrusty russell531.25%133.33%
Total16100.00%3100.00%


static void add_kallsyms(struct module *mod, const struct load_info *info) { }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton1275.00%133.33%
rusty russellrusty russell318.75%133.33%
michal miroslawmichal miroslaw16.25%133.33%
Total16100.00%3100.00%

#endif /* CONFIG_KALLSYMS */
static void dynamic_debug_setup(struct _ddebug *debug, unsigned int num) { if (!debug) return; #ifdef CONFIG_DYNAMIC_DEBUG if (ddebug_add_module(debug, num, debug->modname)) pr_err("dynamic debug error adding module: %s\n", debug->modname); #endif }

Contributors

PersonTokensPropCommitsCommitProp
jason baronjason baron3266.67%240.00%
rusty russellrusty russell1531.25%240.00%
andrew mortonandrew morton12.08%120.00%
Total48100.00%5100.00%


static void dynamic_debug_remove(struct _ddebug *debug) { if (debug) ddebug_remove_module(debug->modname); }

Contributors

PersonTokensPropCommitsCommitProp
yehuda sadehyehuda sadeh22100.00%1100.00%
Total22100.00%1100.00%


void * __weak module_alloc(unsigned long size) { return vmalloc_exec(size); }

Contributors

PersonTokensPropCommitsCommitProp
jonas bonnjonas bonn17100.00%1100.00%
Total17100.00%1100.00%

#ifdef CONFIG_DEBUG_KMEMLEAK
static void kmemleak_load_module(const struct module *mod, const struct load_info *info) { unsigned int i; /* only scan the sections containing data */ kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL); for (i = 1; i < info->hdr->e_shnum; i++) { /* Scan all writable sections that's not executable */ if (!(info->sechdrs[i].sh_flags & SHF_ALLOC) || !(info->sechdrs[i].sh_flags & SHF_WRITE) || (info->sechdrs[i].sh_flags & SHF_EXECINSTR)) continue; kmemleak_scan_area((void *)info->sechdrs[i].sh_addr, info->sechdrs[i].sh_size, GFP_KERNEL); } }

Contributors

PersonTokensPropCommitsCommitProp
catalin marinascatalin marinas8264.57%240.00%
steven rostedtsteven rostedt2318.11%120.00%
rusty russellrusty russell2116.54%120.00%
linus torvaldslinus torvalds10.79%120.00%
Total127100.00%5100.00%

#else
static inline void kmemleak_load_module(const struct module *mod, const struct load_info *info) { }

Contributors

PersonTokensPropCommitsCommitProp
catalin marinascatalin marinas1372.22%133.33%
rusty russellrusty russell422.22%133.33%
linus torvaldslinus torvalds15.56%133.33%
Total18100.00%3100.00%

#endif #ifdef CONFIG_MODULE_SIG
static int module_sig_check(struct load_info *info, int flags) { int err = -ENOKEY; const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; const void *mod = info->hdr; /* * Require flags == 0, as a module with version information * removed is no longer the module that was signed */ if (flags == 0 && info->len > markerlen && memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { /* We truncate the module to discard the signature */ info->len -= markerlen; err = mod_verify_sig(mod, &info->len); } if (!err) { info->sig_ok = true; return 0; } /* Not having a signature is only an error if we're strict. */ if (err == -ENOKEY && !sig_enforce) err = 0; return err; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell8869.84%125.00%
kees cookkees cook1915.08%125.00%
david howellsdavid howells118.73%125.00%
ben hutchingsben hutchings86.35%125.00%
Total126100.00%4100.00%

#else /* !CONFIG_MODULE_SIG */
static int module_sig_check(struct load_info *info, int flags) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell1482.35%150.00%
ben hutchingsben hutchings317.65%150.00%
Total17100.00%2100.00%

#endif /* !CONFIG_MODULE_SIG */ /* Sanity checks against invalid binaries, wrong arch, weird elf version. */
static int elf_header_check(struct load_info *info) { if (info->len < sizeof(*(info->hdr))) return -ENOEXEC; if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0 || info->hdr->e_type != ET_REL || !elf_check_arch(info->hdr) || info->hdr->e_shentsize != sizeof(Elf_Shdr)) return -ENOEXEC; if (info->hdr->e_shoff >= info->len || (info->hdr->e_shnum * sizeof(Elf_Shdr) > info->len - info->hdr->e_shoff)) return -ENOEXEC; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell5444.63%120.00%
kees cookkees cook3125.62%120.00%
linus torvaldslinus torvalds2722.31%240.00%
david howellsdavid howells97.44%120.00%
Total121100.00%5100.00%

#define COPY_CHUNK_SIZE (16*PAGE_SIZE)
static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned long len) { do { unsigned long n = min(len, COPY_CHUNK_SIZE); if (copy_from_user(dst, usrc, n) != 0) return -EFAULT; cond_resched(); dst += n; usrc += n; len -= n; } while (len); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds74100.00%1100.00%
Total74100.00%1100.00%

#ifdef CONFIG_LIVEPATCH
static int check_modinfo_livepatch(struct module *mod, struct load_info *info) { if (get_modinfo(info, "livepatch")) { mod->klp = true; add_taint_module(mod, TAINT_LIVEPATCH, LOCKDEP_STILL_OK); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jessica yujessica yu2657.78%150.00%
josh poimboeufjosh poimboeuf1942.22%150.00%
Total45100.00%2100.00%

#else /* !CONFIG_LIVEPATCH */
static int check_modinfo_livepatch(struct module *mod, struct load_info *info) { if (get_modinfo(info, "livepatch")) { pr_err("%s: module is marked as livepatch module, but livepatch support is disabled", mod->name); return -ENOEXEC; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jessica yujessica yu4297.67%150.00%
josh poimboeufjosh poimboeuf12.33%150.00%
Total43100.00%2100.00%

#endif /* CONFIG_LIVEPATCH */ /* Sets info->hdr and info->len. */
static int copy_module_from_user(const void __user *umod, unsigned long len, struct load_info *info) { int err; info->len = len; if (info->len < sizeof(*(info->hdr))) return -ENOEXEC; err = security_kernel_read_file(NULL, READING_MODULE); if (err) return err; /* Suck in entire file: we'll want most of it. */ info->hdr = __vmalloc(info->len, GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN, PAGE_KERNEL); if (!info->hdr) return -ENOMEM; if (copy_chunked_from_user(info->hdr, umod, info->len) != 0) { vfree(info->hdr); return -EFAULT; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
kees cookkees cook7255.38%225.00%
rusty russellrusty russell4534.62%337.50%
kirill a. shutemovkirill a. shutemov96.92%112.50%
mimi zoharmimi zohar32.31%112.50%
linus torvaldslinus torvalds10.77%112.50%
Total130100.00%8100.00%


static void free_copy(struct load_info *info) { vfree(info->hdr); }

Contributors

PersonTokensPropCommitsCommitProp
kees cookkees cook1477.78%150.00%
linus torvaldslinus torvalds422.22%150.00%
Total18100.00%2100.00%


static int rewrite_section_headers(struct load_info *info, int flags) { unsigned int i; /* This should always be true, but let's be sure. */ info->sechdrs[0].sh_addr = 0; for (i = 1; i < info->hdr->e_shnum; i++) { Elf_Shdr *shdr = &info->sechdrs[i]; if (shdr->sh_type != SHT_NOBITS && info->len < shdr->sh_offset + shdr->sh_size) { pr_err("Module len %lu truncated\n", info->len); return -ENOEXEC; } /* Mark all sections sh_addr with their address in the temporary image. */ shdr->sh_addr = (size_t)info->hdr + shdr->sh_offset; #ifndef CONFIG_MODULE_UNLOAD /* Don't load .exit sections */ if (strstarts(info->secstrings+shdr->sh_name, ".exit")) shdr->sh_flags &= ~(unsigned long)SHF_ALLOC; #endif } /* Track but don't keep modinfo and version sections. */ if (flags & MODULE_INIT_IGNORE_MODVERSIONS) info->index.vers = 0; /* Pretend no __versions section! */ else info->index.vers = find_sec(info, "__versions"); info->index.info = find_sec(info, ".modinfo"); info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC; info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell16973.48%342.86%
linus torvaldslinus torvalds4218.26%228.57%
kees cookkees cook187.83%114.29%
andrew mortonandrew morton10.43%114.29%
Total230100.00%7100.00%

/* * Set up our basic convenience variables (pointers to section headers, * search for module section index etc), and do some basic section * verification. * * Return the temporary module pointer (we'll replace it with the final * one when we move the module sections around). */
static struct module *setup_load_info(struct load_info *info, int flags) { unsigned int i; int err; struct module *mod; /* Set up the convenience variables */ info->sechdrs = (void *)info->hdr + info->hdr->e_shoff; info->secstrings = (void *)info->hdr + info->sechdrs[info->hdr->e_shstrndx].sh_offset; err = rewrite_section_headers(info, flags); if (err) return ERR_PTR(err); /* Find internal symbols and strings. */ for (i = 1; i < info->hdr->e_shnum; i++) { if (info->sechdrs[i].sh_type == SHT_SYMTAB) { info->index.sym = i; info->index.str = info->sechdrs[i].sh_link; info->strtab = (char *)info->hdr + info->sechdrs[info->index.str].sh_offset; break; } } info->index.mod = find_sec(info, ".gnu.linkonce.this_module"); if (!info->index.mod) { pr_warn("No module found in object\n"); return ERR_PTR(-ENOEXEC); } /* This is temporary: point mod into copy of data. */ mod = (void *)info->sechdrs[info->index.mod].sh_addr; if (info->index.sym == 0) { pr_warn("%s: module has no symbols (stripped?)\n", mod->name); return ERR_PTR(-ENOEXEC); } info->index.pcpu = find_pcpusec(info); /* Check module struct version now, before we try to use module. */ if (!check_modstruct_version(info->sechdrs, info->index.vers, mod)) return ERR_PTR(-ENOEXEC); return mod; }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds23779.26%222.22%
rusty russellrusty russell5518.39%555.56%
ben hutchingsben hutchings51.67%111.11%
andrew mortonandrew morton20.67%111.11%
Total299100.00%9100.00%


static int check_modinfo(struct module *mod, struct load_info *info, int flags) { const char *modmagic = get_modinfo(info, "vermagic"); int err; if (flags & MODULE_INIT_IGNORE_VERMAGIC) modmagic = NULL; /* This is allowed: modprobe --force will invalidate it. */ if (!modmagic) { err = try_to_force_load(mod, "bad vermagic"); if (err) return err; } else if (!same_magic(modmagic, vermagic, info->index.vers)) { pr_err("%s: version magic '%s' should be '%s'\n", mod->name, modmagic, vermagic); return -ENOEXEC; } if (!get_modinfo(info, "intree")) { if (!test_taint(TAINT_OOT_MODULE)) pr_warn("%s: loading out-of-tree module taints kernel.\n", mod->name); add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK); } if (get_modinfo(info, "staging")) { add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK); pr_warn("%s: module is from the staging directory, the quality " "is unknown, you have been warned.\n", mod->name); } err = check_modinfo_livepatch(mod, info); if (err) return err; /* Set up license info based on the info section */ set_license(mod, get_modinfo(info, "license")); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds10752.45%218.18%
rusty russellrusty russell4120.10%436.36%
libor pechaceklibor pechacek199.31%19.09%
ben hutchingsben hutchings178.33%19.09%
jessica yujessica yu157.35%19.09%
andrew mortonandrew morton41.96%19.09%
josh poimboeufjosh poimboeuf10.49%19.09%
Total204100.00%11100.00%


static int find_module_sections(struct module *mod, struct load_info *info) { mod->kp = section_objs(info, "__param", sizeof(*mod->kp), &mod->num_kp); mod->syms = section_objs(info, "__ksymtab", sizeof(*mod->syms), &mod->num_syms); mod->crcs = section_addr(info, "__kcrctab"); mod->gpl_syms = section_objs(info, "__ksymtab_gpl", sizeof(*mod->gpl_syms), &mod->num_gpl_syms); mod->gpl_crcs = section_addr(info, "__kcrctab_gpl"); mod->gpl_future_syms = section_objs(info, "__ksymtab_gpl_future", sizeof(*mod->gpl_future_syms), &mod->num_gpl_future_syms); mod->gpl_future_crcs = section_addr(info, "__kcrctab_gpl_future"); #ifdef CONFIG_UNUSED_SYMBOLS mod->unused_syms = section_objs(info, "__ksymtab_unused", sizeof(*mod->unused_syms), &mod->num_unused_syms); mod->unused_crcs = section_addr(info, "__kcrctab_unused"); mod->unused_gpl_syms = section_objs(info, "__ksymtab_unused_gpl", sizeof(*mod->unused_gpl_syms), &mod->num_unused_gpl_syms); mod->unused_gpl_crcs = section_addr(info, "__kcrctab_unused_gpl"); #endif #ifdef CONFIG_CONSTRUCTORS mod->ctors = section_objs(info, ".ctors", sizeof(*mod->ctors), &mod->num_ctors); if (!mod->ctors) mod->ctors = section_objs(info, ".init_array", sizeof(*mod->ctors), &mod->num_ctors); else if (find_sec(info, ".init_array")) { /* * This shouldn't happen with same compiler and binutils * building all parts of the module. */ pr_warn("%s: has both .ctors and .init_array.\n", mod->name); return -EINVAL; } #endif #ifdef CONFIG_TRACEPOINTS mod->tracepoints_ptrs = section_objs(info, "__tracepoints_ptrs", sizeof(*mod->tracepoints_ptrs), &mod->num_tracepoints); #endif #ifdef HAVE_JUMP_LABEL mod->jump_entries = section_objs(info, "__jump_table", sizeof(*mod->jump_entries), &mod->num_jump_entries); #endif #ifdef CONFIG_EVENT_TRACING mod->trace_events = section_objs(info, "_ftrace_events", sizeof(*mod->trace_events), &mod->num_trace_events); mod->trace_enums = section_objs(info, "_ftrace_enum_map", sizeof(*mod->trace_enums), &mod->num_trace_enums); #endif #ifdef CONFIG_TRACING mod->trace_bprintk_fmt_start = section_objs(info, "__trace_printk_fmt", sizeof(*mod->trace_bprintk_fmt_start), &mod->num_trace_bprintk_fmt); #endif #ifdef CONFIG_FTRACE_MCOUNT_RECORD /* sechdrs[0].sh_size is always zero */ mod->ftrace_callsites = section_objs(info, "__mcount_loc", sizeof(*mod->ftrace_callsites), &mod->num_ftrace_callsites); #endif mod->extable = section_objs(info, "__ex_table", sizeof(*mod->extable), &mod->num_exentries); if (section_addr(info, "__obsparm")) pr_warn("%s: Ignoring obsolete parameters\n", mod->name); info->debug = section_objs(info, "__verbose", sizeof(*info->debug), &info->num_debug); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds29654.31%211.11%
rusty russellrusty russell9617.61%633.33%
frantisek hrbatafrantisek hrbata6011.01%15.56%
steven rostedtsteven rostedt539.72%211.11%
jason baronjason baron295.32%15.56%
pre-gitpre-git50.92%211.11%
mathieu desnoyersmathieu desnoyers30.55%15.56%
ionut alexaionut alexa10.18%15.56%
kai germaschewskikai germaschewski10.18%15.56%
andrew mortonandrew morton10.18%15.56%
Total545100.00%18100.00%


static int move_module(struct module *mod, struct load_info *info) { int i; void *ptr; /* Do the allocs. */ ptr = module_alloc(mod->core_layout.size); /* * The pointer to this block is stored in the module structure * which is inside the block. Just mark it as not being a * leak. */ kmemleak_not_leak(ptr); if (!ptr) return -ENOMEM; memset(ptr, 0, mod->core_layout.size); mod->core_layout.base = ptr; if (mod->init_layout.size) { ptr = module_alloc(mod->init_layout.size); /* * The pointer to this block is stored in the module structure * which is inside the block. This block doesn't need to be * scanned as it contains data and code that will be freed * after the module is initialized. */ kmemleak_ignore(ptr); if (!ptr) { module_memfree(mod->core_layout.base); return -ENOMEM; } memset(ptr, 0, mod->init_layout.size); mod->init_layout.base = ptr; } else mod->init_layout.base = NULL; /* Transfer each section which specifies SHF_ALLOC */ pr_debug("final section addresses:\n"); for (i = 0; i < info->hdr->e_shnum; i++) { void *dest; Elf_Shdr *shdr = &info->sechdrs[i]; if (!(shdr->sh_flags & SHF_ALLOC)) continue; if (shdr->sh_entsize & INIT_OFFSET_MASK) dest = mod->init_layout.base + (shdr->sh_entsize & ~INIT_OFFSET_MASK); else dest = mod->core_layout.base + shdr->sh_entsize; if (shdr->sh_type != SHT_NOBITS) memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size); /* Update sh_addr to point to copy in image. */ shdr->sh_addr = (unsigned long)dest; pr_debug("\t0x%lx %s\n", (long)shdr->sh_addr, info->secstrings + shdr->sh_name); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell14849.66%1052.63%
linus torvaldslinus torvalds13143.96%210.53%
andrew mortonandrew morton62.01%15.26%
kai germaschewskikai germaschewski51.68%315.79%
jim cromiejim cromie51.68%15.26%
peter zijlstrapeter zijlstra20.67%15.26%
pre-gitpre-git10.34%15.26%
Total298100.00%19100.00%


static int check_module_license_and_versions(struct module *mod) { int prev_taint = test_taint(TAINT_PROPRIETARY_MODULE); /* * ndiswrapper is under GPL by itself, but loads proprietary modules. * Don't use add_taint_module(), as it would prevent ndiswrapper from * using GPL-only symbols it needs. */ if (strcmp(mod->name, "ndiswrapper") == 0) add_taint(TAINT_PROPRIETARY_MODULE, LOCKDEP_NOW_UNRELIABLE); /* driverloader was caught wrongly pretending to be under GPL */ if (strcmp(mod->name, "driverloader") == 0) add_taint_module(mod, TAINT_PROPRIETARY_MODULE, LOCKDEP_NOW_UNRELIABLE); /* lve claims to be GPL but upstream won't provide source */ if (strcmp(mod->name, "lve") == 0) add_taint_module(mod, TAINT_PROPRIETARY_MODULE, LOCKDEP_NOW_UNRELIABLE); if (!prev_taint && test_taint(TAINT_PROPRIETARY_MODULE)) pr_warn("%s: module license taints kernel.\n", mod->name); #ifdef CONFIG_MODVERSIONS if ((mod->num_syms && !mod->crcs) || (mod->num_gpl_syms && !mod->gpl_crcs) || (mod->num_gpl_future_syms && !mod->gpl_future_crcs) #ifdef CONFIG_UNUSED_SYMBOLS || (mod->num_unused_syms && !mod->unused_crcs) || (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs) #endif ) { return try_to_force_load(mod, "no versions for exported symbols"); } #endif return 0; }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds12064.86%114.29%
libor pechaceklibor pechacek2714.59%114.29%
matthew garrettmatthew garrett2111.35%114.29%
rusty russellrusty russell84.32%228.57%
kai germaschewskikai germaschewski84.32%114.29%
arjan van de venarjan van de ven10.54%114.29%
Total185100.00%7100.00%


static void flush_module_icache(const struct module *mod) { mm_segment_t old_fs; /* flush the icache in correct context */ old_fs = get_fs(); set_fs(KERNEL_DS); /* * Flush the instruction cache, since we've played with text. * Do it before processing of module parameters, so the module * can provide parameter accessor functions of its own. */ if (mod->init_layout.base) flush_icache_range((unsigned long)mod->init_layout.base, (unsigned long)mod->init_layout.base + mod->init_layout.size); flush_icache_range((unsigned long)mod->core_layout.base, (unsigned long)mod->core_layout.base + mod->core_layout.size); set_fs(old_fs); }

Contributors

PersonTokensPropCommitsCommitProp
linus torvaldslinus torvalds6061.22%233.33%
rusty russellrusty russell2121.43%116.67%
greg kroah-hartmangreg kroah-hartman1111.22%116.67%
jan beulichjan beulich33.06%116.67%
andrew mortonandrew morton33.06%116.67%
Total98100.00%6100.00%


int __weak module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonas bonnjonas bonn26100.00%1100.00%
Total26100.00%1100.00%

/* module_blacklist is a comma-separated list of module names */ static char *module_blacklist;
static bool blacklisted(char *module_name) { const char *p; size_t len; if (!module_blacklist) return false; for (p = module_blacklist; *p; p += len) { len = strcspn(p, ","); if (strlen(module_name) == len && !memcmp(module_name, p, len)) return true; if (p[len] == ',') len++; } return false; }

Contributors

PersonTokensPropCommitsCommitProp
prarit bhargavaprarit bhargava87100.00%1100.00%
Total87100.00%1100.00%

core_param(module_blacklist, module_blacklist, charp, 0400);
static struct module *layout_and_allocate(struct load_info *info, int flags) { /* Module within temporary copy. */ struct module *mod; unsigned int ndx; int err; mod = setup_load_info(info, flags); if (IS_ERR(mod)) return mod; if (blacklisted(mod->name)) return ERR_PTR(-EPERM); err = check_modinfo(mod, info, flags); if (err) return ERR_PTR(err); /* Allow arches to frob section contents and sizes. */ err = module_frob_arch_sections(info->hdr, info->sechdrs, info->secstrings, mod); if (err < 0) return ERR_PTR(err); /* We will do a special allocation for per-cpu sections later. */ info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC; /* * Mark ro_after_init section with SHF_RO_AFTER_INIT so that * layout_sections() can put it in the right place. * Note: ro_after_init sections also have SHF_{WRITE,ALLOC} set. */ ndx = find_sec(info, ".data..ro_after_init"); if (ndx) info->sechdrs[ndx].sh_flags |= SHF_RO_AFTER_INIT; /* Determine total sizes, and put offsets in sh_entsize. For now this is done generically; there doesn't appear to be any special cases for the architectures. */ layout_sections(mod, info); layout_symtab(mod, info); /* Allocate and move to the final place */ err = move_module(mod, info); if (err) return ERR_PTR(err); /* Module has been copied to its final place now: return it. */ mod = (void *)info->sechdrs[info->index.mod].sh_addr; kmemleak_load_module(mod, info); return mod; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell13057.02%847.06%
linus torvaldslinus torvalds4921.49%317.65%
jessica yujessica yu2912.72%15.88%
prarit bhargavaprarit bhargava167.02%15.88%
dave jonesdave jones10.44%15.88%
denys vlasenkodenys vlasenko10.44%15.88%
florin malitaflorin malita10.44%15.88%
randy dunlaprandy dunlap10.44%15.88%
Total228100.00%17100.00%

/* mod is no longer valid after this! */
static void module_deallocate(struct module *mod, struct load_info *info) { percpu_modfree(mod); module_arch_freeing_init(mod); module_memfree(mod->init_layout.base); module_memfree(mod->core_layout.base); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell3477.27%562.50%
linus torvaldslinus torvalds920.45%225.00%
arjan van de venarjan van de ven12.27%112.50%
Total44100.00%8100.00%


int __weak module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonas bonnjonas bonn24100.00%1100.00%
Total24100.00%1100.00%


static int post_relocation(struct module *mod, const struct load_info *info) { /* Sort exception table now relocations are done. */ sort_extable(mod->extable, mod->extable + mod->num_exentries); /* Copy relocated percpu area over. */ percpu_modcopy(mod, (void *)info->sechdrs[info->index.pcpu].sh_addr, info->sechdrs[info->index.pcpu].sh_size); /* Setup kallsyms-specific fields. */ add_kallsyms(mod, info); /* Arch-specific module finalizing. */ return module_finalize(info->hdr, info->sechdrs, mod); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell92100.00%2100.00%
Total92100.00%2100.00%

/* Is this module of this name done loading? No locks held. */
static bool finished_loading(const char *name) { struct module *mod; bool ret; /* * The module_mutex should not be a heavily contended lock; * if we get the occasional sleep here, we'll go an extra iteration * in the wait_event_interruptible(), which is harmless. */ sched_annotate_sleep(); mutex_lock(&module_mutex); mod = find_module_all(name, strlen(name), true); ret = !mod || mod->state == MODULE_STATE_LIVE || mod->state == MODULE_STATE_GOING; mutex_unlock(&module_mutex); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell6086.96%360.00%
mathias krausemathias krause57.25%120.00%
peter zijlstrapeter zijlstra45.80%120.00%
Total69100.00%5100.00%

/* Call module constructors. */
static void do_mod_ctors(struct module *mod) { #ifdef CONFIG_CONSTRUCTORS unsigned long i; for (i = 0; i < mod->num_ctors; i++) mod->ctors[i](); #endif }

Contributors

PersonTokensPropCommitsCommitProp
kees cookkees cook3784.09%133.33%
rusty russellrusty russell715.91%266.67%
Total44100.00%3100.00%

/* For freeing module_init on success, in case kallsyms traversing */ struct mod_initfree { struct rcu_head rcu; void *module_init; };
static void do_free_init(struct rcu_head *head) { struct mod_initfree *m = container_of(head, struct mod_initfree, rcu); module_memfree(m->module_init); kfree(m); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell38100.00%1100.00%
Total38100.00%1100.00%

/* * This is where the real work happens. * * Keep it uninlined to provide a reliable breakpoint target, e.g. for the gdb * helper command 'lx-symbols'. */
static noinline int do_init_module(struct module *mod) { int ret = 0; struct mod_initfree *freeinit; freeinit = kmalloc(sizeof(*freeinit), GFP_KERNEL); if (!freeinit) { ret = -ENOMEM; goto fail; } freeinit->module_init = mod->init_layout.base; /* * We want to find out whether @mod uses async during init. Clear * PF_USED_ASYNC. async_schedule*() will set it. */ current->flags &= ~PF_USED_ASYNC; do_mod_ctors(mod); /* Start the module */ if (mod->init != NULL) ret = do_one_initcall(mod->init); if (ret < 0) { goto fail_free_freeinit; } if (ret > 0) { pr_warn("%s: '%s'->init suspiciously returned %d, it should " "follow 0/-E convention\n" "%s: loading module anyway...\n", __func__, mod->name, ret, __func__); dump_stack(); } /* Now it's a first class citizen! */ mod->state = MODULE_STATE_LIVE; blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_LIVE, mod); /* * We need to finish all async code before the module init sequence * is done. This has potential to deadlock. For example, a newly * detected block device can trigger request_module() of the * default iosched from async probing task. Once userland helper * reaches here, async_synchronize_full() will wait on the async * task waiting on request_module() and deadlock. * * This deadlock is avoided by perfomring async_synchronize_full() * iff module init queued any async jobs. This isn't a full * solution as it will deadlock the same if module loading from * async jobs nests more than once; however, due to the various * constraints, this hack seems to be the best option for now. * Please refer to the following thread for details. * * http://thread.gmane.org/gmane.linux.kernel/1420814 */ if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC)) async_synchronize_full(); mutex_lock(&module_mutex); /* Drop initial reference. */ module_put(mod); trim_init_extable(mod); #ifdef CONFIG_KALLSYMS /* Switch to core kallsyms now init is done: kallsyms may be walking! */ rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms); #endif module_enable_ro(mod, true); mod_tree_remove_init(mod); disable_ro_nx(&mod->init_layout); module_arch_freeing_init(mod); mod->init_layout.base = NULL; mod->init_layout.size = 0; mod->init_layout.ro_size = 0; mod->init_layout.ro_after_init_size = 0; mod->init_layout.text_size = 0; /* * We want to free module_init, but be aware that kallsyms may be * walking this with preempt disabled. In all the failure paths, we * call synchronize_sched(), but we don't want to slow down the success * path, so use actual RCU here. */ call_rcu_sched(&freeinit->rcu, do_free_init); mutex_unlock(&module_mutex); wake_up_all(&module_wq); return 0; fail_free_freeinit: kfree(freeinit); fail: /* Try to protect us from buggy refcounters. */ mod->state = MODULE_STATE_GOING; synchronize_sched(); module_put(mod); blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GOING, mod); klp_module_going(mod); ftrace_release_mod(mod); free_module(mod); wake_up_all(&module_wq); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell16446.86%1344.83%
kees cookkees cook8825.14%13.45%
jessica yujessica yu257.14%310.34%
linus torvaldslinus torvalds236.57%26.90%
tejun heotejun heo174.86%13.45%
peter zijlstrapeter zijlstra72.00%26.90%
luis r. rodriguezluis r. rodriguez72.00%13.45%
catalin marinascatalin marinas61.71%13.45%
steven rostedtsteven rostedt51.43%13.45%
andrew mortonandrew morton30.86%13.45%
arjan van de venarjan van de ven20.57%13.45%
peter oberparleiterpeter oberparleiter20.57%13.45%
jan kiszkajan kiszka10.29%13.45%
Total350100.00%29100.00%


static int may_init_module(void) { if (!capable(CAP_SYS_MODULE) || modules_disabled) return -EPERM; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
kees cookkees cook2288.00%150.00%
linus torvaldslinus torvalds312.00%150.00%
Total25100.00%2100.00%

/* * We try to place it in the list now to make sure it's unique before * we dedicate too many resources. In particular, temporary percpu * memory exhaustion. */
static int add_unformed_module(struct module *mod) { int err; struct module *old; mod->state = MODULE_STATE_UNFORMED; again: mutex_lock(&module_mutex); old = find_module_all(mod->name, strlen(mod->name), true); if (old != NULL) { if (old->state == MODULE_STATE_COMING || old->state == MODULE_STATE_UNFORMED) { /* Wait in case it fails to load. */ mutex_unlock(&module_mutex); err = wait_event_interruptible(module_wq, finished_loading(mod->name)); if (err) goto out_unlocked; goto again; } err = -EEXIST; goto out; } mod_update_bounds(mod); list_add_rcu(&mod->list, &modules); mod_tree_insert(mod); err = 0; out: mutex_unlock(&module_mutex); out_unlocked: return err; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell11173.03%228.57%
peter zijlstrapeter zijlstra1811.84%342.86%
kees cookkees cook127.89%114.29%
mathias krausemathias krause117.24%114.29%
Total152100.00%7100.00%


static int complete_formation(struct module *mod, struct load_info *info) { int err; mutex_lock(&module_mutex); /* Find duplicate symbols (must be called under lock). */ err = verify_export_symbols(mod); if (err < 0) goto out; /* This relies on module_mutex for list integrity. */ module_bug_finalize(info->hdr, info->sechdrs, mod); module_enable_ro(mod, false); module_enable_nx(mod); /* Mark state as coming so strong_try_module_get() ignores us, * but kallsyms etc. can see us. */ mod->state = MODULE_STATE_COMING; mutex_unlock(&module_mutex); return 0; out: mutex_unlock(&module_mutex); return err; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell7882.11%360.00%
jessica yujessica yu1717.89%240.00%
Total95100.00%5100.00%


static int prepare_coming_module(struct module *mod) { int err; ftrace_module_enable(mod); err = klp_module_coming(mod); if (err) return err; blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jessica yujessica yu3269.57%360.00%
rusty russellrusty russell1430.43%240.00%
Total46100.00%5100.00%


static int unknown_module_param_cb(char *param, char *val, const char *modname, void *arg) { struct module *mod = arg; int ret; if (strcmp(param, "async_probe") == 0) { mod->async_probe_requested = true; return 0; } /* Check for magic 'dyndbg' arg */ ret = ddebug_dyndbg_module_param_cb(param, val, modname); if (ret != 0) pr_warn("%s: unknown parameter '%s' ignored\n", modname, param); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell4654.12%125.00%
luis r. rodriguezluis r. rodriguez3844.71%250.00%
andrew mortonandrew morton11.18%125.00%
Total85100.00%4100.00%

/* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */
static int load_module(struct load_info *info, const char __user *uargs, int flags) { struct module *mod; long err; char *after_dashes; err = module_sig_check(info, flags); if (err) goto free_copy; err = elf_header_check(info); if (err) goto free_copy; /* Figure out module layout, and allocate all the memory. */ mod = layout_and_allocate(info, flags); if (IS_ERR(mod)) { err = PTR_ERR(mod); goto free_copy; } /* Reserve our place in the list. */ err = add_unformed_module(mod); if (err) goto free_module; #ifdef CONFIG_MODULE_SIG mod->sig_ok = info->sig_ok; if (!mod->sig_ok) { pr_notice_once("%s: module verification failed: signature " "and/or required key missing - tainting " "kernel\n", mod->name); add_taint_module(mod, TAINT_UNSIGNED_MODULE, LOCKDEP_STILL_OK); } #endif /* To avoid stressing percpu allocator, do this once we're unique. */ err = percpu_modalloc(mod, info); if (err) goto unlink_mod; /* Now module is in final location, initialize linked lists, etc. */ err = module_unload_init(mod); if (err) goto unlink_mod; init_param_lock(mod); /* Now we've got everything in the final locations, we can * find optional sections. */ err = find_module_sections(mod, info); if (err) goto free_unload; err = check_module_license_and_versions(mod); if (err) goto free_unload; /* Set up MODINFO_ATTR fields */ setup_modinfo(mod, info); /* Fix up syms, so that st_value is a pointer to location. */ err = simplify_symbols(mod, info); if (err < 0) goto free_modinfo; err = apply_relocations(mod, info); if (err < 0) goto free_modinfo; err = post_relocation(mod, info); if (err < 0) goto free_modinfo; flush_module_icache(mod); /* Now copy in args */ mod->args = strndup_user(uargs, ~0UL >> 1); if (IS_ERR(mod->args)) { err = PTR_ERR(mod->args); goto free_arch_cleanup; } dynamic_debug_setup(info->debug, info->num_debug); /* Ftrace init must be called in the MODULE_STATE_UNFORMED state */ ftrace_module_init(mod); /* Finally it's fully formed, ready to start executing. */ err = complete_formation(mod, info); if (err) goto ddebug_cleanup; err = prepare_coming_module(mod); if (err) goto bug_cleanup; /* Module is ready to execute: parsing args may do that. */ after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, -32768, 32767, mod, unknown_module_param_cb); if (IS_ERR(after_dashes)) { err = PTR_ERR(after_dashes); goto coming_cleanup; } else if (after_dashes) { pr_warn("%s: parameters '%s' after `--' ignored\n", mod->name, after_dashes); } /* Link in to syfs. */ err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp); if (err < 0) goto coming_cleanup; if (is_livepatch_module(mod)) { err = copy_module_elf(mod, info); if (err < 0) goto sysfs_cleanup; } /* Get rid of temporary copy. */ free_copy(info); /* Done! */ trace_module_load(mod); return do_init_module(mod); sysfs_cleanup: mod_sysfs_teardown(mod); coming_cleanup: blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GOING, mod); klp_module_going(mod); bug_cleanup: /* module_bug_cleanup needs module_mutex protection */ mutex_lock(&module_mutex); module_bug_cleanup(mod); mutex_unlock(&module_mutex); /* we can't deallocate the module until we clear memory protection */ module_disable_ro(mod); module_disable_nx(mod); ddebug_cleanup: dynamic_debug_remove(info->debug); synchronize_sched(); kfree(mod->args); free_arch_cleanup: module_arch_cleanup(mod); free_modinfo: free_modinfo(mod); free_unload: module_unload_free(mod); unlink_mod: mutex_lock(&module_mutex); /* Unlink carefully: kallsyms could be walking list. */ list_del_rcu(&mod->list); mod_tree_remove(mod); wake_up_all(&module_wq); /* Wait for RCU-sched synchronizing before releasing mod->list. */ synchronize_sched(); mutex_unlock(&module_mutex); free_module: /* * Ftrace needs to clean up what it initialized. * This does nothing if ftrace_module_init() wasn't called, * but it must be called outside of module_mutex. */ ftrace_release_mod(mod); /* Free lock-classes; relies on the preceding sync_rcu() */ lockdep_free_key_range(mod->core_layout.base, mod->core_layout.size); module_deallocate(mod, info); free_copy: free_copy(info); return err; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell40358.92%3252.46%
kees cookkees cook8011.70%11.64%
jessica yujessica yu679.80%34.92%
linus torvaldslinus torvalds213.07%46.56%
peter zijlstrapeter zijlstra172.49%34.92%
greg kroah-hartmangreg kroah-hartman162.34%11.64%
yehuda sadehyehuda sadeh162.34%11.64%
steven rostedtsteven rostedt121.75%23.28%
li zefanli zefan91.32%11.64%
frantisek hrbatafrantisek hrbata91.32%11.64%
andy lutomirskiandy lutomirski91.32%11.64%
pawel mollpawel moll71.02%11.64%
dan streetmandan streetman40.58%11.64%
andrew mortonandrew morton30.44%11.64%
jan beulichjan beulich20.29%11.64%
ben hutchingsben hutchings20.29%11.64%
luis r. rodriguezluis r. rodriguez20.29%23.28%
masami hiramatsumasami hiramatsu20.29%11.64%
kevin cernekeekevin cernekee10.15%11.64%
mathieu desnoyersmathieu desnoyers10.15%11.64%
marcel holtmannmarcel holtmann10.15%11.64%
Total684100.00%61100.00%

SYSCALL_DEFINE3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs) { int err; struct load_info info = { }; err = may_init_module(); if (err) return err; pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n", umod, len, uargs); err = copy_module_from_user(umod, len, &info); if (err) return err; return load_module(&info, uargs, 0); } SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags) { struct load_info info = { }; loff_t size; void *hdr; int err; err = may_init_module(); if (err) return err; pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags); if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS |MODULE_INIT_IGNORE_VERMAGIC)) return -EINVAL; err = kernel_read_file_from_fd(fd, &hdr, &size, INT_MAX, READING_MODULE); if (err) return err; info.hdr = hdr; info.len = size; return load_module(&info, uargs, flags); }
static inline int within(unsigned long addr, void *start, unsigned long size) { return ((void *)addr >= start && (void *)addr < start + size); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell3997.50%266.67%
peter oberparleiterpeter oberparleiter12.50%133.33%
Total40100.00%3100.00%

#ifdef CONFIG_KALLSYMS /* * This ignores the intensely annoying "mapping symbols" found * in ARM ELF files: $a, $t and $d. */
static inline int is_arm_mapping_symbol(const char *str) { if (str[0] == '.' && str[1] == 'L') return true; return str[0] == '$' && strchr("axtd", str[1]) && (str[2] == '\0' || str[2] == '.'); }

Contributors

PersonTokensPropCommitsCommitProp
russell kingrussell king6498.46%266.67%
kyle mcmartinkyle mcmartin11.54%133.33%
Total65100.00%3100.00%


static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum) { return kallsyms->strtab + kallsyms->symtab[symnum].st_name; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell31100.00%2100.00%
Total31100.00%2100.00%


static const char *get_ksymbol(struct module *mod, unsigned long addr, unsigned long *size, unsigned long *offset) { unsigned int i, best = 0; unsigned long nextval; struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); /* At worse, next value is at end of module */ if (within_module_init(addr, mod)) nextval = (unsigned long)mod->init_layout.base+mod->init_layout.text_size; else nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size; /* Scan for closest preceding symbol, and next symbol. (ELF starts real symbols at 1). */ for (i = 1; i < kallsyms->num_symtab; i++) { if (kallsyms->symtab[i].st_shndx == SHN_UNDEF) continue; /* We ignore unnamed symbols: they're uninformative * and inserted at a whim. */ if (*symname(kallsyms, i) == '\0' || is_arm_mapping_symbol(symname(kallsyms, i))) continue; if (kallsyms->symtab[i].st_value <= addr && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value) best = i; if (kallsyms->symtab[i].st_value > addr && kallsyms->symtab[i].st_value < nextval) nextval = kallsyms->symtab[i].st_value; } if (!best) return NULL; if (size) *size = nextval - kallsyms->symtab[best].st_value; if (offset) *offset = addr - kallsyms->symtab[best].st_value; return symname(kallsyms, best); }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell26596.01%763.64%
alexey dobriyanalexey dobriyan82.90%19.09%
masami hiramatsumasami hiramatsu10.36%19.09%
lucas de marchilucas de marchi10.36%19.09%
kai germaschewskikai germaschewski10.36%19.09%
Total276100.00%11100.00%

/* For kallsyms to ask for address resolution. NULL means not found. Careful * not to lock to avoid deadlock on oopses, simply disable preemption. */
const char *module_address_lookup(unsigned long addr, unsigned long *size, unsigned long *offset, char **modname, char *namebuf) { const char *ret = NULL; struct module *mod; preempt_disable(); mod = __module_address(addr); if (mod) { if (modname) *modname = mod->name; ret = get_ksymbol(mod, addr, size, offset); } /* Make a copy in here where it's safe */ if (ret) { strncpy(namebuf, ret, KSYM_NAME_LEN - 1); ret = namebuf; } preempt_enable(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell9586.36%457.14%
peter zijlstrapeter zijlstra109.09%114.29%
franck bui-huufranck bui-huu43.64%114.29%
andrew mortonandrew morton10.91%114.29%
Total110100.00%7100.00%


int lookup_module_symbol_name(unsigned long addr, char *symname) { struct module *mod; preempt_disable(); list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) continue; if (within_module(addr, mod)) { const char *sym; sym = get_ksymbol(mod, addr, NULL, NULL); if (!sym) goto out; strlcpy(symname, sym, KSYM_NAME_LEN); preempt_enable(); return 0; } } out: preempt_enable(); return -ERANGE; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan8483.17%233.33%
rusty russellrusty russell1514.85%233.33%
petr mladekpetr mladek10.99%116.67%
andi kleenandi kleen10.99%116.67%
Total101100.00%6100.00%


int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name) { struct module *mod; preempt_disable(); list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) continue; if (within_module(addr, mod)) { const char *sym; sym = get_ksymbol(mod, addr, size, offset); if (!sym) goto out; if (modname) strlcpy(modname, mod->name, MODULE_NAME_LEN); if (name) strlcpy(name, sym, KSYM_NAME_LEN); preempt_enable(); return 0; } } out: preempt_enable(); return -ERANGE; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan11787.31%233.33%
rusty russellrusty russell1511.19%233.33%
petr mladekpetr mladek10.75%116.67%
andi kleenandi kleen10.75%116.67%
Total134100.00%6100.00%


int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, char *name, char *module_name, int *exported) { struct module *mod; preempt_disable(); list_for_each_entry_rcu(mod, &modules, list) { struct mod_kallsyms *kallsyms; if (mod->state == MODULE_STATE_UNFORMED) continue; kallsyms = rcu_dereference_sched(mod->kallsyms); if (symnum < kallsyms->num_symtab) { *value = kallsyms->symtab[symnum].st_value; *type = kallsyms->symtab[symnum].st_info; strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN); strlcpy(module_name, mod->name, MODULE_NAME_LEN); *exported = is_exported(name, *value, mod); preempt_enable(); return 0; } symnum -= kallsyms->num_symtab; } preempt_enable(); return -ERANGE; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell12074.07%550.00%
alexey dobriyanalexey dobriyan3420.99%220.00%
andreas gruenbacherandreas gruenbacher42.47%110.00%
tim abbotttim abbott31.85%110.00%
andi kleenandi kleen10.62%110.00%
Total162100.00%10100.00%


static unsigned long mod_find_symname(struct module *mod, const char *name) { unsigned int i; struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); for (i = 0; i < kallsyms->num_symtab; i++) if (strcmp(name, symname(kallsyms, i)) == 0 && kallsyms->symtab[i].st_info != 'U') return kallsyms->symtab[i].st_value; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton5865.91%125.00%
rusty russellrusty russell2022.73%250.00%
keith owenskeith owens1011.36%125.00%
Total88100.00%4100.00%

/* Look for this name: can be of form module:name. */
unsigned long module_kallsyms_lookup_name(const char *name) { struct module *mod; char *colon; unsigned long ret = 0; /* Don't lock: we're in enough trouble already. */ preempt_disable(); if ((colon = strchr(name, ':')) != NULL) { if ((mod = find_module_all(name, colon - name, false)) != NULL) ret = mod_find_symname(mod, colon+1); } else { list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) continue; if ((ret = mod_find_symname(mod, name)) != 0) break; } } preempt_enable(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton9679.34%120.00%
rusty russellrusty russell1714.05%240.00%
mathias krausemathias krause75.79%120.00%
andi kleenandi kleen10.83%120.00%
Total121100.00%5100.00%


int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, unsigned long), void *data) { struct module *mod; unsigned int i; int ret; module_assert_mutex(); list_for_each_entry(mod, &modules, list) { /* We hold module_mutex: no need for rcu_dereference_sched */ struct mod_kallsyms *kallsyms = mod->kallsyms; if (mod->state == MODULE_STATE_UNFORMED) continue; for (i = 0; i < kallsyms->num_symtab; i++) { ret = fn(data, symname(kallsyms, i), mod, kallsyms->symtab[i].st_value); if (ret != 0) return ret; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
anders kaseorganders kaseorg9977.34%120.00%
rusty russellrusty russell2620.31%360.00%
peter zijlstrapeter zijlstra32.34%120.00%
Total128100.00%5100.00%

#endif /* CONFIG_KALLSYMS */
static char *module_flags(struct module *mod, char *buf) { int bx = 0; BUG_ON(mod->state == MODULE_STATE_UNFORMED); if (mod->taints || mod->state == MODULE_STATE_GOING || mod->state == MODULE_STATE_COMING) { buf[bx++] = '('; bx += module_flags_taint(mod, buf + bx); /* Show a - for module-is-being-unloaded */ if (mod->state == MODULE_STATE_GOING) buf[bx++] = '-'; /* Show a + for module-is-being-loaded */ if (mod->state == MODULE_STATE_COMING) buf[bx++] = '+'; buf[bx++] = ')'; } buf[bx] = '\0'; return buf; }

Contributors

PersonTokensPropCommitsCommitProp
arjan van de venarjan van de ven5343.80%120.00%
florin malitaflorin malita4940.50%120.00%
rusty russellrusty russell97.44%120.00%
kay sieverskay sievers64.96%120.00%
greg kroah-hartmangreg kroah-hartman43.31%120.00%
Total121100.00%5100.00%

#ifdef CONFIG_PROC_FS /* Called by the /proc file system to return a list of modules. */
static void *m_start(struct seq_file *m, loff_t *pos) { mutex_lock(&module_mutex); return seq_list_start(&modules, *pos); }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan32100.00%1100.00%
Total32100.00%1100.00%


static void *m_next(struct seq_file *m, void *p, loff_t *pos) { return seq_list_next(p, &modules, pos); }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan31100.00%1100.00%
Total31100.00%1100.00%


static void m_stop(struct seq_file *m, void *p) { mutex_unlock(&module_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan21100.00%1100.00%
Total21100.00%1100.00%


static int m_show(struct seq_file *m, void *p) { struct module *mod = list_entry(p, struct module, list); char buf[8]; /* We always ignore unformed modules. */ if (mod->state == MODULE_STATE_UNFORMED) return 0; seq_printf(m, "%s %u", mod->name, mod->init_layout.size + mod->core_layout.size); print_unload_info(m, mod); /* Informative for users. */ seq_printf(m, " %s", mod->state == MODULE_STATE_GOING ? "Unloading" : mod->state == MODULE_STATE_COMING ? "Loading" : "Live"); /* Used by oprofile and other similar tools. */ seq_printf(m, " 0x%pK", mod->core_layout.base); /* Taints info */ if (mod->taints) seq_printf(m, " %s", module_flags(mod, buf)); seq_puts(m, "\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell9765.10%545.45%
florin malitaflorin malita2617.45%19.09%
ingo molnaringo molnar2214.77%19.09%
arjan van de venarjan van de ven10.67%19.09%
denys vlasenkodenys vlasenko10.67%19.09%
ionut alexaionut alexa10.67%19.09%
kees cookkees cook10.67%19.09%
Total149100.00%11100.00%

/* Format: modulename size refcount deps address Where refcount is a number or -, and deps is a comma-separated list of depends or -. */ static const struct seq_operations modules_op = { .start = m_start, .next = m_next, .stop = m_stop, .show = m_show };
static int modules_open(struct inode *inode, struct file *file) { return seq_open(file, &modules_op); }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan25100.00%1100.00%
Total25100.00%1100.00%

static const struct file_operations proc_modules_operations = { .open = modules_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, };
static int __init proc_modules_init(void) { proc_create("modules", 0, NULL, &proc_modules_operations); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan24100.00%1100.00%
Total24100.00%1100.00%

module_init(proc_modules_init); #endif /* Given an address, look for it in the module exception tables. */
const struct exception_table_entry *search_module_extables(unsigned long addr) { const struct exception_table_entry *e = NULL; struct module *mod; preempt_disable(); list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) continue; if (mod->num_exentries == 0) continue; e = search_extable(mod->extable, mod->extable + mod->num_exentries - 1, addr); if (e) break; } preempt_enable(); /* Now, if we found one, we are running inside it now, hence we cannot unload the module, hence no refcnt needed. */ return e; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell8797.75%466.67%
daniel walkerdaniel walker11.12%116.67%
andi kleenandi kleen11.12%116.67%
Total89100.00%6100.00%

/* * is_module_address - is this address inside a module? * @addr: the address to check. * * See is_module_text_address() if you simply want to see if the address * is code (not data). */
bool is_module_address(unsigned long addr) { bool ret; preempt_disable(); ret = __module_address(addr) != NULL; preempt_enable(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
ingo molnaringo molnar1756.67%133.33%
rusty russellrusty russell1343.33%266.67%
Total30100.00%3100.00%

/* * __module_address - get the module which contains an address. * @addr: the address. * * Must be called with preempt disabled or module mutex held so that * module doesn't get freed during this. */
struct module *__module_address(unsigned long addr) { struct module *mod; if (addr < module_addr_min || addr > module_addr_max) return NULL; module_assert_mutex_or_preempt(); mod = mod_find(addr); if (mod) { BUG_ON(!within_module(addr, mod)); if (mod->state == MODULE_STATE_UNFORMED) mod = NULL; } return mod; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell4563.38%555.56%
peter zijlstrapeter zijlstra2535.21%333.33%
petr mladekpetr mladek11.41%111.11%
Total71100.00%9100.00%

EXPORT_SYMBOL_GPL(__module_address); /* * is_module_text_address - is this address inside module code? * @addr: the address to check. * * See is_module_address() if you simply want to see if the address is * anywhere in a module. See kernel_text_address() for testing if an * address corresponds to kernel or module code. */
bool is_module_text_address(unsigned long addr) { bool ret; preempt_disable(); ret = __module_text_address(addr) != NULL; preempt_enable(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell30100.00%1100.00%
Total30100.00%1100.00%

/* * __module_text_address - get the module whose code contains an address. * @addr: the address. * * Must be called with preempt disabled or module mutex held so that * module doesn't get freed during this. */
struct module *__module_text_address(unsigned long addr) { struct module *mod = __module_address(addr); if (mod) { /* Make sure it's within the text section. */ if (!within(addr, mod->init_layout.base, mod->init_layout.text_size) && !within(addr, mod->core_layout.base, mod->core_layout.text_size)) mod = NULL; } return mod; }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell73100.00%4100.00%
Total73100.00%4100.00%

EXPORT_SYMBOL_GPL(__module_text_address); /* Don't grab lock, we're oopsing. */
void print_modules(void) { struct module *mod; char buf[8]; printk(KERN_DEFAULT "Modules linked in:"); /* Most callers should already have preempt disabled, but make sure */ preempt_disable(); list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) continue; pr_cont(" %s%s", mod->name, module_flags(mod, buf)); } preempt_enable(); if (last_unloaded_module[0]) pr_cont(" [last unloaded: %s]", last_unloaded_module); pr_cont("\n"); }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton3541.18%112.50%
arjan van de venarjan van de ven1416.47%225.00%
randy dunlaprandy dunlap1315.29%112.50%
rusty russellrusty russell1112.94%112.50%
andi kleenandi kleen89.41%112.50%
jiri slabyjiri slaby33.53%112.50%
linus torvaldslinus torvalds11.18%112.50%
Total85100.00%8100.00%

#ifdef CONFIG_MODVERSIONS /* Generate the signature for all relevant module structures here. * If these change, we don't want to try to parse the module. */
void module_layout(struct module *mod, struct modversion_info *ver, struct kernel_param *kp, struct kernel_symbol *ks, struct tracepoint * const *tp) { }

Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell2993.55%266.67%
mathieu desnoyersmathieu desnoyers26.45%133.33%
Total31100.00%3100.00%

EXPORT_SYMBOL(module_layout); #endif

Overall Contributors

PersonTokensPropCommitsCommitProp
rusty russellrusty russell830242.38%11529.56%
linus torvaldslinus torvalds14337.32%133.34%
jessica yujessica yu9014.60%51.29%
peter zijlstrapeter zijlstra7173.66%112.83%
tejun heotejun heo5042.57%102.57%
kees cookkees cook4742.42%41.03%
roland mcgrathroland mcgrath4742.42%10.26%
kay sieverskay sievers4612.35%102.57%
andrew mortonandrew morton4422.26%153.86%
alexey dobriyanalexey dobriyan4302.20%82.06%
greg kroah-hartmangreg kroah-hartman4262.17%123.08%
matthieu castetmatthieu castet4232.16%10.26%
jan beulichjan beulich3821.95%20.51%
pre-gitpre-git2861.46%174.37%
jonathan corbetjonathan corbet2651.35%10.26%
matt domschmatt domsch2421.24%10.26%
kai germaschewskikai germaschewski2141.09%82.06%
steven rostedtsteven rostedt2131.09%143.60%
arjan van de venarjan van de ven1530.78%61.54%
masami hiramatsumasami hiramatsu1410.72%71.80%
prarit bhargavaprarit bhargava1320.67%20.51%
tim abbotttim abbott1260.64%30.77%
florin malitaflorin malita1160.59%10.26%
catalin marinascatalin marinas1110.57%30.77%
kevin winchesterkevin winchester1030.53%10.26%
anders kaseorganders kaseorg990.51%10.26%
alessio igor boganialessio igor bogani980.50%20.51%
jonas bonnjonas bonn910.46%10.26%
ian s. nelsonian s. nelson810.41%10.26%
ben hutchingsben hutchings770.39%30.77%
ashutosh naikashutosh naik760.39%20.51%
frantisek hrbatafrantisek hrbata690.35%10.26%
jason baronjason baron670.34%41.03%
russell kingrussell king650.33%20.51%
ingo molnaringo molnar630.32%41.03%
sam ravnborgsam ravnborg620.32%20.51%
josh poimboeufjosh poimboeuf620.32%20.51%
helge dellerhelge deller590.30%30.77%
john levonjohn levon560.29%10.26%
kevin cernekeekevin cernekee550.28%10.26%
luis r. rodriguezluis r. rodriguez540.28%41.03%
denys vlasenkodenys vlasenko540.28%30.77%
libor pechaceklibor pechacek460.23%10.26%
mathias krausemathias krause440.22%10.26%
li zhongli zhong440.22%10.26%
peter oberparleiterpeter oberparleiter430.22%20.51%
jan glauberjan glauber420.21%20.51%
miroslav benesmiroslav benes420.21%10.26%
yehuda sadehyehuda sadeh380.19%10.26%
mimi zoharmimi zohar340.17%10.26%
americo wangamerico wang330.17%10.26%
randy dunlaprandy dunlap310.16%41.03%
andi kleenandi kleen310.16%20.51%
al viroal viro300.15%10.26%
denis v. lunevdenis v. lunev290.15%10.26%
mathieu desnoyersmathieu desnoyers280.14%30.77%
david howellsdavid howells250.13%30.77%
li zefanli zefan240.12%10.26%
richard hendersonrichard henderson240.12%20.51%
eric w. biedermaneric w. biederman230.12%10.26%
matthew garrettmatthew garrett210.11%10.26%
ed swierked swierk210.11%10.26%
jason wesseljason wessel210.11%10.26%
jim cromiejim cromie200.10%10.26%
laura abbottlaura abbott170.09%10.26%
bernd schmidtbernd schmidt150.08%10.26%
joe mariojoe mario140.07%10.26%
brian gerstbrian gerst130.07%10.26%
heiko carstensheiko carstens120.06%10.26%
dave youngdave young110.06%10.26%
akinobu mitaakinobu mita110.06%20.51%
keith owenskeith owens100.05%10.26%
trent piephotrent piepho90.05%10.26%
kirill a. shutemovkirill a. shutemov90.05%10.26%
andy lutomirskiandy lutomirski90.05%10.26%
ionut alexaionut alexa80.04%10.26%
christoph lameterchristoph lameter80.04%20.51%
pawel mollpawel moll70.04%10.26%
stephen rothwellstephen rothwell60.03%10.26%
daniel bluemandaniel blueman60.03%10.26%
alan sternalan stern60.03%10.26%
nick pigginnick piggin50.03%10.26%
chris wrightchris wright50.03%10.26%
james hoganjames hogan40.02%10.26%
franck bui-huufranck bui-huu40.02%10.26%
andreas gruenbacherandreas gruenbacher40.02%10.26%
dan streetmandan streetman40.02%10.26%
luis de bethencourtluis de bethencourt30.02%10.26%
jiri slabyjiri slaby30.02%10.26%
yannick guerriniyannick guerrini30.02%10.26%
petr mladekpetr mladek30.02%10.26%
lucas de marchilucas de marchi20.01%10.26%
matti linnanvuorimatti linnanvuori20.01%10.26%
jan kiszkajan kiszka20.01%10.26%
jianjun kongjianjun kong20.01%10.26%
eric dumazeteric dumazet20.01%10.26%
dave jonesdave jones20.01%20.51%
tim schmielautim schmielau20.01%10.26%
satoru takeuchisatoru takeuchi20.01%10.26%
daniel walkerdaniel walker10.01%10.26%
david mosbergerdavid mosberger10.01%10.26%
jiri kosinajiri kosina10.01%10.26%
marcel holtmannmarcel holtmann10.01%10.26%
christoph hellwigchristoph hellwig10.01%10.26%
robert p. j. dayrobert p. j. day10.01%10.26%
kyle mcmartinkyle mcmartin10.01%10.26%
paul gortmakerpaul gortmaker10.01%10.26%
chen gangchen gang10.01%10.26%
michal miroslawmichal miroslaw10.01%10.26%
Total19588100.00%389100.00%
Directory: kernel