Annotation of embedaddon/strongswan/src/libstrongswan/utils/integrity_checker.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2009 Martin Willi
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #define _GNU_SOURCE
! 17:
! 18: #include "integrity_checker.h"
! 19:
! 20: #include <dlfcn.h>
! 21: #include <link.h>
! 22: #include <fcntl.h>
! 23: #include <errno.h>
! 24: #include <unistd.h>
! 25: #include <sys/stat.h>
! 26: #include <sys/types.h>
! 27:
! 28: #include "debug.h"
! 29: #include "library.h"
! 30:
! 31: typedef struct private_integrity_checker_t private_integrity_checker_t;
! 32:
! 33: /**
! 34: * Private data of an integrity_checker_t object.
! 35: */
! 36: struct private_integrity_checker_t {
! 37:
! 38: /**
! 39: * Public integrity_checker_t interface.
! 40: */
! 41: integrity_checker_t public;
! 42:
! 43: /**
! 44: * dlopen handle to checksum library
! 45: */
! 46: void *handle;
! 47:
! 48: /**
! 49: * checksum array
! 50: */
! 51: integrity_checksum_t *checksums;
! 52:
! 53: /**
! 54: * number of checksums in array
! 55: */
! 56: int checksum_count;
! 57: };
! 58:
! 59: METHOD(integrity_checker_t, build_file, uint32_t,
! 60: private_integrity_checker_t *this, char *file, size_t *len)
! 61: {
! 62: uint32_t checksum;
! 63: chunk_t *contents;
! 64:
! 65: contents = chunk_map(file, FALSE);
! 66: if (!contents)
! 67: {
! 68: DBG1(DBG_LIB, " opening '%s' failed: %s", file, strerror(errno));
! 69: return 0;
! 70: }
! 71: *len = contents->len;
! 72: checksum = chunk_hash_static(*contents);
! 73: chunk_unmap(contents);
! 74:
! 75: return checksum;
! 76: }
! 77:
! 78: /**
! 79: * dl_iterate_phdr callback function
! 80: */
! 81: static int callback(struct dl_phdr_info *dlpi, size_t size, Dl_info *dli)
! 82: {
! 83: /* We are looking for the dlpi_addr matching the address of our dladdr().
! 84: * dl_iterate_phdr() returns such an address for other (unknown) objects
! 85: * in very rare cases (e.g. in a chrooted gentoo, but only if
! 86: * the checksum_builder is invoked by 'make'). As a workaround, we filter
! 87: * objects by dlpi_name; valid objects have a library name.
! 88: */
! 89: if (dli->dli_fbase == (void*)dlpi->dlpi_addr &&
! 90: dlpi->dlpi_name && *dlpi->dlpi_name)
! 91: {
! 92: int i;
! 93:
! 94: for (i = 0; i < dlpi->dlpi_phnum; i++)
! 95: {
! 96: const ElfW(Phdr) *sgmt = &dlpi->dlpi_phdr[i];
! 97:
! 98: /* we are interested in the executable LOAD segment */
! 99: if (sgmt->p_type == PT_LOAD && (sgmt->p_flags & PF_X))
! 100: {
! 101: /* safe begin of segment in dli_fbase */
! 102: dli->dli_fbase = (void*)sgmt->p_vaddr + dlpi->dlpi_addr;
! 103: /* safe end of segment in dli_saddr */
! 104: dli->dli_saddr = dli->dli_fbase + sgmt->p_memsz;
! 105: return 1;
! 106: }
! 107: }
! 108: }
! 109: return 0;
! 110: }
! 111:
! 112: METHOD(integrity_checker_t, build_segment, uint32_t,
! 113: private_integrity_checker_t *this, void *sym, size_t *len)
! 114: {
! 115: chunk_t segment;
! 116: Dl_info dli;
! 117:
! 118: if (dladdr(sym, &dli) == 0)
! 119: {
! 120: DBG1(DBG_LIB, " unable to locate symbol: %s", dlerror());
! 121: return 0;
! 122: }
! 123: /* we reuse the Dl_info struct as in/out parameter */
! 124: if (!dl_iterate_phdr((void*)callback, &dli))
! 125: {
! 126: DBG1(DBG_LIB, " executable section not found");
! 127: return 0;
! 128: }
! 129:
! 130: segment = chunk_create(dli.dli_fbase, dli.dli_saddr - dli.dli_fbase);
! 131: *len = segment.len;
! 132: return chunk_hash_static(segment);
! 133: }
! 134:
! 135: /**
! 136: * Find a checksum by its name
! 137: */
! 138: static integrity_checksum_t *find_checksum(private_integrity_checker_t *this,
! 139: char *name)
! 140: {
! 141: int i;
! 142:
! 143: for (i = 0; i < this->checksum_count; i++)
! 144: {
! 145: if (streq(this->checksums[i].name, name))
! 146: {
! 147: return &this->checksums[i];
! 148: }
! 149: }
! 150: return NULL;
! 151: }
! 152:
! 153: METHOD(integrity_checker_t, check_file, bool,
! 154: private_integrity_checker_t *this, char *name, char *file)
! 155: {
! 156: integrity_checksum_t *cs;
! 157: uint32_t sum;
! 158: size_t len = 0;
! 159:
! 160: cs = find_checksum(this, name);
! 161: if (!cs)
! 162: {
! 163: DBG1(DBG_LIB, " '%s' file checksum not found", name);
! 164: return FALSE;
! 165: }
! 166: sum = build_file(this, file, &len);
! 167: if (!sum)
! 168: {
! 169: return FALSE;
! 170: }
! 171: if (cs->file_len != len)
! 172: {
! 173: DBG1(DBG_LIB, " invalid '%s' file size: %u bytes, expected %u bytes",
! 174: name, len, cs->file_len);
! 175: return FALSE;
! 176: }
! 177: if (cs->file != sum)
! 178: {
! 179: DBG1(DBG_LIB, " invalid '%s' file checksum: %08x, expected %08x",
! 180: name, sum, cs->file);
! 181: return FALSE;
! 182: }
! 183: DBG2(DBG_LIB, " valid '%s' file checksum: %08x", name, sum);
! 184: return TRUE;
! 185: }
! 186:
! 187: METHOD(integrity_checker_t, check_segment, bool,
! 188: private_integrity_checker_t *this, char *name, void *sym)
! 189: {
! 190: integrity_checksum_t *cs;
! 191: uint32_t sum;
! 192: size_t len = 0;
! 193:
! 194: cs = find_checksum(this, name);
! 195: if (!cs)
! 196: {
! 197: DBG1(DBG_LIB, " '%s' segment checksum not found", name);
! 198: return FALSE;
! 199: }
! 200: sum = build_segment(this, sym, &len);
! 201: if (!sum)
! 202: {
! 203: return FALSE;
! 204: }
! 205: if (cs->segment_len != len)
! 206: {
! 207: DBG1(DBG_LIB, " invalid '%s' segment size: %u bytes,"
! 208: " expected %u bytes", name, len, cs->segment_len);
! 209: return FALSE;
! 210: }
! 211: if (cs->segment != sum)
! 212: {
! 213: DBG1(DBG_LIB, " invalid '%s' segment checksum: %08x, expected %08x",
! 214: name, sum, cs->segment);
! 215: return FALSE;
! 216: }
! 217: DBG2(DBG_LIB, " valid '%s' segment checksum: %08x", name, sum);
! 218: return TRUE;
! 219: }
! 220:
! 221: METHOD(integrity_checker_t, check, bool,
! 222: private_integrity_checker_t *this, char *name, void *sym)
! 223: {
! 224: Dl_info dli;
! 225:
! 226: if (dladdr(sym, &dli) == 0)
! 227: {
! 228: DBG1(DBG_LIB, "unable to locate symbol: %s", dlerror());
! 229: return FALSE;
! 230: }
! 231: if (!check_file(this, name, (char*)dli.dli_fname))
! 232: {
! 233: return FALSE;
! 234: }
! 235: if (!check_segment(this, name, sym))
! 236: {
! 237: return FALSE;
! 238: }
! 239: return TRUE;
! 240: }
! 241:
! 242: METHOD(integrity_checker_t, destroy, void,
! 243: private_integrity_checker_t *this)
! 244: {
! 245: if (this->handle)
! 246: {
! 247: dlclose(this->handle);
! 248: }
! 249: free(this);
! 250: }
! 251:
! 252: /**
! 253: * See header
! 254: */
! 255: integrity_checker_t *integrity_checker_create(char *checksum_library)
! 256: {
! 257: private_integrity_checker_t *this;
! 258:
! 259: INIT(this,
! 260: .public = {
! 261: .check_file = _check_file,
! 262: .build_file = _build_file,
! 263: .check_segment = _check_segment,
! 264: .build_segment = _build_segment,
! 265: .check = _check,
! 266: .destroy = _destroy,
! 267: },
! 268: );
! 269:
! 270: if (checksum_library)
! 271: {
! 272: this->handle = dlopen(checksum_library, RTLD_LAZY);
! 273: if (this->handle)
! 274: {
! 275: int *checksum_count;
! 276:
! 277: this->checksums = dlsym(this->handle, "checksums");
! 278: checksum_count = dlsym(this->handle, "checksum_count");
! 279: if (this->checksums && checksum_count)
! 280: {
! 281: this->checksum_count = *checksum_count;
! 282: }
! 283: else
! 284: {
! 285: DBG1(DBG_LIB, "checksum library '%s' invalid",
! 286: checksum_library);
! 287: }
! 288: }
! 289: else
! 290: {
! 291: DBG1(DBG_LIB, "loading checksum library '%s' failed",
! 292: checksum_library);
! 293: }
! 294: }
! 295: return &this->public;
! 296: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>