Home | History | Annotate | Line # | Download | only in tcs
      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