aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/module-internal.h13
-rw-r--r--kernel/module.c93
-rw-r--r--kernel/module_signing.c23
4 files changed, 129 insertions, 1 deletions
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
55obj-$(CONFIG_PROVE_LOCKING) += spinlock.o 55obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
56obj-$(CONFIG_UID16) += uid16.o 56obj-$(CONFIG_UID16) += uid16.o
57obj-$(CONFIG_MODULES) += module.o 57obj-$(CONFIG_MODULES) += module.o
58obj-$(CONFIG_MODULE_SIG) += module_signing.o
58obj-$(CONFIG_KALLSYMS) += kallsyms.o 59obj-$(CONFIG_KALLSYMS) += kallsyms.o
59obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o 60obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
60obj-$(CONFIG_KEXEC) += kexec.o 61obj-$(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
12extern 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);
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)
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 */
19int mod_verify_sig(const void *mod, unsigned long modlen,
20 const void *sig, unsigned long siglen)
21{
22 return -ENOKEY;
23}