6

I am wanting to use the function getname in my kernel module. It is not exported. Since I am running into this problem right now, I would like to know how to access and use any kernel symbol that is not exported. I figure that the steps necessary to use one will differ depending what the symbol is, so I'd like to see how it would be done for a type (e.g., a struct), a variable, a table of pointers (like the system call table), and a function. How can these be done in either of these cases:

  • When I know the address of the symbol from System.map or /proc/kallsyms.
  • When I know the name of the symbol and want to use kallsyms_lookup_name in retrieving it.

I currently know how to hijack system calls and this requires declaring something like

asmlinkage <return_type> (*<name_for_system_call>)(<the types of the its arguments separated by commas>);

Would something like that be used? In this answer to another question, the example presented by the poster is

#include <linux/kallsyms.h>

static void (*machine_power_off_p)(void);
machine_power_off = (void*) kallsyms_lookup_name("machine_power_off");

But what if the symbol returns a pointer? Would I place an asterisk to the left of (*machine_power_off_p)?

Melab
  • 2,594
  • 7
  • 30
  • 51
  • "Would I place an asterisk to the left of the first set of parentheses?" Which parentheses? There are lots of parentheses in your question. So are you asking how to invoke a function pointer? Google should be able to tell you that. For example: [How do function pointers in C work?](http://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work) – kaylum Nov 04 '16 at 20:38
  • @kaylum The first set in the example right above that question. – Melab Nov 04 '16 at 21:43
  • 1
    `But what if the symbol returns a pointer?` - Then replace *left* `void` in the example with returning type (e.g., `struct filename *`). The question is actually about usage of pointer-to-functions, as kaylum have noticed. – Tsyvarev Nov 04 '16 at 21:53

2 Answers2

4

#include <linux/fs.h> declares extern struct filename *getname(const char __user *);. A pointer to this function has type struct filename *(*)(const char __user *). If declaring a variable of that type, the variable name goes after the * in (*). So you can declare a variable of that type and assign the return value of kallsyms_lookup_name("getname") to it as follows:

static struct filename *(*getname_p)(const char __user *);

/* within a function body... */
getname_p = (struct filename *(*)(const char __user *))
            kallsyms_lookup_name("getname");

For your other case where you want to use a numeric address, just replace the kallsyms_lookup_name function call with the actual number (kallsyms_lookup_name returns the symbol value as a number anyway).

EDIT 2021-01-19

The GCC typeof extension can be used to copy the prototype of getname from #include <linux/fs.h> to the getname_p pointer as follows:

#include <linux/fs.h>

static typeof(&getname) getname_p;

/* within a function body... */
getname_p = (typeof(&getname))kallsyms_lookup_name("getname");

EDIT 2021-05-17

From the 5.7 kernel onwards kallsyms_lookup_name and kallsyms_on_each_symbol are no longer exported to loadable kernel modules.

Ian Abbott
  • 15,083
  • 19
  • 33
  • Is there anyway to define the function as `getname` instead of `getname_p`? Can it be done in such a way as to not require looking up the original function's declaration? – Melab Jan 19 '21 at 02:23
  • @Melab The function pointer variable cannot be called `getname` unless it is declared in an inner scope (such as within a function body) because it would conflict with the declaration of the `getname` function declared by `#include `. However, you can simplify the declaration of the `getname_p` variable and the casting of the return value of `kallsyms_lookup_name` by making use of the GCC `typeof` extension, as shown in my edited answer above. – Ian Abbott Jan 19 '21 at 10:13
0

Accessing not exported function doesn't differ from accessing exported functions, except that you can't resolve its address in kernel. You can do trick like this:

static void (*your_func)(void);
your_func=0xhex_addr;

or for struct

strucr your_struct{int i;double j} *stru;
stru=0xhex_addr;

Type of a pointer just defines how many bytes would be read or written from or to pointer's address.

For structure or variable hex address even may reside in kernel code segment, but you'll get segmentation fault if you'll try to write something to that struct or var - reading would be legit. And one more thing... when doing this trick with structure don't forget about structure data alignment.

nopasara
  • 538
  • 3
  • 10