Skip to content

Commit c7aaee4

Browse files
committed
refactor: enhance ftrace integration and symbol resolution in HymoFS
- Introduced a fallback mechanism for ftrace symbol resolution, utilizing kallsyms to ensure compatibility with kernels that do not export certain symbols. - Updated the handling of kretprobe instances to improve data management and organization, particularly in the context of ftrace callbacks. - Enhanced logging for ftrace registration and resolution processes, providing clearer feedback on the status of symbol lookups and potential issues. - Refactored the Makefile to ensure ftrace support is always compiled, improving the overall robustness of the HymoFS module.
1 parent 3bbbc0b commit c7aaee4

4 files changed

Lines changed: 185 additions & 53 deletions

File tree

src/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ obj-m += hymofs_lkm.o
88
hymofs_lkm-objs := hymofs_core.o hymofs_tracepoint.o hymofs_ftrace.o
99

1010
ccflags-y += -gz=none
11+
# Ftrace: always compile (headers need types); runtime __symbol_get, fallback to kprobes if unavailable.
12+
# CONFIG_FUNCTION_TRACER: ftrace_func_t typedef in ftrace.h (pulled in via kprobes.h).
13+
ccflags-y += -DCONFIG_DYNAMIC_FTRACE=1 -DCONFIG_FUNCTION_TRACER=1
1114
# Do NOT add -fno-sanitize=cfi here: init/exit must have kernel-expected CFI type for
1215
# do_one_initcall. Use HYMO_NOCFI only on functions that make indirect calls to resolved symbols.
1316

src/hymofs_core.c

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
#include <linux/module.h>
1717
#include <linux/kernel.h>
1818
#include <linux/kallsyms.h>
19+
#ifndef arch_ftrace_get_regs
20+
#define arch_ftrace_get_regs(fregs) (NULL)
21+
#endif
1922
#include <linux/kprobes.h>
2023
#include <linux/errno.h>
2124
#include <linux/string.h>
@@ -295,8 +298,21 @@ static char *(*hymo_d_absolute_path)(const struct path *, char *, int);
295298
static char *(*hymo_dentry_path_raw)(const struct dentry *, char *, int);
296299
static char *(*hymo_d_path)(const struct path *, char *, int);
297300
static struct dentry *(*hymo_d_hash_and_lookup)(struct dentry *, const struct qstr *);
298-
/* d_real_inode: get real (e.g. lower) inode for overlay; used for statfs f_type passthrough */
299-
static struct inode *(*hymo_d_real_inode)(struct dentry *);
301+
/* d_real_inode: get real (e.g. lower) inode for overlay; used for statfs f_type passthrough.
302+
* d_real_inode is static inline in kernel, not in kallsyms. Use d_op->d_real when DCACHE_OP_REAL. */
303+
#ifndef D_REAL_DATA
304+
#define D_REAL_DATA 0
305+
#endif
306+
static struct inode *hymo_d_real_inode_impl(struct dentry *dentry)
307+
{
308+
struct dentry *real;
309+
310+
if (unlikely(dentry->d_flags & DCACHE_OP_REAL) && dentry->d_op && dentry->d_op->d_real) {
311+
real = dentry->d_op->d_real(dentry, D_REAL_DATA);
312+
return real && real->d_inode ? real->d_inode : dentry->d_inode;
313+
}
314+
return dentry->d_inode;
315+
}
300316
/* path_put, dput, dget, iput, iterate_dir: use kernel exports directly (EXPORT_SYMBOL), no lookup */
301317

