huawei-mrd-kernel/security/hw_root_scan/kcode.c

160 lines
3.5 KiB
C
Raw Permalink Normal View History

/*
* Copyright (c) Huawei Technologies Co., Ltd. 2016-2018. All rights reserved.
* Description: the kcode.c for kernel code integrity checking
* Author: Yongzheng Wu <Wu.Yongzheng@huawei.com>
* likun <quentin.lee@huawei.com>
* likan <likan82@huawei.com>
* Create: 2016-06-18
*/
#include "./include/kcode.h"
#ifdef CONFIG_HW_ROOT_SCAN_ENG_DEBUG
#define MAX_CODE_SIZE (50000000)
#else
#define MAX_CODE_SIZE (30000000)
#endif
static const char *TAG = "kcode";
static const struct memrange {
char *start;
char *end;
} ranges[] = {
{_stext, _etext},
{NULL, NULL}
};
static size_t g_memrange_size;
/* Do sanity check on _stext, __v7_setup_stack, _etext.
* The size of android-msm-hammerhead-3.4-lollipop-release is 14583504.
* We think it's good as long as the size is less than 30M.
*/
static int kcode_verify_ranges(void)
{
const struct memrange *range;
char *ptr = NULL;
g_memrange_size = 0;
for (range = ranges; range->start != NULL; range++) {
if (range->end <= range->start) {
RSLogError(TAG, "range error 1, start=%pK, end=%pK",
range->start, range->end);
return 1;
}
/* kernel code is aligned with 4 bytes */
if (((unsigned int)((range->end - range->start) - 1) > MAX_CODE_SIZE) ||
((uintptr_t)range->start % 4) ||
((uintptr_t)range->end % 4)) {
RSLogError(TAG, "range error 2, start=%pK, end=%pK",
range->start, range->end);
return 1;
}
if ((ptr != NULL) && (range->start <= ptr)) {
RSLogError(TAG, "range error 3, prev=%pK, start=%pK",
ptr, range->start);
return 1;
}
ptr = range->end;
g_memrange_size += (unsigned int)(range->end - range->start);
}
if (g_memrange_size > MAX_CODE_SIZE) {
RSLogError(TAG, "range error 4, g_memrange_size=%zu",
g_memrange_size);
return 1;
}
return 0;
}
int kcode_scan(uint8_t *hash)
{
int i;
int err;
struct crypto_shash *tfm = crypto_alloc_shash("sha256", 0, 0);
SHASH_DESC_ON_STACK(shash, tfm);
if (IS_ERR(tfm)) {
RSLogError(TAG, "crypto_alloc_hash(sha256) error %ld",
PTR_ERR(tfm));
return -ENOMEM;
}
if (g_memrange_size == 0) {
if (kcode_verify_ranges()) {
crypto_free_shash(tfm);
return -ENOMEM;
}
}
shash->tfm = tfm;
shash->flags = 0;
err = crypto_shash_init(shash);
if (err < 0) {
RSLogError(TAG, "crypto_shash_init() error %d", err);
crypto_free_shash(tfm);
return err;
}
for (i = 0; ranges[i].start != NULL; i++) {
crypto_shash_update(shash, (char *)ranges[i].start,
(unsigned int)(ranges[i].end - ranges[i].start));
}
err = crypto_shash_final(shash, (u8 *)hash);
RSLogDebug(TAG, "kscan result %d", err);
crypto_free_shash(tfm);
return err;
}
size_t kcode_get_size(void)
{
return (size_t)(_etext - _stext);
}
void kcode_copy(char *buffer)
{
memcpy(buffer, _stext, (ulong)(_etext - _stext));
}
int kcode_syscall_scan(uint8_t *hash)
{
size_t size;
void *ptr = (void *)sys_call_table;
int err;
struct crypto_shash *tfm = crypto_alloc_shash("sha256", 0, 0);
SHASH_DESC_ON_STACK(shash, tfm);
if (IS_ERR(tfm)) {
RSLogError(TAG, "crypto_alloc_hash(sha256) error %ld",
PTR_ERR(tfm));
return -ENOMEM;
}
shash->tfm = tfm;
shash->flags = 0;
err = crypto_shash_init(shash);
if (err < 0) {
RSLogError(TAG, "crypto_shash_init error %d", err);
crypto_free_shash(tfm);
return err;
}
/* define NR_syscalls as 326 */
size = NR_syscalls * sizeof(void *);
crypto_shash_update(shash, (char *)ptr, (unsigned int)size);
err = crypto_shash_final(shash, (u8 *)hash);
RSLogDebug(TAG, "syscallscan result %d", err);
crypto_free_shash(tfm);
return err;
}