Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/security/integrity/ima/ima_api.c
10817 views
1
/*
2
* Copyright (C) 2008 IBM Corporation
3
*
4
* Author: Mimi Zohar <[email protected]>
5
*
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License as
8
* published by the Free Software Foundation, version 2 of the
9
* License.
10
*
11
* File: ima_api.c
12
* Implements must_measure, collect_measurement, store_measurement,
13
* and store_template.
14
*/
15
#include <linux/module.h>
16
#include <linux/slab.h>
17
18
#include "ima.h"
19
static const char *IMA_TEMPLATE_NAME = "ima";
20
21
/*
22
* ima_store_template - store ima template measurements
23
*
24
* Calculate the hash of a template entry, add the template entry
25
* to an ordered list of measurement entries maintained inside the kernel,
26
* and also update the aggregate integrity value (maintained inside the
27
* configured TPM PCR) over the hashes of the current list of measurement
28
* entries.
29
*
30
* Applications retrieve the current kernel-held measurement list through
31
* the securityfs entries in /sys/kernel/security/ima. The signed aggregate
32
* TPM PCR (called quote) can be retrieved using a TPM user space library
33
* and is used to validate the measurement list.
34
*
35
* Returns 0 on success, error code otherwise
36
*/
37
int ima_store_template(struct ima_template_entry *entry,
38
int violation, struct inode *inode)
39
{
40
const char *op = "add_template_measure";
41
const char *audit_cause = "hashing_error";
42
int result;
43
44
memset(entry->digest, 0, sizeof(entry->digest));
45
entry->template_name = IMA_TEMPLATE_NAME;
46
entry->template_len = sizeof(entry->template);
47
48
if (!violation) {
49
result = ima_calc_template_hash(entry->template_len,
50
&entry->template,
51
entry->digest);
52
if (result < 0) {
53
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
54
entry->template_name, op,
55
audit_cause, result, 0);
56
return result;
57
}
58
}
59
result = ima_add_template_entry(entry, violation, op, inode);
60
return result;
61
}
62
63
/*
64
* ima_add_violation - add violation to measurement list.
65
*
66
* Violations are flagged in the measurement list with zero hash values.
67
* By extending the PCR with 0xFF's instead of with zeroes, the PCR
68
* value is invalidated.
69
*/
70
void ima_add_violation(struct inode *inode, const unsigned char *filename,
71
const char *op, const char *cause)
72
{
73
struct ima_template_entry *entry;
74
int violation = 1;
75
int result;
76
77
/* can overflow, only indicator */
78
atomic_long_inc(&ima_htable.violations);
79
80
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
81
if (!entry) {
82
result = -ENOMEM;
83
goto err_out;
84
}
85
memset(&entry->template, 0, sizeof(entry->template));
86
strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
87
result = ima_store_template(entry, violation, inode);
88
if (result < 0)
89
kfree(entry);
90
err_out:
91
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
92
op, cause, result, 0);
93
}
94
95
/**
96
* ima_must_measure - measure decision based on policy.
97
* @inode: pointer to inode to measure
98
* @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
99
* @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP)
100
*
101
* The policy is defined in terms of keypairs:
102
* subj=, obj=, type=, func=, mask=, fsmagic=
103
* subj,obj, and type: are LSM specific.
104
* func: FILE_CHECK | BPRM_CHECK | FILE_MMAP
105
* mask: contains the permission mask
106
* fsmagic: hex value
107
*
108
* Return 0 to measure. For matching a DONT_MEASURE policy, no policy,
109
* or other error, return an error code.
110
*/
111
int ima_must_measure(struct inode *inode, int mask, int function)
112
{
113
int must_measure;
114
115
must_measure = ima_match_policy(inode, function, mask);
116
return must_measure ? 0 : -EACCES;
117
}
118
119
/*
120
* ima_collect_measurement - collect file measurement
121
*
122
* Calculate the file hash, if it doesn't already exist,
123
* storing the measurement and i_version in the iint.
124
*
125
* Must be called with iint->mutex held.
126
*
127
* Return 0 on success, error code otherwise
128
*/
129
int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
130
{
131
int result = -EEXIST;
132
133
if (!(iint->flags & IMA_MEASURED)) {
134
u64 i_version = file->f_dentry->d_inode->i_version;
135
136
memset(iint->digest, 0, IMA_DIGEST_SIZE);
137
result = ima_calc_hash(file, iint->digest);
138
if (!result)
139
iint->version = i_version;
140
}
141
return result;
142
}
143
144
/*
145
* ima_store_measurement - store file measurement
146
*
147
* Create an "ima" template and then store the template by calling
148
* ima_store_template.
149
*
150
* We only get here if the inode has not already been measured,
151
* but the measurement could already exist:
152
* - multiple copies of the same file on either the same or
153
* different filesystems.
154
* - the inode was previously flushed as well as the iint info,
155
* containing the hashing info.
156
*
157
* Must be called with iint->mutex held.
158
*/
159
void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
160
const unsigned char *filename)
161
{
162
const char *op = "add_template_measure";
163
const char *audit_cause = "ENOMEM";
164
int result = -ENOMEM;
165
struct inode *inode = file->f_dentry->d_inode;
166
struct ima_template_entry *entry;
167
int violation = 0;
168
169
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
170
if (!entry) {
171
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
172
op, audit_cause, result, 0);
173
return;
174
}
175
memset(&entry->template, 0, sizeof(entry->template));
176
memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE);
177
strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
178
179
result = ima_store_template(entry, violation, inode);
180
if (!result)
181
iint->flags |= IMA_MEASURED;
182
else
183
kfree(entry);
184
}
185
186