blob: 3b1179c7684ea126758f30feeeb58ec8b65daf8a [file] [log] [blame]
/*
* Task Integrity Verifier
*
* Copyright (C) 2016 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.
*/
#ifndef _LINUX_TASK_INTEGRITY_H
#define _LINUX_TASK_INTEGRITY_H
#include <linux/atomic.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/dcache.h>
struct linux_binprm;
struct task_integrity;
struct integrity_label {
uint16_t len;
uint8_t data[0];
} __packed;
enum five_event {
FIVE_RESET_INTEGRITY,
FIVE_VERIFY_BUNCH_FILES,
};
/*
* This is list of numbers which Hamming distance is 16
*
* 0x00000000 <-- used
* 0x0f0f0f0f,
* 0xf0f0f0f0,
* 0x0000ffff,
* 0xffff0000,
* 0xff00ff00,
* 0x00ff00ff,
* 0x33333333,<-- used
* 0xcccccccc,<-- used
* 0x55555555,<-- used
* 0x5a5a5a5a,<-- used
* 0xa5a5a5a5,
* 0xaaaaaaaa,<-- used
* 0x3c3c3c3c,<-- used
* 0xc3c3c3c3,
* 0xffffffff <-- used
*/
enum task_integrity_value {
INTEGRITY_NONE = 0x00000000,
INTEGRITY_PRELOAD = 0x33333333,
INTEGRITY_PRELOAD_ALLOW_SIGN = 0xcccccccc,
INTEGRITY_MIXED = 0x55555555,
INTEGRITY_MIXED_ALLOW_SIGN = 0x5a5a5a5a,
INTEGRITY_DMVERITY = 0xaaaaaaaa,
INTEGRITY_DMVERITY_ALLOW_SIGN = 0x3c3c3c3c,
INTEGRITY_PROCESSING = 0xffffffff
};
struct processing_event_list {
enum five_event event;
struct task_struct *task;
struct file *file;
int function;
struct list_head list;
};
enum task_integrity_reset_cause {
CAUSE_UNSET,
CAUSE_UNKNOWN,
CAUSE_MISMATCH_LABEL,
CAUSE_BAD_FS,
CAUSE_NO_CERT,
CAUSE_INVALID_HASH_LENGTH,
CAUSE_INVALID_HEADER,
CAUSE_CALC_HASH_FAILED,
CAUSE_INVALID_LABEL_DATA,
CAUSE_INVALID_SIGNATURE_DATA,
CAUSE_INVALID_HASH,
CAUSE_INVALID_CALC_CERT_HASH,
CAUSE_INVALID_UPDATE_LABEL,
CAUSE_INVALID_SIGNATURE,
CAUSE_UKNOWN_FIVE_DATA,
CAUSE_PTRACE,
CAUSE_VMRW,
CAUSE_EXEC,
CAUSE_TAMPERED,
CAUSE_MAX,
};
struct task_integrity {
enum task_integrity_value user_value;
enum task_integrity_value value;
atomic_t usage_count;
spinlock_t value_lock;
spinlock_t list_lock;
struct integrity_label *label;
struct processing_event_list events;
enum task_integrity_reset_cause reset_cause;
struct file *reset_file;
};
#ifdef CONFIG_FIVE
#ifdef CONFIG_FIVE_GKI_10
#define TASK_INTEGRITY(task) \
((struct task_integrity *)((task)->android_vendor_data1[2]))
static inline void task_integrity_assign(struct task_struct *task,
struct task_integrity *tint)
{
task->android_vendor_data1[2] = (u64)tint;
}
#else
#define TASK_INTEGRITY(task) ((task)->integrity)
static inline void task_integrity_assign(struct task_struct *task,
struct task_integrity *tint)
{
task->integrity = tint;
}
#endif
extern void task_integrity_set_reset_reason(struct task_integrity *intg,
enum task_integrity_reset_cause cause, struct file *file);
struct task_integrity *task_integrity_alloc(void);
void task_integrity_free(struct task_integrity *intg);
void task_integrity_clear(struct task_integrity *tint);
static inline void task_integrity_get(struct task_integrity *intg)
{
BUG_ON(!atomic_read(&intg->usage_count));
atomic_inc(&intg->usage_count);
}
static inline void task_integrity_put(struct task_integrity *intg)
{
BUG_ON(!atomic_read(&intg->usage_count));
if (atomic_dec_and_test(&intg->usage_count))
task_integrity_free(intg);
}
static inline void __task_integrity_set(struct task_integrity *intg,
enum task_integrity_value value)
{
intg->value = value;
}
static inline void task_integrity_set(struct task_integrity *intg,
enum task_integrity_value value)
{
spin_lock(&intg->value_lock);
intg->value = value;
spin_unlock(&intg->value_lock);
}
static inline void task_integrity_reset(struct task_integrity *intg)
{
task_integrity_set(intg, INTEGRITY_NONE);
// If cause is already set, this function will be skipped
task_integrity_set_reset_reason(intg, CAUSE_UNKNOWN, NULL);
}
extern void task_integrity_delayed_reset(struct task_struct *task,
enum task_integrity_reset_cause cause, struct file *file);
static inline enum task_integrity_value task_integrity_read(
struct task_integrity *intg)
{
enum task_integrity_value value;
spin_lock(&intg->value_lock);
value = intg->value;
spin_unlock(&intg->value_lock);
return value;
}
static inline bool task_integrity_value_allow_sign(
enum task_integrity_value tint)
{
if (tint == INTEGRITY_PRELOAD_ALLOW_SIGN
|| tint == INTEGRITY_MIXED_ALLOW_SIGN
|| tint == INTEGRITY_DMVERITY_ALLOW_SIGN) {
return true;
}
return false;
}
/**
* task_integrity_allow_sign - check whether application is allowed to sign
* @intg: pointer to the corresponding integrity struct (Should not be NULL)
*
* On success return true.
*/
static inline bool task_integrity_allow_sign(struct task_integrity *intg)
{
enum task_integrity_value tint =
task_integrity_read(intg);
return task_integrity_value_allow_sign(tint);
}
static inline enum task_integrity_value task_integrity_user_read(
struct task_integrity *intg)
{
return intg->user_value;
}
static inline void task_integrity_user_set(struct task_integrity *intg,
enum task_integrity_value value)
{
intg->user_value = value;
}
static inline void task_integrity_reset_both(struct task_integrity *intg)
{
task_integrity_reset(intg);
intg->user_value = INTEGRITY_NONE;
}
extern int task_integrity_copy(struct task_integrity *from,
struct task_integrity *to);
extern int five_bprm_check(struct linux_binprm *bprm);
extern void five_file_free(struct file *file);
extern int five_file_mmap(struct file *file, unsigned long prot);
extern int five_file_open(struct file *file);
extern int five_file_verify(struct task_struct *task, struct file *file);
extern void five_task_free(struct task_struct *task);
extern void five_inode_post_setattr(struct task_struct *tsk,
struct dentry *dentry);
extern int five_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len);
extern int five_inode_removexattr(struct dentry *dentry,
const char *xattr_name);
extern int five_fcntl_sign(struct file *file,
struct integrity_label __user *label);
extern int five_fcntl_verify_async(struct file *file);
extern int five_fcntl_verify_sync(struct file *file);
extern int five_fcntl_edit(struct file *file);
extern int five_fcntl_close(struct file *file);
extern int five_fcntl_debug(struct file *file, void __user *arg);
extern int five_fork(struct task_struct *task, struct task_struct *child_task);
extern int five_ptrace(struct task_struct *task, long request);
extern int five_process_vm_rw(struct task_struct *task, int write);
extern char const * const tint_reset_cause_to_string(
enum task_integrity_reset_cause cause);
#else
#define TASK_INTEGRITY(task) (NULL)
static inline void task_integrity_assign(struct task_struct *task,
struct task_integrity *tint)
{
}
static inline struct task_integrity *task_integrity_alloc(void)
{
return NULL;
}
static inline void task_integrity_free(struct task_integrity *intg)
{
}
static inline void task_integrity_clear(struct task_integrity *tint)
{
}
static inline void task_integrity_set(struct task_integrity *intg,
enum task_integrity_value value)
{
}
static inline void task_integrity_reset(struct task_integrity *intg)
{
}
static inline enum task_integrity_value task_integrity_read(
struct task_integrity *intg)
{
return INTEGRITY_NONE;
}
static inline void task_integrity_user_set(struct task_integrity *intg,
enum task_integrity_value value)
{
}
static inline enum task_integrity_value task_integrity_user_read(
struct task_integrity *intg)
{
return INTEGRITY_NONE;
}
static inline void task_integrity_delayed_reset(struct task_struct *task,
enum task_integrity_reset_cause cause, struct file *file)
{
}
static inline void task_integrity_reset_both(struct task_integrity *intg)
{
}
static inline void task_integrity_add_file(struct task_integrity *intg)
{
}
static inline void task_integrity_report_file(struct task_integrity *intg)
{
}
static inline int five_bprm_check(struct linux_binprm *bprm)
{
return 0;
}
static inline void five_file_free(struct file *file)
{
}
static inline int five_file_mmap(struct file *file, unsigned long prot)
{
return 0;
}
static inline int five_file_open(struct file *file)
{
return 0;
}
static inline int five_file_verify(struct task_struct *task, struct file *file)
{
return 0;
}
static inline void five_task_free(struct task_struct *task)
{
}
static inline void five_inode_post_setattr(struct task_struct *tsk,
struct dentry *dentry)
{
}
static inline int five_inode_setxattr(struct dentry *dentry,
const char *xattr_name,
const void *xattr_value,
size_t xattr_value_len)
{
return 0;
}
static inline int five_inode_removexattr(struct dentry *dentry,
const char *xattr_name)
{
return 0;
}
static inline int five_fcntl_sign(struct file *file,
struct integrity_label __user *label)
{
return 0;
}
static inline int five_fcntl_verify_async(struct file *file)
{
return 0;
}
static inline int five_fcntl_verify_sync(struct file *file)
{
return 0;
}
static inline int five_fcntl_edit(struct file *file)
{
return 0;
}
static inline int five_fcntl_close(struct file *file)
{
return 0;
}
static inline int five_fcntl_debug(struct file *file, void __user *arg)
{
return 0;
}
static inline int five_fork(struct task_struct *task,
struct task_struct *child_task)
{
return 0;
}
static inline int five_ptrace(struct task_struct *task, long request)
{
return 0;
}
static inline int five_process_vm_rw(struct task_struct *task, int write)
{
return 0;
}
static inline int task_integrity_copy(struct task_integrity *from,
struct task_integrity *to)
{
return 0;
}
static inline char const * const tint_reset_cause_to_string(
enum task_integrity_reset_cause cause)
{
return NULL;
}
static inline void task_integrity_set_reset_reason(struct task_integrity *intg,
enum task_integrity_reset_cause cause, struct file *file)
{
}
#endif
#endif /* _LINUX_TASK_INTEGRITY_H */