302318
/* vfs_getxattr addr for resolving source path's SELinux context (set when xattr kretprobe registered) */
@@ -3035,11 +3051,10 @@ static int hymo_statfs_entry(struct kretprobe_instance *ri, struct pt_regs *regs
30353051
if (hymo_kern_path(path_buf, 0, &p) != 0)
30363052
return 0;
30373053
if ((unsigned long)p.dentry->d_sb->s_magic == OVERLAYFS_SUPER_MAGIC) {
3038-
real_ino = hymo_d_real_inode ? hymo_d_real_inode(p.dentry) : NULL;
3054+
real_ino = hymo_d_real_inode_impl(p.dentry);
30393055
if (real_ino && real_ino->i_sb != p.dentry->d_sb)
30403056
d->spoof_f_type = (unsigned long)real_ino->i_sb->s_magic;
30413057
else
3042-
/* Fallback when d_real_inode missing (e.g. older kernel): use EROFS to match typical resolved type */
30433058
d->spoof_f_type = (unsigned long)EROFS_SUPER_MAGIC;
30443059
}
30453060
path_put(&p);
@@ -3116,7 +3131,7 @@ static struct kretprobe hymo_krp_cmdline_read = {
31163131
* iterate_dir: filldir filter (runs in fs callback context, not kprobe)
31173132
* ====================================================================== */
31183133

3119-
static HYMO_NOCFI HYMO_FILLDIR_RET_TYPE
3134+
HYMO_NOCFI HYMO_FILLDIR_RET_TYPE
31203135
hymofs_filldir_filter(struct dir_context *ctx, const char *name,
31213136
int namlen, loff_t offset, u64 ino, unsigned int d_type)
31223137
{
@@ -4333,9 +4348,7 @@ static int __init hymofs_lkm_init(void)
43334348
pr_warn("HymoFS: d_path not found, path resolution in populate/merge/hide may fail\n");
43344349
if (!hymo_d_hash_and_lookup)
43354350
pr_warn("HymoFS: d_hash_and_lookup not found, merge dedup and hide filter disabled\n");
4336-
hymo_d_real_inode = (void *)hymofs_lookup_name("d_real_inode");
4337-
if (!hymo_d_real_inode)
4338-
pr_warn("HymoFS: d_real_inode not found, statfs f_type passthrough (real lower fs) disabled\n");
4351+
/* d_real_inode is inline in kernel; we use hymo_d_real_inode_impl via d_op->d_real */
43394352
if (!hymo_filp_open || !hymo_kernel_read)
43404353
pr_warn("HymoFS: filp_open/kernel_read not found, allowlist disabled\n");
43414354
/* Prefer __ksu_is_allow_uid_for_current (handles uid 0) over __ksu_is_allow_uid */
@@ -4700,16 +4713,16 @@ static int __init hymofs_lkm_init(void)
47004713
#if HYMOFS_VFS_KPROBES
47014714
if (!hymo_skip_vfs_param) {
47024715
/* Install VFS hooks: try ftrace (entry) + kretprobe (exit) first,
4703-
* fallback to kprobe+kretprobe. getname_flags always uses kprobe. */
4716+
* fallback to kprobe+kretprobe only if ftrace unavailable. getname_flags uses kprobe. */
47044717
{
47054718
size_t i;
47064719
int ret;
47074720
size_t start_idx = (hymofs_tracepoint_path_registered() ? 1 : 0);
47084721

4709-
#ifdef CONFIG_DYNAMIC_FTRACE
47104722
{
47114723
unsigned long ft_addr[4];
47124724

4725+
pr_info("HymoFS: trying ftrace for VFS entry (preferred over kprobes)\n");
47134726
ret = hymofs_ftrace_try_register(ft_addr);
47144727
if (ret == 0) {
47154728
hymo_vfs_getxattr_addr = (void *)ft_addr[3];
@@ -4756,10 +4769,9 @@ static int __init hymofs_lkm_init(void)
47564769
unregister_kretprobe(&hymo_krp_vfs_getxattr);
47574770
}
47584771
} else {
4759-
pr_warn("HymoFS: ftrace registration failed: %d, falling back to kprobes\n", ret);
4772+
pr_info("HymoFS: ftrace unavailable (err=%d), using kprobes\n", ret);
47604773
}
47614774
}
4762-
#endif
47634775

47644776
/* getname_flags: always kprobe (needs skip-original) */
47654777
if (start_idx == 0) {
@@ -4956,31 +4968,28 @@ static void __exit hymofs_lkm_exit(void)
49564968
#if HYMOFS_VFS_KPROBES
49574969
hymofs_tracepoint_path_exit();
49584970
if (!hymo_skip_vfs_param) {
4959-
#ifdef CONFIG_DYNAMIC_FTRACE
4960-
if (hymo_vfs_use_ftrace) {
4961-
hymofs_ftrace_unregister();
4962-
if (hymo_getxattr_kprobe_registered)
4963-
unregister_kretprobe(&hymo_krp_vfs_getxattr);
4964-
unregister_kretprobe(&hymo_krp_iterate_dir);
4965-
unregister_kretprobe(&hymo_krp_d_path);
4966-
unregister_kretprobe(&hymo_krp_vfs_getattr);
4967-
if (hymo_getname_kprobe_registered)
4968-
unregister_kprobe(&hymofs_kprobes[0]);
4969-
} else
4970-
#endif
4971-
{
4972-
if (hymo_getxattr_kprobe_registered)
4973-
unregister_kretprobe(&hymo_krp_vfs_getxattr);
4974-
unregister_kretprobe(&hymo_krp_iterate_dir);
4975-
unregister_kretprobe(&hymo_krp_d_path);
4976-
unregister_kretprobe(&hymo_krp_vfs_getattr);
4977-
{
4978-
size_t i, start = hymofs_tracepoint_path_registered() ? 1 : 0;
4979-
for (i = start; i < HYMOFS_VFS_HOOK_COUNT; i++)
4980-
unregister_kprobe(&hymofs_kprobes[i]);
4971+
if (hymo_vfs_use_ftrace) {
4972+
hymofs_ftrace_unregister();
4973+
if (hymo_getxattr_kprobe_registered)
4974+
unregister_kretprobe(&hymo_krp_vfs_getxattr);
4975+
unregister_kretprobe(&hymo_krp_iterate_dir);
4976+
unregister_kretprobe(&hymo_krp_d_path);
4977+
unregister_kretprobe(&hymo_krp_vfs_getattr);
4978+
if (hymo_getname_kprobe_registered)
4979+
unregister_kprobe(&hymofs_kprobes[0]);
4980+
} else {
4981+
if (hymo_getxattr_kprobe_registered)
4982+
unregister_kretprobe(&hymo_krp_vfs_getxattr);
4983+
unregister_kretprobe(&hymo_krp_iterate_dir);
4984+
unregister_kretprobe(&hymo_krp_d_path);
4985+
unregister_kretprobe(&hymo_krp_vfs_getattr);
4986+
{
4987+
size_t i, start = hymofs_tracepoint_path_registered() ? 1 : 0;
4988+
for (i = start; i < HYMOFS_VFS_HOOK_COUNT; i++)
4989+
unregister_kprobe(&hymofs_kprobes[i]);
4990+
}
49814991
}
49824992
}
4983-
}
49844993
#endif
49854994

49864995
/* Clean up all rules and wait for RCU grace period */

0 commit comments

Comments
 (0)