mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
drivers/linux: simplify and fix symbol resolving for kernels >= 5.10
There's no need to have a 'return 0' stub for the static calls. Simply make them call an initialization function that will do the necessary lookup and static call updates. This avoids the need for callers to do the update themselves prior to making use of the functions, as the first user will now do it for us implicitly. Right now we would be doing it ahead of time for 'page_is_ram' users and *always* for users of chipsec_lookup_name(). The latter is clearly unintentional. For kernels that have CONFIG_KPROBES disabled the kprobe based method to get the address of kallsyms_lookup_name() will fail with '-ENOSYS'. Returning this error code in chipsec_lookup_name() isn't appropriate as users will wrongly use it as a function pointer as they expect only NULL as a possible error value. On top of fixing that, remove the ugly #ifdef'ery for 'page_is_ram' users by providing a helper function that does "The Right Thing" depending on the kernel version -- either use the static call or a direct function pointer dereference. Fix a few adjacent whitespace errors while touching the code. Also reduce the visibility of the related symbols by making them static. Last but not least lower the printk level to DEBUG when we fail to register the kprobe. It's not important enough to warrant an "alert". The already existing follow up handling of the failing symbol resolving will provide meaningful messages already. Signed-off-by: Mathias Krause <minipli@grsecurity.net>
This commit is contained in:
committed by
Nathaniel Mitchell
parent
a25b6e85fe
commit
397b1b8d8b
+66
-51
@@ -55,28 +55,17 @@ MODULE_LICENSE("GPL");
|
||||
#include <linux/static_call.h>
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
static struct kprobe kp = {
|
||||
.symbol_name = "kallsyms_lookup_name",
|
||||
.flags = KPROBE_FLAG_DISABLED
|
||||
};
|
||||
|
||||
unsigned long kallsyms_lookup_name_c(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int page_is_ram_c(unsigned long pagenr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_STATIC_CALL(chipsec_lookup_name_sc, kallsyms_lookup_name_c);
|
||||
DEFINE_STATIC_CALL(chipsec_page_is_ram_sc, page_is_ram_c);
|
||||
static unsigned long chipsec_lookup_name_scinit(const char *name);
|
||||
static int chipsec_page_is_ram_scinit(unsigned long pagenr);
|
||||
DEFINE_STATIC_CALL(chipsec_lookup_name_sc, chipsec_lookup_name_scinit);
|
||||
DEFINE_STATIC_CALL(chipsec_page_is_ram_sc, chipsec_page_is_ram_scinit);
|
||||
#endif
|
||||
|
||||
// function page_is_ram is not exported
|
||||
// function page_is_ram is not exported
|
||||
// for modules, but is available in kallsyms.
|
||||
// So we need determine this address using dirty tricks
|
||||
int (*guess_page_is_ram)(unsigned long pagenr);
|
||||
static int (*guess_page_is_ram)(unsigned long pagenr);
|
||||
static int chipsec_page_is_ram(unsigned long pagenr);
|
||||
// same with phys_mem_accesss_prot
|
||||
pgprot_t (*guess_phys_mem_access_prot)(struct file *file, unsigned long pfn,
|
||||
unsigned long size, pgprot_t vma_prot);
|
||||
@@ -321,13 +310,9 @@ void *my_xlate_dev_mem_ptr(unsigned long phys)
|
||||
void *addr=NULL;
|
||||
unsigned long start = phys & PAGE_MASK;
|
||||
unsigned long pfn = PFN_DOWN(phys);
|
||||
|
||||
/* If page is RAM, we can use __va. Otherwise ioremap and unmap. */
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
|
||||
if (static_call(chipsec_page_is_ram_sc)(start >> PAGE_SHIFT)) {
|
||||
#else
|
||||
if ((*guess_page_is_ram)(start >> PAGE_SHIFT)) {
|
||||
#endif
|
||||
|
||||
/* If page is RAM, we can use __va. Otherwise ioremap and unmap. */
|
||||
if (chipsec_page_is_ram(start >> PAGE_SHIFT)) {
|
||||
if (PageHighMem(pfn_to_page(pfn))) {
|
||||
/* The buffer does not have a mapping. Map it! */
|
||||
addr = kmap(pfn_to_page(pfn));
|
||||
@@ -358,17 +343,12 @@ void my_unxlate_dev_mem_ptr(unsigned long phys,void *addr)
|
||||
{
|
||||
unsigned long pfn = PFN_DOWN(phys); //get page number
|
||||
|
||||
/* If page is RAM, check for highmem, and eventualy do nothing.
|
||||
/* If page is RAM, check for highmem, and eventualy do nothing.
|
||||
Otherwise need to iounmap. */
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
|
||||
if (static_call(chipsec_page_is_ram_sc)((phys >> PAGE_SHIFT))) {
|
||||
#else
|
||||
if ((*guess_page_is_ram)(phys >> PAGE_SHIFT)) {
|
||||
#endif
|
||||
|
||||
if (PageHighMem(pfn_to_page(pfn))) {
|
||||
/* Need to kunmap kmaped memory*/
|
||||
kunmap(pfn_to_page(pfn));
|
||||
if (chipsec_page_is_ram((phys >> PAGE_SHIFT))) {
|
||||
if (PageHighMem(pfn_to_page(pfn))) {
|
||||
/* Need to kunmap kmaped memory*/
|
||||
kunmap(pfn_to_page(pfn));
|
||||
dbgprint ("unxlate: Highmem detected");
|
||||
}
|
||||
return;
|
||||
@@ -1743,7 +1723,7 @@ static struct miscdevice chipsec_dev = {
|
||||
*/
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0) && LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0)
|
||||
|
||||
unsigned long chipsec_lookup_name(const char *name)
|
||||
static unsigned long chipsec_lookup_name(const char *name)
|
||||
{
|
||||
unsigned int i = 0, first_space_idx = 0, second_space_idx = 0; /* Read Index and indexes of spaces */
|
||||
struct file *proc_ksyms = NULL;
|
||||
@@ -1815,34 +1795,69 @@ cleanup:
|
||||
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
|
||||
|
||||
unsigned long chipsec_lookup_name(const char *name)
|
||||
{
|
||||
int kp_ret = 0;
|
||||
unsigned long kaddr = 0;
|
||||
static struct kprobe kp = {
|
||||
.symbol_name = "kallsyms_lookup_name",
|
||||
.flags = KPROBE_FLAG_DISABLED
|
||||
};
|
||||
|
||||
unsigned long (*chipsec_lookup_name_fp)(const char *name);
|
||||
static unsigned long chipsec_lookup_name_scinit(const char *name)
|
||||
{
|
||||
unsigned long (*chipsec_lookup_name_fp)(const char *name) = NULL;
|
||||
int kp_ret;
|
||||
|
||||
kp_ret = register_kprobe(&kp);
|
||||
if(kp_ret < 0){
|
||||
printk(KERN_ALERT"register_kprobe failed, returned %d\n", kp_ret);
|
||||
return kp_ret;
|
||||
if (kp_ret < 0) {
|
||||
dbgprint("register_kprobe failed, returned %d", kp_ret);
|
||||
} else {
|
||||
chipsec_lookup_name_fp = (unsigned long (*) (const char *name))kp.addr;
|
||||
unregister_kprobe(&kp);
|
||||
}
|
||||
|
||||
chipsec_lookup_name_fp = (unsigned long (*) (const char *name))kp.addr;
|
||||
unregister_kprobe(&kp);
|
||||
if (chipsec_lookup_name_fp) {
|
||||
static_call_update(chipsec_lookup_name_sc, chipsec_lookup_name_fp);
|
||||
return static_call(chipsec_lookup_name_sc)(name);
|
||||
}
|
||||
|
||||
static_call_update(chipsec_lookup_name_sc, chipsec_lookup_name_fp);
|
||||
kaddr = static_call(chipsec_lookup_name_sc)(name);
|
||||
|
||||
return kaddr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long chipsec_lookup_name(const char *name)
|
||||
{
|
||||
return static_call(chipsec_lookup_name_sc)(name);
|
||||
}
|
||||
|
||||
#else
|
||||
unsigned long chipsec_lookup_name(const char *name){
|
||||
|
||||
static unsigned long chipsec_lookup_name(const char *name){
|
||||
return kallsyms_lookup_name(name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
|
||||
|
||||
static int chipsec_page_is_ram_scinit(unsigned long pagenr)
|
||||
{
|
||||
BUG_ON(guess_page_is_ram == NULL); // resolved in find_symbols()
|
||||
static_call_update(chipsec_page_is_ram_sc, guess_page_is_ram);
|
||||
return static_call(chipsec_page_is_ram_sc)(pagenr);
|
||||
}
|
||||
|
||||
static int chipsec_page_is_ram(unsigned long pagenr)
|
||||
{
|
||||
return static_call(chipsec_page_is_ram_sc)(pagenr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int chipsec_page_is_ram(unsigned long pagenr)
|
||||
{
|
||||
BUG_ON(guess_page_is_ram == NULL); // resolved in find_symbols()
|
||||
return guess_page_is_ram(pagenr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int find_symbols(void)
|
||||
{
|
||||
//Older kernels don't have kallsyms_lookup_name. Use FMEM method (pass from run.sh)
|
||||
|
||||
Reference in New Issue
Block a user