RHEL4/kernel/module-verify.c
<<
>>
Prefs
   1/* module-verify.c: module verifier
   2 *
   3 * Written by David Howells (dhowells@redhat.com)
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License
   7 * as published by the Free Software Foundation; either version
   8 * 2 of the License, or (at your option) any later version.
   9 */
  10
  11#include <linux/config.h>
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/slab.h>
  15#include <linux/elf.h>
  16#include <linux/crypto.h>
  17#include <linux/crypto/ksign.h>
  18#include "module-verify.h"
  19
  20#if 0
  21#define _debug(FMT, ...) printk(FMT, ##__VA_ARGS__)
  22#else
  23#define _debug(FMT, ...) do {} while (0)
  24#endif
  25
  26static int module_verify_elf(struct module_verify_data *mvdata);
  27
  28/*****************************************************************************/
  29/*
  30 * verify a module's integrity
  31 * - check the ELF is viable
  32 * - check the module's signature if it has one
  33 */
  34int module_verify(const Elf_Ehdr *hdr, size_t size)
  35{
  36        struct module_verify_data mvdata;
  37        int ret;
  38
  39        memset(&mvdata, 0, sizeof(mvdata));
  40        mvdata.buffer   = hdr;
  41        mvdata.hdr      = hdr;
  42        mvdata.size     = size;
  43
  44        ret = module_verify_elf(&mvdata);
  45        if (ret < 0) {
  46                if (ret == -ELIBBAD)
  47                        printk("Module failed ELF checks\n");
  48                goto error;
  49        }
  50
  51#ifdef CONFIG_MODULE_SIG
  52        ret = module_verify_signature(&mvdata);
  53#endif
  54
  55 error:
  56        kfree(mvdata.secsizes);
  57        kfree(mvdata.canonlist);
  58        return ret;
  59
  60} /* end module_verify() */
  61
  62/*****************************************************************************/
  63/*
  64 * verify the ELF structure of a module
  65 */
  66static int module_verify_elf(struct module_verify_data *mvdata)
  67{
  68        const Elf_Ehdr *hdr = mvdata->hdr;
  69        const Elf_Shdr *section, *section2, *secstop;
  70        const Elf_Rela *relas, *rela, *relastop;
  71        const Elf_Rel *rels, *rel, *relstop;
  72        const Elf_Sym *symbol, *symstop;
  73        size_t size, sssize, *secsize, tmp, tmp2;
  74        long last;
  75        int line;
  76
  77        size = mvdata->size;
  78        mvdata->nsects = hdr->e_shnum;
  79
  80#define elfcheck(X) \
  81do { if (unlikely(!(X))) { line = __LINE__; goto elfcheck_error; } } while(0)
  82
  83#define seccheck(X) \
  84do { if (unlikely(!(X))) { line = __LINE__; goto seccheck_error; } } while(0)
  85
  86#define symcheck(X) \
  87do { if (unlikely(!(X))) { line = __LINE__; goto symcheck_error; } } while(0)
  88
  89#define relcheck(X) \
  90do { if (unlikely(!(X))) { line = __LINE__; goto relcheck_error; } } while(0)
  91
  92#define relacheck(X) \
  93do { if (unlikely(!(X))) { line = __LINE__; goto relacheck_error; } } while(0)
  94
  95        /* validate the ELF header */
  96        elfcheck(hdr->e_ehsize < size);
  97        elfcheck(hdr->e_entry == 0);
  98        elfcheck(hdr->e_phoff == 0);
  99        elfcheck(hdr->e_phnum == 0);
 100
 101        elfcheck(hdr->e_shnum < SHN_LORESERVE);
 102        elfcheck(hdr->e_shoff < size);
 103        elfcheck(hdr->e_shoff >= hdr->e_ehsize);
 104        elfcheck((hdr->e_shoff & (sizeof(long) - 1)) == 0);
 105        elfcheck(hdr->e_shstrndx > 0);
 106        elfcheck(hdr->e_shstrndx < hdr->e_shnum);
 107        elfcheck(hdr->e_shentsize == sizeof(Elf_Shdr));
 108
 109        tmp = (size_t) hdr->e_shentsize * (size_t) hdr->e_shnum;
 110        elfcheck(tmp <= size - hdr->e_shoff);
 111
 112        /* allocate a table to hold in-file section sizes */
 113        mvdata->secsizes = kmalloc(hdr->e_shnum * sizeof(size_t), GFP_KERNEL);
 114        if (!mvdata->secsizes)
 115                return -ENOMEM;
 116
 117        memset(mvdata->secsizes, 0, hdr->e_shnum * sizeof(size_t));
 118
 119        /* validate the ELF section headers */
 120        mvdata->sections = mvdata->buffer + hdr->e_shoff;
 121        secstop = mvdata->sections + mvdata->nsects;
 122
 123        sssize = mvdata->sections[hdr->e_shstrndx].sh_size;
 124        elfcheck(sssize > 0);
 125
 126        section = mvdata->sections;
 127        seccheck(section->sh_type == SHT_NULL);
 128        seccheck(section->sh_size == 0);
 129        seccheck(section->sh_offset == 0);
 130
 131        secsize = mvdata->secsizes + 1;
 132        for (section++; section < secstop; secsize++, section++) {
 133                seccheck(section->sh_name < sssize);
 134                seccheck(section->sh_link < hdr->e_shnum);
 135
 136                if (section->sh_entsize > 0)
 137                        seccheck(section->sh_size % section->sh_entsize == 0);
 138
 139                seccheck(section->sh_offset >= hdr->e_ehsize);
 140                seccheck(section->sh_offset < size);
 141
 142                /* determine the section's in-file size */
 143                tmp = size - section->sh_offset;
 144                if (section->sh_offset < hdr->e_shoff)
 145                        tmp = hdr->e_shoff - section->sh_offset;
 146
 147                for (section2 = mvdata->sections + 1; section2 < secstop; section2++) {
 148                        if (section->sh_offset < section2->sh_offset) {
 149                                tmp2 = section2->sh_offset - section->sh_offset;
 150                                if (tmp2 < tmp)
 151                                        tmp = tmp2;
 152                        }
 153                }
 154                *secsize = tmp;
 155
 156                _debug("Section %ld: %zx bytes at %lx\n",
 157                       section - mvdata->sections,
 158                       *secsize,
 159                       section->sh_offset);
 160
 161                /* perform section type specific checks */
 162                switch (section->sh_type) {
 163                case SHT_NOBITS:
 164                        break;
 165
 166                case SHT_REL:
 167                        seccheck(section->sh_entsize == sizeof(Elf_Rel));
 168                        goto more_rel_checks;
 169
 170                case SHT_RELA:
 171                        seccheck(section->sh_entsize == sizeof(Elf_Rela));
 172                more_rel_checks:
 173                        seccheck(section->sh_info > 0);
 174                        seccheck(section->sh_info < hdr->e_shnum);
 175                        goto more_sec_checks;
 176
 177                case SHT_SYMTAB:
 178                        seccheck(section->sh_entsize == sizeof(Elf_Sym));
 179                        goto more_sec_checks;
 180
 181                default:
 182                more_sec_checks:
 183                        /* most types of section must be contained entirely
 184                         * within the file */
 185                        seccheck(section->sh_size <= *secsize);
 186                        break;
 187                }
 188        }
 189
 190        /* validate the ELF section names */
 191        section = &mvdata->sections[hdr->e_shstrndx];
 192
 193        seccheck(section->sh_offset != hdr->e_shoff);
 194
 195        mvdata->secstrings = mvdata->buffer + section->sh_offset;
 196
 197        last = -1;
 198        for (section = mvdata->sections + 1; section < secstop; section++) {
 199                const char *secname;
 200                tmp = sssize - section->sh_name;
 201                secname = mvdata->secstrings + section->sh_name;
 202                seccheck(secname[0] != 0);
 203                if (section->sh_name > last)
 204                        last = section->sh_name;
 205        }
 206
 207        if (last > -1) {
 208                tmp = sssize - last;
 209                elfcheck(memchr(mvdata->secstrings + last, 0, tmp) != NULL);
 210        }
 211
 212        /* look for various sections in the module */
 213        for (section = mvdata->sections + 1; section < secstop; section++) {
 214                switch (section->sh_type) {
 215                case SHT_SYMTAB:
 216                        if (strcmp(mvdata->secstrings + section->sh_name,
 217                                   ".symtab") == 0
 218                            ) {
 219                                seccheck(mvdata->symbols == NULL);
 220                                mvdata->symbols =
 221                                        mvdata->buffer + section->sh_offset;
 222                                mvdata->nsyms =
 223                                        section->sh_size / sizeof(Elf_Sym);
 224                                seccheck(section->sh_size > 0);
 225                        }
 226                        break;
 227
 228                case SHT_STRTAB:
 229                        if (strcmp(mvdata->secstrings + section->sh_name,
 230                                   ".strtab") == 0
 231                            ) {
 232                                seccheck(mvdata->strings == NULL);
 233                                mvdata->strings =
 234                                        mvdata->buffer + section->sh_offset;
 235                                sssize = mvdata->nstrings = section->sh_size;
 236                                seccheck(section->sh_size > 0);
 237                        }
 238                        break;
 239                }
 240        }
 241
 242        if (!mvdata->symbols) {
 243                printk("Couldn't locate module symbol table\n");
 244                goto format_error;
 245        }
 246
 247        if (!mvdata->strings) {
 248                printk("Couldn't locate module strings table\n");
 249                goto format_error;
 250        }
 251
 252        /* validate the symbol table */
 253        symstop = mvdata->symbols + mvdata->nsyms;
 254
 255        symbol = mvdata->symbols;
 256        symcheck(ELF_ST_TYPE(symbol[0].st_info) == STT_NOTYPE);
 257        symcheck(symbol[0].st_shndx == SHN_UNDEF);
 258        symcheck(symbol[0].st_value == 0);
 259        symcheck(symbol[0].st_size == 0);
 260
 261        last = -1;
 262        for (symbol++; symbol < symstop; symbol++) {
 263                symcheck(symbol->st_name < sssize);
 264                if (symbol->st_name > last)
 265                        last = symbol->st_name;
 266                symcheck(symbol->st_shndx < mvdata->nsects ||
 267                         symbol->st_shndx >= SHN_LORESERVE);
 268        }
 269
 270        if (last > -1) {
 271                tmp = sssize - last;
 272                elfcheck(memchr(mvdata->strings + last, 0, tmp) != NULL);
 273        }
 274
 275        /* validate each relocation table as best we can */
 276        for (section = mvdata->sections + 1; section < secstop; section++) {
 277                section2 = mvdata->sections + section->sh_info;
 278
 279                switch (section->sh_type) {
 280                case SHT_REL:
 281                        rels = mvdata->buffer + section->sh_offset;
 282                        relstop = mvdata->buffer + section->sh_offset + section->sh_size;
 283
 284                        for (rel = rels; rel < relstop; rel++) {
 285                                relcheck(rel->r_offset < section2->sh_size);
 286                                relcheck(ELF_R_SYM(rel->r_info) < mvdata->nsyms);
 287                        }
 288
 289                        break;
 290
 291                case SHT_RELA:
 292                        relas = mvdata->buffer + section->sh_offset;
 293                        relastop = mvdata->buffer + section->sh_offset + section->sh_size;
 294
 295                        for (rela = relas; rela < relastop; rela++) {
 296                                relacheck(rela->r_offset < section2->sh_size);
 297                                relacheck(ELF_R_SYM(rela->r_info) < mvdata->nsyms);
 298                        }
 299
 300                        break;
 301
 302                default:
 303                        break;
 304                }
 305        }
 306
 307
 308        _debug("ELF okay\n");
 309        return 0;
 310
 311 elfcheck_error:
 312        printk("Verify ELF error (assertion %d)\n", line);
 313        goto format_error;
 314
 315 seccheck_error:
 316        printk("Verify ELF error [sec %ld] (assertion %d)\n",
 317               (long)(section - mvdata->sections), line);
 318        goto format_error;
 319
 320 symcheck_error:
 321        printk("Verify ELF error [sym %ld] (assertion %d)\n",
 322               (long)(symbol - mvdata->symbols), line);
 323        goto format_error;
 324
 325 relcheck_error:
 326        printk("Verify ELF error [sec %ld rel %ld] (assertion %d)\n",
 327               (long)(section - mvdata->sections),
 328               (long)(rel - rels), line);
 329        goto format_error;
 330
 331 relacheck_error:
 332        printk("Verify ELF error [sec %ld rela %ld] (assertion %d)\n",
 333               (long)(section - mvdata->sections),
 334               (long)(rela - relas), line);
 335        goto format_error;
 336
 337 format_error:
 338        return -ELIBBAD;
 339
 340} /* end module_verify_elf() */
 341