KASAN reported a stack-out-of-bounds access in ima_appraise_measurement
from is_bprm_creds_for_exec:

BUG: KASAN: stack-out-of-bounds in ima_appraise_measurement+0x12dc/0x16a0
 Read of size 1 at addr ffffc9000160f940 by task sudo/550
The buggy address belongs to stack of task sudo/550
and is located at offset 24 in frame:
  ima_appraise_measurement+0x0/0x16a0
This frame has 2 objects:
  [48, 56) 'file'
  [80, 148) 'hash'

This is caused by using container_of on the *file pointer. This offset
calculation is what triggers the stack-out-of-bounds error.

In order to fix this, pass in a bprm_is_check boolean which can be set
depending on how process_measurement is called. If the caller has a
linux_binprm pointer and the function is BPRM_CHECK we can determine
is_check and set it then. Otherwise set it to false.

Fixes: 95b3cdafd7cb7 ("ima: instantiate the bprm_creds_for_exec() hook")

Signed-off-by: Chris J Arges <[email protected]>
---
 security/integrity/ima/ima.h          |  4 ++--
 security/integrity/ima/ima_appraise.c | 15 ++-------------
 security/integrity/ima/ima_main.c     | 18 +++++++++---------
 3 files changed, 13 insertions(+), 24 deletions(-)

diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index e3d71d8d56e3..2c9e50c02634 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -441,7 +441,7 @@ int ima_check_blacklist(struct ima_iint_cache *iint,
 int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
                             struct file *file, const unsigned char *filename,
                             struct evm_ima_xattr_data *xattr_value,
-                            int xattr_len, const struct modsig *modsig);
+                            int xattr_len, const struct modsig *modsig, bool 
bprm_is_check);
 int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode,
                      int mask, enum ima_hooks func);
 void ima_update_xattr(struct ima_iint_cache *iint, struct file *file);
@@ -466,7 +466,7 @@ static inline int ima_appraise_measurement(enum ima_hooks 
func,
                                           const unsigned char *filename,
                                           struct evm_ima_xattr_data 
*xattr_value,
                                           int xattr_len,
-                                          const struct modsig *modsig)
+                                          const struct modsig *modsig, bool 
bprm_is_check)
 {
        return INTEGRITY_UNKNOWN;
 }
diff --git a/security/integrity/ima/ima_appraise.c 
b/security/integrity/ima/ima_appraise.c
index 5149ff4fd50d..ea2079417318 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -470,17 +470,6 @@ int ima_check_blacklist(struct ima_iint_cache *iint,
        return rc;
 }
 
-static bool is_bprm_creds_for_exec(enum ima_hooks func, struct file *file)
-{
-       struct linux_binprm *bprm;
-
-       if (func == BPRM_CHECK) {
-               bprm = container_of(&file, struct linux_binprm, file);
-               return bprm->is_check;
-       }
-       return false;
-}
-
 /*
  * ima_appraise_measurement - appraise file measurement
  *
@@ -492,7 +481,7 @@ static bool is_bprm_creds_for_exec(enum ima_hooks func, 
struct file *file)
 int ima_appraise_measurement(enum ima_hooks func, struct ima_iint_cache *iint,
                             struct file *file, const unsigned char *filename,
                             struct evm_ima_xattr_data *xattr_value,
-                            int xattr_len, const struct modsig *modsig)
+                            int xattr_len, const struct modsig *modsig, bool 
bprm_is_check)
 {
        static const char op[] = "appraise_data";
        int audit_msgno = AUDIT_INTEGRITY_DATA;
@@ -514,7 +503,7 @@ int ima_appraise_measurement(enum ima_hooks func, struct 
ima_iint_cache *iint,
         * of the script interpreter(userspace). Differentiate kernel and
         * userspace enforced integrity audit messages.
         */
-       if (is_bprm_creds_for_exec(func, file))
+       if (bprm_is_check)
                audit_msgno = AUDIT_INTEGRITY_USERSPACE;
 
        /* If reading the xattr failed and there's no modsig, error out. */
