Files
vendor-reset/src/ftrace.c
Alyssa Ross 4b466e92a2 Fix GCC declaration-after-statement error
Since upgrading to Linux v5.18 in Nixpkgs, we've been seeing an
"ISO C90 forbids mixed declarations and code" error from GCC.

This patch fixes it by initializing regs as part of its declaration,
meaning hook will no longer be declared after a statement.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2022-09-29 16:27:23 +10:00

132 lines
3.5 KiB
C

/*
Vendor Reset - Vendor Specific Reset
Copyright (C) 2020 Geoffrey McRae <geoff@hostfission.com>
Copyright (C) 2020 Adam Madsen <adam@ajmadsen.com>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kallsyms.h>
#include <linux/kernel.h>
#include <linux/ftrace.h>
#include <linux/kprobes.h>
#include <linux/pci.h>
#include <linux/version.h>
#include "ftrace.h"
/*
* Much of this file was inspired by https://www.apriorit.com/dev-blog/546-hooking-linux-functions-2
*
* Honestly the whole removal of kallsyms_lookup_name is hella fishy, Google.
* Thank you, Filip Pynckels
* http://users.telenet.be/pynckels/2020-2-Linux-kernel-unexported-kallsyms-functions.pdf
*/
static int resolve_hook_address(struct ftrace_hook *hook)
{
struct kprobe kp = { .symbol_name = hook->name };
if (register_kprobe(&kp))
{
pr_warn("unresolved symbol %s\n", hook->name);
return -ENOENT;
}
hook->address = (unsigned long)kp.addr;
unregister_kprobe(&kp);
*((unsigned long *)hook->original) = hook->address;
return 0;
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0))
static void notrace fh_trace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *regs)
{
#else
static void notrace fh_trace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct ftrace_regs *fregs)
{
struct pt_regs *regs = ftrace_get_regs(fregs);
#endif
struct ftrace_hook *hook = to_ftrace_hook(ops);
if (!within_module(parent_ip, THIS_MODULE))
regs->ip = (unsigned long)hook->function;
}
int fh_install_hook(struct ftrace_hook *hook)
{
int err;
err = resolve_hook_address(hook);
if (err)
return err;
hook->ops.func = fh_trace_thunk;
hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS |
FTRACE_OPS_FL_IPMODIFY;
err = ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0);
if (err)
{
pr_warn("ftrace_set_filter_ip() failed: %d\n", err);
return err;
}
err = register_ftrace_function(&hook->ops);
if (err)
{
pr_warn("register_ftrace_function() failed in fh_install_hook: %d\n", err);
ftrace_set_filter_ip(&hook->ops, hook->address, 1, 0);
return err;
}
return 0;
}
void fh_remove_hook(struct ftrace_hook *hook)
{
int err;
err = unregister_ftrace_function(&hook->ops);
if (err)
{
pr_warn("unregister_ftrace_function() failed: %d\n", err);
}
err = ftrace_set_filter_ip(&hook->ops, hook->address, 1, 0);
if (err)
{
pr_warn("ftrace_set_filter_ip() failed in fh_remove_hook: %d\n", err);
}
}
int fh_install_hooks(struct ftrace_hook *hooks)
{
int ret;
struct ftrace_hook *hook;
for (hook = hooks; hook->name; ++hook)
if ((ret = fh_install_hook(hook)))
return ret;
return 0;
}
void fh_remove_hooks(struct ftrace_hook *hooks)
{
struct ftrace_hook *hook;
for (hook = hooks; hook->name; ++hook)
fh_remove_hook(hook);
}