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>