diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2012-09-26 05:09:40 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2012-10-10 05:30:55 -0400 |
commit | 106a4ee258d14818467829bf0e12aeae14c16cd7 (patch) | |
tree | 4a5d002eceff4a028ebc8d88223b1ed735bee224 /kernel/module.c | |
parent | c26fd69fa00916a31a47f5f096fd7be924106df8 (diff) |
module: signature checking hook
We do a very simple search for a particular string appended to the module
(which is cache-hot and about to be SHA'd anyway). There's both a config
option and a boot parameter which control whether we accept or fail with
unsigned modules and modules that are signed with an unknown key.
If module signing is enabled, the kernel will be tainted if a module is
loaded that is unsigned or has a signature for which we don't have the
key.
(Useful feedback and tweaks by David Howells <dhowells@redhat.com>)
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
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) |