Commit | Line | Data |
---|---|---|
2fe5d6de MZ |
1 | /* |
2 | * Copyright (C) 2011 IBM Corporation | |
3 | * | |
4 | * Author: | |
5 | * Mimi Zohar <zohar@us.ibm.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation, version 2 of the License. | |
10 | */ | |
11 | #include <linux/module.h> | |
12 | #include <linux/file.h> | |
13 | #include <linux/fs.h> | |
14 | #include <linux/xattr.h> | |
15 | #include <linux/magic.h> | |
16 | #include <linux/ima.h> | |
17 | #include <linux/evm.h> | |
18 | ||
19 | #include "ima.h" | |
20 | ||
21 | static int __init default_appraise_setup(char *str) | |
22 | { | |
23 | if (strncmp(str, "off", 3) == 0) | |
24 | ima_appraise = 0; | |
25 | else if (strncmp(str, "fix", 3) == 0) | |
26 | ima_appraise = IMA_APPRAISE_FIX; | |
27 | return 1; | |
28 | } | |
29 | ||
30 | __setup("ima_appraise=", default_appraise_setup); | |
31 | ||
32 | /* | |
33 | * ima_must_appraise - set appraise flag | |
34 | * | |
35 | * Return 1 to appraise | |
36 | */ | |
37 | int ima_must_appraise(struct inode *inode, enum ima_hooks func, int mask) | |
38 | { | |
07f6a794 MZ |
39 | if (!ima_appraise) |
40 | return 0; | |
41 | ||
42 | return ima_match_policy(inode, func, mask, IMA_APPRAISE); | |
2fe5d6de MZ |
43 | } |
44 | ||
45 | static void ima_fix_xattr(struct dentry *dentry, | |
46 | struct integrity_iint_cache *iint) | |
47 | { | |
5a44b412 MZ |
48 | iint->ima_xattr.type = IMA_XATTR_DIGEST; |
49 | __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, (u8 *)&iint->ima_xattr, | |
50 | sizeof iint->ima_xattr, 0); | |
2fe5d6de MZ |
51 | } |
52 | ||
53 | /* | |
54 | * ima_appraise_measurement - appraise file measurement | |
55 | * | |
56 | * Call evm_verifyxattr() to verify the integrity of 'security.ima'. | |
57 | * Assuming success, compare the xattr hash with the collected measurement. | |
58 | * | |
59 | * Return 0 on success, error code otherwise | |
60 | */ | |
61 | int ima_appraise_measurement(struct integrity_iint_cache *iint, | |
62 | struct file *file, const unsigned char *filename) | |
63 | { | |
64 | struct dentry *dentry = file->f_dentry; | |
65 | struct inode *inode = dentry->d_inode; | |
8606404f | 66 | struct evm_ima_xattr_data *xattr_value = NULL; |
2fe5d6de MZ |
67 | enum integrity_status status = INTEGRITY_UNKNOWN; |
68 | const char *op = "appraise_data"; | |
69 | char *cause = "unknown"; | |
70 | int rc; | |
71 | ||
72 | if (!ima_appraise) | |
73 | return 0; | |
74 | if (!inode->i_op->getxattr) | |
75 | return INTEGRITY_UNKNOWN; | |
76 | ||
77 | if (iint->flags & IMA_APPRAISED) | |
78 | return iint->ima_status; | |
79 | ||
8606404f DK |
80 | rc = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)&xattr_value, |
81 | 0, GFP_NOFS); | |
2fe5d6de MZ |
82 | if (rc <= 0) { |
83 | if (rc && rc != -ENODATA) | |
84 | goto out; | |
85 | ||
86 | cause = "missing-hash"; | |
87 | status = | |
88 | (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL; | |
89 | goto out; | |
90 | } | |
91 | ||
8606404f | 92 | status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); |
2fe5d6de MZ |
93 | if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) { |
94 | if ((status == INTEGRITY_NOLABEL) | |
95 | || (status == INTEGRITY_NOXATTRS)) | |
96 | cause = "missing-HMAC"; | |
97 | else if (status == INTEGRITY_FAIL) | |
98 | cause = "invalid-HMAC"; | |
99 | goto out; | |
100 | } | |
101 | ||
8606404f DK |
102 | switch (xattr_value->type) { |
103 | case IMA_XATTR_DIGEST: | |
104 | rc = memcmp(xattr_value->digest, iint->ima_xattr.digest, | |
105 | IMA_DIGEST_SIZE); | |
106 | if (rc) { | |
107 | cause = "invalid-hash"; | |
108 | status = INTEGRITY_FAIL; | |
109 | print_hex_dump_bytes("security.ima: ", DUMP_PREFIX_NONE, | |
110 | xattr_value, sizeof(*xattr_value)); | |
111 | print_hex_dump_bytes("collected: ", DUMP_PREFIX_NONE, | |
112 | (u8 *)&iint->ima_xattr, | |
113 | sizeof iint->ima_xattr); | |
114 | break; | |
115 | } | |
116 | status = INTEGRITY_PASS; | |
117 | break; | |
118 | case EVM_IMA_XATTR_DIGSIG: | |
119 | iint->flags |= IMA_DIGSIG; | |
120 | rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, | |
121 | xattr_value->digest, rc - 1, | |
122 | iint->ima_xattr.digest, | |
123 | IMA_DIGEST_SIZE); | |
124 | if (rc == -EOPNOTSUPP) { | |
125 | status = INTEGRITY_UNKNOWN; | |
126 | } else if (rc) { | |
127 | cause = "invalid-signature"; | |
128 | status = INTEGRITY_FAIL; | |
129 | } else { | |
130 | status = INTEGRITY_PASS; | |
131 | } | |
132 | break; | |
133 | default: | |
134 | status = INTEGRITY_UNKNOWN; | |
135 | cause = "unknown-ima-data"; | |
136 | break; | |
2fe5d6de | 137 | } |
8606404f | 138 | |
2fe5d6de MZ |
139 | out: |
140 | if (status != INTEGRITY_PASS) { | |
8606404f DK |
141 | if ((ima_appraise & IMA_APPRAISE_FIX) && |
142 | (!xattr_value || | |
143 | xattr_value->type != EVM_IMA_XATTR_DIGSIG)) { | |
2fe5d6de MZ |
144 | ima_fix_xattr(dentry, iint); |
145 | status = INTEGRITY_PASS; | |
146 | } | |
147 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, | |
148 | op, cause, rc, 0); | |
8606404f DK |
149 | } else { |
150 | iint->flags |= IMA_APPRAISED; | |
2fe5d6de MZ |
151 | } |
152 | iint->ima_status = status; | |
8606404f | 153 | kfree(xattr_value); |
2fe5d6de MZ |
154 | return status; |
155 | } | |
156 | ||
157 | /* | |
158 | * ima_update_xattr - update 'security.ima' hash value | |
159 | */ | |
160 | void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) | |
161 | { | |
162 | struct dentry *dentry = file->f_dentry; | |
163 | int rc = 0; | |
164 | ||
8606404f DK |
165 | /* do not collect and update hash for digital signatures */ |
166 | if (iint->flags & IMA_DIGSIG) | |
167 | return; | |
168 | ||
2fe5d6de MZ |
169 | rc = ima_collect_measurement(iint, file); |
170 | if (rc < 0) | |
171 | return; | |
8606404f | 172 | |
2fe5d6de MZ |
173 | ima_fix_xattr(dentry, iint); |
174 | } | |
175 | ||
176 | /** | |
177 | * ima_inode_post_setattr - reflect file metadata changes | |
178 | * @dentry: pointer to the affected dentry | |
179 | * | |
180 | * Changes to a dentry's metadata might result in needing to appraise. | |
181 | * | |
182 | * This function is called from notify_change(), which expects the caller | |
183 | * to lock the inode's i_mutex. | |
184 | */ | |
185 | void ima_inode_post_setattr(struct dentry *dentry) | |
186 | { | |
187 | struct inode *inode = dentry->d_inode; | |
188 | struct integrity_iint_cache *iint; | |
189 | int must_appraise, rc; | |
190 | ||
191 | if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode) | |
192 | || !inode->i_op->removexattr) | |
193 | return; | |
194 | ||
195 | must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); | |
196 | iint = integrity_iint_find(inode); | |
197 | if (iint) { | |
198 | if (must_appraise) | |
199 | iint->flags |= IMA_APPRAISE; | |
200 | else | |
201 | iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED); | |
202 | } | |
203 | if (!must_appraise) | |
204 | rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA); | |
205 | return; | |
206 | } | |
42c63330 MZ |
207 | |
208 | /* | |
209 | * ima_protect_xattr - protect 'security.ima' | |
210 | * | |
211 | * Ensure that not just anyone can modify or remove 'security.ima'. | |
212 | */ | |
213 | static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, | |
214 | const void *xattr_value, size_t xattr_value_len) | |
215 | { | |
216 | if (strcmp(xattr_name, XATTR_NAME_IMA) == 0) { | |
217 | if (!capable(CAP_SYS_ADMIN)) | |
218 | return -EPERM; | |
219 | return 1; | |
220 | } | |
221 | return 0; | |
222 | } | |
223 | ||
224 | static void ima_reset_appraise_flags(struct inode *inode) | |
225 | { | |
226 | struct integrity_iint_cache *iint; | |
227 | ||
228 | if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)) | |
229 | return; | |
230 | ||
231 | iint = integrity_iint_find(inode); | |
232 | if (!iint) | |
233 | return; | |
234 | ||
235 | iint->flags &= ~(IMA_COLLECTED | IMA_APPRAISED | IMA_MEASURED); | |
236 | return; | |
237 | } | |
238 | ||
239 | int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, | |
240 | const void *xattr_value, size_t xattr_value_len) | |
241 | { | |
242 | int result; | |
243 | ||
244 | result = ima_protect_xattr(dentry, xattr_name, xattr_value, | |
245 | xattr_value_len); | |
246 | if (result == 1) { | |
247 | ima_reset_appraise_flags(dentry->d_inode); | |
248 | result = 0; | |
249 | } | |
250 | return result; | |
251 | } | |
252 | ||
253 | int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) | |
254 | { | |
255 | int result; | |
256 | ||
257 | result = ima_protect_xattr(dentry, xattr_name, NULL, 0); | |
258 | if (result == 1) { | |
259 | ima_reset_appraise_flags(dentry->d_inode); | |
260 | result = 0; | |
261 | } | |
262 | return result; | |
263 | } |