ima: use dynamically allocated hash storage
authorDmitry Kasatkin <d.kasatkin@samsung.com>
Thu, 25 Apr 2013 07:44:04 +0000 (10:44 +0300)
committerMimi Zohar <zohar@linux.vnet.ibm.com>
Fri, 25 Oct 2013 21:17:00 +0000 (17:17 -0400)
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: Dmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
security/integrity/iint.c
security/integrity/ima/ima_api.c
security/integrity/ima/ima_appraise.c
security/integrity/integrity.h

index 74522dbd10a6e093fe293786f83a10ca8d7361bc..c49d3f14cbec96b49e2b8bedf15b4be570c5a7ef 100644 (file)
@@ -70,6 +70,8 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
 
 static void iint_free(struct integrity_iint_cache *iint)
 {
+       kfree(iint->ima_hash);
+       iint->ima_hash = NULL;
        iint->version = 0;
        iint->flags = 0UL;
        iint->ima_file_status = INTEGRITY_UNKNOWN;
index 1dba98e2d7e99b6e2d83b1374427297d6a7c4011..5a7942e20814f880da20fdf5b143c7cdae9a24ab 100644 (file)
@@ -44,7 +44,10 @@ int ima_store_template(struct ima_template_entry *entry,
        const char *op = "add_template_measure";
        const char *audit_cause = "hashing_error";
        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));
        entry->template_name = IMA_TEMPLATE_NAME;
@@ -52,14 +55,14 @@ int ima_store_template(struct ima_template_entry *entry,
 
        if (!violation) {
                result = ima_calc_buffer_hash(&entry->template,
-                                             entry->template_len, &hash);
+                                             entry->template_len, &hash.hdr);
                if (result < 0) {
                        integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
                                            entry->template_name, op,
                                            audit_cause, result, 0);
                        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);
        return result;
@@ -146,6 +149,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
        struct inode *inode = file_inode(file);
        const char *filename = file->f_dentry->d_name.name;
        int result = 0;
+       struct {
+               struct ima_digest_data hdr;
+               char digest[IMA_MAX_DIGEST_SIZE];
+       } hash;
 
        if (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,
                u64 i_version = file_inode(file)->i_version;
 
                /* use default hash algorithm */
-               iint->ima_hash.algo = ima_hash_algo;
+               hash.hdr.algo = ima_hash_algo;
 
                if (xattr_value)
-                       ima_get_hash_algo(*xattr_value, *xattr_len,
-                                         &iint->ima_hash);
+                       ima_get_hash_algo(*xattr_value, *xattr_len, &hash.hdr);
 
-               result = ima_calc_file_hash(file, &iint->ima_hash);
+               result = ima_calc_file_hash(file, &hash.hdr);
                if (!result) {
-                       iint->version = i_version;
-                       iint->flags |= IMA_COLLECTED;
+                       int length = sizeof(hash.hdr) + hash.hdr.length;
+                       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)
@@ -208,21 +222,24 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
                return;
        }
        memset(&entry->template, 0, sizeof(entry->template));
-       if (iint->ima_hash.algo != ima_hash_algo) {
-               struct ima_digest_data hash;
+       if (iint->ima_hash->algo != ima_hash_algo) {
+               struct {
+                       struct ima_digest_data hdr;
+                       char digest[IMA_MAX_DIGEST_SIZE];
+               } hash;
 
-               hash.algo = ima_hash_algo;
-               result = ima_calc_file_hash(file, &hash);
+               hash.hdr.algo = ima_hash_algo;
+               result = ima_calc_file_hash(file, &hash.hdr);
                if (result)
                        integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
                                            filename, "collect_data", "failed",
                                            result, 0);
                else
-                       memcpy(entry->template.digest, hash.digest,
-                              hash.length);
+                       memcpy(entry->template.digest, hash.hdr.digest,
+                              hash.hdr.length);
        } else
-               memcpy(entry->template.digest, iint->ima_hash.digest,
-                      iint->ima_hash.length);
+               memcpy(entry->template.digest, iint->ima_hash->digest,
+                      iint->ima_hash->length);
        strcpy(entry->template.file_name,
               (strlen(filename) > IMA_EVENT_NAME_LEN_MAX) ?
               file->f_dentry->d_name.name : filename);
@@ -238,14 +255,14 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
                           const unsigned char *filename)
 {
        struct audit_buffer *ab;
-       char hash[(iint->ima_hash.length * 2) + 1];
+       char hash[(iint->ima_hash->length * 2) + 1];
        int i;
 
        if (iint->flags & IMA_AUDITED)
                return;
 
-       for (i = 0; i < iint->ima_hash.length; i++)
-               hex_byte_pack(hash + (i * 2), iint->ima_hash.digest[i]);
+       for (i = 0; i < iint->ima_hash->length; i++)
+               hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
        hash[i * 2] = '\0';
 
        ab = audit_log_start(current->audit_context, GFP_KERNEL,
index e1865a6e80ecc5d274658706d13fca3bf332dd0d..116630ca5ff361e0fdc4a77e459a743d1a674d60 100644 (file)
@@ -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,
                         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,
-                                    &iint->ima_hash.type,
-                                    1 + iint->ima_hash.length, 0);
+                                    &iint->ima_hash->type,
+                                    1 + iint->ima_hash->length, 0);
 }
 
 /* Return specific func appraised cached result */
@@ -186,13 +186,13 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
                        status = INTEGRITY_FAIL;
                        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
                           version occupied 20 bytes in xattr, instead of 16
                         */
                        rc = memcmp(xattr_value->digest,
-                                   iint->ima_hash.digest,
-                                   iint->ima_hash.length);
+                                   iint->ima_hash->digest,
+                                   iint->ima_hash->length);
                else
                        rc = -EINVAL;
                if (rc) {
@@ -206,8 +206,8 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
                iint->flags |= IMA_DIGSIG;
                rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
                                             (const char *)xattr_value, rc,
-                                            iint->ima_hash.digest,
-                                            iint->ima_hash.length);
+                                            iint->ima_hash->digest,
+                                            iint->ima_hash->length);
                if (rc == -EOPNOTSUPP) {
                        status = INTEGRITY_UNKNOWN;
                } else if (rc) {
index aead6b2b548846498b4c58bca6e05442d2d83abe..5429ca59125b0ed5c53ef669cfc24f934552caea 100644 (file)
@@ -67,7 +67,7 @@ struct ima_digest_data {
        u8 algo;
        u8 length;
        u8 type;
-       u8 digest[IMA_MAX_DIGEST_SIZE];
+       u8 digest[0];
 } __packed;
 
 /*
@@ -93,7 +93,7 @@ struct integrity_iint_cache {
        enum integrity_status ima_bprm_status:4;
        enum integrity_status ima_module_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