Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Dmitry Kasatkin and committed by
Mimi Zohar
3ea7a560 e7a2ad7e

+59 -15
+47 -14
security/integrity/ima/ima_appraise.c
··· 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 ··· 46 45 static int ima_fix_xattr(struct dentry *dentry, 47 46 struct integrity_iint_cache *iint) 48 47 { 49 - iint->ima_hash->type = IMA_XATTR_DIGEST; 50 - return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, 51 - &iint->ima_hash->type, 52 - 1 + iint->ima_hash->length, 0); 48 + int rc, offset; 49 + u8 algo = iint->ima_hash->algo; 50 + 51 + if (algo <= HASH_ALGO_SHA1) { 52 + offset = 1; 53 + iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST; 54 + } else { 55 + offset = 0; 56 + iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG; 57 + iint->ima_hash->xattr.ng.algo = algo; 58 + } 59 + rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, 60 + &iint->ima_hash->xattr.data[offset], 61 + (sizeof(iint->ima_hash->xattr) - offset) + 62 + iint->ima_hash->length, 0); 63 + return rc; 53 64 } 54 65 55 66 /* Return specific func appraised cached result */ ··· 125 112 { 126 113 struct signature_v2_hdr *sig; 127 114 128 - if (!xattr_value || xattr_len < 0 || xattr_len <= 1 + sizeof(*sig)) 115 + if (!xattr_value || xattr_len < 2) 129 116 return; 130 117 131 - sig = (typeof(sig)) xattr_value->digest; 132 - 133 - if (xattr_value->type != EVM_IMA_XATTR_DIGSIG || sig->version != 2) 134 - return; 135 - 136 - hash->algo = sig->hash_algo; 118 + switch (xattr_value->type) { 119 + case EVM_IMA_XATTR_DIGSIG: 120 + sig = (typeof(sig))xattr_value; 121 + if (sig->version != 2 || xattr_len <= sizeof(*sig)) 122 + return; 123 + hash->algo = sig->hash_algo; 124 + break; 125 + case IMA_XATTR_DIGEST_NG: 126 + hash->algo = xattr_value->digest[0]; 127 + break; 128 + case IMA_XATTR_DIGEST: 129 + /* this is for backward compatibility */ 130 + if (xattr_len == 21) { 131 + unsigned int zero = 0; 132 + if (!memcmp(&xattr_value->digest[16], &zero, 4)) 133 + hash->algo = HASH_ALGO_MD5; 134 + else 135 + hash->algo = HASH_ALGO_SHA1; 136 + } else if (xattr_len == 17) 137 + hash->algo = HASH_ALGO_MD5; 138 + break; 139 + } 137 140 } 138 141 139 142 int ima_read_xattr(struct dentry *dentry, ··· 182 153 enum integrity_status status = INTEGRITY_UNKNOWN; 183 154 const char *op = "appraise_data"; 184 155 char *cause = "unknown"; 185 - int rc = xattr_len; 156 + int rc = xattr_len, hash_start = 0; 186 157 187 158 if (!ima_appraise) 188 159 return 0; ··· 209 180 goto out; 210 181 } 211 182 switch (xattr_value->type) { 183 + case IMA_XATTR_DIGEST_NG: 184 + /* first byte contains algorithm id */ 185 + hash_start = 1; 212 186 case IMA_XATTR_DIGEST: 213 187 if (iint->flags & IMA_DIGSIG_REQUIRED) { 214 188 cause = "IMA signature required"; 215 189 status = INTEGRITY_FAIL; 216 190 break; 217 191 } 218 - if (xattr_len - 1 >= iint->ima_hash->length) 192 + if (xattr_len - sizeof(xattr_value->type) - hash_start >= 193 + iint->ima_hash->length) 219 194 /* xattr length may be longer. md5 hash in previous 220 195 version occupied 20 bytes in xattr, instead of 16 221 196 */ 222 - rc = memcmp(xattr_value->digest, 197 + rc = memcmp(&xattr_value->digest[hash_start], 223 198 iint->ima_hash->digest, 224 199 iint->ima_hash->length); 225 200 else
+12 -1
security/integrity/integrity.h
··· 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 { ··· 67 66 struct ima_digest_data { 68 67 u8 algo; 69 68 u8 length; 70 - u8 type; 69 + union { 70 + struct { 71 + u8 unused; 72 + u8 type; 73 + } sha1; 74 + struct { 75 + u8 type; 76 + u8 algo; 77 + } ng; 78 + u8 data[2]; 79 + } xattr; 71 80 u8 digest[0]; 72 81 } __packed; 73 82