1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23ce1217dSRoberto Sassu /*
33ce1217dSRoberto Sassu * Copyright (C) 2013 Politecnico di Torino, Italy
4c9fecf50SAlexander A. Klimov * TORSEC group -- https://security.polito.it
53ce1217dSRoberto Sassu *
63ce1217dSRoberto Sassu * Author: Roberto Sassu <roberto.sassu@polito.it>
73ce1217dSRoberto Sassu *
83ce1217dSRoberto Sassu * File: ima_template_lib.c
93ce1217dSRoberto Sassu * Library of supported template fields.
103ce1217dSRoberto Sassu */
114d7aeee7SRoberto Sassu
123ce1217dSRoberto Sassu #include "ima_template_lib.h"
13026d7fc9SRoberto Sassu #include <linux/xattr.h>
148314b673SRoberto Sassu #include <linux/evm.h>
153ce1217dSRoberto Sassu
ima_template_hash_algo_allowed(u8 algo)164d7aeee7SRoberto Sassu static bool ima_template_hash_algo_allowed(u8 algo)
174d7aeee7SRoberto Sassu {
184d7aeee7SRoberto Sassu if (algo == HASH_ALGO_SHA1 || algo == HASH_ALGO_MD5)
194d7aeee7SRoberto Sassu return true;
204d7aeee7SRoberto Sassu
214d7aeee7SRoberto Sassu return false;
224d7aeee7SRoberto Sassu }
234d7aeee7SRoberto Sassu
244d7aeee7SRoberto Sassu enum data_formats {
254d7aeee7SRoberto Sassu DATA_FMT_DIGEST = 0,
264d7aeee7SRoberto Sassu DATA_FMT_DIGEST_WITH_ALGO,
27989dc725SMimi Zohar DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO,
28bcbc9b0cSMimi Zohar DATA_FMT_STRING,
29cde1391aSRoberto Sassu DATA_FMT_HEX,
30cde1391aSRoberto Sassu DATA_FMT_UINT
314d7aeee7SRoberto Sassu };
324d7aeee7SRoberto Sassu
33989dc725SMimi Zohar enum digest_type {
34989dc725SMimi Zohar DIGEST_TYPE_IMA,
3554f03916SMimi Zohar DIGEST_TYPE_VERITY,
36989dc725SMimi Zohar DIGEST_TYPE__LAST
37989dc725SMimi Zohar };
38989dc725SMimi Zohar
3954f03916SMimi Zohar #define DIGEST_TYPE_NAME_LEN_MAX 7 /* including NUL */
40989dc725SMimi Zohar static const char * const digest_type_name[DIGEST_TYPE__LAST] = {
4154f03916SMimi Zohar [DIGEST_TYPE_IMA] = "ima",
4254f03916SMimi Zohar [DIGEST_TYPE_VERITY] = "verity"
43989dc725SMimi Zohar };
44989dc725SMimi Zohar
ima_write_template_field_data(const void * data,const u32 datalen,enum data_formats datafmt,struct ima_field_data * field_data)453ce1217dSRoberto Sassu static int ima_write_template_field_data(const void *data, const u32 datalen,
463ce1217dSRoberto Sassu enum data_formats datafmt,
473ce1217dSRoberto Sassu struct ima_field_data *field_data)
483ce1217dSRoberto Sassu {
493ce1217dSRoberto Sassu u8 *buf, *buf_ptr;
50e3b64c26SRoberto Sassu u32 buflen = datalen;
513ce1217dSRoberto Sassu
52e3b64c26SRoberto Sassu if (datafmt == DATA_FMT_STRING)
533ce1217dSRoberto Sassu buflen = datalen + 1;
543ce1217dSRoberto Sassu
553ce1217dSRoberto Sassu buf = kzalloc(buflen, GFP_KERNEL);
563ce1217dSRoberto Sassu if (!buf)
573ce1217dSRoberto Sassu return -ENOMEM;
583ce1217dSRoberto Sassu
593ce1217dSRoberto Sassu memcpy(buf, data, datalen);
603ce1217dSRoberto Sassu
613ce1217dSRoberto Sassu /*
623ce1217dSRoberto Sassu * Replace all space characters with underscore for event names and
633ce1217dSRoberto Sassu * strings. This avoid that, during the parsing of a measurements list,
643ce1217dSRoberto Sassu * filenames with spaces or that end with the suffix ' (deleted)' are
653ce1217dSRoberto Sassu * split into multiple template fields (the space is the delimitator
663ce1217dSRoberto Sassu * character for measurements lists in ASCII format).
673ce1217dSRoberto Sassu */
68e3b64c26SRoberto Sassu if (datafmt == DATA_FMT_STRING) {
693ce1217dSRoberto Sassu for (buf_ptr = buf; buf_ptr - buf < datalen; buf_ptr++)
703ce1217dSRoberto Sassu if (*buf_ptr == ' ')
713ce1217dSRoberto Sassu *buf_ptr = '_';
723ce1217dSRoberto Sassu }
733ce1217dSRoberto Sassu
743ce1217dSRoberto Sassu field_data->data = buf;
753ce1217dSRoberto Sassu field_data->len = buflen;
763ce1217dSRoberto Sassu return 0;
773ce1217dSRoberto Sassu }
783ce1217dSRoberto Sassu
ima_show_template_data_ascii(struct seq_file * m,enum ima_show_type show,enum data_formats datafmt,struct ima_field_data * field_data)793ce1217dSRoberto Sassu static void ima_show_template_data_ascii(struct seq_file *m,
803ce1217dSRoberto Sassu enum ima_show_type show,
813ce1217dSRoberto Sassu enum data_formats datafmt,
823ce1217dSRoberto Sassu struct ima_field_data *field_data)
833ce1217dSRoberto Sassu {
8445b26133SMimi Zohar u8 *buf_ptr = field_data->data;
8545b26133SMimi Zohar u32 buflen = field_data->len;
864d7aeee7SRoberto Sassu
873ce1217dSRoberto Sassu switch (datafmt) {
88989dc725SMimi Zohar case DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO:
894d7aeee7SRoberto Sassu case DATA_FMT_DIGEST_WITH_ALGO:
90989dc725SMimi Zohar buf_ptr = strrchr(field_data->data, ':');
914d7aeee7SRoberto Sassu if (buf_ptr != field_data->data)
924d7aeee7SRoberto Sassu seq_printf(m, "%s", field_data->data);
934d7aeee7SRoberto Sassu
944d7aeee7SRoberto Sassu /* skip ':' and '\0' */
954d7aeee7SRoberto Sassu buf_ptr += 2;
964d7aeee7SRoberto Sassu buflen -= buf_ptr - field_data->data;
97df561f66SGustavo A. R. Silva fallthrough;
983ce1217dSRoberto Sassu case DATA_FMT_DIGEST:
99bcbc9b0cSMimi Zohar case DATA_FMT_HEX:
100bcbc9b0cSMimi Zohar if (!buflen)
101bcbc9b0cSMimi Zohar break;
1024d7aeee7SRoberto Sassu ima_print_digest(m, buf_ptr, buflen);
1033ce1217dSRoberto Sassu break;
1043ce1217dSRoberto Sassu case DATA_FMT_STRING:
1054d7aeee7SRoberto Sassu seq_printf(m, "%s", buf_ptr);
1063ce1217dSRoberto Sassu break;
107cde1391aSRoberto Sassu case DATA_FMT_UINT:
108cde1391aSRoberto Sassu switch (field_data->len) {
109cde1391aSRoberto Sassu case sizeof(u8):
110cde1391aSRoberto Sassu seq_printf(m, "%u", *(u8 *)buf_ptr);
111cde1391aSRoberto Sassu break;
112cde1391aSRoberto Sassu case sizeof(u16):
113cde1391aSRoberto Sassu if (ima_canonical_fmt)
114cde1391aSRoberto Sassu seq_printf(m, "%u",
11524c9ae23SRoberto Sassu le16_to_cpu(*(__le16 *)buf_ptr));
116cde1391aSRoberto Sassu else
117cde1391aSRoberto Sassu seq_printf(m, "%u", *(u16 *)buf_ptr);
118cde1391aSRoberto Sassu break;
119cde1391aSRoberto Sassu case sizeof(u32):
120cde1391aSRoberto Sassu if (ima_canonical_fmt)
121cde1391aSRoberto Sassu seq_printf(m, "%u",
12224c9ae23SRoberto Sassu le32_to_cpu(*(__le32 *)buf_ptr));
123cde1391aSRoberto Sassu else
124cde1391aSRoberto Sassu seq_printf(m, "%u", *(u32 *)buf_ptr);
125cde1391aSRoberto Sassu break;
126cde1391aSRoberto Sassu case sizeof(u64):
127cde1391aSRoberto Sassu if (ima_canonical_fmt)
128cde1391aSRoberto Sassu seq_printf(m, "%llu",
12924c9ae23SRoberto Sassu le64_to_cpu(*(__le64 *)buf_ptr));
130cde1391aSRoberto Sassu else
131cde1391aSRoberto Sassu seq_printf(m, "%llu", *(u64 *)buf_ptr);
132cde1391aSRoberto Sassu break;
133cde1391aSRoberto Sassu default:
134cde1391aSRoberto Sassu break;
135cde1391aSRoberto Sassu }
1367d2201d4SGustavo A. R. Silva break;
1373ce1217dSRoberto Sassu default:
1383ce1217dSRoberto Sassu break;
1393ce1217dSRoberto Sassu }
1403ce1217dSRoberto Sassu }
1413ce1217dSRoberto Sassu
ima_show_template_data_binary(struct seq_file * m,enum ima_show_type show,enum data_formats datafmt,struct ima_field_data * field_data)1423ce1217dSRoberto Sassu static void ima_show_template_data_binary(struct seq_file *m,
1433ce1217dSRoberto Sassu enum ima_show_type show,
1443ce1217dSRoberto Sassu enum data_formats datafmt,
1453ce1217dSRoberto Sassu struct ima_field_data *field_data)
1463ce1217dSRoberto Sassu {
147c019e307SRoberto Sassu u32 len = (show == IMA_SHOW_BINARY_OLD_STRING_FMT) ?
148c019e307SRoberto Sassu strlen(field_data->data) : field_data->len;
1493e8e5503SRoberto Sassu
150d68a6fe9SMimi Zohar if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) {
1516b26285fSRoberto Sassu u32 field_len = !ima_canonical_fmt ?
1526b26285fSRoberto Sassu len : (__force u32)cpu_to_le32(len);
153d68a6fe9SMimi Zohar
154d68a6fe9SMimi Zohar ima_putc(m, &field_len, sizeof(field_len));
155d68a6fe9SMimi Zohar }
156c019e307SRoberto Sassu
157c019e307SRoberto Sassu if (!len)
1583ce1217dSRoberto Sassu return;
1593e8e5503SRoberto Sassu
160c019e307SRoberto Sassu ima_putc(m, field_data->data, len);
1613ce1217dSRoberto Sassu }
1623ce1217dSRoberto Sassu
ima_show_template_field_data(struct seq_file * m,enum ima_show_type show,enum data_formats datafmt,struct ima_field_data * field_data)1633ce1217dSRoberto Sassu static void ima_show_template_field_data(struct seq_file *m,
1643ce1217dSRoberto Sassu enum ima_show_type show,
1653ce1217dSRoberto Sassu enum data_formats datafmt,
1663ce1217dSRoberto Sassu struct ima_field_data *field_data)
1673ce1217dSRoberto Sassu {
1683ce1217dSRoberto Sassu switch (show) {
1693ce1217dSRoberto Sassu case IMA_SHOW_ASCII:
1703ce1217dSRoberto Sassu ima_show_template_data_ascii(m, show, datafmt, field_data);
1713ce1217dSRoberto Sassu break;
1723ce1217dSRoberto Sassu case IMA_SHOW_BINARY:
1733e8e5503SRoberto Sassu case IMA_SHOW_BINARY_NO_FIELD_LEN:
174c019e307SRoberto Sassu case IMA_SHOW_BINARY_OLD_STRING_FMT:
1753ce1217dSRoberto Sassu ima_show_template_data_binary(m, show, datafmt, field_data);
1763ce1217dSRoberto Sassu break;
1773ce1217dSRoberto Sassu default:
1783ce1217dSRoberto Sassu break;
1793ce1217dSRoberto Sassu }
1803ce1217dSRoberto Sassu }
1813ce1217dSRoberto Sassu
ima_show_template_digest(struct seq_file * m,enum ima_show_type show,struct ima_field_data * field_data)1823ce1217dSRoberto Sassu void ima_show_template_digest(struct seq_file *m, enum ima_show_type show,
1833ce1217dSRoberto Sassu struct ima_field_data *field_data)
1843ce1217dSRoberto Sassu {
1853ce1217dSRoberto Sassu ima_show_template_field_data(m, show, DATA_FMT_DIGEST, field_data);
1863ce1217dSRoberto Sassu }
1873ce1217dSRoberto Sassu
ima_show_template_digest_ng(struct seq_file * m,enum ima_show_type show,struct ima_field_data * field_data)1884d7aeee7SRoberto Sassu void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show,
1894d7aeee7SRoberto Sassu struct ima_field_data *field_data)
1904d7aeee7SRoberto Sassu {
1914d7aeee7SRoberto Sassu ima_show_template_field_data(m, show, DATA_FMT_DIGEST_WITH_ALGO,
1924d7aeee7SRoberto Sassu field_data);
1934d7aeee7SRoberto Sassu }
1944d7aeee7SRoberto Sassu
ima_show_template_digest_ngv2(struct seq_file * m,enum ima_show_type show,struct ima_field_data * field_data)195989dc725SMimi Zohar void ima_show_template_digest_ngv2(struct seq_file *m, enum ima_show_type show,
196989dc725SMimi Zohar struct ima_field_data *field_data)
197989dc725SMimi Zohar {
198989dc725SMimi Zohar ima_show_template_field_data(m, show,
199989dc725SMimi Zohar DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO,
200989dc725SMimi Zohar field_data);
201989dc725SMimi Zohar }
202989dc725SMimi Zohar
ima_show_template_string(struct seq_file * m,enum ima_show_type show,struct ima_field_data * field_data)2033ce1217dSRoberto Sassu void ima_show_template_string(struct seq_file *m, enum ima_show_type show,
2043ce1217dSRoberto Sassu struct ima_field_data *field_data)
2053ce1217dSRoberto Sassu {
2063ce1217dSRoberto Sassu ima_show_template_field_data(m, show, DATA_FMT_STRING, field_data);
2073ce1217dSRoberto Sassu }
2083ce1217dSRoberto Sassu
ima_show_template_sig(struct seq_file * m,enum ima_show_type show,struct ima_field_data * field_data)209bcbc9b0cSMimi Zohar void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
210bcbc9b0cSMimi Zohar struct ima_field_data *field_data)
211bcbc9b0cSMimi Zohar {
212bcbc9b0cSMimi Zohar ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
213bcbc9b0cSMimi Zohar }
214bcbc9b0cSMimi Zohar
ima_show_template_buf(struct seq_file * m,enum ima_show_type show,struct ima_field_data * field_data)21586b4da8cSPrakhar Srivastava void ima_show_template_buf(struct seq_file *m, enum ima_show_type show,
21686b4da8cSPrakhar Srivastava struct ima_field_data *field_data)
21786b4da8cSPrakhar Srivastava {
21886b4da8cSPrakhar Srivastava ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
21986b4da8cSPrakhar Srivastava }
22086b4da8cSPrakhar Srivastava
ima_show_template_uint(struct seq_file * m,enum ima_show_type show,struct ima_field_data * field_data)221cde1391aSRoberto Sassu void ima_show_template_uint(struct seq_file *m, enum ima_show_type show,
222cde1391aSRoberto Sassu struct ima_field_data *field_data)
223cde1391aSRoberto Sassu {
224cde1391aSRoberto Sassu ima_show_template_field_data(m, show, DATA_FMT_UINT, field_data);
225cde1391aSRoberto Sassu }
226cde1391aSRoberto Sassu
227b17fd9ecSRoberto Sassu /**
228b17fd9ecSRoberto Sassu * ima_parse_buf() - Parses lengths and data from an input buffer
229b17fd9ecSRoberto Sassu * @bufstartp: Buffer start address.
230b17fd9ecSRoberto Sassu * @bufendp: Buffer end address.
231b17fd9ecSRoberto Sassu * @bufcurp: Pointer to remaining (non-parsed) data.
232b17fd9ecSRoberto Sassu * @maxfields: Length of fields array.
233b17fd9ecSRoberto Sassu * @fields: Array containing lengths and pointers of parsed data.
234b17fd9ecSRoberto Sassu * @curfields: Number of array items containing parsed data.
235b17fd9ecSRoberto Sassu * @len_mask: Bitmap (if bit is set, data length should not be parsed).
236b17fd9ecSRoberto Sassu * @enforce_mask: Check if curfields == maxfields and/or bufcurp == bufendp.
237b17fd9ecSRoberto Sassu * @bufname: String identifier of the input buffer.
238b17fd9ecSRoberto Sassu *
239b17fd9ecSRoberto Sassu * Return: 0 on success, -EINVAL on error.
240b17fd9ecSRoberto Sassu */
ima_parse_buf(void * bufstartp,void * bufendp,void ** bufcurp,int maxfields,struct ima_field_data * fields,int * curfields,unsigned long * len_mask,int enforce_mask,char * bufname)241b17fd9ecSRoberto Sassu int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
242b17fd9ecSRoberto Sassu int maxfields, struct ima_field_data *fields, int *curfields,
243b17fd9ecSRoberto Sassu unsigned long *len_mask, int enforce_mask, char *bufname)
244b17fd9ecSRoberto Sassu {
245b17fd9ecSRoberto Sassu void *bufp = bufstartp;
246b17fd9ecSRoberto Sassu int i;
247b17fd9ecSRoberto Sassu
248b17fd9ecSRoberto Sassu for (i = 0; i < maxfields; i++) {
249b17fd9ecSRoberto Sassu if (len_mask == NULL || !test_bit(i, len_mask)) {
250b17fd9ecSRoberto Sassu if (bufp > (bufendp - sizeof(u32)))
251b17fd9ecSRoberto Sassu break;
252b17fd9ecSRoberto Sassu
253b17fd9ecSRoberto Sassu if (ima_canonical_fmt)
25424c9ae23SRoberto Sassu fields[i].len = le32_to_cpu(*(__le32 *)bufp);
25524c9ae23SRoberto Sassu else
25624c9ae23SRoberto Sassu fields[i].len = *(u32 *)bufp;
257b17fd9ecSRoberto Sassu
258b17fd9ecSRoberto Sassu bufp += sizeof(u32);
259b17fd9ecSRoberto Sassu }
260b17fd9ecSRoberto Sassu
261b17fd9ecSRoberto Sassu if (bufp > (bufendp - fields[i].len))
262b17fd9ecSRoberto Sassu break;
263b17fd9ecSRoberto Sassu
264b17fd9ecSRoberto Sassu fields[i].data = bufp;
265b17fd9ecSRoberto Sassu bufp += fields[i].len;
266b17fd9ecSRoberto Sassu }
267b17fd9ecSRoberto Sassu
268b17fd9ecSRoberto Sassu if ((enforce_mask & ENFORCE_FIELDS) && i != maxfields) {
269b17fd9ecSRoberto Sassu pr_err("%s: nr of fields mismatch: expected: %d, current: %d\n",
270b17fd9ecSRoberto Sassu bufname, maxfields, i);
271b17fd9ecSRoberto Sassu return -EINVAL;
272b17fd9ecSRoberto Sassu }
273b17fd9ecSRoberto Sassu
274b17fd9ecSRoberto Sassu if ((enforce_mask & ENFORCE_BUFEND) && bufp != bufendp) {
275b17fd9ecSRoberto Sassu pr_err("%s: buf end mismatch: expected: %p, current: %p\n",
276b17fd9ecSRoberto Sassu bufname, bufendp, bufp);
277b17fd9ecSRoberto Sassu return -EINVAL;
278b17fd9ecSRoberto Sassu }
279b17fd9ecSRoberto Sassu
280b17fd9ecSRoberto Sassu if (curfields)
281b17fd9ecSRoberto Sassu *curfields = i;
282b17fd9ecSRoberto Sassu
283b17fd9ecSRoberto Sassu if (bufcurp)
284b17fd9ecSRoberto Sassu *bufcurp = bufp;
285b17fd9ecSRoberto Sassu
286b17fd9ecSRoberto Sassu return 0;
287b17fd9ecSRoberto Sassu }
288b17fd9ecSRoberto Sassu
ima_eventdigest_init_common(const u8 * digest,u32 digestsize,u8 digest_type,u8 hash_algo,struct ima_field_data * field_data)2893878d505SThiago Jung Bauermann static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
290989dc725SMimi Zohar u8 digest_type, u8 hash_algo,
291dcf4e392SRoberto Sassu struct ima_field_data *field_data)
2924d7aeee7SRoberto Sassu {
2933ce1217dSRoberto Sassu /*
2944d7aeee7SRoberto Sassu * digest formats:
2954d7aeee7SRoberto Sassu * - DATA_FMT_DIGEST: digest
29664466462SMimi Zohar * - DATA_FMT_DIGEST_WITH_ALGO: <hash algo> + ':' + '\0' + digest,
297989dc725SMimi Zohar * - DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO:
298989dc725SMimi Zohar * <digest type> + ':' + <hash algo> + ':' + '\0' + digest,
29964466462SMimi Zohar *
30064466462SMimi Zohar * where 'DATA_FMT_DIGEST' is the original digest format ('d')
30164466462SMimi Zohar * with a hash size limitation of 20 bytes,
30254f03916SMimi Zohar * where <digest type> is either "ima" or "verity",
30364466462SMimi Zohar * where <hash algo> is the hash_algo_name[] string.
3044d7aeee7SRoberto Sassu */
305989dc725SMimi Zohar u8 buffer[DIGEST_TYPE_NAME_LEN_MAX + CRYPTO_MAX_ALG_NAME + 2 +
306989dc725SMimi Zohar IMA_MAX_DIGEST_SIZE] = { 0 };
3074d7aeee7SRoberto Sassu enum data_formats fmt = DATA_FMT_DIGEST;
3084d7aeee7SRoberto Sassu u32 offset = 0;
3094d7aeee7SRoberto Sassu
310989dc725SMimi Zohar if (digest_type < DIGEST_TYPE__LAST && hash_algo < HASH_ALGO__LAST) {
311989dc725SMimi Zohar fmt = DATA_FMT_DIGEST_WITH_TYPE_AND_ALGO;
312989dc725SMimi Zohar offset += 1 + sprintf(buffer, "%s:%s:",
313989dc725SMimi Zohar digest_type_name[digest_type],
314dcf4e392SRoberto Sassu hash_algo_name[hash_algo]);
315989dc725SMimi Zohar } else if (hash_algo < HASH_ALGO__LAST) {
316989dc725SMimi Zohar fmt = DATA_FMT_DIGEST_WITH_ALGO;
317989dc725SMimi Zohar offset += 1 + sprintf(buffer, "%s:",
318989dc725SMimi Zohar hash_algo_name[hash_algo]);
3194d7aeee7SRoberto Sassu }
3204d7aeee7SRoberto Sassu
3214d7aeee7SRoberto Sassu if (digest)
3224d7aeee7SRoberto Sassu memcpy(buffer + offset, digest, digestsize);
3234d7aeee7SRoberto Sassu else
3244d7aeee7SRoberto Sassu /*
3254d7aeee7SRoberto Sassu * If digest is NULL, the event being recorded is a violation.
3269fab303aSMimi Zohar * Make room for the digest by increasing the offset by the
3279fab303aSMimi Zohar * hash algorithm digest size.
3284d7aeee7SRoberto Sassu */
3299fab303aSMimi Zohar offset += hash_digest_size[hash_algo];
3304d7aeee7SRoberto Sassu
3314d7aeee7SRoberto Sassu return ima_write_template_field_data(buffer, offset + digestsize,
3324d7aeee7SRoberto Sassu fmt, field_data);
3334d7aeee7SRoberto Sassu }
3344d7aeee7SRoberto Sassu
3354d7aeee7SRoberto Sassu /*
3364d7aeee7SRoberto Sassu * This function writes the digest of an event (with size limit).
3373ce1217dSRoberto Sassu */
ima_eventdigest_init(struct ima_event_data * event_data,struct ima_field_data * field_data)33823b57419SRoberto Sassu int ima_eventdigest_init(struct ima_event_data *event_data,
3393ce1217dSRoberto Sassu struct ima_field_data *field_data)
3403ce1217dSRoberto Sassu {
3418c54135eSMimi Zohar struct ima_max_digest_data hash;
342*38aa3f5aSGustavo A. R. Silva struct ima_digest_data *hash_hdr = container_of(&hash.hdr,
343*38aa3f5aSGustavo A. R. Silva struct ima_digest_data, hdr);
3444d7aeee7SRoberto Sassu u8 *cur_digest = NULL;
3454d7aeee7SRoberto Sassu u32 cur_digestsize = 0;
3463ce1217dSRoberto Sassu struct inode *inode;
3473ce1217dSRoberto Sassu int result;
3483ce1217dSRoberto Sassu
3493ce1217dSRoberto Sassu memset(&hash, 0, sizeof(hash));
3503ce1217dSRoberto Sassu
3518d94eb9bSRoberto Sassu if (event_data->violation) /* recording a violation. */
3523ce1217dSRoberto Sassu goto out;
3533ce1217dSRoberto Sassu
35423b57419SRoberto Sassu if (ima_template_hash_algo_allowed(event_data->iint->ima_hash->algo)) {
35523b57419SRoberto Sassu cur_digest = event_data->iint->ima_hash->digest;
35623b57419SRoberto Sassu cur_digestsize = event_data->iint->ima_hash->length;
3573ce1217dSRoberto Sassu goto out;
3583ce1217dSRoberto Sassu }
3593ce1217dSRoberto Sassu
3606cc7c266SRoberto Sassu if ((const char *)event_data->filename == boot_aggregate_name) {
3616cc7c266SRoberto Sassu if (ima_tpm_chip) {
3626cc7c266SRoberto Sassu hash.hdr.algo = HASH_ALGO_SHA1;
363*38aa3f5aSGustavo A. R. Silva result = ima_calc_boot_aggregate(hash_hdr);
3646cc7c266SRoberto Sassu
3656cc7c266SRoberto Sassu /* algo can change depending on available PCR banks */
3666cc7c266SRoberto Sassu if (!result && hash.hdr.algo != HASH_ALGO_SHA1)
3676cc7c266SRoberto Sassu result = -EINVAL;
3686cc7c266SRoberto Sassu
3696cc7c266SRoberto Sassu if (result < 0)
3706cc7c266SRoberto Sassu memset(&hash, 0, sizeof(hash));
3716cc7c266SRoberto Sassu }
3726cc7c266SRoberto Sassu
373*38aa3f5aSGustavo A. R. Silva cur_digest = hash_hdr->digest;
3746cc7c266SRoberto Sassu cur_digestsize = hash_digest_size[HASH_ALGO_SHA1];
3756cc7c266SRoberto Sassu goto out;
3766cc7c266SRoberto Sassu }
3776cc7c266SRoberto Sassu
37823b57419SRoberto Sassu if (!event_data->file) /* missing info to re-calculate the digest */
3793ce1217dSRoberto Sassu return -EINVAL;
3803ce1217dSRoberto Sassu
38123b57419SRoberto Sassu inode = file_inode(event_data->file);
3824d7aeee7SRoberto Sassu hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ?
3834d7aeee7SRoberto Sassu ima_hash_algo : HASH_ALGO_SHA1;
384*38aa3f5aSGustavo A. R. Silva result = ima_calc_file_hash(event_data->file, hash_hdr);
3853ce1217dSRoberto Sassu if (result) {
3863ce1217dSRoberto Sassu integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
38723b57419SRoberto Sassu event_data->filename, "collect_data",
3883ce1217dSRoberto Sassu "failed", result, 0);
3893ce1217dSRoberto Sassu return result;
3903ce1217dSRoberto Sassu }
391*38aa3f5aSGustavo A. R. Silva cur_digest = hash_hdr->digest;
3924d7aeee7SRoberto Sassu cur_digestsize = hash.hdr.length;
3933ce1217dSRoberto Sassu out:
394712a49bdSRoberto Sassu return ima_eventdigest_init_common(cur_digest, cur_digestsize,
395989dc725SMimi Zohar DIGEST_TYPE__LAST, HASH_ALGO__LAST,
396989dc725SMimi Zohar field_data);
3973ce1217dSRoberto Sassu }
3983ce1217dSRoberto Sassu
3993ce1217dSRoberto Sassu /*
4004d7aeee7SRoberto Sassu * This function writes the digest of an event (without size limit).
4013ce1217dSRoberto Sassu */
ima_eventdigest_ng_init(struct ima_event_data * event_data,struct ima_field_data * field_data)40223b57419SRoberto Sassu int ima_eventdigest_ng_init(struct ima_event_data *event_data,
40323b57419SRoberto Sassu struct ima_field_data *field_data)
4043ce1217dSRoberto Sassu {
40509091c44SMimi Zohar u8 *cur_digest = NULL, hash_algo = ima_hash_algo;
4064d7aeee7SRoberto Sassu u32 cur_digestsize = 0;
4074d7aeee7SRoberto Sassu
4088d94eb9bSRoberto Sassu if (event_data->violation) /* recording a violation. */
4094d7aeee7SRoberto Sassu goto out;
4104d7aeee7SRoberto Sassu
41123b57419SRoberto Sassu cur_digest = event_data->iint->ima_hash->digest;
41223b57419SRoberto Sassu cur_digestsize = event_data->iint->ima_hash->length;
4134d7aeee7SRoberto Sassu
41423b57419SRoberto Sassu hash_algo = event_data->iint->ima_hash->algo;
4154d7aeee7SRoberto Sassu out:
4164d7aeee7SRoberto Sassu return ima_eventdigest_init_common(cur_digest, cur_digestsize,
417989dc725SMimi Zohar DIGEST_TYPE__LAST, hash_algo,
418989dc725SMimi Zohar field_data);
419989dc725SMimi Zohar }
420989dc725SMimi Zohar
421989dc725SMimi Zohar /*
422989dc725SMimi Zohar * This function writes the digest of an event (without size limit),
423989dc725SMimi Zohar * prefixed with both the digest type and hash algorithm.
424989dc725SMimi Zohar */
ima_eventdigest_ngv2_init(struct ima_event_data * event_data,struct ima_field_data * field_data)425989dc725SMimi Zohar int ima_eventdigest_ngv2_init(struct ima_event_data *event_data,
426989dc725SMimi Zohar struct ima_field_data *field_data)
427989dc725SMimi Zohar {
428989dc725SMimi Zohar u8 *cur_digest = NULL, hash_algo = ima_hash_algo;
429989dc725SMimi Zohar u32 cur_digestsize = 0;
430989dc725SMimi Zohar u8 digest_type = DIGEST_TYPE_IMA;
431989dc725SMimi Zohar
432989dc725SMimi Zohar if (event_data->violation) /* recording a violation. */
433989dc725SMimi Zohar goto out;
434989dc725SMimi Zohar
435989dc725SMimi Zohar cur_digest = event_data->iint->ima_hash->digest;
436989dc725SMimi Zohar cur_digestsize = event_data->iint->ima_hash->length;
437989dc725SMimi Zohar
438989dc725SMimi Zohar hash_algo = event_data->iint->ima_hash->algo;
43954f03916SMimi Zohar if (event_data->iint->flags & IMA_VERITY_REQUIRED)
44054f03916SMimi Zohar digest_type = DIGEST_TYPE_VERITY;
441989dc725SMimi Zohar out:
442989dc725SMimi Zohar return ima_eventdigest_init_common(cur_digest, cur_digestsize,
443989dc725SMimi Zohar digest_type, hash_algo,
444989dc725SMimi Zohar field_data);
4454d7aeee7SRoberto Sassu }
4464d7aeee7SRoberto Sassu
4473878d505SThiago Jung Bauermann /*
4483878d505SThiago Jung Bauermann * This function writes the digest of the file which is expected to match the
4493878d505SThiago Jung Bauermann * digest contained in the file's appended signature.
4503878d505SThiago Jung Bauermann */
ima_eventdigest_modsig_init(struct ima_event_data * event_data,struct ima_field_data * field_data)4513878d505SThiago Jung Bauermann int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
4523878d505SThiago Jung Bauermann struct ima_field_data *field_data)
4533878d505SThiago Jung Bauermann {
4543878d505SThiago Jung Bauermann enum hash_algo hash_algo;
4553878d505SThiago Jung Bauermann const u8 *cur_digest;
4563878d505SThiago Jung Bauermann u32 cur_digestsize;
4573878d505SThiago Jung Bauermann
4583878d505SThiago Jung Bauermann if (!event_data->modsig)
4593878d505SThiago Jung Bauermann return 0;
4603878d505SThiago Jung Bauermann
4613878d505SThiago Jung Bauermann if (event_data->violation) {
4623878d505SThiago Jung Bauermann /* Recording a violation. */
4633878d505SThiago Jung Bauermann hash_algo = HASH_ALGO_SHA1;
4643878d505SThiago Jung Bauermann cur_digest = NULL;
4653878d505SThiago Jung Bauermann cur_digestsize = 0;
4663878d505SThiago Jung Bauermann } else {
4673878d505SThiago Jung Bauermann int rc;
4683878d505SThiago Jung Bauermann
4693878d505SThiago Jung Bauermann rc = ima_get_modsig_digest(event_data->modsig, &hash_algo,
4703878d505SThiago Jung Bauermann &cur_digest, &cur_digestsize);
4713878d505SThiago Jung Bauermann if (rc)
4723878d505SThiago Jung Bauermann return rc;
4733878d505SThiago Jung Bauermann else if (hash_algo == HASH_ALGO__LAST || cur_digestsize == 0)
4743878d505SThiago Jung Bauermann /* There was some error collecting the digest. */
4753878d505SThiago Jung Bauermann return -EINVAL;
4763878d505SThiago Jung Bauermann }
4773878d505SThiago Jung Bauermann
4783878d505SThiago Jung Bauermann return ima_eventdigest_init_common(cur_digest, cur_digestsize,
479989dc725SMimi Zohar DIGEST_TYPE__LAST, hash_algo,
480989dc725SMimi Zohar field_data);
4813878d505SThiago Jung Bauermann }
4823878d505SThiago Jung Bauermann
ima_eventname_init_common(struct ima_event_data * event_data,struct ima_field_data * field_data,bool size_limit)48323b57419SRoberto Sassu static int ima_eventname_init_common(struct ima_event_data *event_data,
4844d7aeee7SRoberto Sassu struct ima_field_data *field_data,
4854d7aeee7SRoberto Sassu bool size_limit)
4864d7aeee7SRoberto Sassu {
4873ce1217dSRoberto Sassu const char *cur_filename = NULL;
488be84f32bSStefan Berger struct name_snapshot filename;
4893ce1217dSRoberto Sassu u32 cur_filename_len = 0;
490be84f32bSStefan Berger bool snapshot = false;
491be84f32bSStefan Berger int ret;
4923ce1217dSRoberto Sassu
49323b57419SRoberto Sassu BUG_ON(event_data->filename == NULL && event_data->file == NULL);
4943ce1217dSRoberto Sassu
49523b57419SRoberto Sassu if (event_data->filename) {
49623b57419SRoberto Sassu cur_filename = event_data->filename;
49723b57419SRoberto Sassu cur_filename_len = strlen(event_data->filename);
4983ce1217dSRoberto Sassu
4994d7aeee7SRoberto Sassu if (!size_limit || cur_filename_len <= IMA_EVENT_NAME_LEN_MAX)
5003ce1217dSRoberto Sassu goto out;
5013ce1217dSRoberto Sassu }
5023ce1217dSRoberto Sassu
50323b57419SRoberto Sassu if (event_data->file) {
504be84f32bSStefan Berger take_dentry_name_snapshot(&filename,
505be84f32bSStefan Berger event_data->file->f_path.dentry);
506be84f32bSStefan Berger snapshot = true;
507be84f32bSStefan Berger cur_filename = filename.name.name;
5083ce1217dSRoberto Sassu cur_filename_len = strlen(cur_filename);
5093ce1217dSRoberto Sassu } else
5103ce1217dSRoberto Sassu /*
5113ce1217dSRoberto Sassu * Truncate filename if the latter is too long and
5123ce1217dSRoberto Sassu * the file descriptor is not available.
5133ce1217dSRoberto Sassu */
5143ce1217dSRoberto Sassu cur_filename_len = IMA_EVENT_NAME_LEN_MAX;
5153ce1217dSRoberto Sassu out:
516be84f32bSStefan Berger ret = ima_write_template_field_data(cur_filename, cur_filename_len,
517e3b64c26SRoberto Sassu DATA_FMT_STRING, field_data);
518be84f32bSStefan Berger
519be84f32bSStefan Berger if (snapshot)
520be84f32bSStefan Berger release_dentry_name_snapshot(&filename);
521be84f32bSStefan Berger
522be84f32bSStefan Berger return ret;
5234d7aeee7SRoberto Sassu }
5244d7aeee7SRoberto Sassu
5254d7aeee7SRoberto Sassu /*
5264d7aeee7SRoberto Sassu * This function writes the name of an event (with size limit).
5274d7aeee7SRoberto Sassu */
ima_eventname_init(struct ima_event_data * event_data,struct ima_field_data * field_data)52823b57419SRoberto Sassu int ima_eventname_init(struct ima_event_data *event_data,
5294d7aeee7SRoberto Sassu struct ima_field_data *field_data)
5304d7aeee7SRoberto Sassu {
53123b57419SRoberto Sassu return ima_eventname_init_common(event_data, field_data, true);
5324d7aeee7SRoberto Sassu }
5334d7aeee7SRoberto Sassu
5344d7aeee7SRoberto Sassu /*
5354d7aeee7SRoberto Sassu * This function writes the name of an event (without size limit).
5364d7aeee7SRoberto Sassu */
ima_eventname_ng_init(struct ima_event_data * event_data,struct ima_field_data * field_data)53723b57419SRoberto Sassu int ima_eventname_ng_init(struct ima_event_data *event_data,
5384d7aeee7SRoberto Sassu struct ima_field_data *field_data)
5394d7aeee7SRoberto Sassu {
54023b57419SRoberto Sassu return ima_eventname_init_common(event_data, field_data, false);
5413ce1217dSRoberto Sassu }
542bcbc9b0cSMimi Zohar
543bcbc9b0cSMimi Zohar /*
544bcbc9b0cSMimi Zohar * ima_eventsig_init - include the file signature as part of the template data
545bcbc9b0cSMimi Zohar */
ima_eventsig_init(struct ima_event_data * event_data,struct ima_field_data * field_data)54623b57419SRoberto Sassu int ima_eventsig_init(struct ima_event_data *event_data,
547bcbc9b0cSMimi Zohar struct ima_field_data *field_data)
548bcbc9b0cSMimi Zohar {
54923b57419SRoberto Sassu struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
550bcbc9b0cSMimi Zohar
551398c42e2SMimi Zohar if (!xattr_value ||
552398c42e2SMimi Zohar (xattr_value->type != EVM_IMA_XATTR_DIGSIG &&
553398c42e2SMimi Zohar xattr_value->type != IMA_VERITY_DIGSIG))
554026d7fc9SRoberto Sassu return ima_eventevmsig_init(event_data, field_data);
555bcbc9b0cSMimi Zohar
5561775cb87SThiago Jung Bauermann return ima_write_template_field_data(xattr_value, event_data->xattr_len,
5571775cb87SThiago Jung Bauermann DATA_FMT_HEX, field_data);
558bcbc9b0cSMimi Zohar }
55986b4da8cSPrakhar Srivastava
56086b4da8cSPrakhar Srivastava /*
56186b4da8cSPrakhar Srivastava * ima_eventbuf_init - include the buffer(kexec-cmldine) as part of the
56286b4da8cSPrakhar Srivastava * template data.
56386b4da8cSPrakhar Srivastava */
ima_eventbuf_init(struct ima_event_data * event_data,struct ima_field_data * field_data)56486b4da8cSPrakhar Srivastava int ima_eventbuf_init(struct ima_event_data *event_data,
56586b4da8cSPrakhar Srivastava struct ima_field_data *field_data)
56686b4da8cSPrakhar Srivastava {
56786b4da8cSPrakhar Srivastava if ((!event_data->buf) || (event_data->buf_len == 0))
56886b4da8cSPrakhar Srivastava return 0;
56986b4da8cSPrakhar Srivastava
57086b4da8cSPrakhar Srivastava return ima_write_template_field_data(event_data->buf,
57186b4da8cSPrakhar Srivastava event_data->buf_len, DATA_FMT_HEX,
57286b4da8cSPrakhar Srivastava field_data);
57386b4da8cSPrakhar Srivastava }
5743878d505SThiago Jung Bauermann
5753878d505SThiago Jung Bauermann /*
5763878d505SThiago Jung Bauermann * ima_eventmodsig_init - include the appended file signature as part of the
5773878d505SThiago Jung Bauermann * template data
5783878d505SThiago Jung Bauermann */
ima_eventmodsig_init(struct ima_event_data * event_data,struct ima_field_data * field_data)5793878d505SThiago Jung Bauermann int ima_eventmodsig_init(struct ima_event_data *event_data,
5803878d505SThiago Jung Bauermann struct ima_field_data *field_data)
5813878d505SThiago Jung Bauermann {
5823878d505SThiago Jung Bauermann const void *data;
5833878d505SThiago Jung Bauermann u32 data_len;
5843878d505SThiago Jung Bauermann int rc;
5853878d505SThiago Jung Bauermann
5863878d505SThiago Jung Bauermann if (!event_data->modsig)
5873878d505SThiago Jung Bauermann return 0;
5883878d505SThiago Jung Bauermann
5893878d505SThiago Jung Bauermann /*
5903878d505SThiago Jung Bauermann * modsig is a runtime structure containing pointers. Get its raw data
5913878d505SThiago Jung Bauermann * instead.
5923878d505SThiago Jung Bauermann */
5933878d505SThiago Jung Bauermann rc = ima_get_raw_modsig(event_data->modsig, &data, &data_len);
5943878d505SThiago Jung Bauermann if (rc)
5953878d505SThiago Jung Bauermann return rc;
5963878d505SThiago Jung Bauermann
5973878d505SThiago Jung Bauermann return ima_write_template_field_data(data, data_len, DATA_FMT_HEX,
5983878d505SThiago Jung Bauermann field_data);
5993878d505SThiago Jung Bauermann }
600026d7fc9SRoberto Sassu
601026d7fc9SRoberto Sassu /*
602026d7fc9SRoberto Sassu * ima_eventevmsig_init - include the EVM portable signature as part of the
603026d7fc9SRoberto Sassu * template data
604026d7fc9SRoberto Sassu */
ima_eventevmsig_init(struct ima_event_data * event_data,struct ima_field_data * field_data)605026d7fc9SRoberto Sassu int ima_eventevmsig_init(struct ima_event_data *event_data,
606026d7fc9SRoberto Sassu struct ima_field_data *field_data)
607026d7fc9SRoberto Sassu {
608026d7fc9SRoberto Sassu struct evm_ima_xattr_data *xattr_data = NULL;
609026d7fc9SRoberto Sassu int rc = 0;
610026d7fc9SRoberto Sassu
611026d7fc9SRoberto Sassu if (!event_data->file)
612026d7fc9SRoberto Sassu return 0;
613026d7fc9SRoberto Sassu
6144609e1f1SChristian Brauner rc = vfs_getxattr_alloc(&nop_mnt_idmap, file_dentry(event_data->file),
615026d7fc9SRoberto Sassu XATTR_NAME_EVM, (char **)&xattr_data, 0,
616026d7fc9SRoberto Sassu GFP_NOFS);
617f6fbd8cbSPaul Moore if (rc <= 0 || xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) {
618f6fbd8cbSPaul Moore rc = 0;
619f6fbd8cbSPaul Moore goto out;
620026d7fc9SRoberto Sassu }
621026d7fc9SRoberto Sassu
622026d7fc9SRoberto Sassu rc = ima_write_template_field_data((char *)xattr_data, rc, DATA_FMT_HEX,
623026d7fc9SRoberto Sassu field_data);
624f6fbd8cbSPaul Moore
625f6fbd8cbSPaul Moore out:
626026d7fc9SRoberto Sassu kfree(xattr_data);
627026d7fc9SRoberto Sassu return rc;
628026d7fc9SRoberto Sassu }
6297dcfeaccSRoberto Sassu
ima_eventinodedac_init_common(struct ima_event_data * event_data,struct ima_field_data * field_data,bool get_uid)6307dcfeaccSRoberto Sassu static int ima_eventinodedac_init_common(struct ima_event_data *event_data,
6317dcfeaccSRoberto Sassu struct ima_field_data *field_data,
6327dcfeaccSRoberto Sassu bool get_uid)
6337dcfeaccSRoberto Sassu {
6347dcfeaccSRoberto Sassu unsigned int id;
6357dcfeaccSRoberto Sassu
6367dcfeaccSRoberto Sassu if (!event_data->file)
6377dcfeaccSRoberto Sassu return 0;
6387dcfeaccSRoberto Sassu
6397dcfeaccSRoberto Sassu if (get_uid)
6407dcfeaccSRoberto Sassu id = i_uid_read(file_inode(event_data->file));
6417dcfeaccSRoberto Sassu else
6427dcfeaccSRoberto Sassu id = i_gid_read(file_inode(event_data->file));
6437dcfeaccSRoberto Sassu
6447dcfeaccSRoberto Sassu if (ima_canonical_fmt) {
6457dcfeaccSRoberto Sassu if (sizeof(id) == sizeof(u16))
6466b26285fSRoberto Sassu id = (__force u16)cpu_to_le16(id);
6477dcfeaccSRoberto Sassu else
6486b26285fSRoberto Sassu id = (__force u32)cpu_to_le32(id);
6497dcfeaccSRoberto Sassu }
6507dcfeaccSRoberto Sassu
6517dcfeaccSRoberto Sassu return ima_write_template_field_data((void *)&id, sizeof(id),
6527dcfeaccSRoberto Sassu DATA_FMT_UINT, field_data);
6537dcfeaccSRoberto Sassu }
6547dcfeaccSRoberto Sassu
6557dcfeaccSRoberto Sassu /*
6567dcfeaccSRoberto Sassu * ima_eventinodeuid_init - include the inode UID as part of the template
6577dcfeaccSRoberto Sassu * data
6587dcfeaccSRoberto Sassu */
ima_eventinodeuid_init(struct ima_event_data * event_data,struct ima_field_data * field_data)6597dcfeaccSRoberto Sassu int ima_eventinodeuid_init(struct ima_event_data *event_data,
6607dcfeaccSRoberto Sassu struct ima_field_data *field_data)
6617dcfeaccSRoberto Sassu {
6627dcfeaccSRoberto Sassu return ima_eventinodedac_init_common(event_data, field_data, true);
6637dcfeaccSRoberto Sassu }
6647dcfeaccSRoberto Sassu
6657dcfeaccSRoberto Sassu /*
6667dcfeaccSRoberto Sassu * ima_eventinodegid_init - include the inode GID as part of the template
6677dcfeaccSRoberto Sassu * data
6687dcfeaccSRoberto Sassu */
ima_eventinodegid_init(struct ima_event_data * event_data,struct ima_field_data * field_data)6697dcfeaccSRoberto Sassu int ima_eventinodegid_init(struct ima_event_data *event_data,
6707dcfeaccSRoberto Sassu struct ima_field_data *field_data)
6717dcfeaccSRoberto Sassu {
6727dcfeaccSRoberto Sassu return ima_eventinodedac_init_common(event_data, field_data, false);
6737dcfeaccSRoberto Sassu }
674f8216f6bSRoberto Sassu
675f8216f6bSRoberto Sassu /*
676f8216f6bSRoberto Sassu * ima_eventinodemode_init - include the inode mode as part of the template
677f8216f6bSRoberto Sassu * data
678f8216f6bSRoberto Sassu */
ima_eventinodemode_init(struct ima_event_data * event_data,struct ima_field_data * field_data)679f8216f6bSRoberto Sassu int ima_eventinodemode_init(struct ima_event_data *event_data,
680f8216f6bSRoberto Sassu struct ima_field_data *field_data)
681f8216f6bSRoberto Sassu {
682f8216f6bSRoberto Sassu struct inode *inode;
6836b26285fSRoberto Sassu u16 mode;
684f8216f6bSRoberto Sassu
685f8216f6bSRoberto Sassu if (!event_data->file)
686f8216f6bSRoberto Sassu return 0;
687f8216f6bSRoberto Sassu
688f8216f6bSRoberto Sassu inode = file_inode(event_data->file);
689f8216f6bSRoberto Sassu mode = inode->i_mode;
690f8216f6bSRoberto Sassu if (ima_canonical_fmt)
6916b26285fSRoberto Sassu mode = (__force u16)cpu_to_le16(mode);
692f8216f6bSRoberto Sassu
693f8216f6bSRoberto Sassu return ima_write_template_field_data((char *)&mode, sizeof(mode),
694f8216f6bSRoberto Sassu DATA_FMT_UINT, field_data);
695f8216f6bSRoberto Sassu }
6968314b673SRoberto Sassu
ima_eventinodexattrs_init_common(struct ima_event_data * event_data,struct ima_field_data * field_data,char type)6978314b673SRoberto Sassu static int ima_eventinodexattrs_init_common(struct ima_event_data *event_data,
6988314b673SRoberto Sassu struct ima_field_data *field_data,
6998314b673SRoberto Sassu char type)
7008314b673SRoberto Sassu {
7018314b673SRoberto Sassu u8 *buffer = NULL;
7028314b673SRoberto Sassu int rc;
7038314b673SRoberto Sassu
7048314b673SRoberto Sassu if (!event_data->file)
7058314b673SRoberto Sassu return 0;
7068314b673SRoberto Sassu
7078314b673SRoberto Sassu rc = evm_read_protected_xattrs(file_dentry(event_data->file), NULL, 0,
7088314b673SRoberto Sassu type, ima_canonical_fmt);
7098314b673SRoberto Sassu if (rc < 0)
7108314b673SRoberto Sassu return 0;
7118314b673SRoberto Sassu
7128314b673SRoberto Sassu buffer = kmalloc(rc, GFP_KERNEL);
7138314b673SRoberto Sassu if (!buffer)
7148314b673SRoberto Sassu return 0;
7158314b673SRoberto Sassu
7168314b673SRoberto Sassu rc = evm_read_protected_xattrs(file_dentry(event_data->file), buffer,
7178314b673SRoberto Sassu rc, type, ima_canonical_fmt);
7188314b673SRoberto Sassu if (rc < 0) {
7198314b673SRoberto Sassu rc = 0;
7208314b673SRoberto Sassu goto out;
7218314b673SRoberto Sassu }
7228314b673SRoberto Sassu
7238314b673SRoberto Sassu rc = ima_write_template_field_data((char *)buffer, rc, DATA_FMT_HEX,
7248314b673SRoberto Sassu field_data);
7258314b673SRoberto Sassu out:
7268314b673SRoberto Sassu kfree(buffer);
7278314b673SRoberto Sassu return rc;
7288314b673SRoberto Sassu }
7298314b673SRoberto Sassu
7308314b673SRoberto Sassu /*
7318314b673SRoberto Sassu * ima_eventinodexattrnames_init - include a list of xattr names as part of the
7328314b673SRoberto Sassu * template data
7338314b673SRoberto Sassu */
ima_eventinodexattrnames_init(struct ima_event_data * event_data,struct ima_field_data * field_data)7348314b673SRoberto Sassu int ima_eventinodexattrnames_init(struct ima_event_data *event_data,
7358314b673SRoberto Sassu struct ima_field_data *field_data)
7368314b673SRoberto Sassu {
7378314b673SRoberto Sassu return ima_eventinodexattrs_init_common(event_data, field_data, 'n');
7388314b673SRoberto Sassu }
7398314b673SRoberto Sassu
7408314b673SRoberto Sassu /*
7418314b673SRoberto Sassu * ima_eventinodexattrlengths_init - include a list of xattr lengths as part of
7428314b673SRoberto Sassu * the template data
7438314b673SRoberto Sassu */
ima_eventinodexattrlengths_init(struct ima_event_data * event_data,struct ima_field_data * field_data)7448314b673SRoberto Sassu int ima_eventinodexattrlengths_init(struct ima_event_data *event_data,
7458314b673SRoberto Sassu struct ima_field_data *field_data)
7468314b673SRoberto Sassu {
7478314b673SRoberto Sassu return ima_eventinodexattrs_init_common(event_data, field_data, 'l');
7488314b673SRoberto Sassu }
7498314b673SRoberto Sassu
7508314b673SRoberto Sassu /*
7518314b673SRoberto Sassu * ima_eventinodexattrvalues_init - include a list of xattr values as part of
7528314b673SRoberto Sassu * the template data
7538314b673SRoberto Sassu */
ima_eventinodexattrvalues_init(struct ima_event_data * event_data,struct ima_field_data * field_data)7548314b673SRoberto Sassu int ima_eventinodexattrvalues_init(struct ima_event_data *event_data,
7558314b673SRoberto Sassu struct ima_field_data *field_data)
7568314b673SRoberto Sassu {
7578314b673SRoberto Sassu return ima_eventinodexattrs_init_common(event_data, field_data, 'v');
7588314b673SRoberto Sassu }
759