implemented an integrity checker class to build and check code integrity

This commit is contained in:
Martin Willi
2009-06-22 15:47:16 +02:00
parent 2927db377d
commit 20d4fc97cf
3 changed files with 371 additions and 0 deletions
+1
View File
@@ -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 \
+275
View File
@@ -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;
}
+95
View File
@@ -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_ @}*/