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
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");
|
|
|