1 /* 2 * Copyright (C) 2013 Politecnico di Torino, Italy 3 * TORSEC group -- http://security.polito.it 4 * 5 * Author: Roberto Sassu <roberto.sassu@polito.it> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation, version 2 of the 10 * License. 11 * 12 * File: ima_template_lib.c 13 * Library of supported template fields. 14 */ 15 #include <crypto/hash_info.h> 16 17 #include "ima_template_lib.h" 18 19 static bool ima_template_hash_algo_allowed(u8 algo) 20 { 21 if (algo == HASH_ALGO_SHA1 || algo == HASH_ALGO_MD5) 22 return true; 23 24 return false; 25 } 26 27 enum data_formats { 28 DATA_FMT_DIGEST = 0, 29 DATA_FMT_DIGEST_WITH_ALGO, 30 DATA_FMT_EVENT_NAME, 31 DATA_FMT_STRING, 32 DATA_FMT_HEX 33 }; 34 35 static int ima_write_template_field_data(const void *data, const u32 datalen, 36 enum data_formats datafmt, 37 struct ima_field_data *field_data) 38 { 39 u8 *buf, *buf_ptr; 40 u32 buflen; 41 42 switch (datafmt) { 43 case DATA_FMT_EVENT_NAME: 44 buflen = IMA_EVENT_NAME_LEN_MAX + 1; 45 break; 46 case DATA_FMT_STRING: 47 buflen = datalen + 1; 48 break; 49 default: 50 buflen = datalen; 51 } 52 53 buf = kzalloc(buflen, GFP_KERNEL); 54 if (!buf) 55 return -ENOMEM; 56 57 memcpy(buf, data, datalen); 58 59 /* 60 * Replace all space characters with underscore for event names and 61 * strings. This avoid that, during the parsing of a measurements list, 62 * filenames with spaces or that end with the suffix ' (deleted)' are 63 * split into multiple template fields (the space is the delimitator 64 * character for measurements lists in ASCII format). 65 */ 66 if (datafmt == DATA_FMT_EVENT_NAME || datafmt == DATA_FMT_STRING) { 67 for (buf_ptr = buf; buf_ptr - buf < datalen; buf_ptr++) 68 if (*buf_ptr == ' ') 69 *buf_ptr = '_'; 70 } 71 72 field_data->data = buf; 73 field_data->len = buflen; 74 return 0; 75 } 76 77 static void ima_show_template_data_ascii(struct seq_file *m, 78 enum ima_show_type show, 79 enum data_formats datafmt, 80 struct ima_field_data *field_data) 81 { 82 u8 *buf_ptr = field_data->data, buflen = field_data->len; 83 84 switch (datafmt) { 85 case DATA_FMT_DIGEST_WITH_ALGO: 86 buf_ptr = strnchr(field_data->data, buflen, ':'); 87 if (buf_ptr != field_data->data) 88 seq_printf(m, "%s", field_data->data); 89 90 /* skip ':' and '\0' */ 91 buf_ptr += 2; 92 buflen -= buf_ptr - field_data->data; 93 case DATA_FMT_DIGEST: 94 case DATA_FMT_HEX: 95 if (!buflen) 96 break; 97 ima_print_digest(m, buf_ptr, buflen); 98 break; 99 case DATA_FMT_STRING: 100 seq_printf(m, "%s", buf_ptr); 101 break; 102 default: 103 break; 104 } 105 } 106 107 static void ima_show_template_data_binary(struct seq_file *m, 108 enum ima_show_type show, 109 enum data_formats datafmt, 110 struct ima_field_data *field_data) 111 { 112 if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) 113 ima_putc(m, &field_data->len, sizeof(u32)); 114 115 if (!field_data->len) 116 return; 117 118 ima_putc(m, field_data->data, field_data->len); 119 } 120 121 static void ima_show_template_field_data(struct seq_file *m, 122 enum ima_show_type show, 123 enum data_formats datafmt, 124 struct ima_field_data *field_data) 125 { 126 switch (show) { 127 case IMA_SHOW_ASCII: 128 ima_show_template_data_ascii(m, show, datafmt, field_data); 129 break; 130 case IMA_SHOW_BINARY: 131 case IMA_SHOW_BINARY_NO_FIELD_LEN: 132 ima_show_template_data_binary(m, show, datafmt, field_data); 133 break; 134 default: 135 break; 136 } 137 } 138 139 void ima_show_template_digest(struct seq_file *m, enum ima_show_type show, 140 struct ima_field_data *field_data) 141 { 142 ima_show_template_field_data(m, show, DATA_FMT_DIGEST, field_data); 143 } 144 145 void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show, 146 struct ima_field_data *field_data) 147 { 148 ima_show_template_field_data(m, show, DATA_FMT_DIGEST_WITH_ALGO, 149 field_data); 150 } 151 152 void ima_show_template_string(struct seq_file *m, enum ima_show_type show, 153 struct ima_field_data *field_data) 154 { 155 ima_show_template_field_data(m, show, DATA_FMT_STRING, field_data); 156 } 157 158 void ima_show_template_sig(struct seq_file *m, enum ima_show_type show, 159 struct ima_field_data *field_data) 160 { 161 ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data); 162 } 163 164 static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo, 165 struct ima_field_data *field_data) 166 { 167 /* 168 * digest formats: 169 * - DATA_FMT_DIGEST: digest 170 * - DATA_FMT_DIGEST_WITH_ALGO: [<hash algo>] + ':' + '\0' + digest, 171 * where <hash algo> is provided if the hash algoritm is not 172 * SHA1 or MD5 173 */ 174 u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 }; 175 enum data_formats fmt = DATA_FMT_DIGEST; 176 u32 offset = 0; 177 178 if (hash_algo < HASH_ALGO__LAST) { 179 fmt = DATA_FMT_DIGEST_WITH_ALGO; 180 offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s", 181 hash_algo_name[hash_algo]); 182 buffer[offset] = ':'; 183 offset += 2; 184 } 185 186 if (digest) 187 memcpy(buffer + offset, digest, digestsize); 188 else 189 /* 190 * If digest is NULL, the event being recorded is a violation. 191 * Make room for the digest by increasing the offset of 192 * IMA_DIGEST_SIZE. 193 */ 194 offset += IMA_DIGEST_SIZE; 195 196 return ima_write_template_field_data(buffer, offset + digestsize, 197 fmt, field_data); 198 } 199 200 /* 201 * This function writes the digest of an event (with size limit). 202 */ 203 int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file, 204 const unsigned char *filename, 205 struct evm_ima_xattr_data *xattr_value, int xattr_len, 206 struct ima_field_data *field_data) 207 { 208 struct { 209 struct ima_digest_data hdr; 210 char digest[IMA_MAX_DIGEST_SIZE]; 211 } hash; 212 u8 *cur_digest = NULL; 213 u32 cur_digestsize = 0; 214 struct inode *inode; 215 int result; 216 217 memset(&hash, 0, sizeof(hash)); 218 219 if (!iint) /* recording a violation. */ 220 goto out; 221 222 if (ima_template_hash_algo_allowed(iint->ima_hash->algo)) { 223 cur_digest = iint->ima_hash->digest; 224 cur_digestsize = iint->ima_hash->length; 225 goto out; 226 } 227 228 if (!file) /* missing info to re-calculate the digest */ 229 return -EINVAL; 230 231 inode = file_inode(file); 232 hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ? 233 ima_hash_algo : HASH_ALGO_SHA1; 234 result = ima_calc_file_hash(file, &hash.hdr); 235 if (result) { 236 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, 237 filename, "collect_data", 238 "failed", result, 0); 239 return result; 240 } 241 cur_digest = hash.hdr.digest; 242 cur_digestsize = hash.hdr.length; 243 out: 244 return ima_eventdigest_init_common(cur_digest, cur_digestsize, 245 HASH_ALGO__LAST, field_data); 246 } 247 248 /* 249 * This function writes the digest of an event (without size limit). 250 */ 251 int ima_eventdigest_ng_init(struct integrity_iint_cache *iint, 252 struct file *file, const unsigned char *filename, 253 struct evm_ima_xattr_data *xattr_value, 254 int xattr_len, struct ima_field_data *field_data) 255 { 256 u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1; 257 u32 cur_digestsize = 0; 258 259 /* If iint is NULL, we are recording a violation. */ 260 if (!iint) 261 goto out; 262 263 cur_digest = iint->ima_hash->digest; 264 cur_digestsize = iint->ima_hash->length; 265 266 hash_algo = iint->ima_hash->algo; 267 out: 268 return ima_eventdigest_init_common(cur_digest, cur_digestsize, 269 hash_algo, field_data); 270 } 271 272 static int ima_eventname_init_common(struct integrity_iint_cache *iint, 273 struct file *file, 274 const unsigned char *filename, 275 struct ima_field_data *field_data, 276 bool size_limit) 277 { 278 const char *cur_filename = NULL; 279 u32 cur_filename_len = 0; 280 enum data_formats fmt = size_limit ? 281 DATA_FMT_EVENT_NAME : DATA_FMT_STRING; 282 283 BUG_ON(filename == NULL && file == NULL); 284 285 if (filename) { 286 cur_filename = filename; 287 cur_filename_len = strlen(filename); 288 289 if (!size_limit || cur_filename_len <= IMA_EVENT_NAME_LEN_MAX) 290 goto out; 291 } 292 293 if (file) { 294 cur_filename = file->f_dentry->d_name.name; 295 cur_filename_len = strlen(cur_filename); 296 } else 297 /* 298 * Truncate filename if the latter is too long and 299 * the file descriptor is not available. 300 */ 301 cur_filename_len = IMA_EVENT_NAME_LEN_MAX; 302 out: 303 return ima_write_template_field_data(cur_filename, cur_filename_len, 304 fmt, field_data); 305 } 306 307 /* 308 * This function writes the name of an event (with size limit). 309 */ 310 int ima_eventname_init(struct integrity_iint_cache *iint, struct file *file, 311 const unsigned char *filename, 312 struct evm_ima_xattr_data *xattr_value, int xattr_len, 313 struct ima_field_data *field_data) 314 { 315 return ima_eventname_init_common(iint, file, filename, 316 field_data, true); 317 } 318 319 /* 320 * This function writes the name of an event (without size limit). 321 */ 322 int ima_eventname_ng_init(struct integrity_iint_cache *iint, struct file *file, 323 const unsigned char *filename, 324 struct evm_ima_xattr_data *xattr_value, int xattr_len, 325 struct ima_field_data *field_data) 326 { 327 return ima_eventname_init_common(iint, file, filename, 328 field_data, false); 329 } 330 331 /* 332 * ima_eventsig_init - include the file signature as part of the template data 333 */ 334 int ima_eventsig_init(struct integrity_iint_cache *iint, struct file *file, 335 const unsigned char *filename, 336 struct evm_ima_xattr_data *xattr_value, int xattr_len, 337 struct ima_field_data *field_data) 338 { 339 enum data_formats fmt = DATA_FMT_HEX; 340 int rc = 0; 341 342 if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG)) 343 goto out; 344 345 rc = ima_write_template_field_data(xattr_value, xattr_len, fmt, 346 field_data); 347 out: 348 return rc; 349 } 350