aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/module.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2012-09-26 05:09:40 -0400
committerRusty Russell <rusty@rustcorp.com.au>2012-10-10 05:30:55 -0400
commit106a4ee258d14818467829bf0e12aeae14c16cd7 (patch)
tree4a5d002eceff4a028ebc8d88223b1ed735bee224 /kernel/module.c
parentc26fd69fa00916a31a47f5f096fd7be924106df8 (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.c93
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);
102struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ 103struct 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
108static bool sig_enforce = true;
109#else
110static bool sig_enforce = false;
111
112static 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
134static 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
140module_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? */
107int modules_disabled = 0; 145int 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
2422static 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 */
2456static 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. */
2383static int copy_and_check(struct load_info *info, 2464static 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)