Commit a35c3fb6 authored by Dmitry Kasatkin's avatar Dmitry Kasatkin Committed by Mimi Zohar

ima: use dynamically allocated hash storage

For each inode in the IMA policy, an iint is allocated.  To support
larger hash digests, the iint digest size changed from 20 bytes to
the maximum supported hash digest size.  Instead of allocating the
maximum size, which most likely is not needed, this patch dynamically
allocates the needed hash storage.

Changelog:
- fix krealloc bug
Signed-off-by: default avatarDmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.vnet.ibm.com>
parent b1aaab22
...@@ -70,6 +70,8 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode) ...@@ -70,6 +70,8 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
static void iint_free(struct integrity_iint_cache *iint) static void iint_free(struct integrity_iint_cache *iint)
{ {
kfree(iint->ima_hash);
iint->ima_hash = NULL;
iint->version = 0; iint->version = 0;
iint->flags = 0UL; iint->flags = 0UL;
iint->ima_file_status = INTEGRITY_UNKNOWN; iint->ima_file_status = INTEGRITY_UNKNOWN;
......
...@@ -44,7 +44,10 @@ int ima_store_template(struct ima_template_entry *entry, ...@@ -44,7 +44,10 @@ int ima_store_template(struct ima_template_entry *entry,
const char *op = "add_template_measure"; const char *op = "add_template_measure";
const char *audit_cause = "hashing_error"; const char *audit_cause = "hashing_error";
int result; int result;
struct ima_digest_data hash; struct {
struct ima_digest_data hdr;
char digest[IMA_MAX_DIGEST_SIZE];
} hash;
memset(entry->digest, 0, sizeof(entry->digest)); memset(entry->digest, 0, sizeof(entry->digest));
entry->template_name = IMA_TEMPLATE_NAME; entry->template_name = IMA_TEMPLATE_NAME;
...@@ -52,14 +55,14 @@ int ima_store_template(struct ima_template_entry *entry, ...@@ -52,14 +55,14 @@ int ima_store_template(struct ima_template_entry *entry,
if (!violation) { if (!violation) {
result = ima_calc_buffer_hash(&entry->template, result = ima_calc_buffer_hash(&entry->template,
entry->template_len, &hash); entry->template_len, &hash.hdr);
if (result < 0) { if (result < 0) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
entry->template_name, op, entry->template_name, op,
audit_cause, result, 0); audit_cause, result, 0);
return result; return result;
} }
memcpy(entry->digest, hash.digest, hash.length); memcpy(entry->digest, hash.hdr.digest, hash.hdr.length);
} }
result = ima_add_template_entry(entry, violation, op, inode); result = ima_add_template_entry(entry, violation, op, inode);
return result; return result;
...@@ -146,6 +149,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -146,6 +149,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
const char *filename = file->f_dentry->d_name.name; const char *filename = file->f_dentry->d_name.name;
int result = 0; int result = 0;
struct {
struct ima_digest_data hdr;
char digest[IMA_MAX_DIGEST_SIZE];
} hash;
if (xattr_value) if (xattr_value)
*xattr_len = ima_read_xattr(file->f_dentry, xattr_value); *xattr_len = ima_read_xattr(file->f_dentry, xattr_value);
...@@ -154,16 +161,23 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, ...@@ -154,16 +161,23 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
u64 i_version = file_inode(file)->i_version; u64 i_version = file_inode(file)->i_version;
/* use default hash algorithm */ /* use default hash algorithm */
iint->ima_hash.algo = ima_hash_algo; hash.hdr.algo = ima_hash_algo;
if (xattr_value) if (xattr_value)
ima_get_hash_algo(*xattr_value, *xattr_len, ima_get_hash_algo(*xattr_value, *xattr_len, &hash.hdr);
&iint->ima_hash);
result = ima_calc_file_hash(file, &iint->ima_hash); result = ima_calc_file_hash(file, &hash.hdr);
if (!result) { if (!result) {
iint->version = i_version; int length = sizeof(hash.hdr) + hash.hdr.length;
iint->flags |= IMA_COLLECTED; void *tmpbuf = krealloc(iint->ima_hash, length,
GFP_NOFS);
if (tmpbuf) {
iint->ima_hash = tmpbuf;
memcpy(iint->ima_hash, &hash, length);
iint->version = i_version;
iint->flags |= IMA_COLLECTED;
} else
result = -ENOMEM;
} }
} }
if (result) if (result)
...@@ -208,21 +222,24 @@ void ima_store_measurement(struct integrity_iint_cache *iint, ...@@ -208,21 +222,24 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
return; return;
} }
memset(&entry->template, 0, sizeof(entry->template)); memset(&entry->template, 0, sizeof(entry->template));
if (iint->ima_hash.algo != ima_hash_algo) { if (iint->ima_hash->algo != ima_hash_algo) {
struct ima_digest_data hash; struct {
struct ima_digest_data hdr;
char digest[IMA_MAX_DIGEST_SIZE];
} hash;
hash.algo = ima_hash_algo; hash.hdr.algo = ima_hash_algo;
result = ima_calc_file_hash(file, &hash); result = ima_calc_file_hash(file, &hash.hdr);
if (result) if (result)
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
filename, "collect_data", "failed", filename, "collect_data", "failed",
result, 0); result, 0);
else else
memcpy(entry->template.digest, hash.digest, memcpy(entry->template.digest, hash.hdr.digest,
hash.length); hash.hdr.length);
} else } else
memcpy(entry->template.digest, iint->ima_hash.digest, memcpy(entry->template.digest, iint->ima_hash->digest,
iint->ima_hash.length); iint->ima_hash->length);
strcpy(entry->template.file_name, strcpy(entry->template.file_name,
(strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ? (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ?
file->f_dentry->d_name.name : filename); file->f_dentry->d_name.name : filename);
...@@ -238,14 +255,14 @@ void ima_audit_measurement(struct integrity_iint_cache *iint, ...@@ -238,14 +255,14 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename) const unsigned char *filename)
{ {
struct audit_buffer *ab; struct audit_buffer *ab;
char hash[(iint->ima_hash.length * 2) + 1]; char hash[(iint->ima_hash->length * 2) + 1];
int i; int i;
if (iint->flags & IMA_AUDITED) if (iint->flags & IMA_AUDITED)
return; return;
for (i = 0; i < iint->ima_hash.length; i++) for (i = 0; i < iint->ima_hash->length; i++)
hex_byte_pack(hash + (i * 2), iint->ima_hash.digest[i]); hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
hash[i * 2] = '\0'; hash[i * 2] = '\0';
ab = audit_log_start(current->audit_context, GFP_KERNEL, ab = audit_log_start(current->audit_context, GFP_KERNEL,
......
...@@ -45,10 +45,10 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func) ...@@ -45,10 +45,10 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)
static int ima_fix_xattr(struct dentry *dentry, static int ima_fix_xattr(struct dentry *dentry,
struct integrity_iint_cache *iint) struct integrity_iint_cache *iint)
{ {
iint->ima_hash.type = IMA_XATTR_DIGEST; iint->ima_hash->type = IMA_XATTR_DIGEST;
return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, return __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
&iint->ima_hash.type, &iint->ima_hash->type,
1 + iint->ima_hash.length, 0); 1 + iint->ima_hash->length, 0);
} }
/* Return specific func appraised cached result */ /* Return specific func appraised cached result */
...@@ -186,13 +186,13 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, ...@@ -186,13 +186,13 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
status = INTEGRITY_FAIL; status = INTEGRITY_FAIL;
break; break;
} }
if (xattr_len - 1 >= iint->ima_hash.length) if (xattr_len - 1 >= iint->ima_hash->length)
/* xattr length may be longer. md5 hash in previous /* xattr length may be longer. md5 hash in previous
version occupied 20 bytes in xattr, instead of 16 version occupied 20 bytes in xattr, instead of 16
*/ */
rc = memcmp(xattr_value->digest, rc = memcmp(xattr_value->digest,
iint->ima_hash.digest, iint->ima_hash->digest,
iint->ima_hash.length); iint->ima_hash->length);
else else
rc = -EINVAL; rc = -EINVAL;
if (rc) { if (rc) {
...@@ -206,8 +206,8 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, ...@@ -206,8 +206,8 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
iint->flags |= IMA_DIGSIG; iint->flags |= IMA_DIGSIG;
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA, rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
(const char *)xattr_value, rc, (const char *)xattr_value, rc,
iint->ima_hash.digest, iint->ima_hash->digest,
iint->ima_hash.length); iint->ima_hash->length);
if (rc == -EOPNOTSUPP) { if (rc == -EOPNOTSUPP) {
status = INTEGRITY_UNKNOWN; status = INTEGRITY_UNKNOWN;
} else if (rc) { } else if (rc) {
......
...@@ -67,7 +67,7 @@ struct ima_digest_data { ...@@ -67,7 +67,7 @@ struct ima_digest_data {
u8 algo; u8 algo;
u8 length; u8 length;
u8 type; u8 type;
u8 digest[IMA_MAX_DIGEST_SIZE]; u8 digest[0];
} __packed; } __packed;
/* /*
...@@ -93,7 +93,7 @@ struct integrity_iint_cache { ...@@ -93,7 +93,7 @@ struct integrity_iint_cache {
enum integrity_status ima_bprm_status:4; enum integrity_status ima_bprm_status:4;
enum integrity_status ima_module_status:4; enum integrity_status ima_module_status:4;
enum integrity_status evm_status:4; enum integrity_status evm_status:4;
struct ima_digest_data ima_hash; struct ima_digest_data *ima_hash;
}; };
/* rbtree tree calls to lookup, insert, delete /* rbtree tree calls to lookup, insert, delete
......
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