| |
| #include <linux/kernel.h> |
| #include <linux/verify.h> |
| #include <linux/module.h> |
| |
| #include <linux/fs.h> |
| |
| int verify_super_block(const struct super_block *sb) |
| { |
| int ret; |
| |
| ret = kernel_rodata_address((unsigned long)sb->s_op); |
| WARN_ONCE(!ret, "superblock: struct super_operations %pS is not const!", sb->s_op); |
| |
| return ret; |
| } |
| |
| int verify_file_operations(const struct file_operations *fops) |
| { |
| int ret = 0; |
| |
| if (IS_ERR_OR_NULL(fops)) |
| return 0; |
| |
| if (!kernel_rodata_address((unsigned long)fops)) { |
| WARN_ONCE(1, "struct file_operations %pS (%p) is not const!", fops, fops); |
| ret = -EINVAL; |
| } |
| |
| /* check if owner is set correctly */ |
| if (fops->owner != __module_address((unsigned long)fops)) { |
| WARN_ONCE(1, "struct file_operations %pS has .owner not set correctly", fops); |
| ret = -EINVAL; |
| } |
| |
| return ret; |
| } |
| |
| int verify_struct_file(struct file *filp) |
| { |
| int ret = 0; |
| |
| if (IS_ERR_OR_NULL(filp)) |
| return 0; |
| |
| if (verify_file_operations(filp->f_op)) { |
| WARN_ONCE(1, "struct file %pS does not have a const f_ops %pS\n", filp, filp->f_op); |
| ret = -EINVAL; |
| } |
| |
| return ret; |
| } |
| |
| int verify_address_space(struct address_space *as) |
| { |
| int ret = 0; |
| |
| if (!kernel_rodata_address((unsigned long)as->a_ops)) { |
| WARN_ONCE(1, "struct address space %pS has non-const a_ops %pS\n", as, as->a_ops); |
| ret = -EINVAL; |
| } |
| return ret; |
| } |