diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libstrongswan/Makefile.am | 1 | ||||
-rw-r--r-- | src/libstrongswan/integrity_checker.c | 275 | ||||
-rw-r--r-- | src/libstrongswan/integrity_checker.h | 95 |
3 files changed, 371 insertions, 0 deletions
diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 212b9547d..da46b6364 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -15,6 +15,7 @@ debug.c debug.h \ enum.c enum.h \ settings.h settings.c \ printf_hook.c printf_hook.h \ +integrity_checker.c integrity_checker.h \ asn1/asn1.c asn1/asn1.h \ asn1/asn1_parser.c asn1/asn1_parser.h \ asn1/oid.c asn1/oid.h \ diff --git a/src/libstrongswan/integrity_checker.c b/src/libstrongswan/integrity_checker.c new file mode 100644 index 000000000..8f812a77e --- /dev/null +++ b/src/libstrongswan/integrity_checker.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#define _GNU_SOURCE + +#include "integrity_checker.h" + +#include <dlfcn.h> +#include <link.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <debug.h> +#include <library.h> + +#define CHECKSUM_LIBRARY IPSEC_DIR"/libchecksum.so" + +typedef struct private_integrity_checker_t private_integrity_checker_t; + +/** + * Private data of an integrity_checker_t object. + */ +struct private_integrity_checker_t { + + /** + * Public integrity_checker_t interface. + */ + integrity_checker_t public; + + /** + * dlopen handle to checksum library + */ + void *handle; + + /** + * checksum array + */ + integrity_checksum_t *checksums; + + /** + * number of checksums in array + */ + int checksum_count; +}; + +/** + * Implementation of integrity_checker_t.build_file + */ +static u_int32_t build_file(private_integrity_checker_t *this, char *file) +{ + u_int32_t checksum; + chunk_t contents; + struct stat sb; + void *addr; + int fd; + + fd = open(file, O_RDONLY); + if (fd == -1) + { + DBG1("opening '%s' failed: %s", file, strerror(errno)); + return 0; + } + + if (fstat(fd, &sb) == -1) + { + DBG1("getting file size of '%s' failed: %s", file, strerror(errno)); + close(fd); + return 0; + } + + addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) + { + DBG1("mapping '%s' failed: %s", file, strerror(errno)); + close(fd); + return 0; + } + + contents = chunk_create(addr, sb.st_size); + checksum = chunk_hash(contents); + + munmap(addr, sb.st_size); + close(fd); + + return checksum; +} + +/** + * dl_iterate_phdr callback function + */ +static int callback(struct dl_phdr_info *dlpi, size_t size, Dl_info *dli) +{ + if (dli->dli_fbase == (void*)dlpi->dlpi_addr) + { + int i; + + for (i = 0; i < dlpi->dlpi_phnum; i++) + { + const Elf32_Phdr *sgmt = &dlpi->dlpi_phdr[i]; + + /* we are interested in the executable LOAD segment */ + if (sgmt->p_type == PT_LOAD && + (sgmt->p_flags & (PF_X | PF_R))) + { + /* safe begin of segment in dli_fbase */ + dli->dli_fbase = (void*)sgmt->p_vaddr + dlpi->dlpi_addr; + /* safe end of segment in dli_saddr */ + dli->dli_saddr = dli->dli_fbase + sgmt->p_memsz; + return 1; + } + } + } + return 0; +} + +/** + * Implementation of integrity_checker_t.build_segment + */ +static u_int32_t build_segment(private_integrity_checker_t *this, void *sym) +{ + chunk_t segment; + Dl_info dli; + + if (dladdr(sym, &dli) == 0) + { + DBG1("unable to locate symbol: %s", strerror(errno)); + return 0; + } + /* we reuse the Dl_info struct as in/out parameter */ + if (!dl_iterate_phdr((void*)callback, &dli)) + { + DBG1("executable section not found"); + return 0; + } + + segment = chunk_create(dli.dli_fbase, dli.dli_saddr - dli.dli_fbase); + return chunk_hash(segment); +} + +/** + * Find a checksum by its name + */ +static integrity_checksum_t *find_checksum(private_integrity_checker_t *this, + char *name) +{ + int i; + + for (i = 0; i < this->checksum_count; i++) + { + if (streq(this->checksums[i].name, name)) + { + return &this->checksums[i]; + } + } + DBG1("no checksum found for %s", name); + return NULL; +} + +/** + * Implementation of integrity_checker_t.check_file + */ +static bool check_file(private_integrity_checker_t *this, + char *name, char *file) +{ + integrity_checksum_t *cs; + u_int32_t sum; + + cs = find_checksum(this, name); + if (!cs) + { + DBG1("file checksum of %s is %08x", name, build_file(this, file)); + return FALSE; + } + sum = build_file(this, file); + if (!sum || cs->file != sum) + { + DBG1("file checksum %s of '%s' invalid (got %08x, expected %08x)", + name, file, sum, cs->file); + return FALSE; + } + DBG1("file checksum %s of '%s' tested successfully", name, file); + return TRUE; +} + +/** + * Implementation of integrity_checker_t.check_segment + */ +static bool check_segment(private_integrity_checker_t *this, + char *name, void *sym) +{ + integrity_checksum_t *cs; + u_int32_t sum; + + cs = find_checksum(this, name); + if (!cs) + { + DBG1("segment checksum of %s is %08x", name, build_segment(this, sym)); + return FALSE; + } + sum = build_segment(this, sym); + if (!sum || cs->segment != sum) + { + DBG1("segment checksum %s invalid (got %08x, expected %08x)", + name, sum, cs->segment); + return FALSE; + } + DBG1("segment checksum %s tested successfully", name); + return TRUE; +} + +/** + * Implementation of integrity_checker_t.destroy. + */ +static void destroy(private_integrity_checker_t *this) +{ + if (this->handle) + { + dlclose(this->handle); + } + free(this); +} + +/** + * See header + */ +integrity_checker_t *integrity_checker_create() +{ + private_integrity_checker_t *this = malloc_thing(private_integrity_checker_t); + + this->public.check_file = (bool(*)(integrity_checker_t*, char *name, char *file))check_file; + this->public.build_file = (u_int32_t(*)(integrity_checker_t*, char *file))build_file; + this->public.check_segment = (bool(*)(integrity_checker_t*, char *name, void *sym))check_segment; + this->public.build_segment = (u_int32_t(*)(integrity_checker_t*, void *sym))build_segment; + this->public.destroy = (void(*)(integrity_checker_t*))destroy; + + this->checksum_count = 0; + this->handle = dlopen(CHECKSUM_LIBRARY, RTLD_LAZY); + if (this->handle) + { + int *checksum_count; + + this->checksums = dlsym(this->handle, "checksums"); + checksum_count = dlsym(this->handle, "checksum_count"); + if (this->checksums && checksum_count) + { + this->checksum_count = *checksum_count; + } + else + { + DBG1("checksum library '%s' invalid", CHECKSUM_LIBRARY); + } + } + else + { + DBG1("loading checksum library '%s' failed", CHECKSUM_LIBRARY); + } + return &this->public; +} + diff --git a/src/libstrongswan/integrity_checker.h b/src/libstrongswan/integrity_checker.h new file mode 100644 index 000000000..dbad06638 --- /dev/null +++ b/src/libstrongswan/integrity_checker.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup integrity_checker integrity_checker + * @{ @ingroup libstrongswan + */ + +#ifndef INTEGRITY_CHECKER_H_ +#define INTEGRITY_CHECKER_H_ + +#include <utils.h> +#include <plugins/plugin.h> + +typedef struct integrity_checker_t integrity_checker_t; +typedef struct integrity_checksum_t integrity_checksum_t; + +/** + * Struct to hold a precalculated checksum, implemented in the checksum library. + */ +struct integrity_checksum_t { + /* name of the checksum */ + char *name; + /* checksum of the file on disk */ + u_int32_t file; + /* checksum of the executable segment in memory */ + u_int32_t segment; +}; + +/** + * Code integrity checker to detect non-malicious file manipulation. + * + * The integrity checker reads the checksums from a separate library + * libchecksum.so to compare the checksums. + */ +struct integrity_checker_t { + + /** + * Check the integrity of a file on disk. + * + * @param name name to lookup checksum + * @param file path to file + * @return TRUE if integrity tested successfully + */ + bool (*check_file)(integrity_checker_t *this, char *name, char *file); + + /** + * Build the integrity checksum of a file on disk. + * + * @param file path to file + * @return checksum, 0 on error + */ + u_int32_t (*build_file)(integrity_checker_t *this, char *file); + + /** + * Check the integrity of the code segment in memory. + * + * @param name name to lookup checksum + * @param sym a symbol in the segment to check + * @return TRUE if integrity tested successfully + */ + bool (*check_segment)(integrity_checker_t *this, char *name, void *sym); + + /** + * Build the integrity checksum of a code segment in memory. + * + * @param sym a symbol in the segment to check + * @return checksum, 0 on error + */ + u_int32_t (*build_segment)(integrity_checker_t *this, void *sym); + + /** + * Destroy a integrity_checker_t. + */ + void (*destroy)(integrity_checker_t *this); +}; + +/** + * Create a integrity_checker instance. + */ +integrity_checker_t *integrity_checker_create(); + +#endif /* INTEGRITY_CHECKER_H_ @}*/ |