|
16 | 16 | #include <linux/module.h> |
17 | 17 | #include <linux/kernel.h> |
18 | 18 | #include <linux/kallsyms.h> |
| 19 | +#ifndef arch_ftrace_get_regs |
| 20 | +#define arch_ftrace_get_regs(fregs) (NULL) |
| 21 | +#endif |
19 | 22 | #include <linux/kprobes.h> |
20 | 23 | #include <linux/errno.h> |
21 | 24 | #include <linux/string.h> |
@@ -295,8 +298,21 @@ static char *(*hymo_d_absolute_path)(const struct path *, char *, int); |
295 | 298 | static char *(*hymo_dentry_path_raw)(const struct dentry *, char *, int); |
296 | 299 | static char *(*hymo_d_path)(const struct path *, char *, int); |
297 | 300 | 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 | +} |
300 | 316 | /* path_put, dput, dget, iput, iterate_dir: use kernel exports directly (EXPORT_SYMBOL), no lookup */ |
301 | 317 |
|
302 | 318 | /* 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 |
3035 | 3051 | if (hymo_kern_path(path_buf, 0, &p) != 0) |
3036 | 3052 | return 0; |
3037 | 3053 | 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); |
3039 | 3055 | if (real_ino && real_ino->i_sb != p.dentry->d_sb) |
3040 | 3056 | d->spoof_f_type = (unsigned long)real_ino->i_sb->s_magic; |
3041 | 3057 | else |
3042 | | - /* Fallback when d_real_inode missing (e.g. older kernel): use EROFS to match typical resolved type */ |
3043 | 3058 | d->spoof_f_type = (unsigned long)EROFS_SUPER_MAGIC; |
3044 | 3059 | } |
3045 | 3060 | path_put(&p); |
@@ -3116,7 +3131,7 @@ static struct kretprobe hymo_krp_cmdline_read = { |
3116 | 3131 | * iterate_dir: filldir filter (runs in fs callback context, not kprobe) |
3117 | 3132 | * ====================================================================== */ |
3118 | 3133 |
|
3119 | | -static HYMO_NOCFI HYMO_FILLDIR_RET_TYPE |
| 3134 | +HYMO_NOCFI HYMO_FILLDIR_RET_TYPE |
3120 | 3135 | hymofs_filldir_filter(struct dir_context *ctx, const char *name, |
3121 | 3136 | int namlen, loff_t offset, u64 ino, unsigned int d_type) |
3122 | 3137 | { |
@@ -4333,9 +4348,7 @@ static int __init hymofs_lkm_init(void) |
4333 | 4348 | pr_warn("HymoFS: d_path not found, path resolution in populate/merge/hide may fail\n"); |
4334 | 4349 | if (!hymo_d_hash_and_lookup) |
4335 | 4350 | 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 */ |
4339 | 4352 | if (!hymo_filp_open || !hymo_kernel_read) |
4340 | 4353 | pr_warn("HymoFS: filp_open/kernel_read not found, allowlist disabled\n"); |
4341 | 4354 | /* 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) |
4700 | 4713 | #if HYMOFS_VFS_KPROBES |
4701 | 4714 | if (!hymo_skip_vfs_param) { |
4702 | 4715 | /* 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. */ |
4704 | 4717 | { |
4705 | 4718 | size_t i; |
4706 | 4719 | int ret; |
4707 | 4720 | size_t start_idx = (hymofs_tracepoint_path_registered() ? 1 : 0); |
4708 | 4721 |
|
4709 | | -#ifdef CONFIG_DYNAMIC_FTRACE |
4710 | 4722 | { |
4711 | 4723 | unsigned long ft_addr[4]; |
4712 | 4724 |
|
| 4725 | + pr_info("HymoFS: trying ftrace for VFS entry (preferred over kprobes)\n"); |
4713 | 4726 | ret = hymofs_ftrace_try_register(ft_addr); |
4714 | 4727 | if (ret == 0) { |
4715 | 4728 | hymo_vfs_getxattr_addr = (void *)ft_addr[3]; |
@@ -4756,10 +4769,9 @@ static int __init hymofs_lkm_init(void) |
4756 | 4769 | unregister_kretprobe(&hymo_krp_vfs_getxattr); |
4757 | 4770 | } |
4758 | 4771 | } 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); |
4760 | 4773 | } |
4761 | 4774 | } |
4762 | | -#endif |
4763 | 4775 |
|
4764 | 4776 | /* getname_flags: always kprobe (needs skip-original) */ |
4765 | 4777 | if (start_idx == 0) { |
@@ -4956,31 +4968,28 @@ static void __exit hymofs_lkm_exit(void) |
4956 | 4968 | #if HYMOFS_VFS_KPROBES |
4957 | 4969 | hymofs_tracepoint_path_exit(); |
4958 | 4970 | 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 | + } |
4981 | 4991 | } |
4982 | 4992 | } |
4983 | | - } |
4984 | 4993 | #endif |
4985 | 4994 |
|
4986 | 4995 | /* Clean up all rules and wait for RCU grace period */ |
|
0 commit comments