diff --git a/security/integrity/ima/ima_main.c 
b/security/integrity/ima/ima_main.c
index 5770cf691912..36ce07063dc7 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -236,7 +236,7 @@ static void ima_file_free(struct file *file)
 static int process_measurement(struct file *file, const struct cred *cred,
                               struct lsm_prop *prop, char *buf, loff_t size,
                               int mask, enum ima_hooks func,
-                              enum kernel_read_file_id read_id)
+                              enum kernel_read_file_id read_id, bool 
bprm_is_check)
 {
        struct inode *real_inode, *inode = file_inode(file);
        struct ima_iint_cache *iint = NULL;
@@ -426,7 +426,7 @@ static int process_measurement(struct file *file, const 
struct cred *cred,
                        inode_lock(inode);
                        rc = ima_appraise_measurement(func, iint, file,
                                                      pathname, xattr_value,
-                                                     xattr_len, modsig);
+                                                     xattr_len, modsig, 
bprm_is_check);
                        inode_unlock(inode);
                }
                if (!rc)
@@ -493,14 +493,14 @@ static int ima_file_mmap(struct file *file, unsigned long 
reqprot,
 
        if (reqprot & PROT_EXEC) {
                ret = process_measurement(file, current_cred(), &prop, NULL,
-                                         0, MAY_EXEC, MMAP_CHECK_REQPROT, 0);
+                                         0, MAY_EXEC, MMAP_CHECK_REQPROT, 0, 
false);
                if (ret)
                        return ret;
        }
 
        if (prot & PROT_EXEC)
                return process_measurement(file, current_cred(), &prop, NULL,
-                                          0, MAY_EXEC, MMAP_CHECK, 0);
+                                          0, MAY_EXEC, MMAP_CHECK, 0, false);
 
        return 0;
 }
@@ -584,7 +584,7 @@ static int ima_bprm_check(struct linux_binprm *bprm)
 
        security_current_getlsmprop_subj(&prop);
        return process_measurement(bprm->file, current_cred(),
-                                  &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0);
+                                  &prop, NULL, 0, MAY_EXEC, BPRM_CHECK, 0, 
bprm->is_check);
 }
 
 /**
@@ -614,7 +614,7 @@ static int ima_creds_check(struct linux_binprm *bprm, const 
struct file *file)
 
        security_current_getlsmprop_subj(&prop);
        return process_measurement((struct file *)file, bprm->cred, &prop, NULL,
-                                  0, MAY_EXEC, CREDS_CHECK, 0);
+                                  0, MAY_EXEC, CREDS_CHECK, 0, false);
 }
 
 /**
@@ -662,7 +662,7 @@ static int ima_file_check(struct file *file, int mask)
        security_current_getlsmprop_subj(&prop);
        return process_measurement(file, current_cred(), &prop, NULL, 0,
                                   mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
-                                          MAY_APPEND), FILE_CHECK, 0);
+                                          MAY_APPEND), FILE_CHECK, 0, false);
 }
 
 static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
@@ -881,7 +881,7 @@ static int ima_read_file(struct file *file, enum 
kernel_read_file_id read_id,
        func = read_idmap[read_id] ?: FILE_CHECK;
        security_current_getlsmprop_subj(&prop);
        return process_measurement(file, current_cred(), &prop, NULL, 0,
-                                  MAY_READ, func, 0);
+                                  MAY_READ, func, 0, false);
 }
 
 const int read_idmap[READING_MAX_ID] = {
@@ -925,7 +925,7 @@ static int ima_post_read_file(struct file *file, char *buf, 
loff_t size,
        func = read_idmap[read_id] ?: FILE_CHECK;
        security_current_getlsmprop_subj(&prop);
        return process_measurement(file, current_cred(), &prop, buf, size,
-                                  MAY_READ, func, read_id);
+                                  MAY_READ, func, read_id, false);
 }
 
 /**
-- 
2.43.0


Reply via email to