Commit 3ea7a56067e663278470c04fd655adf809e72d4d
Committed by
Mimi Zohar
1 parent
e7a2ad7eb6
Exists in
master
and in
16 other branches
ima: provide hash algo info in the xattr
All files labeled with 'security.ima' hashes, are hashed using the same hash algorithm. Changing from one hash algorithm to another, requires relabeling the filesystem. This patch defines a new xattr type, which includes the hash algorithm, permitting different files to be hashed with different algorithms. Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Showing 2 changed files with 59 additions and 15 deletions Side-by-side Diff
security/integrity/ima/ima_appraise.c
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | #include <linux/magic.h> |
16 | 16 | #include <linux/ima.h> |
17 | 17 | #include <linux/evm.h> |
18 | +#include <crypto/hash_info.h> | |
18 | 19 | |
19 | 20 | #include "ima.h" |
20 | 21 | |
... | ... | @@ -45,10 +46,22 @@ |
45 | 46 | static int ima_fix_xattr(struct dentry *dentry, |
46 | 47 | struct integrity_iint_cache *iint) |
47 | 48 | { |
48 | - iint->ima_hash->type = IMA_XATTR_DIGEST; | |
49 | - return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, | |
50 | - &iint->ima_hash->type, | |
51 | - 1 + iint->ima_hash->length, 0); | |
49 | + int rc, offset; | |
50 | + u8 algo = iint->ima_hash->algo; | |
51 | + | |
52 | + if (algo <= HASH_ALGO_SHA1) { | |
53 | + offset = 1; | |
54 | + iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST; | |
55 | + } else { | |
56 | + offset = 0; | |
57 | + iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG; | |
58 | + iint->ima_hash->xattr.ng.algo = algo; | |
59 | + } | |
60 | + rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, | |
61 | + &iint->ima_hash->xattr.data[offset], | |
62 | + (sizeof(iint->ima_hash->xattr) - offset) + | |
63 | + iint->ima_hash->length, 0); | |
64 | + return rc; | |
52 | 65 | } |
53 | 66 | |
54 | 67 | /* Return specific func appraised cached result */ |
55 | 68 | |
... | ... | @@ -112,15 +125,31 @@ |
112 | 125 | { |
113 | 126 | struct signature_v2_hdr *sig; |
114 | 127 | |
115 | - if (!xattr_value || xattr_len < 0 || xattr_len <= 1 + sizeof(*sig)) | |
128 | + if (!xattr_value || xattr_len < 2) | |
116 | 129 | return; |
117 | 130 | |
118 | - sig = (typeof(sig)) xattr_value->digest; | |
119 | - | |
120 | - if (xattr_value->type != EVM_IMA_XATTR_DIGSIG || sig->version != 2) | |
121 | - return; | |
122 | - | |
123 | - hash->algo = sig->hash_algo; | |
131 | + switch (xattr_value->type) { | |
132 | + case EVM_IMA_XATTR_DIGSIG: | |
133 | + sig = (typeof(sig))xattr_value; | |
134 | + if (sig->version != 2 || xattr_len <= sizeof(*sig)) | |
135 | + return; | |
136 | + hash->algo = sig->hash_algo; | |
137 | + break; | |
138 | + case IMA_XATTR_DIGEST_NG: | |
139 | + hash->algo = xattr_value->digest[0]; | |
140 | + break; | |
141 | + case IMA_XATTR_DIGEST: | |
142 | + /* this is for backward compatibility */ | |
143 | + if (xattr_len == 21) { | |
144 | + unsigned int zero = 0; | |
145 | + if (!memcmp(&xattr_value->digest[16], &zero, 4)) | |
146 | + hash->algo = HASH_ALGO_MD5; | |
147 | + else | |
148 | + hash->algo = HASH_ALGO_SHA1; | |
149 | + } else if (xattr_len == 17) | |
150 | + hash->algo = HASH_ALGO_MD5; | |
151 | + break; | |
152 | + } | |
124 | 153 | } |
125 | 154 | |
126 | 155 | int ima_read_xattr(struct dentry *dentry, |
... | ... | @@ -153,7 +182,7 @@ |
153 | 182 | enum integrity_status status = INTEGRITY_UNKNOWN; |
154 | 183 | const char *op = "appraise_data"; |
155 | 184 | char *cause = "unknown"; |
156 | - int rc = xattr_len; | |
185 | + int rc = xattr_len, hash_start = 0; | |
157 | 186 | |
158 | 187 | if (!ima_appraise) |
159 | 188 | return 0; |
160 | 189 | |
161 | 190 | |
... | ... | @@ -180,17 +209,21 @@ |
180 | 209 | goto out; |
181 | 210 | } |
182 | 211 | switch (xattr_value->type) { |
212 | + case IMA_XATTR_DIGEST_NG: | |
213 | + /* first byte contains algorithm id */ | |
214 | + hash_start = 1; | |
183 | 215 | case IMA_XATTR_DIGEST: |
184 | 216 | if (iint->flags & IMA_DIGSIG_REQUIRED) { |
185 | 217 | cause = "IMA signature required"; |
186 | 218 | status = INTEGRITY_FAIL; |
187 | 219 | break; |
188 | 220 | } |
189 | - if (xattr_len - 1 >= iint->ima_hash->length) | |
221 | + if (xattr_len - sizeof(xattr_value->type) - hash_start >= | |
222 | + iint->ima_hash->length) | |
190 | 223 | /* xattr length may be longer. md5 hash in previous |
191 | 224 | version occupied 20 bytes in xattr, instead of 16 |
192 | 225 | */ |
193 | - rc = memcmp(xattr_value->digest, | |
226 | + rc = memcmp(&xattr_value->digest[hash_start], | |
194 | 227 | iint->ima_hash->digest, |
195 | 228 | iint->ima_hash->length); |
196 | 229 | else |
security/integrity/integrity.h
... | ... | @@ -54,6 +54,7 @@ |
54 | 54 | IMA_XATTR_DIGEST = 0x01, |
55 | 55 | EVM_XATTR_HMAC, |
56 | 56 | EVM_IMA_XATTR_DIGSIG, |
57 | + IMA_XATTR_DIGEST_NG, | |
57 | 58 | }; |
58 | 59 | |
59 | 60 | struct evm_ima_xattr_data { |
... | ... | @@ -66,7 +67,17 @@ |
66 | 67 | struct ima_digest_data { |
67 | 68 | u8 algo; |
68 | 69 | u8 length; |
69 | - u8 type; | |
70 | + union { | |
71 | + struct { | |
72 | + u8 unused; | |
73 | + u8 type; | |
74 | + } sha1; | |
75 | + struct { | |
76 | + u8 type; | |
77 | + u8 algo; | |
78 | + } ng; | |
79 | + u8 data[2]; | |
80 | + } xattr; | |
70 | 81 | u8 digest[0]; |
71 | 82 | } __packed; |
72 | 83 |