Commit 98a38a5d authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus

* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus:
  params.c: Use new strtobool function to process boolean inputs
  debugfs: move to new strtobool
  Add a strtobool function matching semantics of existing in kernel equivalents
  modpost: Update 64k section support for binutils 2.18.50
  module: Use binary search in lookup_symbol()
  module: Use the binary search for symbols resolution
  lib: Add generic binary search function to the kernel.
  module: Sort exported symbols
  module: each_symbol_section instead of each_symbol
  module: split unset_section_ro_nx function.
  module: undo module RONX protection correctly.
  module: zero mod->init_ro_size after init is freed.
  minor ANSI prototype sparse fix
  module: reorder kparam_array to remove alignment padding on 64 bit builds
  module: remove 64 bit alignment padding from struct module with CONFIG_TRACE*
  module: do not hide __modver_version_show declaration behind ifdef
  module: deal with alignment issues in built-in module versions
parents 7663164f f721a465
...@@ -11,5 +11,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable); ...@@ -11,5 +11,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable);
int set_memory_ro(unsigned long addr, int numpages); int set_memory_ro(unsigned long addr, int numpages);
int set_memory_rw(unsigned long addr, int numpages); int set_memory_rw(unsigned long addr, int numpages);
int set_memory_nx(unsigned long addr, int numpages); int set_memory_nx(unsigned long addr, int numpages);
int set_memory_x(unsigned long addr, int numpages);
#endif /* _S390_CACHEFLUSH_H */ #endif /* _S390_CACHEFLUSH_H */
...@@ -54,3 +54,8 @@ int set_memory_nx(unsigned long addr, int numpages) ...@@ -54,3 +54,8 @@ int set_memory_nx(unsigned long addr, int numpages)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(set_memory_nx); EXPORT_SYMBOL_GPL(set_memory_nx);
int set_memory_x(unsigned long addr, int numpages)
{
return 0;
}
...@@ -429,24 +429,15 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf, ...@@ -429,24 +429,15 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
{ {
char buf[32]; char buf[32];
int buf_size; int buf_size;
bool bv;
u32 *val = file->private_data; u32 *val = file->private_data;
buf_size = min(count, (sizeof(buf)-1)); buf_size = min(count, (sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size)) if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT; return -EFAULT;
switch (buf[0]) { if (strtobool(buf, &bv) == 0)
case 'y': *val = bv;
case 'Y':
case '1':
*val = 1;
break;
case 'n':
case 'N':
case '0':
*val = 0;
break;
}
return count; return count;
} }
......
...@@ -274,70 +274,70 @@ ...@@ -274,70 +274,70 @@
/* Kernel symbol table: Normal symbols */ \ /* Kernel symbol table: Normal symbols */ \
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab) = .; \ VMLINUX_SYMBOL(__start___ksymtab) = .; \
*(__ksymtab) \ *(SORT(___ksymtab+*)) \
VMLINUX_SYMBOL(__stop___ksymtab) = .; \ VMLINUX_SYMBOL(__stop___ksymtab) = .; \
} \ } \
\ \
/* Kernel symbol table: GPL-only symbols */ \ /* Kernel symbol table: GPL-only symbols */ \
__ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \
*(__ksymtab_gpl) \ *(SORT(___ksymtab_gpl+*)) \
VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \
} \ } \
\ \
/* Kernel symbol table: Normal unused symbols */ \ /* Kernel symbol table: Normal unused symbols */ \
__ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \ __ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \ VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \
*(__ksymtab_unused) \ *(SORT(___ksymtab_unused+*)) \
VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \ VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \
} \ } \
\ \
/* Kernel symbol table: GPL-only unused symbols */ \ /* Kernel symbol table: GPL-only unused symbols */ \
__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \ __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \ VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \
*(__ksymtab_unused_gpl) \ *(SORT(___ksymtab_unused_gpl+*)) \
VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \ VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \
} \ } \
\ \
/* Kernel symbol table: GPL-future-only symbols */ \ /* Kernel symbol table: GPL-future-only symbols */ \
__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \ __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \ VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \
*(__ksymtab_gpl_future) \ *(SORT(___ksymtab_gpl_future+*)) \
VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \ VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \
} \ } \
\ \
/* Kernel symbol table: Normal symbols */ \ /* Kernel symbol table: Normal symbols */ \
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab) = .; \ VMLINUX_SYMBOL(__start___kcrctab) = .; \
*(__kcrctab) \ *(SORT(___kcrctab+*)) \
VMLINUX_SYMBOL(__stop___kcrctab) = .; \ VMLINUX_SYMBOL(__stop___kcrctab) = .; \
} \ } \
\ \
/* Kernel symbol table: GPL-only symbols */ \ /* Kernel symbol table: GPL-only symbols */ \
__kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \
*(__kcrctab_gpl) \ *(SORT(___kcrctab_gpl+*)) \
VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \
} \ } \
\ \
/* Kernel symbol table: Normal unused symbols */ \ /* Kernel symbol table: Normal unused symbols */ \
__kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \ __kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \ VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \
*(__kcrctab_unused) \ *(SORT(___kcrctab_unused+*)) \
VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \ VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \
} \ } \
\ \
/* Kernel symbol table: GPL-only unused symbols */ \ /* Kernel symbol table: GPL-only unused symbols */ \
__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \ __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \ VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \
*(__kcrctab_unused_gpl) \ *(SORT(___kcrctab_unused_gpl+*)) \
VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \ VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \
} \ } \
\ \
/* Kernel symbol table: GPL-future-only symbols */ \ /* Kernel symbol table: GPL-future-only symbols */ \
__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \ __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \ VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \
*(__kcrctab_gpl_future) \ *(SORT(___kcrctab_gpl_future+*)) \
VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \
} \ } \
\ \
......
#ifndef _LINUX_BSEARCH_H
#define _LINUX_BSEARCH_H
#include <linux/types.h>
void *bsearch(const void *key, const void *base, size_t num, size_t size,
int (*cmp)(const void *key, const void *elt));
#endif /* _LINUX_BSEARCH_H */
...@@ -64,6 +64,9 @@ struct module_version_attribute { ...@@ -64,6 +64,9 @@ struct module_version_attribute {
const char *version; const char *version;
} __attribute__ ((__aligned__(sizeof(void *)))); } __attribute__ ((__aligned__(sizeof(void *))));
extern ssize_t __modver_version_show(struct module_attribute *,
struct module *, char *);
struct module_kobject struct module_kobject
{ {
struct kobject kobj; struct kobject kobj;
...@@ -172,12 +175,7 @@ extern struct module __this_module; ...@@ -172,12 +175,7 @@ extern struct module __this_module;
#define MODULE_VERSION(_version) MODULE_INFO(version, _version) #define MODULE_VERSION(_version) MODULE_INFO(version, _version)
#else #else
#define MODULE_VERSION(_version) \ #define MODULE_VERSION(_version) \
extern ssize_t __modver_version_show(struct module_attribute *, \ static struct module_version_attribute ___modver_attr = { \
struct module *, char *); \
static struct module_version_attribute __modver_version_attr \
__used \
__attribute__ ((__section__ ("__modver"),aligned(sizeof(void *)))) \
= { \
.mattr = { \ .mattr = { \
.attr = { \ .attr = { \
.name = "version", \ .name = "version", \
...@@ -187,7 +185,10 @@ extern struct module __this_module; ...@@ -187,7 +185,10 @@ extern struct module __this_module;
}, \ }, \
.module_name = KBUILD_MODNAME, \ .module_name = KBUILD_MODNAME, \
.version = _version, \ .version = _version, \
} }; \
static const struct module_version_attribute \
__used __attribute__ ((__section__ ("__modver"))) \
* __moduleparam_const __modver_attr = &___modver_attr
#endif #endif
/* Optional firmware file (or files) needed by the module /* Optional firmware file (or files) needed by the module
...@@ -223,7 +224,7 @@ struct module_use { ...@@ -223,7 +224,7 @@ struct module_use {
extern void *__crc_##sym __attribute__((weak)); \ extern void *__crc_##sym __attribute__((weak)); \
static const unsigned long __kcrctab_##sym \ static const unsigned long __kcrctab_##sym \
__used \ __used \
__attribute__((section("__kcrctab" sec), unused)) \ __attribute__((section("___kcrctab" sec "+" #sym), unused)) \
= (unsigned long) &__crc_##sym; = (unsigned long) &__crc_##sym;
#else #else
#define __CRC_SYMBOL(sym, sec) #define __CRC_SYMBOL(sym, sec)
...@@ -238,7 +239,7 @@ struct module_use { ...@@ -238,7 +239,7 @@ struct module_use {
= MODULE_SYMBOL_PREFIX #sym; \ = MODULE_SYMBOL_PREFIX #sym; \
static const struct kernel_symbol __ksymtab_##sym \ static const struct kernel_symbol __ksymtab_##sym \
__used \ __used \
__attribute__((section("__ksymtab" sec), unused)) \ __attribute__((section("___ksymtab" sec "+" #sym), unused)) \
= { (unsigned long)&sym, __kstrtab_##sym } = { (unsigned long)&sym, __kstrtab_##sym }
#define EXPORT_SYMBOL(sym) \ #define EXPORT_SYMBOL(sym) \
...@@ -367,34 +368,35 @@ struct module ...@@ -367,34 +368,35 @@ struct module
struct module_notes_attrs *notes_attrs; struct module_notes_attrs *notes_attrs;
#endif #endif
/* The command line arguments (may be mangled). People like
keeping pointers to this stuff */
char *args;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* Per-cpu data. */ /* Per-cpu data. */
void __percpu *percpu; void __percpu *percpu;
unsigned int percpu_size; unsigned int percpu_size;
#endif #endif
/* The command line arguments (may be mangled). People like
keeping pointers to this stuff */
char *args;
#ifdef CONFIG_TRACEPOINTS #ifdef CONFIG_TRACEPOINTS
struct tracepoint * const *tracepoints_ptrs;
unsigned int num_tracepoints; unsigned int num_tracepoints;
struct tracepoint * const *tracepoints_ptrs;
#endif #endif
#ifdef HAVE_JUMP_LABEL #ifdef HAVE_JUMP_LABEL
struct jump_entry *jump_entries; struct jump_entry *jump_entries;
unsigned int num_jump_entries; unsigned int num_jump_entries;
#endif #endif
#ifdef CONFIG_TRACING #ifdef CONFIG_TRACING
const char **trace_bprintk_fmt_start;
unsigned int num_trace_bprintk_fmt; unsigned int num_trace_bprintk_fmt;
const char **trace_bprintk_fmt_start;
#endif #endif
#ifdef CONFIG_EVENT_TRACING #ifdef CONFIG_EVENT_TRACING
struct ftrace_event_call **trace_events; struct ftrace_event_call **trace_events;
unsigned int num_trace_events; unsigned int num_trace_events;
#endif #endif
#ifdef CONFIG_FTRACE_MCOUNT_RECORD #ifdef CONFIG_FTRACE_MCOUNT_RECORD
unsigned long *ftrace_callsites;
unsigned int num_ftrace_callsites; unsigned int num_ftrace_callsites;
unsigned long *ftrace_callsites;
#endif #endif
#ifdef CONFIG_MODULE_UNLOAD #ifdef CONFIG_MODULE_UNLOAD
...@@ -475,8 +477,9 @@ const struct kernel_symbol *find_symbol(const char *name, ...@@ -475,8 +477,9 @@ const struct kernel_symbol *find_symbol(const char *name,
bool warn); bool warn);
/* Walk the exported symbol table */ /* Walk the exported symbol table */
bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner, bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
unsigned int symnum, void *data), void *data); struct module *owner,
void *data), void *data);
/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
symnum out of range. */ symnum out of range. */
......
...@@ -67,9 +67,9 @@ struct kparam_string { ...@@ -67,9 +67,9 @@ struct kparam_string {
struct kparam_array struct kparam_array
{ {
unsigned int max; unsigned int max;
unsigned int elemsize;
unsigned int *num; unsigned int *num;
const struct kernel_param_ops *ops; const struct kernel_param_ops *ops;
unsigned int elemsize;
void *elem; void *elem;
}; };
...@@ -371,8 +371,9 @@ extern int param_get_invbool(char *buffer, const struct kernel_param *kp); ...@@ -371,8 +371,9 @@ extern int param_get_invbool(char *buffer, const struct kernel_param *kp);
*/ */
#define module_param_array_named(name, array, type, nump, perm) \ #define module_param_array_named(name, array, type, nump, perm) \
static const struct kparam_array __param_arr_##name \ static const struct kparam_array __param_arr_##name \
= { ARRAY_SIZE(array), nump, &param_ops_##type, \ = { .max = ARRAY_SIZE(array), .num = nump, \
sizeof(array[0]), array }; \ .ops = &param_ops_##type, \
.elemsize = sizeof(array[0]), .elem = array }; \
__module_param_call(MODULE_PARAM_PREFIX, name, \ __module_param_call(MODULE_PARAM_PREFIX, name, \
&param_array_ops, \ &param_array_ops, \
.arr = &__param_arr_##name, \ .arr = &__param_arr_##name, \
......
...@@ -123,6 +123,7 @@ extern char **argv_split(gfp_t gfp, const char *str, int *argcp); ...@@ -123,6 +123,7 @@ extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
extern void argv_free(char **argv); extern void argv_free(char **argv);
extern bool sysfs_streq(const char *s1, const char *s2); extern bool sysfs_streq(const char *s1, const char *s2);
extern int strtobool(const char *s, bool *res);
#ifdef CONFIG_BINARY_PRINTF #ifdef CONFIG_BINARY_PRINTF
int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args); int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args);
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <linux/kmemleak.h> #include <linux/kmemleak.h>
#include <linux/jump_label.h> #include <linux/jump_label.h>
#include <linux/pfn.h> #include <linux/pfn.h>
#include <linux/bsearch.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/module.h> #include <trace/events/module.h>
...@@ -240,14 +241,13 @@ static bool each_symbol_in_section(const struct symsearch *arr, ...@@ -240,14 +241,13 @@ static bool each_symbol_in_section(const struct symsearch *arr,
struct module *owner, struct module *owner,
bool (*fn)(const struct symsearch *syms, bool (*fn)(const struct symsearch *syms,
struct module *owner, struct module *owner,
unsigned int symnum, void *data), void *data),
void *data) void *data)
{ {
unsigned int i, j; unsigned int j;
for (j = 0; j < arrsize; j++) { for (j = 0; j < arrsize; j++) {
for (i = 0; i < arr[j].stop - arr[j].start; i++) if (fn(&arr[j], owner, data))
if (fn(&arr[j], owner, i, data))
return true; return true;
} }
...@@ -255,8 +255,10 @@ static bool each_symbol_in_section(const struct symsearch *arr, ...@@ -255,8 +255,10 @@ static bool each_symbol_in_section(const struct symsearch *arr,
} }
/* Returns true as soon as fn returns true, otherwise false. */ /* Returns true as soon as fn returns true, otherwise false. */
bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner, bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
unsigned int symnum, void *data), void *data) struct module *owner,
void *data),
void *data)
{ {
struct module *mod; struct module *mod;
static const struct symsearch arr[] = { static const struct symsearch arr[] = {
...@@ -309,7 +311,7 @@ bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner, ...@@ -309,7 +311,7 @@ bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
} }
return false; return false;
} }
EXPORT_SYMBOL_GPL(each_symbol); EXPORT_SYMBOL_GPL(each_symbol_section);
struct find_symbol_arg { struct find_symbol_arg {
/* Input */ /* Input */
...@@ -323,15 +325,12 @@ struct find_symbol_arg { ...@@ -323,15 +325,12 @@ struct find_symbol_arg {
const struct kernel_symbol *sym; const struct kernel_symbol *sym;
}; };
static bool find_symbol_in_section(const struct symsearch *syms, static bool check_symbol(const struct symsearch *syms,
struct module *owner, struct module *owner,
unsigned int symnum, void *data) unsigned int symnum, void *data)
{ {
struct find_symbol_arg *fsa = data; struct find_symbol_arg *fsa = data;
if (strcmp(syms->start[symnum].name, fsa->name) != 0)
return false;
if (!fsa->gplok) { if (!fsa->gplok) {
if (syms->licence == GPL_ONLY) if (syms->licence == GPL_ONLY)
return false; return false;
...@@ -365,6 +364,30 @@ static bool find_symbol_in_section(const struct symsearch *syms, ...@@ -365,6 +364,30 @@ static bool find_symbol_in_section(const struct symsearch *syms,
return true; return true;
} }
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);
}
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;
}
/* Find a symbol and return it, along with, (optional) crc and /* Find a symbol and return it, along with, (optional) crc and
* (optional) module which owns it. Needs preempt disabled or module_mutex. */ * (optional) module which owns it. Needs preempt disabled or module_mutex. */
const struct kernel_symbol *find_symbol(const char *name, const struct kernel_symbol *find_symbol(const char *name,
...@@ -379,7 +402,7 @@ const struct kernel_symbol *find_symbol(const char *name, ...@@ -379,7 +402,7 @@ const struct kernel_symbol *find_symbol(const char *name,
fsa.gplok = gplok; fsa.gplok = gplok;
fsa.warn = warn; fsa.warn = warn;
if (each_symbol(find_symbol_in_section, &fsa)) { if (each_symbol_section(find_symbol_in_section, &fsa)) {
if (owner) if (owner)
*owner = fsa.owner; *owner = fsa.owner;
if (crc) if (crc)
...@@ -1607,27 +1630,28 @@ static void set_section_ro_nx(void *base, ...@@ -1607,27 +1630,28 @@ static void set_section_ro_nx(void *base,
} }
} }
/* Setting memory back to RW+NX before releasing it */ static void unset_module_core_ro_nx(struct module *mod)
void unset_section_ro_nx(struct module *mod, void *module_region)
{ {
unsigned long total_pages; set_page_attributes(mod->module_core + mod->core_text_size,
mod->module_core + mod->core_size,
if (mod->module_core == module_region) { set_memory_x);
/* Set core as NX+RW */ set_page_attributes(mod->module_core,
total_pages = MOD_NUMBER_OF_PAGES(mod->module_core, mod->core_size); mod->module_core + mod->core_ro_size,
set_memory_nx((unsigned long)mod->module_core, total_pages); set_memory_rw);
set_memory_rw((unsigned long)mod->module_core, total_pages); }
} else if (mod->module_init == module_region) { static void unset_module_init_ro_nx(struct module *mod)
/* Set init as NX+RW */ {
total_pages = MOD_NUMBER_OF_PAGES(mod->module_init, mod->init_size); set_page_attributes(mod->module_init + mod->init_text_size,
set_memory_nx((unsigned long)mod->module_init, total_pages); mod->module_init + mod->init_size,
set_memory_rw((unsigned long)mod->module_init, total_pages); set_memory_x);
} set_page_attributes(mod->module_init,
mod->module_init + mod->init_ro_size,
set_memory_rw);
} }
/* Iterate through all modules and set each module's text as RW */ /* Iterate through all modules and set each module's text as RW */
void set_all_modules_text_rw() void set_all_modules_text_rw(void)
{ {
struct module *mod; struct module *mod;
...@@ -1648,7 +1672,7 @@ void set_all_modules_text_rw() ...@@ -1648,7 +1672,7 @@ void set_all_modules_text_rw()
} }
/* Iterate through all modules and set each module's text as RO */ /* Iterate through all modules and set each module's text as RO */
void set_all_modules_text_ro() void set_all_modules_text_ro(void)
{ {
struct module *mod; struct module *mod;
...@@ -1669,7 +1693,8 @@ void set_all_modules_text_ro() ...@@ -1669,7 +1693,8 @@ void set_all_modules_text_ro()
} }
#else #else
static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { } static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }
static inline void unset_section_ro_nx(struct module *mod, void *module_region) { } static void unset_module_core_ro_nx(struct module *mod) { }
static void unset_module_init_ro_nx(struct module *mod) { }
#endif #endif
/* Free a module, remove from lists, etc. */ /* Free a module, remove from lists, etc. */
...@@ -1696,7 +1721,7 @@ static void free_module(struct module *mod) ...@@ -1696,7 +1721,7 @@ static void free_module(struct module *mod)
destroy_params(mod->kp, mod->num_kp); destroy_params(mod->kp, mod->num_kp);
/* This may be NULL, but that's OK */ /* This may be NULL, but that's OK */
unset_section_ro_nx(mod, mod->module_init); unset_module_init_ro_nx(mod);
module_free(mod, mod->module_init); module_free(mod, mod->module_init);
kfree(mod->args); kfree(mod->args);
percpu_modfree(mod); percpu_modfree(mod);
...@@ -1705,7 +1730,7 @@ static void free_module(struct module *mod) ...@@ -1705,7 +1730,7 @@ static void free_module(struct module *mod)
lockdep_free_key_range(mod->module_core, mod->core_size); lockdep_free_key_range(mod->module_core, mod->core_size);
/* Finally, free the core (containing the module structure) */ /* Finally, free the core (containing the module structure) */
unset_section_ro_nx(mod, mod->module_core); unset_module_core_ro_nx(mod);
module_free(mod, mod->module_core); module_free(mod, mod->module_core);
#ifdef CONFIG_MPU #ifdef CONFIG_MPU
...@@ -2030,11 +2055,8 @@ static const struct kernel_symbol *lookup_symbol(const char *name, ...@@ -2030,11 +2055,8 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
const struct kernel_symbol *start, const struct kernel_symbol *start,
const struct kernel_symbol *stop) const struct kernel_symbol *stop)
{ {
const struct kernel_symbol *ks = start; return bsearch(name, start, stop - start,
for (; ks < stop; ks++) sizeof(struct kernel_symbol), cmp_name);
if (strcmp(ks->name, name) == 0)
return ks;
return NULL;
} }
static int is_exported(const char *name, unsigned long value, static int is_exported(const char *name, unsigned long value,
...@@ -2931,10 +2953,11 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, ...@@ -2931,10 +2953,11 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
mod->symtab = mod->core_symtab; mod->symtab = mod->core_symtab;
mod->strtab = mod->core_strtab; mod->strtab = mod->core_strtab;
#endif #endif
unset_section_ro_nx(mod, mod->module_init); unset_module_init_ro_nx(mod);
module_free(mod, mod->module_init); module_free(mod, mod->module_init);
mod->module_init = NULL; mod->module_init = NULL;
mod->init_size = 0; mod->init_size = 0;
mod->init_ro_size = 0;
mod->init_text_size = 0; mod->init_text_size = 0;
mutex_unlock(&module_mutex); mutex_unlock(&module_mutex);
......
...@@ -297,21 +297,15 @@ EXPORT_SYMBOL(param_ops_charp); ...@@ -297,21 +297,15 @@ EXPORT_SYMBOL(param_ops_charp);
int param_set_bool(const char *val, const struct kernel_param *kp) int param_set_bool(const char *val, const struct kernel_param *kp)
{ {
bool v; bool v;
int ret;
/* No equals means "set"... */ /* No equals means "set"... */
if (!val) val = "1"; if (!val) val = "1";
/* One of =[yYnN01] */ /* One of =[yYnN01] */
switch (val[0]) { ret = strtobool(val, &v);
case 'y': case 'Y': case '1': if (ret)
v = true; return ret;
break;
case 'n': case 'N': case '0':
v = false;
break;
default:
return -EINVAL;
}
if (kp->flags & KPARAM_ISBOOL) if (kp->flags & KPARAM_ISBOOL)
*(bool *)kp->arg = v; *(bool *)kp->arg = v;
...@@ -821,15 +815,18 @@ ssize_t __modver_version_show(struct module_attribute *mattr, ...@@ -821,15 +815,18 @@ ssize_t __modver_version_show(struct module_attribute *mattr,
return sprintf(buf, "%s\n", vattr->version); return sprintf(buf, "%s\n", vattr->version);
} }
extern struct module_version_attribute __start___modver[], __stop___modver[]; extern const struct module_version_attribute *__start___modver[];
extern const struct module_version_attribute *__stop___modver[];
static void __init version_sysfs_builtin(void) static void __init version_sysfs_builtin(void)
{ {
const struct module_version_attribute *vattr; const struct module_version_attribute **p;
struct module_kobject *mk; struct module_kobject *mk;
int err; int err;
for (vattr = __start___modver; vattr < __stop___modver; vattr++) { for (p = __start___modver; p < __stop___modver; p++) {
const struct module_version_attribute *vattr = *p;
mk = locate_module_kobject(vattr->module_name); mk = locate_module_kobject(vattr->module_name);
if (mk) { if (mk) {
err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr); err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
......
...@@ -21,7 +21,8 @@ lib-y += kobject.o kref.o klist.o ...@@ -21,7 +21,8 @@ lib-y += kobject.o kref.o klist.o
obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \
bsearch.o
obj-y += kstrtox.o obj-y += kstrtox.o
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
......
/*
* A generic implementation of binary search for the Linux kernel
*
* Copyright (C) 2008-2009 Ksplice, Inc.
* Author: Tim Abbott <tabbott@ksplice.com>
*
* 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; version 2.
*/
#include <linux/module.h>
#include <linux/bsearch.h>
/*
* bsearch - binary search an array of elements
* @key: pointer to item being searched for
* @base: pointer to first element to search
* @num: number of elements
* @size: size of each element
* @cmp: pointer to comparison function
*
* This function does a binary search on the given array. The
* contents of the array should already be in ascending sorted order
* under the provided comparison function.
*
* Note that the key need not have the same type as the elements in
* the array, e.g. key could be a string and the comparison function
* could compare the string with the struct's name field. However, if
* the key and elements in the array are of the same type, you can use
* the same comparison function for both sort() and bsearch().
*/
void *bsearch(const void *key, const void *base, size_t num, size_t size,
int (*cmp)(const void *key, const void *elt))
{
size_t start = 0, end = num;
int result;
while (start < end) {
size_t mid = start + (end - start) / 2;
result = cmp(key, base + mid * size);
if (result < 0)
end = mid;
else if (result > 0)
start = mid + 1;
else
return (void *)base + mid * size;
}
return NULL;
}
EXPORT_SYMBOL(bsearch);
...@@ -535,6 +535,35 @@ bool sysfs_streq(const char *s1, const char *s2) ...@@ -535,6 +535,35 @@ bool sysfs_streq(const char *s1, const char *s2)
} }
EXPORT_SYMBOL(sysfs_streq); EXPORT_SYMBOL(sysfs_streq);
/**
* strtobool - convert common user inputs into boolean values
* @s: input string
* @res: result
*
* This routine returns 0 iff the first character is one of 'Yy1Nn0'.
* Otherwise it will return -EINVAL. Value pointed to by res is
* updated upon finding a match.
*/
int strtobool(const char *s, bool *res)
{
switch (s[0]) {
case 'y':
case 'Y':
case '1':
*res = true;
break;
case 'n':
case 'N':
case '0':
*res = false;
break;
default:
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(strtobool);
#ifndef __HAVE_ARCH_MEMSET #ifndef __HAVE_ARCH_MEMSET
/** /**
* memset - Fill a region of memory with the given value * memset - Fill a region of memory with the given value
......
...@@ -420,11 +420,10 @@ static int parse_elf(struct elf_info *info, const char *filename) ...@@ -420,11 +420,10 @@ static int parse_elf(struct elf_info *info, const char *filename)
return 0; return 0;
} }
if (hdr->e_shnum == 0) { if (hdr->e_shnum == SHN_UNDEF) {
/* /*
* There are more than 64k sections, * There are more than 64k sections,
* read count from .sh_size. * read count from .sh_size.
* note: it doesn't need shndx2secindex()
*/ */
info->num_sections = TO_NATIVE(sechdrs[0].sh_size); info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
} }
...@@ -432,8 +431,7 @@ static int parse_elf(struct elf_info *info, const char *filename) ...@@ -432,8 +431,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
info->num_sections = hdr->e_shnum; info->num_sections = hdr->e_shnum;
} }
if (hdr->e_shstrndx == SHN_XINDEX) { if (hdr->e_shstrndx == SHN_XINDEX) {
info->secindex_strings = info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
shndx2secindex(TO_NATIVE(sechdrs[0].sh_link));
} }
else { else {
info->secindex_strings = hdr->e_shstrndx; info->secindex_strings = hdr->e_shstrndx;
...@@ -489,7 +487,7 @@ static int parse_elf(struct elf_info *info, const char *filename) ...@@ -489,7 +487,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
sechdrs[i].sh_offset; sechdrs[i].sh_offset;
info->symtab_stop = (void *)hdr + info->symtab_stop = (void *)hdr +
sechdrs[i].sh_offset + sechdrs[i].sh_size; sechdrs[i].sh_offset + sechdrs[i].sh_size;
sh_link_idx = shndx2secindex(sechdrs[i].sh_link); sh_link_idx = sechdrs[i].sh_link;
info->strtab = (void *)hdr + info->strtab = (void *)hdr +
sechdrs[sh_link_idx].sh_offset; sechdrs[sh_link_idx].sh_offset;
} }
...@@ -516,11 +514,9 @@ static int parse_elf(struct elf_info *info, const char *filename) ...@@ -516,11 +514,9 @@ static int parse_elf(struct elf_info *info, const char *filename)
if (symtab_shndx_idx != ~0U) { if (symtab_shndx_idx != ~0U) {
Elf32_Word *p; Elf32_Word *p;
if (symtab_idx != if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
shndx2secindex(sechdrs[symtab_shndx_idx].sh_link))
fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
filename, filename, sechdrs[symtab_shndx_idx].sh_link,
shndx2secindex(sechdrs[symtab_shndx_idx].sh_link),
symtab_idx); symtab_idx);
/* Fix endianness */ /* Fix endianness */
for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
...@@ -1446,7 +1442,7 @@ static unsigned int *reloc_location(struct elf_info *elf, ...@@ -1446,7 +1442,7 @@ static unsigned int *reloc_location(struct elf_info *elf,
Elf_Shdr *sechdr, Elf_Rela *r) Elf_Shdr *sechdr, Elf_Rela *r)
{ {
Elf_Shdr *sechdrs = elf->sechdrs; Elf_Shdr *sechdrs = elf->sechdrs;
int section = shndx2secindex(sechdr->sh_info); int section = sechdr->sh_info;
return (void *)elf->hdr + sechdrs[section].sh_offset + return (void *)elf->hdr + sechdrs[section].sh_offset +
r->r_offset; r->r_offset;
......
...@@ -145,33 +145,22 @@ static inline int is_shndx_special(unsigned int i) ...@@ -145,33 +145,22 @@ static inline int is_shndx_special(unsigned int i)
return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
} }
/* shndx is in [0..SHN_LORESERVE) U (SHN_HIRESERVE, 0xfffffff], thus: /*
* shndx == 0 <=> sechdrs[0] * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
* ...... * the way to -256..-1, to avoid conflicting with real section
* shndx == SHN_LORESERVE-1 <=> sechdrs[SHN_LORESERVE-1] * indices.
* shndx == SHN_HIRESERVE+1 <=> sechdrs[SHN_LORESERVE]
* shndx == SHN_HIRESERVE+2 <=> sechdrs[SHN_LORESERVE+1]
* ......
* fyi: sym->st_shndx is uint16, SHN_LORESERVE = ff00, SHN_HIRESERVE = ffff,
* so basically we map 0000..feff -> 0000..feff
* ff00..ffff -> (you are a bad boy, dont do it)
* 10000..xxxx -> ff00..(xxxx-0x100)
*/ */
static inline unsigned int shndx2secindex(unsigned int i) #define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
{
if (i <= SHN_HIRESERVE)
return i;
return i - (SHN_HIRESERVE + 1 - SHN_LORESERVE);
}
/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
static inline unsigned int get_secindex(const struct elf_info *info, static inline unsigned int get_secindex(const struct elf_info *info,
const Elf_Sym *sym) const Elf_Sym *sym)
{ {
if (is_shndx_special(sym->st_shndx))
return SPECIAL(sym->st_shndx);
if (sym->st_shndx != SHN_XINDEX) if (sym->st_shndx != SHN_XINDEX)
return sym->st_shndx; return sym->st_shndx;
return shndx2secindex(info->symtab_shndx_start[sym - return info->symtab_shndx_start[sym - info->symtab_start];
info->symtab_start]);
} }
/* file2alias.c */ /* file2alias.c */
......
...@@ -5,4 +5,15 @@ ...@@ -5,4 +5,15 @@
*/ */
SECTIONS { SECTIONS {
/DISCARD/ : { *(.discard) } /DISCARD/ : { *(.discard) }
__ksymtab : { *(SORT(___ksymtab+*)) }
__ksymtab_gpl : { *(SORT(___ksymtab_gpl+*)) }
__ksymtab_unused : { *(SORT(___ksymtab_unused+*)) }
__ksymtab_unused_gpl : { *(SORT(___ksymtab_unused_gpl+*)) }
__ksymtab_gpl_future : { *(SORT(___ksymtab_gpl_future+*)) }
__kcrctab : { *(SORT(___kcrctab+*)) }
__kcrctab_gpl : { *(SORT(___kcrctab_gpl+*)) }
__kcrctab_unused : { *(SORT(___kcrctab_unused+*)) }
__kcrctab_unused_gpl : { *(SORT(___kcrctab_unused_gpl+*)) }
__kcrctab_gpl_future : { *(SORT(___kcrctab_gpl_future+*)) }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment