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