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 bool size_limit) 167 { 168 /* 169 * digest formats: 170 * - DATA_FMT_DIGEST: digest 171 * - DATA_FMT_DIGEST_WITH_ALGO: [<hash algo>] + ':' + '\0' + digest, 172 * where <hash algo> is provided if the hash algoritm is not 173 * SHA1 or MD5 174 */ 175 u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 }; 176 enum data_formats fmt = DATA_FMT_DIGEST; 177 u32 offset = 0; 178 179 if (!size_limit) { 180 fmt = DATA_FMT_DIGEST_WITH_ALGO; 181 if (hash_algo < HASH_ALGO__LAST) 182 offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, 183 "%s", hash_algo_name[hash_algo]); 184 buffer[offset] = ':'; 185 offset += 2; 186 } 187 188 if (digest) 189 memcpy(buffer + offset, digest, digestsize); 190 else 191 /* 192 * If digest is NULL, the event being recorded is a violation. 193 * Make room for the digest by increasing the offset of 194 * IMA_DIGEST_SIZE. 195 */ 196 offset += IMA_DIGEST_SIZE; 197 198 return ima_write_template_field_data(buffer, offset + digestsize, 199 fmt, field_data); 200 } 201 202 /* 203 * This function writes the digest of an event (with size limit). 204 */ 205 int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file, 206 const unsigned char *filename, 207 struct evm_ima_xattr_data *xattr_value, int xattr_len, 208 struct ima_field_data *field_data) 209 { 210 struct { 211 struct ima_digest_data hdr; 212 char digest[IMA_MAX_DIGEST_SIZE]; 213 } hash; 214 u8 *cur_digest = NULL; 215 u32 cur_digestsize = 0; 216 struct inode *inode; 217 int result; 218 219 memset(&hash, 0, sizeof(hash)); 220 221 if (!iint) /* recording a violation. */ 222 goto out; 223 224 if (ima_template_hash_algo_allowed(iint->ima_hash->algo)) { 225 cur_digest = iint->ima_hash->digest; 226 cur_digestsize = iint->ima_hash->length; 227 goto out; 228 } 229 230 if (!file) /* missing info to re-calculate the digest */ 231 return -EINVAL; 232 233 inode = file_inode(file); 234 hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ? 235 ima_hash_algo : HASH_ALGO_SHA1; 236 result = ima_calc_file_hash(file, &hash.hdr); 237 if (result) { 238 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, 239 filename, "collect_data", 240 "failed", result, 0); 241 return result; 242 } 243 cur_digest = hash.hdr.digest; 244 cur_digestsize = hash.hdr.length; 245 out: 246 return ima_eventdigest_init_common(cur_digest, cur_digestsize, -1, 247 field_data, true); 248 } 249 250 /* 251 * This function writes the digest of an event (without size limit). 252 */ 253 int ima_eventdigest_ng_init(struct integrity_iint_cache *iint, 254 struct file *file, const unsigned char *filename, 255 struct evm_ima_xattr_data *xattr_value, 256 int xattr_len, struct ima_field_data *field_data) 257 { 258 u8 *cur_digest = NULL, hash_algo = HASH_ALGO__LAST; 259 u32 cur_digestsize = 0; 260 261 /* If iint is NULL, we are recording a violation. */ 262 if (!iint) 263 goto out; 264 265 cur_digest = iint->ima_hash->digest; 266 cur_digestsize = iint->ima_hash->length; 267 268 hash_algo = iint->ima_hash->algo; 269 out: 270 return ima_eventdigest_init_common(cur_digest, cur_digestsize, 271 hash_algo, field_data, false); 272 } 273 274 static int ima_eventname_init_common(struct integrity_iint_cache *iint, 275 struct file *file, 276 const unsigned char *filename, 277 struct ima_field_data *field_data, 278 bool size_limit) 279 { 280 const char *cur_filename = NULL; 281 u32 cur_filename_len = 0; 282 enum data_formats fmt = size_limit ? 283 DATA_FMT_EVENT_NAME : DATA_FMT_STRING; 284 285 BUG_ON(filename == NULL && file == NULL); 286 287 if (filename) { 288 cur_filename = filename; 289 cur_filename_len = strlen(filename); 290 291 if (!size_limit || cur_filename_len <= IMA_EVENT_NAME_LEN_MAX) 292 goto out; 293 } 294 295 if (file) { 296 cur_filename = file->f_dentry->d_name.name; 297 cur_filename_len = strlen(cur_filename); 298 } else 299 /* 300 * Truncate filename if the latter is too long and 301 * the file descriptor is not available. 302 */ 303 cur_filename_len = IMA_EVENT_NAME_LEN_MAX; 304 out: 305 return ima_write_template_field_data(cur_filename, cur_filename_len, 306 fmt, field_data); 307 } 308 309 /* 310 * This function writes the name of an event (with size limit). 311 */ 312 int ima_eventname_init(struct integrity_iint_cache *iint, struct file *file, 313 const unsigned char *filename, 314 struct evm_ima_xattr_data *xattr_value, int xattr_len, 315 struct ima_field_data *field_data) 316 { 317 return ima_eventname_init_common(iint, file, filename, 318 field_data, true); 319 } 320 321 /* 322 * This function writes the name of an event (without size limit). 323 */ 324 int ima_eventname_ng_init(struct integrity_iint_cache *iint, struct file *file, 325 const unsigned char *filename, 326 struct evm_ima_xattr_data *xattr_value, int xattr_len, 327 struct ima_field_data *field_data) 328 { 329 return ima_eventname_init_common(iint, file, filename, 330 field_data, false); 331 } 332 333 /* 334 * ima_eventsig_init - include the file signature as part of the template data 335 */ 336 int ima_eventsig_init(struct integrity_iint_cache *iint, struct file *file, 337 const unsigned char *filename, 338 struct evm_ima_xattr_data *xattr_value, int xattr_len, 339 struct ima_field_data *field_data) 340 { 341 enum data_formats fmt = DATA_FMT_HEX; 342 int rc = 0; 343 344 if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG)) 345 goto out; 346 347 rc = ima_write_template_field_data(xattr_value, xattr_len, fmt, 348 field_data); 349 out: 350 return rc; 351 } 352