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 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 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 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 352 ima_close(FILE *handle) 353 { 354 fclose((FILE *)handle); 355 356 return 0; 357 } 358 #endif 359