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>