Annotation of embedaddon/strongswan/src/libstrongswan/utils/integrity_checker.c, revision 1.1.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>