From: Krzysztof Struczynski krzysztof.struczynski@huawei.com
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I49KW1 CVE: NA
--------------------------------
IMA namespace reference will be required in ima_file_free() to check the policy and find inode integrity data for the correct ima namespace. ima_file_free() is called on __fput(), and __fput() may be called after releasing namespaces in exit_task_namespaces() in do_exit() and therefore nsproxy reference cannot be used - it is already set to NULL.
This is a preparation for namespacing policy and inode integrity data.
Signed-off-by: Krzysztof Struczynski krzysztof.struczynski@huawei.com Reviewed-by: Zhang Tianxing zhangtianxing3@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/file_table.c | 6 ++++- include/linux/fs.h | 3 +++ include/linux/ima.h | 6 +++++ security/integrity/ima/ima_main.c | 37 +++++++++++++++++++++++++++++-- 4 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/fs/file_table.c b/fs/file_table.c index 709ada3151da..40020a81c216 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -109,6 +109,8 @@ static struct file *__alloc_file(int flags, const struct cred *cred) return ERR_PTR(error); }
+ ima_file_alloc(f); + atomic_long_set(&f->f_count, 1); rwlock_init(&f->f_owner.lock); spin_lock_init(&f->f_lock); @@ -259,8 +261,10 @@ static void __fput(struct file *file) struct inode *inode = file->f_inode; fmode_t mode = file->f_mode;
- if (unlikely(!(file->f_mode & FMODE_OPENED))) + if (unlikely(!(file->f_mode & FMODE_OPENED))) { + ima_file_free(file); goto out; + }
might_sleep();
diff --git a/include/linux/fs.h b/include/linux/fs.h index 700a262611e7..163a02c780a9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -950,6 +950,9 @@ struct file { struct address_space *f_mapping; errseq_t f_wb_err; errseq_t f_sb_err; /* for syncfs */ +#ifdef CONFIG_IMA + void *f_ima; +#endif } __randomize_layout __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
diff --git a/include/linux/ima.h b/include/linux/ima.h index 77e7f512f61b..88734870af59 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -22,6 +22,7 @@ struct llist_node; extern int ima_bprm_check(struct linux_binprm *bprm); extern int ima_file_check(struct file *file, int mask); extern void ima_post_create_tmpfile(struct inode *inode); +extern int ima_file_alloc(struct file *file); extern void ima_file_free(struct file *file); extern int ima_file_mmap(struct file *file, unsigned long prot); extern int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot); @@ -70,6 +71,11 @@ static inline void ima_post_create_tmpfile(struct inode *inode) { }
+static inline int ima_file_alloc(struct file *file) +{ + return 0; +} + static inline void ima_file_free(struct file *file) { return; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index fbec552886c1..c124ad4f2c82 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -238,6 +238,30 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint, mutex_unlock(&iint->mutex); }
+/** + * ima_file_alloc - called on __alloc_file() + * @file: pointer to file structure being created + * + * Bind IMA namespace to the file descriptor. This is necessary, because + * __fput can be called after exit_task_namespaces() in do_exit(). + * In that case nsproxy is already NULL and ima ns has to be found + * differently in ima_file_free(). If process joins different ima ns, files + * opened in the old ns will point to that (old) ns. + */ +int ima_file_alloc(struct file *file) +{ + /* It is possible that ima_file_alloc() is called after + * exit_task_namespaces(), when IMA does the last writer check from + * __fput(). In that case it's not necessary to store the namespace + * information */ + if (!current->nsproxy) + return 0; + + file->f_ima = get_current_ns(); + get_ima_ns((struct ima_namespace *)file->f_ima); + return 0; +} + /** * ima_file_free - called on __fput() * @file: pointer to file structure being freed @@ -248,15 +272,24 @@ void ima_file_free(struct file *file) { struct inode *inode = file_inode(file); struct integrity_iint_cache *iint; + struct ima_namespace *ima_ns = (struct ima_namespace *)file->f_ima;
- if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + if (!ima_ns) return;
+ if (unlikely(!(file->f_mode & FMODE_OPENED))) + goto out; + + if (!ima_policy_flag || !S_ISREG(inode->i_mode)) + goto out; + iint = integrity_iint_find(inode); if (!iint) - return; + goto out;
ima_check_last_writer(iint, inode, file); +out: + put_ima_ns(ima_ns); }
static int process_measurement(struct file *file, const struct cred *cred,