Commit 3ea7a560 authored by Dmitry Kasatkin's avatar Dmitry Kasatkin Committed by Mimi Zohar

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: default avatarDmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.vnet.ibm.com>
parent e7a2ad7e
......@@ -15,6 +15,7 @@
#include <linux/magic.h>
#include <linux/ima.h>
#include <linux/evm.h>
#include <crypto/hash_info.h>
#include "ima.h"
......@@ -45,10 +46,22 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
static int ima_fix_xattr(struct dentry *dentry,
struct integrity_iint_cache *iint)
{
iint->ima_hash->type = IMA_XATTR_DIGEST;
return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
&iint->ima_hash->type,
1 + iint->ima_hash->length, 0);
int rc, offset;
u8 algo = iint->ima_hash->algo;
if (algo <= HASH_ALGO_SHA1) {
offset = 1;
iint->ima_hash->xattr.sha1.type = IMA_XATTR_DIGEST;
} else {
offset = 0;
iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG;
iint->ima_hash->xattr.ng.algo = algo;
}
rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
&iint->ima_hash->xattr.data[offset],
(sizeof(iint->ima_hash->xattr) - offset) +
iint->ima_hash->length, 0);
return rc;
}
/* Return specific func appraised cached result */
......@@ -112,15 +125,31 @@ void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len,
{
struct signature_v2_hdr *sig;
if (!xattr_value || xattr_len < 0 || xattr_len <= 1 + sizeof(*sig))
if (!xattr_value || xattr_len < 2)
return;
sig = (typeof(sig)) xattr_value->digest;
if (xattr_value->type != EVM_IMA_XATTR_DIGSIG || sig->version != 2)
switch (xattr_value->type) {
case EVM_IMA_XATTR_DIGSIG:
sig = (typeof(sig))xattr_value;
if (sig->version != 2 || xattr_len <= sizeof(*sig))
return;
hash->algo = sig->hash_algo;
break;
case IMA_XATTR_DIGEST_NG:
hash->algo = xattr_value->digest[0];
break;
case IMA_XATTR_DIGEST:
/* this is for backward compatibility */
if (xattr_len == 21) {
unsigned int zero = 0;
if (!memcmp(&xattr_value->digest[16], &zero, 4))
hash->algo = HASH_ALGO_MD5;
else
hash->algo = HASH_ALGO_SHA1;
} else if (xattr_len == 17)
hash->algo = HASH_ALGO_MD5;
break;
}
}
int ima_read_xattr(struct dentry *dentry,
......@@ -153,7 +182,7 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
enum integrity_status status = INTEGRITY_UNKNOWN;
const char *op = "appraise_data";
char *cause = "unknown";
int rc = xattr_len;
int rc = xattr_len, hash_start = 0;
if (!ima_appraise)
return 0;
......@@ -180,17 +209,21 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
goto out;
}
switch (xattr_value->type) {
case IMA_XATTR_DIGEST_NG:
/* first byte contains algorithm id */
hash_start = 1;
case IMA_XATTR_DIGEST:
if (iint->flags & IMA_DIGSIG_REQUIRED) {
cause = "IMA signature required";
status = INTEGRITY_FAIL;
break;
}
if (xattr_len - 1 >= iint->ima_hash->length)
if (xattr_len - sizeof(xattr_value->type) - hash_start >=
iint->ima_hash->length)
/* xattr length may be longer. md5 hash in previous
version occupied 20 bytes in xattr, instead of 16
*/
rc = memcmp(xattr_value->digest,
rc = memcmp(&xattr_value->digest[hash_start],
iint->ima_hash->digest,
iint->ima_hash->length);
else
......
......@@ -54,6 +54,7 @@ enum evm_ima_xattr_type {
IMA_XATTR_DIGEST = 0x01,
EVM_XATTR_HMAC,
EVM_IMA_XATTR_DIGSIG,
IMA_XATTR_DIGEST_NG,
};
struct evm_ima_xattr_data {
......@@ -66,7 +67,17 @@ struct evm_ima_xattr_data {
struct ima_digest_data {
u8 algo;
u8 length;
union {
struct {
u8 unused;
u8 type;
} sha1;
struct {
u8 type;
u8 algo;
} ng;
u8 data[2];
} xattr;
u8 digest[0];
} __packed;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment