summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/ima_policy2
-rw-r--r--include/linux/ima.h6
-rw-r--r--security/integrity/evm/evm_crypto.c33
-rw-r--r--security/integrity/ima/ima.h1
-rw-r--r--security/integrity/ima/ima_api.c5
-rw-r--r--security/integrity/ima/ima_appraise.c3
-rw-r--r--security/integrity/ima/ima_main.c38
-rw-r--r--security/integrity/ima/ima_policy.c7
-rw-r--r--security/security.c7
9 files changed, 67 insertions, 35 deletions
diff --git a/Documentation/ABI/testing/ima_policy b/Documentation/ABI/testing/ima_policy
index db17fc8a0c9f..49db0ff288e5 100644
--- a/Documentation/ABI/testing/ima_policy
+++ b/Documentation/ABI/testing/ima_policy
@@ -35,7 +35,7 @@ Description:
[FIRMWARE_CHECK]
[KEXEC_KERNEL_CHECK] [KEXEC_INITRAMFS_CHECK]
[KEXEC_CMDLINE] [KEY_CHECK] [CRITICAL_DATA]
- [SETXATTR_CHECK]
+ [SETXATTR_CHECK][MMAP_CHECK_REQPROT]
mask:= [[^]MAY_READ] [[^]MAY_WRITE] [[^]MAY_APPEND]
[[^]MAY_EXEC]
fsmagic:= hex value
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 172b113a9864..86b57757c7b1 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -21,7 +21,8 @@ extern int ima_file_check(struct file *file, int mask);
extern void ima_post_create_tmpfile(struct mnt_idmap *idmap,
struct inode *inode);
extern void ima_file_free(struct file *file);
-extern int ima_file_mmap(struct file *file, unsigned long prot);
+extern int ima_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags);
extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot);
extern int ima_load_data(enum kernel_load_data_id id, bool contents);
extern int ima_post_load_data(char *buf, loff_t size,
@@ -76,7 +77,8 @@ static inline void ima_file_free(struct file *file)
return;
}
-static inline int ima_file_mmap(struct file *file, unsigned long prot)
+static inline int ima_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags)
{
return 0;
}
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 52b811da6989..033804f5a5f2 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -183,8 +183,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
* Dump large security xattr values as a continuous ascii hexademical string.
* (pr_debug is limited to 64 bytes.)
*/
-static void dump_security_xattr(const char *prefix, const void *src,
- size_t count)
+static void dump_security_xattr_l(const char *prefix, const void *src,
+ size_t count)
{
#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
char *asciihex, *p;
@@ -200,6 +200,16 @@ static void dump_security_xattr(const char *prefix, const void *src,
#endif
}
+static void dump_security_xattr(const char *name, const char *value,
+ size_t value_len)
+{
+ if (value_len < 64)
+ pr_debug("%s: (%zu) [%*phN]\n", name, value_len,
+ (int)value_len, value);
+ else
+ dump_security_xattr_l(name, value, value_len);
+}
+
/*
* Calculate the HMAC value across the set of protected security xattrs.
*
@@ -254,15 +264,9 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
if (is_ima)
ima_present = true;
- if (req_xattr_value_len < 64)
- pr_debug("%s: (%zu) [%*phN]\n", req_xattr_name,
- req_xattr_value_len,
- (int)req_xattr_value_len,
- req_xattr_value);
- else
- dump_security_xattr(req_xattr_name,
- req_xattr_value,
- req_xattr_value_len);
+ dump_security_xattr(req_xattr_name,
+ req_xattr_value,
+ req_xattr_value_len);
continue;
}
size = vfs_getxattr_alloc(&nop_mnt_idmap, dentry, xattr->name,
@@ -286,12 +290,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
if (is_ima)
ima_present = true;
- if (xattr_size < 64)
- pr_debug("%s: (%zu) [%*phN]", xattr->name, xattr_size,
- (int)xattr_size, xattr_value);
- else
- dump_security_xattr(xattr->name, xattr_value,
- xattr_size);
+ dump_security_xattr(xattr->name, xattr_value, xattr_size);
}
hmac_add_misc(desc, inode, type, data->digest);
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index d8530e722515..c29db699c996 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -190,6 +190,7 @@ static inline unsigned int ima_hash_key(u8 *digest)
hook(NONE, none) \
hook(FILE_CHECK, file) \
hook(MMAP_CHECK, mmap) \
+ hook(MMAP_CHECK_REQPROT, mmap_reqprot) \
hook(BPRM_CHECK, bprm) \
hook(CREDS_CHECK, creds) \
hook(POST_SETATTR, post_setattr) \
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 9345fd66f5b8..d3662f4acadc 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -179,7 +179,8 @@ err_out:
* subj=, obj=, type=, func=, mask=, fsmagic=
* subj,obj, and type: are LSM specific.
* func: FILE_CHECK | BPRM_CHECK | CREDS_CHECK | MMAP_CHECK | MODULE_CHECK
- * | KEXEC_CMDLINE | KEY_CHECK | CRITICAL_DATA
+ * | KEXEC_CMDLINE | KEY_CHECK | CRITICAL_DATA | SETXATTR_CHECK
+ * | MMAP_CHECK_REQPROT
* mask: contains the permission mask
* fsmagic: hex value
*
@@ -292,7 +293,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
result = ima_calc_file_hash(file, &hash.hdr);
}
- if (result == -ENOMEM)
+ if (result && result != -EBADF && result != -EINVAL)
goto out;
length = sizeof(hash.hdr) + hash.hdr.length;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 555342d337f9..491c1aca0b1c 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -111,6 +111,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
{
switch (func) {
case MMAP_CHECK:
+ case MMAP_CHECK_REQPROT:
return iint->ima_mmap_status;
case BPRM_CHECK:
return iint->ima_bprm_status;
@@ -131,6 +132,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
{
switch (func) {
case MMAP_CHECK:
+ case MMAP_CHECK_REQPROT:
iint->ima_mmap_status = status;
break;
case BPRM_CHECK:
@@ -155,6 +157,7 @@ static void ima_cache_flags(struct integrity_iint_cache *iint,
{
switch (func) {
case MMAP_CHECK:
+ case MMAP_CHECK_REQPROT:
iint->flags |= (IMA_MMAP_APPRAISED | IMA_APPRAISED);
break;
case BPRM_CHECK:
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 358578267fea..d66a0a36415e 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -89,7 +89,8 @@ static int mmap_violation_check(enum ima_hooks func, struct file *file,
struct inode *inode;
int rc = 0;
- if ((func == MMAP_CHECK) && mapping_writably_mapped(file->f_mapping)) {
+ if ((func == MMAP_CHECK || func == MMAP_CHECK_REQPROT) &&
+ mapping_writably_mapped(file->f_mapping)) {
rc = -ETXTBSY;
inode = file_inode(file);
@@ -227,7 +228,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
action = ima_get_action(file_mnt_idmap(file), inode, cred, secid,
mask, func, &pcr, &template_desc, NULL,
&allowed_algos);
- violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
+ violation_check = ((func == FILE_CHECK || func == MMAP_CHECK ||
+ func == MMAP_CHECK_REQPROT) &&
(ima_policy_flag & IMA_MEASURE));
if (!action && !violation_check)
return 0;
@@ -337,7 +339,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
rc = ima_collect_measurement(iint, file, buf, size, hash_algo, modsig);
- if (rc == -ENOMEM)
+ if (rc != 0 && rc != -EBADF && rc != -EINVAL)
goto out_locked;
if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */
@@ -397,7 +399,9 @@ out:
/**
* ima_file_mmap - based on policy, collect/store measurement.
* @file: pointer to the file to be measured (May be NULL)
- * @prot: contains the protection that will be applied by the kernel.
+ * @reqprot: protection requested by the application
+ * @prot: protection that will be applied by the kernel
+ * @flags: operational flags
*
* Measure files being mmapped executable based on the ima_must_measure()
* policy decision.
@@ -405,15 +409,27 @@ out:
* On success return 0. On integrity appraisal error, assuming the file
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/
-int ima_file_mmap(struct file *file, unsigned long prot)
+int ima_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags)
{
u32 secid;
+ int ret;
- if (file && (prot & PROT_EXEC)) {
- security_current_getsecid_subj(&secid);
+ if (!file)
+ return 0;
+
+ security_current_getsecid_subj(&secid);
+
+ if (reqprot & PROT_EXEC) {
+ ret = process_measurement(file, current_cred(), secid, NULL,
+ 0, MAY_EXEC, MMAP_CHECK_REQPROT);
+ if (ret)
+ return ret;
+ }
+
+ if (prot & PROT_EXEC)
return process_measurement(file, current_cred(), secid, NULL,
0, MAY_EXEC, MMAP_CHECK);
- }
return 0;
}
@@ -454,6 +470,10 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
action = ima_get_action(file_mnt_idmap(vma->vm_file), inode,
current_cred(), secid, MAY_EXEC, MMAP_CHECK,
&pcr, &template, NULL, NULL);
+ action |= ima_get_action(file_mnt_idmap(vma->vm_file), inode,
+ current_cred(), secid, MAY_EXEC,
+ MMAP_CHECK_REQPROT, &pcr, &template, NULL,
+ NULL);
/* Is the mmap'ed file in policy? */
if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK)))
@@ -563,7 +583,7 @@ static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
* ima_file_hash can be called when ima_collect_measurement has still
* not been called, we might not always have a hash.
*/
- if (!iint->ima_hash) {
+ if (!iint->ima_hash || !(iint->flags & IMA_COLLECTED)) {
mutex_unlock(&iint->mutex);
return -EOPNOTSUPP;
}
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index fc128a6b4abe..3ca8b7348c2e 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -697,6 +697,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
switch (func) {
case MMAP_CHECK:
+ case MMAP_CHECK_REQPROT:
return IMA_MMAP_APPRAISE;
case BPRM_CHECK:
return IMA_BPRM_APPRAISE;
@@ -1266,6 +1267,7 @@ static bool ima_validate_rule(struct ima_rule_entry *entry)
case NONE:
case FILE_CHECK:
case MMAP_CHECK:
+ case MMAP_CHECK_REQPROT:
case BPRM_CHECK:
case CREDS_CHECK:
case POST_SETATTR:
@@ -1504,6 +1506,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
else if ((strcmp(args[0].from, "FILE_MMAP") == 0)
|| (strcmp(args[0].from, "MMAP_CHECK") == 0))
entry->func = MMAP_CHECK;
+ else if ((strcmp(args[0].from, "MMAP_CHECK_REQPROT") == 0))
+ entry->func = MMAP_CHECK_REQPROT;
else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
entry->func = BPRM_CHECK;
else if (strcmp(args[0].from, "CREDS_CHECK") == 0)
@@ -1955,7 +1959,8 @@ ssize_t ima_parse_add_rule(char *rule)
}
/**
- * ima_delete_rules() called to cleanup invalid in-flight policy.
+ * ima_delete_rules() - called to cleanup invalid in-flight policy.
+ *
* We don't need locking as we operate on the temp list, which is
* different from the active one. There is also only one user of
* ima_delete_rules() at a time.
diff --git a/security/security.c b/security/security.c
index 4e1150c44ab7..cf6cc576736f 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1661,12 +1661,13 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot)
int security_mmap_file(struct file *file, unsigned long prot,
unsigned long flags)
{
+ unsigned long prot_adj = mmap_prot(file, prot);
int ret;
- ret = call_int_hook(mmap_file, 0, file, prot,
- mmap_prot(file, prot), flags);
+
+ ret = call_int_hook(mmap_file, 0, file, prot, prot_adj, flags);
if (ret)
return ret;
- return ima_file_mmap(file, prot);
+ return ima_file_mmap(file, prot, prot_adj, flags);
}
int security_mmap_addr(unsigned long addr)