| /* |
| * 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 */ |