diff options
| -rw-r--r-- | Documentation/kernel-parameters.txt | 6 | ||||
| -rw-r--r-- | include/linux/module.h | 8 | ||||
| -rw-r--r-- | init/Kconfig | 14 | ||||
| -rw-r--r-- | kernel/Makefile | 1 | ||||
| -rw-r--r-- | kernel/module-internal.h | 13 | ||||
| -rw-r--r-- | kernel/module.c | 93 | ||||
| -rw-r--r-- | kernel/module_signing.c | 23 |
7 files changed, 157 insertions, 1 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ad7e2e5088c1..9b2b8d3ae3e0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -1582,6 +1582,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 1582 | log everything. Information is printed at KERN_DEBUG | 1582 | log everything. Information is printed at KERN_DEBUG |
| 1583 | so loglevel=8 may also need to be specified. | 1583 | so loglevel=8 may also need to be specified. |
| 1584 | 1584 | ||
| 1585 | module.sig_enforce | ||
| 1586 | [KNL] When CONFIG_MODULE_SIG is set, this means that | ||
| 1587 | modules without (valid) signatures will fail to load. | ||
| 1588 | Note that if CONFIG_MODULE_SIG_ENFORCE is set, that | ||
| 1589 | is always true, so this option does nothing. | ||
| 1590 | |||
| 1585 | mousedev.tap_time= | 1591 | mousedev.tap_time= |
| 1586 | [MOUSE] Maximum time between finger touching and | 1592 | [MOUSE] Maximum time between finger touching and |
| 1587 | leaving touchpad surface for touch to be considered | 1593 | leaving touchpad surface for touch to be considered |
diff --git a/include/linux/module.h b/include/linux/module.h index fbcafe2ee13e..7760c6d344a3 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
| @@ -21,6 +21,9 @@ | |||
| 21 | #include <linux/percpu.h> | 21 | #include <linux/percpu.h> |
| 22 | #include <asm/module.h> | 22 | #include <asm/module.h> |
| 23 | 23 | ||
| 24 | /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ | ||
| 25 | #define MODULE_SIG_STRING "~Module signature appended~\n" | ||
| 26 | |||
| 24 | /* Not Yet Implemented */ | 27 | /* Not Yet Implemented */ |
| 25 | #define MODULE_SUPPORTED_DEVICE(name) | 28 | #define MODULE_SUPPORTED_DEVICE(name) |
| 26 | 29 | ||
| @@ -260,6 +263,11 @@ struct module | |||
| 260 | const unsigned long *unused_gpl_crcs; | 263 | const unsigned long *unused_gpl_crcs; |
| 261 | #endif | 264 | #endif |
| 262 | 265 | ||
| 266 | #ifdef CONFIG_MODULE_SIG | ||
| 267 | /* Signature was verified. */ | ||
| 268 | bool sig_ok; | ||
| 269 | #endif | ||
| 270 | |||
| 263 | /* symbols that will be GPL-only in the near future. */ | 271 | /* symbols that will be GPL-only in the near future. */ |
| 264 | const struct kernel_symbol *gpl_future_syms; | 272 | const struct kernel_symbol *gpl_future_syms; |
| 265 | const unsigned long *gpl_future_crcs; | 273 | const unsigned long *gpl_future_crcs; |
diff --git a/init/Kconfig b/init/Kconfig index 66cc885abbc6..fa8ccad1ea43 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
| @@ -1585,6 +1585,20 @@ config MODULE_SRCVERSION_ALL | |||
| 1585 | the version). With this option, such a "srcversion" field | 1585 | the version). With this option, such a "srcversion" field |
| 1586 | will be created for all modules. If unsure, say N. | 1586 | will be created for all modules. If unsure, say N. |
| 1587 | 1587 | ||
| 1588 | config MODULE_SIG | ||
| 1589 | bool "Module signature verification" | ||
| 1590 | depends on MODULES | ||
| 1591 | help | ||
| 1592 | Check modules for valid signatures upon load: the signature | ||
| 1593 | is simply appended to the module. For more information see | ||
| 1594 | Documentation/module-signing.txt. | ||
| 1595 | |||
| 1596 | config MODULE_SIG_FORCE | ||
| 1597 | bool "Require modules to be validly signed" | ||
| 1598 | depends on MODULE_SIG | ||
| 1599 | help | ||
| 1600 | Reject unsigned modules or signed modules for which we don't have a | ||
| 1601 | key. Without this, such modules will simply taint the kernel. | ||
| 1588 | endif # MODULES | 1602 | endif # MODULES |
| 1589 | 1603 | ||
| 1590 | config INIT_ALL_POSSIBLE | 1604 | config INIT_ALL_POSSIBLE |
diff --git a/kernel/Makefile b/kernel/Makefile index c0cc67ad764c..08ba8a6abd1c 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
| @@ -55,6 +55,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o | |||
| 55 | obj-$(CONFIG_PROVE_LOCKING) += spinlock.o | 55 | obj-$(CONFIG_PROVE_LOCKING) += spinlock.o |
| 56 | obj-$(CONFIG_UID16) += uid16.o | 56 | obj-$(CONFIG_UID16) += uid16.o |
| 57 | obj-$(CONFIG_MODULES) += module.o | 57 | obj-$(CONFIG_MODULES) += module.o |
| 58 | obj-$(CONFIG_MODULE_SIG) += module_signing.o | ||
| 58 | obj-$(CONFIG_KALLSYMS) += kallsyms.o | 59 | obj-$(CONFIG_KALLSYMS) += kallsyms.o |
| 59 | obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o | 60 | obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o |
| 60 | obj-$(CONFIG_KEXEC) += kexec.o | 61 | obj-$(CONFIG_KEXEC) += kexec.o |
diff --git a/kernel/module-internal.h b/kernel/module-internal.h new file mode 100644 index 000000000000..033c17fd70ef --- /dev/null +++ b/kernel/module-internal.h | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | /* Module internals | ||
| 2 | * | ||
| 3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | extern int mod_verify_sig(const void *mod, unsigned long modlen, | ||
| 13 | const void *sig, unsigned long siglen); | ||
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) |
diff --git a/kernel/module_signing.c b/kernel/module_signing.c new file mode 100644 index 000000000000..499728aecafb --- /dev/null +++ b/kernel/module_signing.c | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* Module signature checker | ||
| 2 | * | ||
| 3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/err.h> | ||
| 14 | #include "module-internal.h" | ||
| 15 | |||
| 16 | /* | ||
| 17 | * Verify the signature on a module. | ||
| 18 | */ | ||
| 19 | int mod_verify_sig(const void *mod, unsigned long modlen, | ||
| 20 | const void *sig, unsigned long siglen) | ||
| 21 | { | ||
| 22 | return -ENOKEY; | ||
| 23 | } | ||
