History

ima: verify mprotect change is consistent with mmap policy

Files can be mmap'ed read/write and later changed to execute to circumvent IMA's mmap appraise policy rules. Due to locking issues (mmap semaphore would be taken prior to i_mutex), files can not be measured or appraised at this point. Eliminate this integrity gap, by denying the mprotect PROT_EXECUTE change, if an mmap appraise policy rule exists. On mprotect change success, return 0. On failure, return -EACESS.

Mimi Zohar committed 6 years ago

Commit 8eb613c1 parent 0c4395f3 files · +64 −1Browse files

Unified · Split

3 files
  1. include/linux/ima.h +7 −0
  2. security/integrity/ima/ima_main.c +51 −0
  3. security/security.c +6 −1
include/linux/ima.h+7−0
@@ -18,6 +18,7 @@ extern int ima_file_check(struct file *file, int mask); · 17 unmodified lines
1818 extern void ima_post_create_tmpfile(struct inode *inode);
1919 extern void ima_file_free(struct file *file);
2020 extern int ima_file_mmap(struct file *file, unsigned long prot);
21+extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot);
2122 extern int ima_load_data(enum kernel_load_data_id id);
2223 extern int ima_read_file(struct file *file, enum kernel_read_file_id id);
2324 extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
@@ -70,6 +71,12 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot) · 46 unmodified lines
7071 return 0;
7172 }
7273
74+static inline int ima_file_mprotect(struct vm_area_struct *vma,
75+ unsigned long prot)
76+{
77+ return 0;
78+}
79+
7380 static inline int ima_load_data(enum kernel_load_data_id id)
7481 {
7582 return 0;
security/integrity/ima/ima_main.c+51−0
@@ -393,6 +393,57 @@ int ima_file_mmap(struct file *file, unsigned long prot) · 392 unmodified lines
393393 return 0;
394394 }
395395
396+/**
397+ * ima_file_mprotect - based on policy, limit mprotect change
398+ * @prot: contains the protection that will be applied by the kernel.
399+ *
400+ * Files can be mmap'ed read/write and later changed to execute to circumvent
401+ * IMA's mmap appraisal policy rules. Due to locking issues (mmap semaphore
402+ * would be taken before i_mutex), files can not be measured or appraised at
403+ * this point. Eliminate this integrity gap by denying the mprotect
404+ * PROT_EXECUTE change, if an mmap appraise policy rule exists.
405+ *
406+ * On mprotect change success, return 0. On failure, return -EACESS.
407+ */
408+int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
409+{
410+ struct ima_template_desc *template;
411+ struct file *file = vma->vm_file;
412+ char filename[NAME_MAX];
413+ char *pathbuf = NULL;
414+ const char *pathname = NULL;
415+ struct inode *inode;
416+ int result = 0;
417+ int action;
418+ u32 secid;
419+ int pcr;
420+
421+ /* Is mprotect making an mmap'ed file executable? */
422+ if (!vma->vm_file || !(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC))
423+ return 0;
424+
425+ security_task_getsecid(current, &secid);
426+ inode = file_inode(vma->vm_file);
427+ action = ima_get_action(inode, current_cred(), secid, MAY_EXEC,
428+ MMAP_CHECK, &pcr, &template, 0);
429+
430+ /* Is the mmap'ed file in policy? */
431+ if (!(action & (IMA_MEASURE | IMA_APPRAISE_SUBMASK)))
432+ return 0;
433+
434+ if (action & IMA_APPRAISE_SUBMASK)
435+ result = -EPERM;
436+
437+ file = vma->vm_file;
438+ pathname = ima_d_path(&file->f_path, &pathbuf, filename);
439+ integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, pathname,
440+ "collect_data", "failed-mprotect", result, 0);
441+ if (pathbuf)
442+ __putname(pathbuf);
443+
444+ return result;
445+}
446+
396447 /**
397448 * ima_bprm_check - based on policy, collect/store measurement.
398449 * @bprm: contains the linux_binprm structure
security/security.c+6−1
@@ -1512,7 +1512,12 @@ int security_mmap_addr(unsigned long addr) · 1511 unmodified lines
15121512 int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
15131513 unsigned long prot)
15141514 {
1515− return call_int_hook(file_mprotect, 0, vma, reqprot, prot);
1515+ int ret;
1516+
1517+ ret = call_int_hook(file_mprotect, 0, vma, reqprot, prot);
1518+ if (ret)
1519+ return ret;
1520+ return ima_file_mprotect(vma, prot);
15161521 }
15171522
15181523 int security_file_lock(struct file *file, unsigned int cmd)