blob: 7d841448f2462ee976047a64a251896576ac8309 [file] [log] [blame]
Roberto Sassu3ce1217d2013-06-07 12:16:30 +02001/*
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 */
Roberto Sassu4d7aeee72013-06-07 12:16:32 +020015#include <crypto/hash_info.h>
16
Roberto Sassu3ce1217d2013-06-07 12:16:30 +020017#include "ima_template_lib.h"
18
Roberto Sassu4d7aeee72013-06-07 12:16:32 +020019static 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
27enum data_formats {
28 DATA_FMT_DIGEST = 0,
29 DATA_FMT_DIGEST_WITH_ALGO,
30 DATA_FMT_EVENT_NAME,
31 DATA_FMT_STRING
32};
33
Roberto Sassu3ce1217d2013-06-07 12:16:30 +020034static int ima_write_template_field_data(const void *data, const u32 datalen,
35 enum data_formats datafmt,
36 struct ima_field_data *field_data)
37{
38 u8 *buf, *buf_ptr;
39 u32 buflen;
40
41 switch (datafmt) {
42 case DATA_FMT_EVENT_NAME:
43 buflen = IMA_EVENT_NAME_LEN_MAX + 1;
44 break;
45 case DATA_FMT_STRING:
46 buflen = datalen + 1;
47 break;
48 default:
49 buflen = datalen;
50 }
51
52 buf = kzalloc(buflen, GFP_KERNEL);
53 if (!buf)
54 return -ENOMEM;
55
56 memcpy(buf, data, datalen);
57
58 /*
59 * Replace all space characters with underscore for event names and
60 * strings. This avoid that, during the parsing of a measurements list,
61 * filenames with spaces or that end with the suffix ' (deleted)' are
62 * split into multiple template fields (the space is the delimitator
63 * character for measurements lists in ASCII format).
64 */
65 if (datafmt == DATA_FMT_EVENT_NAME || datafmt == DATA_FMT_STRING) {
66 for (buf_ptr = buf; buf_ptr - buf < datalen; buf_ptr++)
67 if (*buf_ptr == ' ')
68 *buf_ptr = '_';
69 }
70
71 field_data->data = buf;
72 field_data->len = buflen;
73 return 0;
74}
75
76static void ima_show_template_data_ascii(struct seq_file *m,
77 enum ima_show_type show,
78 enum data_formats datafmt,
79 struct ima_field_data *field_data)
80{
Roberto Sassu4d7aeee72013-06-07 12:16:32 +020081 u8 *buf_ptr = field_data->data, buflen = field_data->len;
82
Roberto Sassu3ce1217d2013-06-07 12:16:30 +020083 switch (datafmt) {
Roberto Sassu4d7aeee72013-06-07 12:16:32 +020084 case DATA_FMT_DIGEST_WITH_ALGO:
85 buf_ptr = strnchr(field_data->data, buflen, ':');
86 if (buf_ptr != field_data->data)
87 seq_printf(m, "%s", field_data->data);
88
89 /* skip ':' and '\0' */
90 buf_ptr += 2;
91 buflen -= buf_ptr - field_data->data;
Roberto Sassu3ce1217d2013-06-07 12:16:30 +020092 case DATA_FMT_DIGEST:
Roberto Sassu4d7aeee72013-06-07 12:16:32 +020093 ima_print_digest(m, buf_ptr, buflen);
Roberto Sassu3ce1217d2013-06-07 12:16:30 +020094 break;
95 case DATA_FMT_STRING:
Roberto Sassu4d7aeee72013-06-07 12:16:32 +020096 seq_printf(m, "%s", buf_ptr);
Roberto Sassu3ce1217d2013-06-07 12:16:30 +020097 break;
98 default:
99 break;
100 }
101}
102
103static void ima_show_template_data_binary(struct seq_file *m,
104 enum ima_show_type show,
105 enum data_formats datafmt,
106 struct ima_field_data *field_data)
107{
108 ima_putc(m, &field_data->len, sizeof(u32));
109 if (!field_data->len)
110 return;
111 ima_putc(m, field_data->data, field_data->len);
112}
113
114static void ima_show_template_field_data(struct seq_file *m,
115 enum ima_show_type show,
116 enum data_formats datafmt,
117 struct ima_field_data *field_data)
118{
119 switch (show) {
120 case IMA_SHOW_ASCII:
121 ima_show_template_data_ascii(m, show, datafmt, field_data);
122 break;
123 case IMA_SHOW_BINARY:
124 ima_show_template_data_binary(m, show, datafmt, field_data);
125 break;
126 default:
127 break;
128 }
129}
130
131void ima_show_template_digest(struct seq_file *m, enum ima_show_type show,
132 struct ima_field_data *field_data)
133{
134 ima_show_template_field_data(m, show, DATA_FMT_DIGEST, field_data);
135}
136
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200137void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show,
138 struct ima_field_data *field_data)
139{
140 ima_show_template_field_data(m, show, DATA_FMT_DIGEST_WITH_ALGO,
141 field_data);
142}
143
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200144void ima_show_template_string(struct seq_file *m, enum ima_show_type show,
145 struct ima_field_data *field_data)
146{
147 ima_show_template_field_data(m, show, DATA_FMT_STRING, field_data);
148}
149
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200150static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
151 struct ima_field_data *field_data,
152 bool size_limit)
153{
154 /*
155 * digest formats:
156 * - DATA_FMT_DIGEST: digest
157 * - DATA_FMT_DIGEST_WITH_ALGO: [<hash algo>] + ':' + '\0' + digest,
158 * where <hash algo> is provided if the hash algoritm is not
159 * SHA1 or MD5
160 */
161 u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 };
162 enum data_formats fmt = DATA_FMT_DIGEST;
163 u32 offset = 0;
164
165 if (!size_limit) {
166 fmt = DATA_FMT_DIGEST_WITH_ALGO;
167 if (hash_algo < HASH_ALGO__LAST)
168 offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1,
169 "%s", hash_algo_name[hash_algo]);
170 buffer[offset] = ':';
171 offset += 2;
172 }
173
174 if (digest)
175 memcpy(buffer + offset, digest, digestsize);
176 else
177 /*
178 * If digest is NULL, the event being recorded is a violation.
179 * Make room for the digest by increasing the offset of
180 * IMA_DIGEST_SIZE.
181 */
182 offset += IMA_DIGEST_SIZE;
183
184 return ima_write_template_field_data(buffer, offset + digestsize,
185 fmt, field_data);
186}
187
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200188/*
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200189 * This function writes the digest of an event (with size limit).
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200190 */
191int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file,
192 const unsigned char *filename,
193 struct ima_field_data *field_data)
194{
195 struct {
196 struct ima_digest_data hdr;
197 char digest[IMA_MAX_DIGEST_SIZE];
198 } hash;
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200199 u8 *cur_digest = NULL;
200 u32 cur_digestsize = 0;
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200201 struct inode *inode;
202 int result;
203
204 memset(&hash, 0, sizeof(hash));
205
206 if (!iint) /* recording a violation. */
207 goto out;
208
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200209 if (ima_template_hash_algo_allowed(iint->ima_hash->algo)) {
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200210 cur_digest = iint->ima_hash->digest;
211 cur_digestsize = iint->ima_hash->length;
212 goto out;
213 }
214
215 if (!file) /* missing info to re-calculate the digest */
216 return -EINVAL;
217
218 inode = file_inode(file);
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200219 hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ?
220 ima_hash_algo : HASH_ALGO_SHA1;
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200221 result = ima_calc_file_hash(file, &hash.hdr);
222 if (result) {
223 integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
224 filename, "collect_data",
225 "failed", result, 0);
226 return result;
227 }
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200228 cur_digest = hash.hdr.digest;
229 cur_digestsize = hash.hdr.length;
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200230out:
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200231 return ima_eventdigest_init_common(cur_digest, cur_digestsize, -1,
232 field_data, true);
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200233}
234
235/*
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200236 * This function writes the digest of an event (without size limit).
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200237 */
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200238int ima_eventdigest_ng_init(struct integrity_iint_cache *iint,
239 struct file *file, const unsigned char *filename,
240 struct ima_field_data *field_data)
241{
242 u8 *cur_digest = NULL, hash_algo = HASH_ALGO__LAST;
243 u32 cur_digestsize = 0;
244
245 /* If iint is NULL, we are recording a violation. */
246 if (!iint)
247 goto out;
248
249 cur_digest = iint->ima_hash->digest;
250 cur_digestsize = iint->ima_hash->length;
251
252 hash_algo = iint->ima_hash->algo;
253out:
254 return ima_eventdigest_init_common(cur_digest, cur_digestsize,
255 hash_algo, field_data, false);
256}
257
258static int ima_eventname_init_common(struct integrity_iint_cache *iint,
259 struct file *file,
260 const unsigned char *filename,
261 struct ima_field_data *field_data,
262 bool size_limit)
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200263{
264 const char *cur_filename = NULL;
265 u32 cur_filename_len = 0;
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200266 enum data_formats fmt = size_limit ?
267 DATA_FMT_EVENT_NAME : DATA_FMT_STRING;
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200268
269 BUG_ON(filename == NULL && file == NULL);
270
271 if (filename) {
272 cur_filename = filename;
273 cur_filename_len = strlen(filename);
274
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200275 if (!size_limit || cur_filename_len <= IMA_EVENT_NAME_LEN_MAX)
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200276 goto out;
277 }
278
279 if (file) {
280 cur_filename = file->f_dentry->d_name.name;
281 cur_filename_len = strlen(cur_filename);
282 } else
283 /*
284 * Truncate filename if the latter is too long and
285 * the file descriptor is not available.
286 */
287 cur_filename_len = IMA_EVENT_NAME_LEN_MAX;
288out:
289 return ima_write_template_field_data(cur_filename, cur_filename_len,
Roberto Sassu4d7aeee72013-06-07 12:16:32 +0200290 fmt, field_data);
291}
292
293/*
294 * This function writes the name of an event (with size limit).
295 */
296int ima_eventname_init(struct integrity_iint_cache *iint, struct file *file,
297 const unsigned char *filename,
298 struct ima_field_data *field_data)
299{
300 return ima_eventname_init_common(iint, file, filename,
301 field_data, true);
302}
303
304/*
305 * This function writes the name of an event (without size limit).
306 */
307int ima_eventname_ng_init(struct integrity_iint_cache *iint, struct file *file,
308 const unsigned char *filename,
309 struct ima_field_data *field_data)
310{
311 return ima_eventname_init_common(iint, file, filename,
312 field_data, false);
Roberto Sassu3ce1217d2013-06-07 12:16:30 +0200313}