Using kallsyms to Obtain Any Kernel Symbol

Suppose that you want to call a Linux kernel function such as ptrace_request() from your guru mode SystemTap script. You can see it in the headers, you can see it in /proc/kallsyms, but when you reference it from a SystemTap script the generated code fails to compile with a linker error.

The reason is that ptrace_request() is missing from the kernel's Module.symvers (which can be found in /usr/src/). A symbol must be added to Module.symvers for the linker to be able to find it when building an out-of-tree kernel module, which is what SystemTap modules are.

A symbol is only added to Module.symvers if it was declared with EXPORT_SYMBOL*(). You can see other functions in the linux source code have an EXPORT_SYMBOL*() annotation but ptrace_request() does not:

In the SystemTap runtime, we do call a few of the non-EXPORTed symbols. (An example can be found in the stp_utrace code.) The workaround we employ is to explicitly look up the address of the function with kallsyms_lookup_name() and then cast it to a function type copied from the kernel-internal header file, as follows:

%{
// Copy original declaration from the header:
extern int ptrace_request(struct task_struct *child, long request,
unsigned long addr, unsigned long data);

// First typedef from the original decl, then #define as typecasted call.
typedef typeof(&ptrace_request) ptrace_request_fn;
#define ptrace_request (* (ptrace_request_fn)kallsyms_ptrace_request)
void *kallsyms_ptrace_request = NULL;
%}

// Make sure to put this code somewhere that will execute
// before your first call to the function:
function init() %{
  kallysms_ptrace_request = (void*)kallsyms_lookup_name("ptrace_request");
%}

You can also use this trick in a guru-mode SystemTap script.

None: GuruModeKallsyms (last edited 2019-05-16 20:19:13 by SerheiMakarov)