1 /* module-verify-sig.c: module signature checker
3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * - Derived from GregKH's RSA module signer
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/elf.h>
17 #include <linux/crypto.h>
18 #include <linux/crypto/ksign.h>
19 #include "module-verify.h"
24 #define _debug(FMT, ...) printk(FMT, ##__VA_ARGS__)
26 #define _debug(FMT, ...) do {} while (0)
30 #define count_and_csum(C, __p,__n) \
33 for (__loop = 0; __loop < __n; __loop++) { \
34 (C)->csum += __p[__loop]; \
35 (C)->xcsum += __p[__loop]; \
37 (C)->signed_size += __n; \
40 #define count_and_csum(C, __p,__n) \
42 (C)->signed_size += __n; \
46 #define crypto_digest_update_data(C,PTR,N) \
49 uint8_t *__p = (uint8_t *)(PTR); \
50 count_and_csum((C), __p, __n); \
51 crypto_hash_update_kernel(&(C)->hash, __p, __n); \
54 #define crypto_digest_update_val(C,VAL) \
56 size_t __n = sizeof(VAL); \
57 uint8_t *__p = (uint8_t *)&(VAL); \
58 count_and_csum((C), __p, __n); \
59 crypto_hash_update_kernel(&(C)->hash, __p, __n); \
62 static int module_verify_canonicalise(struct module_verify_data *mvdata);
64 static int extract_elf_rela(struct module_verify_data *mvdata,
66 const Elf_Rela *relatab, size_t nrels,
69 static int extract_elf_rel(struct module_verify_data *mvdata,
71 const Elf_Rel *reltab, size_t nrels,
74 static int signedonly;
76 static int __init sign_setup(char *str)
81 __setup("enforcemodulesig", sign_setup);
84 * verify a module's signature
86 int module_verify_signature(struct module_verify_data *mvdata)
88 const Elf_Shdr *sechdrs = mvdata->sections;
89 const char *secstrings = mvdata->secstrings;
94 for (i = 1; i < mvdata->nsects; i++) {
95 switch (sechdrs[i].sh_type) {
97 if (strcmp(mvdata->secstrings + sechdrs[i].sh_name,
98 ".module_sig") == 0) {
99 mvdata->sig_index = i;
105 if (mvdata->sig_index <= 0)
108 sig = mvdata->buffer + sechdrs[mvdata->sig_index].sh_offset;
109 sig_size = sechdrs[mvdata->sig_index].sh_size;
111 _debug("sig in section %d (size %d)\n",
112 mvdata->sig_index, sig_size);
114 /* produce a canonicalisation map for the sections */
115 ret = module_verify_canonicalise(mvdata);
119 /* grab an SHA1 transformation context
120 * - !!! if this tries to load the sha1.ko module, we will deadlock!!!
122 mvdata->hash.tfm = crypto_hash_cast(crypto_alloc_tfm2("sha1", 0, 1));
123 if (!mvdata->hash.tfm) {
124 printk("Couldn't load module - SHA1 transform unavailable\n");
128 crypto_hash_init(&mvdata->hash);
134 /* load data from each relevant section into the digest */
135 for (i = 1; i < mvdata->nsects; i++) {
136 unsigned long sh_type = sechdrs[i].sh_type;
137 unsigned long sh_info = sechdrs[i].sh_info;
138 unsigned long sh_size = sechdrs[i].sh_size;
139 unsigned long sh_flags = sechdrs[i].sh_flags;
140 const char *sh_name = secstrings + sechdrs[i].sh_name;
141 const void *data = mvdata->buffer + sechdrs[i].sh_offset;
143 if (i == mvdata->sig_index)
150 /* it would be nice to include relocation sections, but the act
151 * of adding a signature to the module seems changes their
152 * contents, because the symtab gets changed when sections are
153 * added or removed */
154 if (sh_type == SHT_REL || sh_type == SHT_RELA) {
155 if (mvdata->canonlist[sh_info]) {
156 uint32_t xsh_info = mvdata->canonmap[sh_info];
158 crypto_digest_update_data(mvdata, sh_name, strlen(sh_name));
159 crypto_digest_update_val(mvdata, sechdrs[i].sh_type);
160 crypto_digest_update_val(mvdata, sechdrs[i].sh_flags);
161 crypto_digest_update_val(mvdata, sechdrs[i].sh_size);
162 crypto_digest_update_val(mvdata, sechdrs[i].sh_addralign);
163 crypto_digest_update_val(mvdata, xsh_info);
165 if (sh_type == SHT_RELA)
166 ret = extract_elf_rela(
169 sh_size / sizeof(Elf_Rela),
172 ret = extract_elf_rel(
175 sh_size / sizeof(Elf_Rel),
185 /* include allocatable loadable sections */
186 if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC)
187 goto include_section;
192 crypto_digest_update_data(mvdata, sh_name, strlen(sh_name));
193 crypto_digest_update_val(mvdata, sechdrs[i].sh_type);
194 crypto_digest_update_val(mvdata, sechdrs[i].sh_flags);
195 crypto_digest_update_val(mvdata, sechdrs[i].sh_size);
196 crypto_digest_update_val(mvdata, sechdrs[i].sh_addralign);
197 crypto_digest_update_data(mvdata, data, sh_size);
199 _debug("%08zx %02x digested the %s section, size %ld\n",
200 mvdata->signed_size, mvdata->csum, sh_name, sh_size);
202 mvdata->canonlist[i] = 1;
205 _debug("Contributed %zu bytes to the digest (csum 0x%02x)\n",
206 mvdata->signed_size, mvdata->xcsum);
208 /* do the actual signature verification */
209 ret = ksign_verify_signature(sig, sig_size, mvdata->hash.tfm);
211 _debug("verify-sig : %d\n", ret);
214 case 0: /* good signature */
217 case -EKEYREJECTED: /* signature mismatch or number format error */
218 printk(KERN_ERR "Module signature verification failed\n");
220 case -ENOKEY: /* signed, but we don't have the public key */
221 printk(KERN_ERR "Module signed with unknown public key\n");
223 default: /* other error (probably ENOMEM) */
230 crypto_free_hash(mvdata->hash.tfm);
231 printk(KERN_ERR "Module format error encountered\n");
234 /* deal with the case of an unsigned module */
238 printk(KERN_ERR "An attempt to load unsigned module was rejected\n");
239 return -EKEYREJECTED;
243 * canonicalise the section table index numbers
245 static int module_verify_canonicalise(struct module_verify_data *mvdata)
247 int canon, loop, changed, tmp;
249 /* produce a list of index numbers of sections that contribute
250 * to the kernel's module image
253 kmalloc(sizeof(int) * mvdata->nsects * 2, GFP_KERNEL);
254 if (!mvdata->canonlist)
257 mvdata->canonmap = mvdata->canonlist + mvdata->nsects;
260 for (loop = 1; loop < mvdata->nsects; loop++) {
261 const Elf_Shdr *section = mvdata->sections + loop;
263 if (loop != mvdata->sig_index) {
264 /* we only need to canonicalise allocatable sections */
265 if (section->sh_flags & SHF_ALLOC)
266 mvdata->canonlist[canon++] = loop;
270 /* canonicalise the index numbers of the contributing section */
274 for (loop = 0; loop < canon - 1; loop++) {
277 x = mvdata->secstrings +
278 mvdata->sections[mvdata->canonlist[loop + 0]].sh_name;
279 y = mvdata->secstrings +
280 mvdata->sections[mvdata->canonlist[loop + 1]].sh_name;
282 if (strcmp(x, y) > 0) {
283 tmp = mvdata->canonlist[loop + 0];
284 mvdata->canonlist[loop + 0] =
285 mvdata->canonlist[loop + 1];
286 mvdata->canonlist[loop + 1] = tmp;
293 for (loop = 0; loop < canon; loop++)
294 mvdata->canonmap[mvdata->canonlist[loop]] = loop + 1;
300 * extract an ELF RELA table
301 * - need to canonicalise the entries in case section addition/removal has
302 * rearranged the symbol table and the section table
304 static int extract_elf_rela(struct module_verify_data *mvdata,
306 const Elf_Rela *relatab, size_t nrels,
310 #if defined(MODULES_ARE_ELF32)
319 #elif defined(MODULES_ARE_ELF64)
329 #error unsupported module type
331 } __attribute__((packed)) relocation;
333 const Elf_Rela *reloc;
334 const Elf_Sym *symbol;
337 /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
338 for (loop = 0; loop < nrels; loop++) {
341 reloc = &relatab[loop];
343 /* decode the relocation */
344 relocation.r_offset = reloc->r_offset;
345 relocation.r_addend = reloc->r_addend;
346 relocation.r_type = ELF_R_TYPE(reloc->r_info);
348 /* decode the symbol referenced by the relocation */
349 symbol = &mvdata->symbols[ELF_R_SYM(reloc->r_info)];
350 relocation.st_info = symbol->st_info;
351 relocation.st_other = symbol->st_other;
352 relocation.st_value = symbol->st_value;
353 relocation.st_size = symbol->st_size;
354 relocation.st_shndx = symbol->st_shndx;
355 st_shndx = symbol->st_shndx;
357 /* canonicalise the section used by the symbol */
358 if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects)
359 relocation.st_shndx = mvdata->canonmap[st_shndx];
361 crypto_digest_update_val(mvdata, relocation);
363 /* undefined symbols must be named if referenced */
364 if (st_shndx == SHN_UNDEF) {
365 const char *name = mvdata->strings + symbol->st_name;
366 crypto_digest_update_data(mvdata,
367 name, strlen(name) + 1);
371 _debug("%08zx %02x digested the %s section, nrels %zu\n",
372 mvdata->signed_size, mvdata->csum, sh_name, nrels);
378 * extract an ELF REL table
379 * - need to canonicalise the entries in case section addition/removal has
380 * rearranged the symbol table and the section table
382 static int extract_elf_rel(struct module_verify_data *mvdata,
384 const Elf_Rel *reltab, size_t nrels,
388 #if defined(MODULES_ARE_ELF32)
396 #elif defined(MODULES_ARE_ELF64)
405 #error unsupported module type
407 } __attribute__((packed)) relocation;
409 const Elf_Rel *reloc;
410 const Elf_Sym *symbol;
413 /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
414 for (loop = 0; loop < nrels; loop++) {
417 reloc = &reltab[loop];
419 /* decode the relocation */
420 relocation.r_offset = reloc->r_offset;
421 relocation.r_type = ELF_R_TYPE(reloc->r_info);
423 /* decode the symbol referenced by the relocation */
424 symbol = &mvdata->symbols[ELF_R_SYM(reloc->r_info)];
425 relocation.st_info = symbol->st_info;
426 relocation.st_other = symbol->st_other;
427 relocation.st_value = symbol->st_value;
428 relocation.st_size = symbol->st_size;
429 relocation.st_shndx = symbol->st_shndx;
430 st_shndx = symbol->st_shndx;
432 /* canonicalise the section used by the symbol */
433 if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects)
434 relocation.st_shndx = mvdata->canonmap[st_shndx];
436 crypto_digest_update_val(mvdata, relocation);
438 /* undefined symbols must be named if referenced */
439 if (st_shndx == SHN_UNDEF) {
440 const char *name = mvdata->strings + symbol->st_name;
441 crypto_digest_update_data(mvdata,
442 name, strlen(name) + 1);
446 _debug("%08zx %02x digested the %s section, nrels %zu\n",
447 mvdata->signed_size, mvdata->csum, sh_name, nrels);