forked from rubenslte/android_kernel_samsung_msm8226
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:
+344
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user