Brad Bishop | 15ae250 | 2019-06-18 21:44:24 -0400 | [diff] [blame^] | 1 | From baaec960e9e7be0b526eaf831b079ddfe5c15124 Mon Sep 17 00:00:00 2001 |
| 2 | From: Mimi Zohar <zohar@linux.vnet.ibm.com> |
| 3 | Date: Thu, 10 Mar 2016 18:19:20 +0200 |
| 4 | Subject: [PATCH] ima: add support for creating files using the mknodat |
| 5 | syscall |
| 6 | |
| 7 | Commit 3034a14 "ima: pass 'opened' flag to identify newly created files" |
| 8 | stopped identifying empty files as new files. However new empty files |
| 9 | can be created using the mknodat syscall. On systems with IMA-appraisal |
| 10 | enabled, these empty files are not labeled with security.ima extended |
| 11 | attributes properly, preventing them from subsequently being opened in |
| 12 | order to write the file data contents. This patch marks these empty |
| 13 | files, created using mknodat, as new in order to allow the file data |
| 14 | contents to be written. |
| 15 | |
| 16 | Files with security.ima xattrs containing a file signature are considered |
| 17 | "immutable" and can not be modified. The file contents need to be |
| 18 | written, before signing the file. This patch relaxes this requirement |
| 19 | for new files, allowing the file signature to be written before the file |
| 20 | contents. |
| 21 | |
| 22 | Upstream-Status: Accepted [https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/security/integrity/ima/ima_appraise.c?id=05d1a717ec0430c916a749b94eb90ab74bbfa356] |
| 23 | |
| 24 | Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com> |
| 25 | --- |
| 26 | fs/namei.c | 2 ++ |
| 27 | include/linux/ima.h | 7 ++++++- |
| 28 | security/integrity/ima/ima_appraise.c | 3 +++ |
| 29 | security/integrity/ima/ima_main.c | 32 +++++++++++++++++++++++++++++++- |
| 30 | 4 files changed, 42 insertions(+), 2 deletions(-) |
| 31 | |
| 32 | diff --git a/fs/namei.c b/fs/namei.c |
| 33 | index ccd7f98..19502da 100644 |
| 34 | --- a/fs/namei.c |
| 35 | +++ b/fs/namei.c |
| 36 | @@ -3526,6 +3526,8 @@ retry: |
| 37 | switch (mode & S_IFMT) { |
| 38 | case 0: case S_IFREG: |
| 39 | error = vfs_create(path.dentry->d_inode,dentry,mode,true); |
| 40 | + if (!error) |
| 41 | + ima_post_path_mknod(dentry); |
| 42 | break; |
| 43 | case S_IFCHR: case S_IFBLK: |
| 44 | error = vfs_mknod(path.dentry->d_inode,dentry,mode, |
| 45 | diff --git a/include/linux/ima.h b/include/linux/ima.h |
| 46 | index 120ccc5..7f51971 100644 |
| 47 | --- a/include/linux/ima.h |
| 48 | +++ b/include/linux/ima.h |
| 49 | @@ -20,7 +20,7 @@ extern void ima_file_free(struct file *file); |
| 50 | extern int ima_file_mmap(struct file *file, unsigned long prot); |
| 51 | extern int ima_module_check(struct file *file); |
| 52 | extern int ima_fw_from_file(struct file *file, char *buf, size_t size); |
| 53 | - |
| 54 | +extern void ima_post_path_mknod(struct dentry *dentry); |
| 55 | #else |
| 56 | static inline int ima_bprm_check(struct linux_binprm *bprm) |
| 57 | { |
| 58 | @@ -52,6 +52,11 @@ static inline int ima_fw_from_file(struct file *file, char *buf, size_t size) |
| 59 | return 0; |
| 60 | } |
| 61 | |
| 62 | +static inline void ima_post_path_mknod(struct dentry *dentry) |
| 63 | +{ |
| 64 | + return; |
| 65 | +} |
| 66 | + |
| 67 | #endif /* CONFIG_IMA */ |
| 68 | |
| 69 | #ifdef CONFIG_IMA_APPRAISE |
| 70 | diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c |
| 71 | index 4df493e..20806ea 100644 |
| 72 | --- a/security/integrity/ima/ima_appraise.c |
| 73 | +++ b/security/integrity/ima/ima_appraise.c |
| 74 | @@ -274,6 +274,11 @@ out: |
| 75 | xattr_value->type != EVM_IMA_XATTR_DIGSIG)) { |
| 76 | if (!ima_fix_xattr(dentry, iint)) |
| 77 | status = INTEGRITY_PASS; |
| 78 | + } else if ((inode->i_size == 0) && |
| 79 | + (iint->flags & IMA_NEW_FILE) && |
| 80 | + (xattr_value && |
| 81 | + xattr_value->type == EVM_IMA_XATTR_DIGSIG)) { |
| 82 | + status = INTEGRITY_PASS; |
| 83 | } |
| 84 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename, |
| 85 | op, cause, rc, 0); |
| 86 | diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c |
| 87 | index eeee00dc..705bf78 100644 |
| 88 | --- a/security/integrity/ima/ima_main.c |
| 89 | +++ b/security/integrity/ima/ima_main.c |
| 90 | @@ -242,7 +242,8 @@ static int process_measurement(struct file *file, int mask, int function, |
| 91 | ima_audit_measurement(iint, pathname); |
| 92 | |
| 93 | out_digsig: |
| 94 | - if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG)) |
| 95 | + if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) && |
| 96 | + !(iint->flags & IMA_NEW_FILE)) |
| 97 | rc = -EACCES; |
| 98 | kfree(xattr_value); |
| 99 | out_free: |
| 100 | @@ -310,6 +311,35 @@ int ima_file_check(struct file *file, int mask, int opened) |
| 101 | EXPORT_SYMBOL_GPL(ima_file_check); |
| 102 | |
| 103 | /** |
| 104 | + * ima_post_path_mknod - mark as a new inode |
| 105 | + * @dentry: newly created dentry |
| 106 | + * |
| 107 | + * Mark files created via the mknodat syscall as new, so that the |
| 108 | + * file data can be written later. |
| 109 | + */ |
| 110 | +void ima_post_path_mknod(struct dentry *dentry) |
| 111 | +{ |
| 112 | + struct integrity_iint_cache *iint; |
| 113 | + struct inode *inode; |
| 114 | + int must_appraise; |
| 115 | + |
| 116 | + if (!dentry || !dentry->d_inode) |
| 117 | + return; |
| 118 | + |
| 119 | + inode = dentry->d_inode; |
| 120 | + if (inode->i_size != 0) |
| 121 | + return; |
| 122 | + |
| 123 | + must_appraise = ima_must_appraise(inode, MAY_ACCESS, FILE_CHECK); |
| 124 | + if (!must_appraise) |
| 125 | + return; |
| 126 | + |
| 127 | + iint = integrity_inode_get(inode); |
| 128 | + if (iint) |
| 129 | + iint->flags |= IMA_NEW_FILE; |
| 130 | +} |
| 131 | + |
| 132 | +/** |
| 133 | * ima_module_check - based on policy, collect/store/appraise measurement. |
| 134 | * @file: pointer to the file to be measured/appraised |
| 135 | * |
| 136 | -- |
| 137 | 2.5.0 |
| 138 | |