RHEL4/kernel/module-verify-sig.c
<<
>>
Prefs
   1/* module-verify-sig.c: module signature checker
   2 *
   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
   6 *
   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.
  11 */
  12
  13#include <linux/config.h>
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/slab.h>
  17#include <linux/elf.h>
  18#include <linux/crypto.h>
  19#include <linux/crypto/ksign.h>
  20#include "module-verify.h"
  21
  22#undef MODSIGN_DEBUG
  23
  24#ifdef MODSIGN_DEBUG
  25#define _debug(FMT, ...) printk(FMT, ##__VA_ARGS__)
  26#else
  27#define _debug(FMT, ...) do {} while (0)
  28#endif
  29
  30#ifdef MODSIGN_DEBUG
  31#define count_and_csum(C, __p,__n)                      \
  32do {                                                    \
  33        int __loop;                                     \
  34        for (__loop = 0; __loop < __n; __loop++) {      \
  35                (C)->csum += __p[__loop];               \
  36                (C)->xcsum += __p[__loop];              \
  37        }                                               \
  38        (C)->signed_size += __n;                        \
  39} while(0)
  40#else
  41#define count_and_csum(C, __p,__n)              \
  42do {                                            \
  43        (C)->signed_size += __n;                \
  44} while(0)
  45#endif
  46
  47#define crypto_digest_update_data(C,PTR,N)                      \
  48do {                                                            \
  49        size_t __n = (N);                                       \
  50        uint8_t *__p = (uint8_t *)(PTR);                        \
  51        count_and_csum((C), __p, __n);                          \
  52        crypto_digest_update_kernel((C)->digest, __p, __n);     \
  53} while(0)
  54
  55#define crypto_digest_update_val(C,VAL)                         \
  56do {                                                            \
  57        size_t __n = sizeof(VAL);                               \
  58        uint8_t *__p = (uint8_t *)&(VAL);                       \
  59        count_and_csum((C), __p, __n);                          \
  60        crypto_digest_update_kernel((C)->digest, __p, __n);     \
  61} while(0)
  62
  63static int module_verify_canonicalise(struct module_verify_data *mvdata);
  64
  65static int extract_elf_rela(struct module_verify_data *mvdata,
  66                            int secix,
  67                            const Elf_Rela *relatab, size_t nrels,
  68                            const char *sh_name);
  69
  70static int extract_elf_rel(struct module_verify_data *mvdata,
  71                           int secix,
  72                           const Elf_Rel *reltab, size_t nrels,
  73                           const char *sh_name);
  74
  75static int signedonly;
  76
  77/*****************************************************************************/
  78/*
  79 * verify a module's signature
  80 */
  81int module_verify_signature(struct module_verify_data *mvdata)
  82{
  83        const Elf_Shdr *sechdrs = mvdata->sections;
  84        const char *secstrings = mvdata->secstrings;
  85        const char *sig;
  86        unsigned sig_size;
  87        int i, ret;
  88
  89        for (i = 1; i < mvdata->nsects; i++) {
  90                switch (sechdrs[i].sh_type) {
  91                case SHT_PROGBITS:
  92                        if (strcmp(mvdata->secstrings + sechdrs[i].sh_name,
  93                                   ".module_sig") == 0) {
  94                                mvdata->sig_index = i;
  95                        }
  96                        break;
  97                }
  98        }
  99
 100        if (mvdata->sig_index <= 0)
 101                goto no_signature;
 102
 103        sig = mvdata->buffer + sechdrs[mvdata->sig_index].sh_offset;
 104        sig_size = sechdrs[mvdata->sig_index].sh_size;
 105
 106        _debug("sig in section %d (size %d)\n",
 107               mvdata->sig_index, sig_size);
 108
 109        /* produce a canonicalisation map for the sections */
 110        ret = module_verify_canonicalise(mvdata);
 111        if (ret < 0) {
 112                if (signedonly)
 113                        return ret;
 114                return 0;
 115        }
 116                
 117        /* grab an SHA1 transformation context
 118         * - !!! if this tries to load the sha1.ko module, we will deadlock!!!
 119         */
 120        mvdata->digest = crypto_alloc_tfm2("sha1", 0, 1);
 121        if (!mvdata->digest) {
 122                printk("Couldn't load module - SHA1 transform unavailable\n");
 123                if (!signedonly)
 124                        return 0;
 125                return -EPERM;
 126        }
 127
 128        crypto_digest_init(mvdata->digest);
 129
 130#ifdef MODSIGN_DEBUG
 131        mvdata->xcsum = 0;
 132#endif
 133
 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;
 142
 143                if (i == mvdata->sig_index)
 144                        continue;
 145
 146#ifdef MODSIGN_DEBUG
 147                mvdata->csum = 0;
 148#endif
 149
 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];
 157
 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);
 164
 165                                if (sh_type == SHT_RELA)
 166                                        ret = extract_elf_rela(
 167                                                mvdata, i,
 168                                                data,
 169                                                sh_size / sizeof(Elf_Rela),
 170                                                sh_name);
 171                                else
 172                                        ret = extract_elf_rel(
 173                                                mvdata, i,
 174                                                data,
 175                                                sh_size / sizeof(Elf_Rel),
 176                                                sh_name);
 177
 178                                if (ret < 0)
 179                                        goto format_error;
 180                        }
 181
 182                        continue;
 183                }
 184
 185                /* include allocatable loadable sections */
 186                if (sh_type != SHT_NOBITS && sh_flags & SHF_ALLOC)
 187                        goto include_section;
 188
 189                continue;
 190
 191        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);
 198
 199                _debug("%08zx %02x digested the %s section, size %ld\n",
 200                       mvdata->signed_size, mvdata->csum, sh_name, sh_size);
 201
 202                mvdata->canonlist[i] = 1;
 203        }
 204
 205        _debug("Contributed %zu bytes to the digest (csum 0x%02x)\n",
 206               mvdata->signed_size, mvdata->xcsum);
 207
 208        /* do the actual signature verification */
 209        i = ksign_verify_signature(sig, sig_size, mvdata->digest);
 210
 211        _debug("verify-sig : %d\n", i);
 212
 213        if (i == 0)
 214                i = 1;
 215        else if (!signedonly)
 216                i = 0;
 217        return i;
 218
 219 format_error:
 220        crypto_free_tfm(mvdata->digest);
 221        if (!signedonly)
 222                return 0;
 223        return -ELIBBAD;
 224
 225        /* deal with the case of an unsigned module */
 226 no_signature:
 227        if (!signedonly)
 228                return 0;
 229        printk("An attempt to load unsigned module was rejected\n");
 230        return -EPERM;
 231
 232} /* end module_verify_signature() */
 233
 234/*****************************************************************************/
 235/*
 236 * canonicalise the section table index numbers
 237 */
 238static int module_verify_canonicalise(struct module_verify_data *mvdata)
 239{
 240        int canon, loop, changed, tmp;
 241
 242        /* produce a list of index numbers of sections that contribute
 243         * to the kernel's module image
 244         */
 245        mvdata->canonlist =
 246                kmalloc(sizeof(int) * mvdata->nsects * 2, GFP_KERNEL);
 247        if (!mvdata->canonlist)
 248                return -ENOMEM;
 249
 250        mvdata->canonmap = mvdata->canonlist + mvdata->nsects;
 251        canon = 0;
 252
 253        for (loop = 1; loop < mvdata->nsects; loop++) {
 254                const Elf_Shdr *section = mvdata->sections + loop;
 255
 256                if (loop != mvdata->sig_index) {
 257                        /* we only need to canonicalise allocatable sections */
 258                        if (section->sh_flags & SHF_ALLOC)
 259                                mvdata->canonlist[canon++] = loop;
 260                }
 261        }
 262
 263        /* canonicalise the index numbers of the contributing section */
 264        do {
 265                changed = 0;
 266
 267                for (loop = 0; loop < canon - 1; loop++) {
 268                        const char *x, *y;
 269
 270                        x = mvdata->secstrings +
 271                                mvdata->sections[mvdata->canonlist[loop + 0]].sh_name;
 272                        y = mvdata->secstrings +
 273                                mvdata->sections[mvdata->canonlist[loop + 1]].sh_name;
 274
 275                        if (strcmp(x, y) > 0) {
 276                                tmp = mvdata->canonlist[loop + 0];
 277                                mvdata->canonlist[loop + 0] =
 278                                        mvdata->canonlist[loop + 1];
 279                                mvdata->canonlist[loop + 1] = tmp;
 280                                changed = 1;
 281                        }
 282                }
 283
 284        } while(changed);
 285
 286        for (loop = 0; loop < canon; loop++)
 287                mvdata->canonmap[mvdata->canonlist[loop]] = loop + 1;
 288
 289        return 0;
 290
 291} /* end module_verify_canonicalise() */
 292
 293/*****************************************************************************/
 294/*
 295 * extract a RELA table
 296 * - need to canonicalise the entries in case section addition/removal has
 297 *   rearranged the symbol table and the section table
 298 */
 299static int extract_elf_rela(struct module_verify_data *mvdata,
 300                            int secix,
 301                            const Elf_Rela *relatab, size_t nrels,
 302                            const char *sh_name)
 303{
 304        struct {
 305#if defined(MODULES_ARE_ELF32)
 306                uint32_t        r_offset;
 307                uint32_t        r_addend;
 308                uint32_t        st_value;
 309                uint32_t        st_size;
 310                uint16_t        st_shndx;
 311                uint8_t         r_type;
 312                uint8_t         st_info;
 313                uint8_t         st_other;
 314#elif defined(MODULES_ARE_ELF64)
 315                uint64_t        r_offset;
 316                uint64_t        r_addend;
 317                uint64_t        st_value;
 318                uint64_t        st_size;
 319                uint32_t        r_type;
 320                uint16_t        st_shndx;
 321                uint8_t         st_info;
 322                uint8_t         st_other;
 323#else
 324#error unsupported module type
 325#endif
 326        } __attribute__((packed)) relocation;
 327
 328        const Elf_Rela *reloc;
 329        const Elf_Sym *symbol;
 330        size_t loop;
 331
 332        /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
 333        for (loop = 0; loop < nrels; loop++) {
 334                int st_shndx;
 335
 336                reloc = &relatab[loop];
 337
 338                /* decode the relocation */
 339                relocation.r_offset = reloc->r_offset;
 340                relocation.r_addend = reloc->r_addend;
 341                relocation.r_type = ELF_R_TYPE(reloc->r_info);
 342
 343                /* decode the symbol referenced by the relocation */
 344                symbol = &mvdata->symbols[ELF_R_SYM(reloc->r_info)];
 345                relocation.st_info = symbol->st_info;
 346                relocation.st_other = symbol->st_other;
 347                relocation.st_value = symbol->st_value;
 348                relocation.st_size = symbol->st_size;
 349                relocation.st_shndx = symbol->st_shndx;
 350                st_shndx = symbol->st_shndx;
 351
 352                /* canonicalise the section used by the symbol */
 353                if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects)
 354                        relocation.st_shndx = mvdata->canonmap[st_shndx];
 355
 356                crypto_digest_update_val(mvdata, relocation);
 357
 358                /* undefined symbols must be named if referenced */
 359                if (st_shndx == SHN_UNDEF) {
 360                        const char *name = mvdata->strings + symbol->st_name;
 361                        crypto_digest_update_data(mvdata,
 362                                                  name, strlen(name) + 1);
 363                }
 364        }
 365
 366        _debug("%08zx %02x digested the %s section, nrels %zu\n",
 367               mvdata->signed_size, mvdata->csum, sh_name, nrels);
 368
 369        return 0;
 370} /* end extract_elf_rela() */
 371
 372/*****************************************************************************/
 373/*
 374 *
 375 */
 376static int extract_elf_rel(struct module_verify_data *mvdata,
 377                           int secix,
 378                           const Elf_Rel *reltab, size_t nrels,
 379                           const char *sh_name)
 380{
 381        struct {
 382#if defined(MODULES_ARE_ELF32)
 383                uint32_t        r_offset;
 384                uint32_t        st_value;
 385                uint32_t        st_size;
 386                uint16_t        st_shndx;
 387                uint8_t         r_type;
 388                uint8_t         st_info;
 389                uint8_t         st_other;
 390#elif defined(MODULES_ARE_ELF64)
 391                uint64_t        r_offset;
 392                uint64_t        st_value;
 393                uint64_t        st_size;
 394                uint32_t        r_type;
 395                uint16_t        st_shndx;
 396                uint8_t         st_info;
 397                uint8_t         st_other;
 398#else
 399#error unsupported module type
 400#endif
 401        } __attribute__((packed)) relocation;
 402
 403        const Elf_Rel *reloc;
 404        const Elf_Sym *symbol;
 405        size_t loop;
 406
 407        /* contribute the relevant bits from a join of { RELA, SYMBOL, SECTION } */
 408        for (loop = 0; loop < nrels; loop++) {
 409                int st_shndx;
 410
 411                reloc = &reltab[loop];
 412
 413                /* decode the relocation */
 414                relocation.r_offset = reloc->r_offset;
 415                relocation.r_type = ELF_R_TYPE(reloc->r_info);
 416
 417                /* decode the symbol referenced by the relocation */
 418                symbol = &mvdata->symbols[ELF_R_SYM(reloc->r_info)];
 419                relocation.st_info = symbol->st_info;
 420                relocation.st_other = symbol->st_other;
 421                relocation.st_value = symbol->st_value;
 422                relocation.st_size = symbol->st_size;
 423                relocation.st_shndx = symbol->st_shndx;
 424                st_shndx = symbol->st_shndx;
 425
 426                /* canonicalise the section used by the symbol */
 427                if (st_shndx > SHN_UNDEF && st_shndx < mvdata->nsects)
 428                        relocation.st_shndx = mvdata->canonmap[st_shndx];
 429
 430                crypto_digest_update_val(mvdata, relocation);
 431
 432                /* undefined symbols must be named if referenced */
 433                if (st_shndx == SHN_UNDEF) {
 434                        const char *name = mvdata->strings + symbol->st_name;
 435                        crypto_digest_update_data(mvdata,
 436                                                  name, strlen(name) + 1);
 437                }
 438        }
 439
 440        _debug("%08zx %02x digested the %s section, nrels %zu\n",
 441               mvdata->signed_size, mvdata->csum, sh_name, nrels);
 442
 443        return 0;
 444} /* end extract_elf_rel() */
 445
 446static int __init sign_setup(char *str)
 447{
 448        signedonly = 1;
 449        return 0;
 450}
 451__setup("enforcemodulesig", sign_setup);
 452