/* * Process Authentificator helpers * * Copyright (C) 2017 Samsung Electronics, Inc. * Egor Uleyskiy, * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include "five.h" #include "five_pa.h" #include "five_hooks.h" #include "five_lv.h" #include "five_porting.h" #include "five_testing.h" __visible_for_testing __mockable int call_five_read_xattr(struct dentry *dentry, char **xattr_value) { return five_read_xattr(dentry, xattr_value); } __visible_for_testing __mockable int call_vfs_setxattr_noperm(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { return __vfs_setxattr_noperm(dentry, name, value, size, flags); } __visible_for_testing __mockable bool call_task_integrity_allow_sign(struct task_integrity *intg) { return task_integrity_allow_sign(intg); } #ifdef CONFIG_FIVE_GKI_10 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) #define F_SIGNATURE(file) ((void *)((file)->android_oem_data1)) static inline void f_signature_assign(struct file *file, void *f_signature) { file->android_oem_data1 = (u64)f_signature; } #else #define F_SIGNATURE(file) ((void *)((file)->android_vendor_data1)) static inline void f_signature_assign(struct file *file, void *f_signature) { file->android_vendor_data1 = (u64)f_signature; } #endif #else #define F_SIGNATURE(file) ((file)->f_signature) static inline void f_signature_assign(struct file *file, void *f_signature) { file->f_signature = f_signature; } #endif __visible_for_testing void pa_process_file(struct task_struct *task, struct file *file) { char *xattr_value = NULL; if (five_check_params(task, file)) return; if (F_SIGNATURE(file)) return; call_five_read_xattr(d_real_comp(file->f_path.dentry), &xattr_value); f_signature_assign(file, xattr_value); } void fivepa_fsignature_free(struct file *file) { kfree(F_SIGNATURE(file)); f_signature_assign(file, NULL); } int proca_fcntl_setxattr(struct file *file, void __user *lv_xattr) { struct inode *inode; struct lv lv_hdr = {0}; int rc = -EPERM; void *x = NULL; if (unlikely(!file || !lv_xattr)) return -EINVAL; inode = file_inode(file); if (unlikely(copy_from_user(&lv_hdr, lv_xattr, sizeof(lv_hdr)))) return -EFAULT; if (unlikely(lv_hdr.length > PAGE_SIZE)) return -EINVAL; x = kmalloc(lv_hdr.length, GFP_NOFS); if (unlikely(!x)) return -ENOMEM; if (unlikely(copy_from_user(x, lv_xattr + sizeof(lv_hdr), lv_hdr.length))) { rc = -EFAULT; goto out; } if (file->f_op && file->f_op->flush) if (file->f_op->flush(file, current->files)) { rc = -EOPNOTSUPP; goto out; } inode_lock(inode); if (call_task_integrity_allow_sign(TASK_INTEGRITY(current))) { rc = call_vfs_setxattr_noperm(d_real_comp(file->f_path.dentry), XATTR_NAME_PA, x, lv_hdr.length, 0); } inode_unlock(inode); out: kfree(x); return rc; } static void proca_hook_file_processed(struct task_struct *task, enum task_integrity_value tint_value, struct file *file, void *xattr, size_t xattr_size, int result); static void proca_hook_file_skipped(struct task_struct *task, enum task_integrity_value tint_value, struct file *file); static struct five_hook_list five_ops[] = { FIVE_HOOK_INIT(file_processed, proca_hook_file_processed), FIVE_HOOK_INIT(file_skipped, proca_hook_file_skipped), }; static void proca_hook_file_processed(struct task_struct *task, enum task_integrity_value tint_value, struct file *file, void *xattr, size_t xattr_size, int result) { pa_process_file(task, file); } static void proca_hook_file_skipped(struct task_struct *task, enum task_integrity_value tint_value, struct file *file) { pa_process_file(task, file); } static __init int proca_module_init(void) { five_add_hooks(five_ops, ARRAY_SIZE(five_ops)); pr_info("PROCA was initialized\n"); return 0; } late_initcall(proca_module_init); MODULE_DESCRIPTION("PROCA module"); MODULE_LICENSE("GPL");