misc: Import SM-G900H kernel source code

* Samsung Package Version: G800HXXU1CRJ1
    * CAF Tag: LA.BF.1.1.3-00110-8x26.0
This commit is contained in:
Francescodario Cuzzocrea
2019-08-02 15:14:10 +02:00
parent 9c7c217b9e
commit 85baa390bf
5281 changed files with 2758302 additions and 38068 deletions
+344
View File
@@ -59,8 +59,86 @@
#include <linux/pfn.h>
#include <linux/bsearch.h>
#ifndef CONFIG_TIMA
#undef CONFIG_TIMA_LKMAUTH
#undef CONFIG_TIMA_LKMAUTH_CODE_PROT
#endif
#ifdef CONFIG_TIMA_LKMAUTH_CODE_PROT
#include <asm/tlbflush.h>
#endif/*CONFIG_TIMA_LKMAUTH_CODE_PROT*/
#define CREATE_TRACE_POINTS
#include <trace/events/module.h>
#ifdef CONFIG_TIMA_LKMAUTH_CODE_PROT
#define TIMA_PAC_CMD_ID 0x3f80d221
#define TIMA_SET_PTE_RO 1
#define TIMA_SET_PTE_NX 2
#endif/*CONFIG_TIMA_LKMAUTH_CODE_PROT*/
#ifdef CONFIG_TIMA_LKMAUTH
#include <linux/qseecom.h>
#include <linux/kobject.h>
#define QSEECOM_ALIGN_SIZE 0x40
#define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1)
#define QSEECOM_ALIGN(x) \
((x + QSEECOM_ALIGN_SIZE) & (~QSEECOM_ALIGN_MASK))
struct qseecom_handle {
void *dev; /* in/out */
unsigned char *sbuf; /* in/out */
uint32_t sbuf_len; /* in/out */
};
struct qseecom_handle *qhandle = NULL;
DEFINE_MUTEX(lkmauth_mutex);
extern int qseecom_start_app(struct qseecom_handle **handle, char *app_name, uint32_t size);
extern int qseecom_shutdown_app(struct qseecom_handle **handle);
extern int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, uint32_t sbuf_len, void *resp_buf, uint32_t rbuf_len);
extern struct device *tima_uevent_dev;
#define SVC_LKMAUTH_ID 0x00050000
#define LKMAUTH_CREATE_CMD(x) (SVC_LKMAUTH_ID | x)
#define MODULE_HASH_DIR "/system"
#define MODULE_DIR "/system/lib/modules"
#define HASH_ALGO QSEE_HASH_SHA1
#define HASH_SIZE QSEE_SHA1_HASH_SZ
/**
* Commands for TZ LKMAUTH application.
* */
typedef enum
{
LKMAUTH_CMD_AUTH = LKMAUTH_CREATE_CMD(0x00000000),
LKMAUTH_CMD_UNKNOWN = LKMAUTH_CREATE_CMD(0x7FFFFFFF)
} lkmauth_cmd_type;
/* Message types for every command - Add one here for every command you add */
typedef struct lkmauth_req_s
{
lkmauth_cmd_type cmd_id;
u32 module_addr_start;
u32 module_len;
u32 min;
u32 max;
char module_name [280];
int module_name_len;
} __attribute__ ((packed)) lkmauth_req_t;
typedef struct lkmauth_rsp_s
{
/** First 4 bytes should always be command id */
lkmauth_cmd_type cmd_id;
int ret;
union {
unsigned char hash[20];
char result_ondemand[256];
} __attribute__ ((packed)) result;
} __attribute__ ((packed)) lkmauth_rsp_t;
#endif
#ifndef ARCH_SHF_SMALL
#define ARCH_SHF_SMALL 0
@@ -71,11 +149,15 @@
* to ensure complete separation of code and data, but
* only when CONFIG_DEBUG_SET_MODULE_RONX=y
*/
#ifdef CONFIG_TIMA_LKMAUTH_CODE_PROT
# define debug_align(X) ALIGN(X, PAGE_SIZE)
#else
#ifdef CONFIG_DEBUG_SET_MODULE_RONX
# define debug_align(X) ALIGN(X, PAGE_SIZE)
#else
# define debug_align(X) (X)
#endif
#endif/*CONFIG_TIMA_LKMAUTH_CODE_PROT*/
/*
* Given BASE and SIZE this macro calculates the number of pages the
@@ -2334,6 +2416,132 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
}
#endif /* CONFIG_KALLSYMS */
#ifdef CONFIG_TIMA_LKMAUTH
int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high);
static int lkmauth(Elf_Ehdr *hdr, int len)
{
int ret = 0; /* value to be returned for lkmauth */
int qsee_ret = 0; /* value used to capture qsee return state */
char *envp[3], *status, *result;
char app_name[MAX_APP_NAME_SIZE];
lkmauth_req_t *kreq = NULL;
lkmauth_rsp_t *krsp = NULL;
int req_len = 0, rsp_len = 0;
mutex_lock(&lkmauth_mutex);
pr_warn("TIMA: lkmauth--launch the tzapp to check kernel module; module len is %d\n", len);
snprintf(app_name, MAX_APP_NAME_SIZE, "%s", "tima_lkm");
if ( NULL == qhandle ) {
/* start the lkmauth tzapp only when it is not loaded. */
qsee_ret = qseecom_start_app(&qhandle, app_name, 1024);
}
if ( NULL == qhandle ) {
/* qhandle is still NULL. It seems we couldn't start lkmauth tzapp. */
pr_err("TIMA: lkmauth--cannot get tzapp handle from kernel.\n");
ret = -1; /* lkm authentication failed. */
goto lkmauth_ret; /* leave the function now. */
}
if (qsee_ret) {
/* Another way for lkmauth tzapp loading to fail. */
pr_err("TIMA: lkmauth--cannot load tzapp from kernel; qsee_ret = %d.\n", qsee_ret);
qhandle = NULL; /* Do we have a memory leak this way? */
ret = -1; /* lkm authentication failed. */
goto lkmauth_ret; /* leave the function now. */
}
/* Generate the request cmd to verify hash of ko.
* Note that we are reusing the same buffer for both request and response,
* and the buffer is allocated in qhandle.
*/
kreq = (struct lkmauth_req_s *)qhandle->sbuf;
kreq->cmd_id = LKMAUTH_CMD_AUTH;
pr_warn("TIMA: lkmauth -- hdr before kreq is : %x\n", (u32)hdr);
kreq->module_addr_start = (u32)hdr;
kreq->module_len = len;
req_len = sizeof(lkmauth_req_t);
if (req_len & QSEECOM_ALIGN_MASK)
req_len = QSEECOM_ALIGN(req_len);
/* prepare the response buffer */
krsp =(struct lkmauth_rsp_s *)(qhandle->sbuf + req_len);
rsp_len = sizeof(lkmauth_rsp_t);
if (rsp_len & QSEECOM_ALIGN_MASK)
rsp_len = QSEECOM_ALIGN(rsp_len);
pr_warn("TIMA: lkmauth--send cmd (%s) cmdlen(%d:%d), rsplen(%d:%d) id 0x%08X, \
req (0x%08X), rsp(0x%08X), module_start_addr(0x%08X) module_len %d\n", \
app_name, sizeof(lkmauth_req_t), req_len, sizeof(lkmauth_rsp_t), rsp_len, \
kreq->cmd_id, (int)kreq, (int)krsp, kreq->module_addr_start, kreq->module_len);
qseecom_set_bandwidth(qhandle, true);
flush_cache_all();
qsee_ret = qseecom_send_command(qhandle, kreq, req_len, krsp, rsp_len);
qseecom_set_bandwidth(qhandle, false);
if (qsee_ret) {
pr_err("TIMA: lkmauth--failed to send cmd to qseecom; qsee_ret = %d.\n", qsee_ret);
pr_warn("TIMA: lkmauth--shutting down the tzapp.\n");
qsee_ret = qseecom_shutdown_app(&qhandle);
if ( qsee_ret ) {
/* Failed to shut down the lkmauth tzapp. What will happen to
* the qhandle in this case? Can it be used for the next lkmauth
* invocation?
*/
pr_err("TIMA: lkmauth--failed to shut down the tzapp.\n");
}
else
qhandle = NULL;
ret = -1;
goto lkmauth_ret;
}
/* parse result */
if (krsp->ret == 0) {
pr_warn("TIMA: lkmauth--verification succeeded.\n");
ret = 0; /* ret should already be 0 before the assignment. */
} else {
pr_err("TIMA: lkmauth--verification failed %d\n", krsp->ret);
ret = -1;
/* Send a notification through uevent. Note that the lkmauth tzapp
* should have already raised an alert in TZ Security log.
*/
status = kzalloc(16, GFP_KERNEL);
if (!status) {
pr_err("TIMA: lkmauth--%s kmalloc failed.\n", __func__);
goto lkmauth_ret;
}
snprintf(status , 16 , "TIMA_STATUS=%d", ret);
envp[0] = status;
result = kzalloc(256, GFP_KERNEL);
if (!result) {
pr_err("TIMA: lkmauth--%s kmalloc failed.\n", __func__);
kfree(envp[0]);
goto lkmauth_ret;
}
snprintf(result , 256, "TIMA_RESULT=%s", krsp->result.result_ondemand);
pr_warn("TIMA: %s result (%s) \n", krsp->result.result_ondemand, result);
envp[1] = result;
envp[2] = NULL;
kobject_uevent_env(&tima_uevent_dev->kobj, KOBJ_CHANGE, envp);
kfree(envp[0]);
kfree(envp[1]);
}
lkmauth_ret:
mutex_unlock(&lkmauth_mutex);
return ret;
}
#endif
static void dynamic_debug_setup(struct _ddebug *debug, unsigned int num)
{
if (!debug)
@@ -2434,6 +2642,13 @@ static int copy_and_check(struct load_info *info,
goto free_hdr;
}
#ifdef CONFIG_TIMA_LKMAUTH
if (lkmauth(hdr, len) != 0) {
err = -ENOEXEC;
goto free_hdr;
}
#endif
info->hdr = hdr;
info->len = len;
return 0;
@@ -3004,6 +3219,132 @@ static void do_mod_ctors(struct module *mod)
mod->ctors[i]();
#endif
}
#ifdef CONFIG_TIMA_LKMAUTH_CODE_PROT
#ifndef TIMA_KERNEL_L1_MANAGE
static inline pmd_t *tima_pmd_off_k(unsigned long virt)
{
return pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt);
}
void tima_set_pte_val(unsigned long virt,int numpages,int flags)
{
unsigned long start = virt;
unsigned long end = virt + (numpages << PAGE_SHIFT);
unsigned long pmd_end;
pmd_t *pmd;
pte_t *pte;
while (virt < end)
{
pmd =tima_pmd_off_k(virt);
pmd_end = min(ALIGN(virt + 1, PMD_SIZE), end);
if ((pmd_val(*pmd) & PMD_TYPE_MASK) != PMD_TYPE_TABLE) {
//printk("Not a pagetable\n");
virt = pmd_end;
continue;
}
while (virt < pmd_end)
{
pte = pte_offset_kernel(pmd, virt);
if(flags == TIMA_SET_PTE_RO)
{
/*Make pages readonly*/
ptep_set_wrprotect(current->mm, virt,pte);
}
if(flags == TIMA_SET_PTE_NX)
{
/*Make pages Non Executable*/
ptep_set_nxprotect(current->mm, virt,pte);
}
virt += PAGE_SIZE;
}
}
flush_tlb_kernel_range(start, end);
}
#endif
void tima_mod_send_smc_instruction(unsigned int *vatext,unsigned int *vadata,unsigned int text_count,unsigned int data_count)
{
unsigned long cmd_id = TIMA_PAC_CMD_ID;
/*Call SMC instruction*/
#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
__asm__ __volatile__(".arch_extension sec\n");
#endif
__asm__ __volatile__ (
"stmfd sp!,{r0-r4,r11}\n"
"mov r11, r0\n"
"mov r0, %0\n"
"mov r1, %1\n"
"mov r2, %2\n"
"mov r3, %3\n"
"mov r4, %4\n"
"smc #11\n"
"mov r6, #0\n"
"pop {r0-r4,r11}\n"
"mcr p15, 0, r6, c8, c3, 0\n"
"dsb\n"
"isb\n"
::"r"(cmd_id),"r"(vatext),"r"(text_count),"r"(vadata),"r"(data_count):"r0","r1","r2","r3","r4","r11","cc");
}
/**
* tima_mod_page_change_access - Wrapper function to change access control permissions of pages
*
* It sends code and data pages to secure side to make code pages readonly and data pages non executable
*
*/
void tima_mod_page_change_access(struct module *mod)
{
unsigned int *vatext,*vadata;/* base virtual address of text and data regions*/
unsigned int text_count,data_count;/* Number of text and data pages present in core section */
/*Lets first pickup core section */
vatext = mod->module_core;
vadata = (int *)((char *)(mod->module_core) + mod->core_ro_size);
text_count = ((char *)vadata - (char *)vatext);
data_count = debug_align(mod->core_size) - text_count;
text_count = text_count / PAGE_SIZE;
data_count = data_count / PAGE_SIZE;
/*Should be atleast a page */
if(!text_count)
text_count = 1;
if(!data_count)
data_count = 1;
#ifdef TIMA_KERNEL_L1_MANAGE
/* Change permissive bits for core section*/
tima_mod_send_smc_instruction(vatext,vadata,text_count,data_count);
#else
/* Change permissive bits for core section and making Code read only, Data Non Executable*/
tima_set_pte_val( (unsigned long)vatext,text_count,TIMA_SET_PTE_RO);
tima_set_pte_val( (unsigned long)vadata,data_count,TIMA_SET_PTE_NX);
#endif/*TIMA_KERNEL_L1_MANAGE*/
/*Lets pickup init section */
vatext = mod->module_init;
vadata = (int *)((char *)(mod->module_init) + mod->init_ro_size);
text_count = ((char *)vadata - (char *)vatext);
data_count = debug_align(mod->init_size) - text_count;
text_count = text_count / PAGE_SIZE;
data_count = data_count / PAGE_SIZE;
#ifdef TIMA_KERNEL_L1_MANAGE
/* Change permissive bits for init section*/
tima_mod_send_smc_instruction(vatext,vadata,text_count,data_count);
#else
/* Change permissive bits for init section and making Code read only,Data Non Executable*/
tima_set_pte_val( (unsigned long)vatext,text_count,TIMA_SET_PTE_RO);
tima_set_pte_val( (unsigned long)vadata,data_count,TIMA_SET_PTE_NX);
#endif/*TIMA_KERNEL_L1_MANAGE*/
}
#endif/*CONFIG_TIMA_LKMAUTH_CODE_PROT*/
/* This is where the real work happens */
SYSCALL_DEFINE3(init_module, void __user *, umod,
@@ -3023,6 +3364,9 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_COMING, mod);
#ifdef CONFIG_TIMA_LKMAUTH_CODE_PROT
tima_mod_page_change_access(mod);
#endif/*CONFIG_TIMA_LKMAUTH_CODE_PROT*/
/* Set RO and NX regions for core */
set_section_ro_nx(mod->module_core,