You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

187 lines
4.4 KiB

/*
* Process Authentificator helpers
*
* Copyright (C) 2017 Samsung Electronics, Inc.
* Egor Uleyskiy, <e.uleyskiy@samsung.com>
*
* 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 <linux/file.h>
#include <linux/module.h>
#include <linux/task_integrity.h>
#include <linux/proca.h>
#include <linux/version.h>
#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");