2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
18 #include "integrity_checker.h"
27 #include <sys/types.h>
32 typedef struct private_integrity_checker_t private_integrity_checker_t
;
35 * Private data of an integrity_checker_t object.
37 struct private_integrity_checker_t
{
40 * Public integrity_checker_t interface.
42 integrity_checker_t
public;
45 * dlopen handle to checksum library
52 integrity_checksum_t
*checksums
;
55 * number of checksums in array
61 * Implementation of integrity_checker_t.build_file
63 static u_int32_t
build_file(private_integrity_checker_t
*this, char *file
)
71 fd
= open(file
, O_RDONLY
);
74 DBG1("opening '%s' failed: %s", file
, strerror(errno
));
78 if (fstat(fd
, &sb
) == -1)
80 DBG1("getting file size of '%s' failed: %s", file
, strerror(errno
));
85 addr
= mmap(NULL
, sb
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
86 if (addr
== MAP_FAILED
)
88 DBG1("mapping '%s' failed: %s", file
, strerror(errno
));
93 contents
= chunk_create(addr
, sb
.st_size
);
94 checksum
= chunk_hash(contents
);
96 munmap(addr
, sb
.st_size
);
103 * dl_iterate_phdr callback function
105 static int callback(struct dl_phdr_info
*dlpi
, size_t size
, Dl_info
*dli
)
107 if (dli
->dli_fbase
== (void*)dlpi
->dlpi_addr
)
111 for (i
= 0; i
< dlpi
->dlpi_phnum
; i
++)
113 const Elf32_Phdr
*sgmt
= &dlpi
->dlpi_phdr
[i
];
115 /* we are interested in the executable LOAD segment */
116 if (sgmt
->p_type
== PT_LOAD
&&
117 (sgmt
->p_flags
& (PF_X
| PF_R
)))
119 /* safe begin of segment in dli_fbase */
120 dli
->dli_fbase
= (void*)sgmt
->p_vaddr
+ dlpi
->dlpi_addr
;
121 /* safe end of segment in dli_saddr */
122 dli
->dli_saddr
= dli
->dli_fbase
+ sgmt
->p_memsz
;
131 * Implementation of integrity_checker_t.build_segment
133 static u_int32_t
build_segment(private_integrity_checker_t
*this, void *sym
)
138 if (dladdr(sym
, &dli
) == 0)
140 DBG1("unable to locate symbol: %s", strerror(errno
));
143 /* we reuse the Dl_info struct as in/out parameter */
144 if (!dl_iterate_phdr((void*)callback
, &dli
))
146 DBG1("executable section not found");
150 segment
= chunk_create(dli
.dli_fbase
, dli
.dli_saddr
- dli
.dli_fbase
);
151 return chunk_hash(segment
);
155 * Find a checksum by its name
157 static integrity_checksum_t
*find_checksum(private_integrity_checker_t
*this,
162 for (i
= 0; i
< this->checksum_count
; i
++)
164 if (streq(this->checksums
[i
].name
, name
))
166 return &this->checksums
[i
];
169 DBG1("no checksum found for %s", name
);
174 * Implementation of integrity_checker_t.check_file
176 static bool check_file(private_integrity_checker_t
*this,
177 char *name
, char *file
)
179 integrity_checksum_t
*cs
;
182 cs
= find_checksum(this, name
);
187 sum
= build_file(this, file
);
188 if (!sum
|| cs
->file
!= sum
)
190 DBG1("file checksum %s of '%s' invalid (got %08x, expected %08x)",
191 name
, file
, sum
, cs
->file
);
194 DBG2("file checksum %s tested successfully", name
);
199 * Implementation of integrity_checker_t.check_segment
201 static bool check_segment(private_integrity_checker_t
*this,
202 char *name
, void *sym
)
204 integrity_checksum_t
*cs
;
207 cs
= find_checksum(this, name
);
212 sum
= build_segment(this, sym
);
213 if (!sum
|| cs
->segment
!= sum
)
215 DBG1("segment checksum %s invalid (got %08x, expected %08x)",
216 name
, sum
, cs
->segment
);
219 DBG2("segment checksum %s tested successfully", name
);
224 * Implementation of integrity_checker_t.destroy.
226 static void destroy(private_integrity_checker_t
*this)
230 dlclose(this->handle
);
238 integrity_checker_t
*integrity_checker_create(char *checksum_library
)
240 private_integrity_checker_t
*this = malloc_thing(private_integrity_checker_t
);
242 this->public.check_file
= (bool(*)(integrity_checker_t
*, char *name
, char *file
))check_file
;
243 this->public.build_file
= (u_int32_t(*)(integrity_checker_t
*, char *file
))build_file
;
244 this->public.check_segment
= (bool(*)(integrity_checker_t
*, char *name
, void *sym
))check_segment
;
245 this->public.build_segment
= (u_int32_t(*)(integrity_checker_t
*, void *sym
))build_segment
;
246 this->public.destroy
= (void(*)(integrity_checker_t
*))destroy
;
248 this->checksum_count
= 0;
250 if (checksum_library
)
252 this->handle
= dlopen(checksum_library
, RTLD_LAZY
);
257 this->checksums
= dlsym(this->handle
, "checksums");
258 checksum_count
= dlsym(this->handle
, "checksum_count");
259 if (this->checksums
&& checksum_count
)
261 this->checksum_count
= *checksum_count
;
265 DBG1("checksum library '%s' invalid", checksum_library
);
270 DBG1("loading checksum library '%s' failed", checksum_library
);
273 return &this->public;