On Thu, 2023-01-26 at 17:38 +0100, Roberto Sassu wrote:
> From: Roberto Sassu <roberto.sassu@huawei.com>
>
> Commit 98de59bfe4b2f ("take calculation of final prot in
> security_mmap_file() into a helper") caused ima_file_mmap() to receive the
> protections requested by the application and not those applied by the
> kernel.
>
> After restoring the original MMAP_CHECK behavior with a patch, existing
> systems might be broken due to not being ready to handle new entries
> (previously missing) in the IMA measurement list.
Is this a broken system or a broken attestation server? The
attestation server might not be able to handle the additional
measurements, but the system, itself, is not broken.
"with a patch" is unnecessary.
>
> Restore the original correct MMAP_CHECK behavior instead of keeping the
^ add missing comma after "behavior"
> current buggy one and introducing a new hook with the correct behavior. The
> second option
^ The second option -> Otherwise,
> would have had the risk of IMA users not noticing the problem
> at all, as they would actively have to update the IMA policy, to switch to
> the correct behavior.
>
> Also, introduce the new MMAP_CHECK_REQPROT hook to keep the current
> behavior, so that IMA users could easily fix a broken system, although this
> approach is discouraged due to potentially missing measurements.
Again, is this a broken system or a broken attestation server?
>
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
Otherwise, the patch looks good.
On Sun, 2023-01-29 at 09:52 -0500, Mimi Zohar wrote:
> On Thu, 2023-01-26 at 17:38 +0100, Roberto Sassu wrote:
> > From: Roberto Sassu <roberto.sassu@huawei.com>
> >
> > Commit 98de59bfe4b2f ("take calculation of final prot in
> > security_mmap_file() into a helper") caused ima_file_mmap() to receive the
> > protections requested by the application and not those applied by the
> > kernel.
> >
> > After restoring the original MMAP_CHECK behavior with a patch, existing
> > systems might be broken due to not being ready to handle new entries
> > (previously missing) in the IMA measurement list.
>
> Is this a broken system or a broken attestation server? The
> attestation server might not be able to handle the additional
> measurements, but the system, itself, is not broken.
Ok, wasn't clear. I meant attestation server. The system itself is not
broken.
> "with a patch" is unnecessary.
Ok.
> > Restore the original correct MMAP_CHECK behavior instead of keeping the
>
> ^ add missing comma after "behavior"
>
> > current buggy one and introducing a new hook with the correct behavior. The
> > second option
>
> ^ The second option -> Otherwise,
>
> > would have had the risk of IMA users not noticing the problem
> > at all, as they would actively have to update the IMA policy, to switch to
> > the correct behavior.
> >
> > Also, introduce the new MMAP_CHECK_REQPROT hook to keep the current
> > behavior, so that IMA users could easily fix a broken system, although this
> > approach is discouraged due to potentially missing measurements.
>
> Again, is this a broken system or a broken attestation server?
>
> > Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
>
> Otherwise, the patch looks good.
Ok, will make the changes.
Thanks
Roberto
@@ -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
@@ -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) \
@@ -179,7 +179,8 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
* 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
*
@@ -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:
@@ -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_user_ns(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;
@@ -411,12 +413,23 @@ 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;
}
@@ -457,6 +470,10 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode,
current_cred(), secid, MAY_EXEC, MMAP_CHECK,
&pcr, &template, NULL, NULL);
+ action |= ima_get_action(file_mnt_user_ns(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)))
@@ -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)