blob: 51af82fa1593de78483b7b5243496de7158b7248 [file] [log] [blame]
/*
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*/
#include <linux/bsearch.h>
#include <linux/dsms.h>
#include <linux/kallsyms.h>
#include <linux/string.h>
#include "dsms_access_control.h"
#include "dsms_debug.h"
typedef int (*cmp_fn_t)(const void *key, const void *element);
/*
* compare_to_policy_entry_key - compare a function name with the function
* name of a policy entry
* @function_name: function name
* @entry: pointer to the policy entry
*
* Returns lexicographic order of the two compared function names
*/
static int compare_policy_entries(const char *function_name,
const struct dsms_policy_entry *entry)
{
return strncmp(function_name, entry->function_name, KSYM_NAME_LEN);
}
/*
* find_policy_entry - find policy entry
* @function_name: function name to find
*
* Returns a pointer to the policy entry for the given function,
* or NULL if not found.
*/
static struct dsms_policy_entry *find_policy_entry(const char *function_name)
{
void *entry;
// see: https://github.com/torvalds/linux/blob/master/lib/bsearch.c
entry = bsearch(function_name,
dsms_policy,
dsms_policy_size(),
(sizeof *dsms_policy),
(cmp_fn_t) compare_policy_entries);
return (struct dsms_policy_entry *)entry;
}
int dsms_verify_access(const void *address)
{
const char *symname;
unsigned long symsize;
unsigned long offset;
char *modname;
char function_name[KSYM_NAME_LEN+1];
int index;
#ifdef DSMS_DEBUG_WHITELIST
printk(DSMS_DEBUG_TAG "dsms_verify_access: "
"Caller function is %pS (%pF)", address, address);
#endif
if (!address) {
#ifdef DSMS_DEBUG_ENABLE
printk(DSMS_DEBUG_TAG "DENY: invalid caller address.");
#endif
return DSMS_DENY;
}
symname = kallsyms_lookup((unsigned long)address,
&symsize, &offset, &modname, function_name);
if (!symname) {
#ifdef DSMS_DEBUG_ENABLE
printk(DSMS_DEBUG_TAG "DENY: caller address not in kallsyms.");
#endif
return DSMS_DENY;
}
function_name[KSYM_NAME_LEN] = 0;
#ifdef DSMS_DEBUG_WHITELIST
printk(DSMS_DEBUG_TAG "kallsyms caller modname = %s, function_name = '%s',"
" offset = 0x%lx", modname, function_name, offset);
#endif
if (modname != NULL) {
#ifdef DSMS_DEBUG_ENABLE
printk(DSMS_DEBUG_TAG "DENY: function '%s' is "
"not a kernel symbol", function_name);
#endif
return DSMS_DENY; // not a kernel symbol
}
#ifdef DSMS_WHITELIST_IGNORE_NAME_SUFFIXES_ENABLE
for (index = 0; index < KSYM_NAME_LEN; index++)
if ((function_name[index] == '.') || (function_name[index] == 0))
break;
function_name[index] = 0;
#endif //DSMS_WHITELIST_IGNORE_NAME_SUFFIXES_ENABLE
if (find_policy_entry(function_name) == NULL) {
#ifdef DSMS_DEBUG_ENABLE
printk(DSMS_DEBUG_TAG "DENY: function '%s': is "
"not allowed by policy", function_name);
#endif
return DSMS_DENY;
}
return DSMS_SUCCESS;
}