diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 93 |
1 files changed, 92 insertions, 1 deletions
diff --git a/kernel/module.c b/kernel/module.c index 74bc19562ca3..68c564edb2c1 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <linux/jump_label.h> | 58 | #include <linux/jump_label.h> |
59 | #include <linux/pfn.h> | 59 | #include <linux/pfn.h> |
60 | #include <linux/bsearch.h> | 60 | #include <linux/bsearch.h> |
61 | #include "module-internal.h" | ||
61 | 62 | ||
62 | #define CREATE_TRACE_POINTS | 63 | #define CREATE_TRACE_POINTS |
63 | #include <trace/events/module.h> | 64 | #include <trace/events/module.h> |
@@ -102,6 +103,43 @@ static LIST_HEAD(modules); | |||
102 | struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ | 103 | struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ |
103 | #endif /* CONFIG_KGDB_KDB */ | 104 | #endif /* CONFIG_KGDB_KDB */ |
104 | 105 | ||
106 | #ifdef CONFIG_MODULE_SIG | ||
107 | #ifdef CONFIG_MODULE_SIG_FORCE | ||
108 | static bool sig_enforce = true; | ||
109 | #else | ||
110 | static bool sig_enforce = false; | ||
111 | |||
112 | static int param_set_bool_enable_only(const char *val, | ||
113 | const struct kernel_param *kp) | ||
114 | { | ||
115 | int err; | ||
116 | bool test; | ||
117 | struct kernel_param dummy_kp = *kp; | ||
118 | |||
119 | dummy_kp.arg = &test; | ||
120 | |||
121 | err = param_set_bool(val, &dummy_kp); | ||
122 | if (err) | ||
123 | return err; | ||
124 | |||
125 | /* Don't let them unset it once it's set! */ | ||
126 | if (!test && sig_enforce) | ||
127 | return -EROFS; | ||
128 | |||
129 | if (test) | ||
130 | sig_enforce = true; | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static const struct kernel_param_ops param_ops_bool_enable_only = { | ||
135 | .set = param_set_bool_enable_only, | ||
136 | .get = param_get_bool, | ||
137 | }; | ||
138 | #define param_check_bool_enable_only param_check_bool | ||
139 | |||
140 | module_param(sig_enforce, bool_enable_only, 0644); | ||
141 | #endif /* !CONFIG_MODULE_SIG_FORCE */ | ||
142 | #endif /* CONFIG_MODULE_SIG */ | ||
105 | 143 | ||
106 | /* Block module loading/unloading? */ | 144 | /* Block module loading/unloading? */ |
107 | int modules_disabled = 0; | 145 | int modules_disabled = 0; |
@@ -136,6 +174,7 @@ struct load_info { | |||
136 | unsigned long symoffs, stroffs; | 174 | unsigned long symoffs, stroffs; |
137 | struct _ddebug *debug; | 175 | struct _ddebug *debug; |
138 | unsigned int num_debug; | 176 | unsigned int num_debug; |
177 | bool sig_ok; | ||
139 | struct { | 178 | struct { |
140 | unsigned int sym, str, mod, vers, info, pcpu; | 179 | unsigned int sym, str, mod, vers, info, pcpu; |
141 | } index; | 180 | } index; |
@@ -2379,7 +2418,49 @@ static inline void kmemleak_load_module(const struct module *mod, | |||
2379 | } | 2418 | } |
2380 | #endif | 2419 | #endif |
2381 | 2420 | ||
2382 | /* Sets info->hdr and info->len. */ | 2421 | #ifdef CONFIG_MODULE_SIG |
2422 | static int module_sig_check(struct load_info *info, | ||
2423 | const void *mod, unsigned long *len) | ||
2424 | { | ||
2425 | int err = -ENOKEY; | ||
2426 | const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; | ||
2427 | const void *p = mod, *end = mod + *len; | ||
2428 | |||
2429 | /* Poor man's memmem. */ | ||
2430 | while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) { | ||
2431 | if (p + markerlen > end) | ||
2432 | break; | ||
2433 | |||
2434 | if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) { | ||
2435 | const void *sig = p + markerlen; | ||
2436 | /* Truncate module up to signature. */ | ||
2437 | *len = p - mod; | ||
2438 | err = mod_verify_sig(mod, *len, sig, end - sig); | ||
2439 | break; | ||
2440 | } | ||
2441 | p++; | ||
2442 | } | ||
2443 | |||
2444 | if (!err) { | ||
2445 | info->sig_ok = true; | ||
2446 | return 0; | ||
2447 | } | ||
2448 | |||
2449 | /* Not having a signature is only an error if we're strict. */ | ||
2450 | if (err == -ENOKEY && !sig_enforce) | ||
2451 | err = 0; | ||
2452 | |||
2453 | return err; | ||
2454 | } | ||
2455 | #else /* !CONFIG_MODULE_SIG */ | ||
2456 | static int module_sig_check(struct load_info *info, | ||
2457 | void *mod, unsigned long *len) | ||
2458 | { | ||
2459 | return 0; | ||
2460 | } | ||
2461 | #endif /* !CONFIG_MODULE_SIG */ | ||
2462 | |||
2463 | /* Sets info->hdr, info->len and info->sig_ok. */ | ||
2383 | static int copy_and_check(struct load_info *info, | 2464 | static int copy_and_check(struct load_info *info, |
2384 | const void __user *umod, unsigned long len, | 2465 | const void __user *umod, unsigned long len, |
2385 | const char __user *uargs) | 2466 | const char __user *uargs) |
@@ -2399,6 +2480,10 @@ static int copy_and_check(struct load_info *info, | |||
2399 | goto free_hdr; | 2480 | goto free_hdr; |
2400 | } | 2481 | } |
2401 | 2482 | ||
2483 | err = module_sig_check(info, hdr, &len); | ||
2484 | if (err) | ||
2485 | goto free_hdr; | ||
2486 | |||
2402 | /* Sanity checks against insmoding binaries or wrong arch, | 2487 | /* Sanity checks against insmoding binaries or wrong arch, |
2403 | weird elf version */ | 2488 | weird elf version */ |
2404 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0 | 2489 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0 |
@@ -2884,6 +2969,12 @@ static struct module *load_module(void __user *umod, | |||
2884 | goto free_copy; | 2969 | goto free_copy; |
2885 | } | 2970 | } |
2886 | 2971 | ||
2972 | #ifdef CONFIG_MODULE_SIG | ||
2973 | mod->sig_ok = info.sig_ok; | ||
2974 | if (!mod->sig_ok) | ||
2975 | add_taint_module(mod, TAINT_FORCED_MODULE); | ||
2976 | #endif | ||
2977 | |||
2887 | /* Now module is in final location, initialize linked lists, etc. */ | 2978 | /* Now module is in final location, initialize linked lists, etc. */ |
2888 | err = module_unload_init(mod); | 2979 | err = module_unload_init(mod); |
2889 | if (err) | 2980 | if (err) |