1
2 /*
3 * Licensed Materials - Property of IBM
4 *
5 * trousers - An open source TCG Software Stack
6 *
7 * (C) Copyright International Business Machines Corp. 2004-2006
8 *
9 */
10
11 /*
12 * imaem.c
13 *
14 * Routines for handling PCR events from the Integrity Measurement
15 * Architecture.
16 *
17 * The external event source format used by IMA:
18 *
19 * 4 bytes PCR Index (bin)
20 * 20 bytes SHA1 template (bin)
21 * 4 bytes template name_len
22 * 1-255 bytes template name
23 * 20 bytes SHA1 IMA(bin)
24 * 4 bytes IMA name len
25 * 1-255 bytes eventname
26 * 1 byte separator = '\0'
27 *
28 *
29 */
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <limits.h>
39 #include <unistd.h>
40
41 #include "trousers/tss.h"
42 #include "trousers_types.h"
43 #include "tcs_tsp.h"
44 #include "tcs_utils.h"
45 #include "tcs_int_literals.h"
46 #include "capabilities.h"
47 #include "tcsps.h"
48 #include "tcslog.h"
49 #include "tcsem.h"
50
51 #ifdef EVLOG_SOURCE_IMA
52
53 #define EVLOG_FILENAME_MAXSIZE 255
54
55 struct ext_log_source ima_source = {
56 ima_open,
57 ima_get_entries_by_pcr,
58 ima_get_entry,
59 ima_close
60 };
61
62 int
ima_open(void * source,FILE ** handle)63 ima_open(void *source, FILE **handle)
64 {
65 FILE *fd;
66
67 if ((fd = fopen((char *)source, "r")) == NULL) {
68 LogError("Error opening PCR log file %s: %s",
69 (char *)source, strerror(errno));
70 return -1;
71 }
72
73 *handle = fd;
74 return 0;
75 }
76
77 TSS_RESULT
ima_get_entries_by_pcr(FILE * handle,UINT32 pcr_index,UINT32 first,UINT32 * count,TSS_PCR_EVENT ** events)78 ima_get_entries_by_pcr(FILE *handle, UINT32 pcr_index, UINT32 first,
79 UINT32 *count, TSS_PCR_EVENT **events)
80 {
81 int pcr_value;
82 char page[IMA_READ_SIZE];
83 int error_path = 1, ptr = 0;
84 UINT32 copied_events = 0, i;
85 struct event_wrapper *list, *cur;
86 TSS_RESULT result = TCSERR(TSS_E_INTERNAL_ERROR);
87 FILE *fp = (FILE *) handle;
88 uint len;
89 char name[EVLOG_FILENAME_MAXSIZE];
90
91 if (!fp) {
92 LogError("File handle is NULL!\n");
93 return 1;
94 }
95
96 if (*count == 0)
97 return TSS_SUCCESS;
98
99 list = calloc(1, sizeof(struct event_wrapper));
100 if (list == NULL) {
101 LogError("malloc of %zd bytes failed.", sizeof(struct event_wrapper));
102 return TCSERR(TSS_E_OUTOFMEMORY);
103 }
104 cur = list;
105
106 rewind(fp);
107
108 while (fread(page, 24, 1, fp)) {
109 /* copy the initial 4 bytes (PCR index) XXX endianess ignored */
110 ptr = 0;
111 memcpy(&pcr_value, &page[ptr], sizeof(int));
112 cur->event.ulPcrIndex = pcr_value;
113 ptr += sizeof(int);
114
115 /* grab this entry */
116 cur->event.ulPcrValueLength = 20;
117 cur->event.rgbPcrValue = malloc(cur->event.ulPcrValueLength);
118 if (cur->event.rgbPcrValue == NULL) {
119 LogError("malloc of %d bytes failed.", 20);
120 result = TCSERR(TSS_E_OUTOFMEMORY);
121 goto free_list;
122 }
123
124 /* copy the template SHA1 XXX endianess ignored */
125 memcpy(cur->event.rgbPcrValue, &page[ptr],
126 cur->event.ulPcrValueLength);
127
128 /* Get the template name size, template name */
129 {
130 char digest[20];
131
132 if (fread(&len, 1, sizeof(len), fp) != (sizeof(len))) {
133 LogError("Failed to read event log file");
134 result = TCSERR(TSS_E_INTERNAL_ERROR);
135 goto free_list;
136 }
137 if (len > EVLOG_FILENAME_MAXSIZE) {
138 LogError("Event log file name too big! Max size is %d", EVLOG_FILENAME_MAXSIZE);
139 result = TCSERR(TSS_E_INTERNAL_ERROR);
140 goto free_list;
141 }
142 memset(name, 0, EVLOG_FILENAME_MAXSIZE);
143 if (fread(name, 1, len, fp) != len) {
144 LogError("Failed to read event log file");
145 result = TCSERR(TSS_E_INTERNAL_ERROR);
146 goto free_list;
147 }
148 if (fread(digest, 1, sizeof digest, fp) != (sizeof(digest))) {
149 LogError("Failed to read event log file");
150 result = TCSERR(TSS_E_INTERNAL_ERROR);
151 goto free_list;
152 }
153 }
154 /* Get the template data namelen and data */
155 if (fread(&cur->event.ulEventLength, 1, sizeof(int), fp) != sizeof(int)) {
156 LogError("Failed to read event log file");
157 result = TCSERR(TSS_E_INTERNAL_ERROR);
158 goto free_list;
159 }
160 cur->event.rgbEvent = malloc(cur->event.ulEventLength + 1);
161 if (cur->event.rgbEvent == NULL) {
162 free(cur->event.rgbPcrValue);
163 LogError("malloc of %u bytes failed.",
164 cur->event.ulEventLength);
165 result = TCSERR(TSS_E_OUTOFMEMORY);
166 goto free_list;
167 }
168 memset(cur->event.rgbEvent, 0, cur->event.ulEventLength);
169 if (fread(cur->event.rgbEvent, 1, cur->event.ulEventLength, fp) != cur->event.ulEventLength) {
170 free(cur->event.rgbPcrValue);
171 LogError("Failed to read event log file");
172 result = TCSERR(TSS_E_INTERNAL_ERROR);
173 goto free_list;
174 }
175
176 copied_events++;
177
178 if (copied_events == *count)
179 goto copy_events;
180
181 cur->next = calloc(1, sizeof(struct event_wrapper));
182 if (cur->next == NULL) {
183 LogError("malloc of %zd bytes failed.",
184 sizeof(struct event_wrapper));
185 result = TCSERR(TSS_E_OUTOFMEMORY);
186 goto free_list;
187 }
188 cur = cur->next;
189 }
190
191 copy_events:
192 /* we've copied all the events we need to from this PCR, now
193 * copy them all into one contiguous memory block
194 */
195 *events = calloc(copied_events, sizeof(TSS_PCR_EVENT));
196 if (*events == NULL) {
197 LogError("malloc of %zd bytes failed.", copied_events * sizeof(TSS_PCR_EVENT));
198 result = TCSERR(TSS_E_OUTOFMEMORY);
199 goto free_list;
200 }
201
202 cur = list;
203 for (i = 0; i < copied_events; i++) {
204 memcpy(&((*events)[i]), &(cur->event), sizeof(TSS_PCR_EVENT));
205 cur = cur->next;
206 }
207
208 *count = copied_events;
209 /* assume we're in an error path until we get here */
210 error_path = 0;
211 result = TSS_SUCCESS;
212
213 free_list:
214 cur = list->next;
215 while (cur != NULL) {
216 if (error_path) {
217 free(cur->event.rgbEvent);
218 free(cur->event.rgbPcrValue);
219 }
220 free(list);
221 list = cur;
222 cur = list->next;
223 }
224 free(list);
225 return result;
226 }
227
228 TSS_RESULT
ima_get_entry(FILE * handle,UINT32 pcr_index,UINT32 * num,TSS_PCR_EVENT ** ppEvent)229 ima_get_entry(FILE *handle, UINT32 pcr_index, UINT32 *num, TSS_PCR_EVENT **ppEvent)
230 {
231 int pcr_value, ptr = 0;
232 uint len;
233 char page[IMA_READ_SIZE];
234 UINT32 seen_indices = 0;
235 TSS_RESULT result = TCSERR(TSS_E_INTERNAL_ERROR);
236 TSS_PCR_EVENT *event = NULL;
237 FILE *fp = (FILE *) handle;
238 char name[EVLOG_FILENAME_MAXSIZE];
239
240 rewind(fp);
241 while (fread(page, 24, 1, fp)) {
242 /* copy the initial 4 bytes (PCR index) XXX endianess ignored */
243 ptr = 0;
244 memcpy(&pcr_value, &page[ptr], sizeof(int));
245
246 if (pcr_index == (UINT32)pcr_value) {
247 ptr += sizeof(int);
248 /* This is the case where we're looking for a specific event number in a
249 * specific PCR index. When we've reached the correct event, malloc
250 * space for it, copy it in, then break out of the while loop */
251 if (ppEvent && seen_indices == *num) {
252 /* grab this entry */
253 event = calloc(1, sizeof(TSS_PCR_EVENT));
254 event->ulPcrIndex = pcr_value;
255 event->rgbPcrValue = NULL;
256 event->rgbEvent = NULL;
257 event->ulPcrValueLength = 20;
258 event->rgbPcrValue = malloc(event->ulPcrValueLength);
259 if (event->rgbPcrValue == NULL) {
260 LogError("malloc of %d bytes failed.", 20);
261 free(event);
262 result = TCSERR(TSS_E_OUTOFMEMORY);
263 goto done;
264 }
265
266 /* copy the template SHA1 XXX endianess ignored */
267 memcpy(event->rgbPcrValue, &page[ptr],
268 event->ulPcrValueLength);
269
270 /* Get the template name size, template name */
271 {
272 char digest[20];
273
274 if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) {
275 LogError("Failed to read event log file");
276 result = TCSERR(TSS_E_INTERNAL_ERROR);
277 goto done;
278 }
279 if (len > EVLOG_FILENAME_MAXSIZE) {
280 LogError("Event log file name too big! Max size is %d", EVLOG_FILENAME_MAXSIZE);
281 result = TCSERR(TSS_E_INTERNAL_ERROR);
282 goto done;
283 }
284 memset(name, 0, EVLOG_FILENAME_MAXSIZE);
285 if (fread(name, 1, len, fp) != len) {
286 LogError("Failed to read event log file");
287 result = TCSERR(TSS_E_INTERNAL_ERROR);
288 goto done;
289 }
290 if (fread(digest, 1, sizeof(digest), fp) != sizeof(digest)) {
291 LogError("Failed to read event log file");
292 result = TCSERR(TSS_E_INTERNAL_ERROR);
293 goto done;
294 }
295 }
296 /* Get the template data namelen and data */
297 if (fread(&event->ulEventLength, 1, sizeof(int), fp) != sizeof(int)) {
298 LogError("Failed to read event log file");
299 result = TCSERR(TSS_E_INTERNAL_ERROR);
300 goto done;
301 }
302 event->rgbEvent = malloc(event->ulEventLength + 1);
303 if (event->rgbEvent == NULL) {
304 LogError("malloc of %u bytes failed.",
305 event->ulEventLength);
306 result = TCSERR(TSS_E_OUTOFMEMORY);
307 goto done;
308 }
309 memset(event->rgbEvent, 0, event->ulEventLength + 1);
310 if (fread(event->rgbEvent, 1, event->ulEventLength, fp) != event->ulEventLength ) {
311 LogError("Failed to read event log file");
312 result = TCSERR(TSS_E_INTERNAL_ERROR);
313 goto done;
314 }
315
316 *ppEvent = event;
317 result = TSS_SUCCESS;
318 break;
319 }
320 }
321 if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) {
322 LogError("Failed to read event log file");
323 result = TCSERR(TSS_E_INTERNAL_ERROR);
324 goto done;
325 }
326 fseek(fp, len + 20, SEEK_CUR);
327 if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) {
328 LogError("Failed to read event log file");
329 result = TCSERR(TSS_E_INTERNAL_ERROR);
330 goto done;
331 }
332 fseek(fp, len, SEEK_CUR);
333 seen_indices++;
334 }
335 done:
336 if (result != TSS_SUCCESS) {
337 if (event != NULL) {
338 free(event->rgbPcrValue);
339 free(event->rgbEvent);
340 }
341 free(event);
342 event = NULL;
343 }
344
345 if (ppEvent == NULL)
346 *num = seen_indices;
347
348 return result;
349 }
350
351 int
ima_close(FILE * handle)352 ima_close(FILE *handle)
353 {
354 fclose((FILE *)handle);
355
356 return 0;
357 }
358 #endif
359