diff --git a/src/bio_helper.c b/src/bio_helper.c index 56ac483a..a27af06b 100644 --- a/src/bio_helper.c +++ b/src/bio_helper.c @@ -588,8 +588,7 @@ int bio_needs_cow(struct bio *bio, struct inode *inode) bio_iter_t iter; bio_iter_bvec_t bvec; -#if defined HAVE_ENUM_REQ_OPF || (defined HAVE_ENUM_REQ_OP && defined HAVE_ENUM_REQ_OPF_WRITE_ZEROES) - //#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) +#if defined HAVE_ENUM_REQ_OP_WRITE_ZEROES if (bio_op(bio) == REQ_OP_WRITE_ZEROES) return 1; #endif diff --git a/src/bio_request_callback.h b/src/bio_request_callback.h index 21a6a5ee..7c4e93d4 100644 --- a/src/bio_request_callback.h +++ b/src/bio_request_callback.h @@ -28,8 +28,14 @@ // length of `% call __fentry__` on x86_64 - uses a 1 byte op and 4 byte // relative address #define FENTRY_CALL_INSTR_BYTES 5 +#elif defined(CONFIG_ARM64) +// arm64 ftrace patch site: two 4-byte instructions emitted by +// -fpatchable-function-entry=2. NOTE: the passthrough using this +// (dattobd_submit_bio_real in submit_bio.c) is dead code on blk-mq devices, so +// this value is not load-bearing here -- it only needs to let the file compile. +#define FENTRY_CALL_INSTR_BYTES (2 * 4) #else -#pragma error "Unsupported architecture" +#error "Unsupported architecture" #endif #define BIO_REQUEST_CALLBACK_FN submit_bio_fn diff --git a/src/configure-tests/feature-tests/ftrace_regs_set_instruction_pointer.c b/src/configure-tests/feature-tests/ftrace_regs_set_instruction_pointer.c new file mode 100644 index 00000000..e82f5489 --- /dev/null +++ b/src/configure-tests/feature-tests/ftrace_regs_set_instruction_pointer.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2026 Datto Inc. + */ + +#include "includes.h" + +MODULE_LICENSE("GPL"); + +static inline void dummy(void){ + struct ftrace_regs *fregs = NULL; + ftrace_regs_set_instruction_pointer(fregs, 0); +} diff --git a/src/ftrace_hooking.c b/src/ftrace_hooking.c index 65230eb1..5969edac 100644 --- a/src/ftrace_hooking.c +++ b/src/ftrace_hooking.c @@ -378,14 +378,13 @@ static int resolve_hook_address(struct ftrace_hook *hook) static void notrace ftrace_callback_handler(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct ftrace_regs *fregs) { - struct pt_regs *regs = ftrace_get_regs(fregs); struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops); #if USE_FENTRY_OFFSET - regs->ip = (unsigned long)hook->function; + dattobd_ftrace_set_ip(fregs, hook->function); #else if (!dattobd_within_module(parent_ip, THIS_MODULE)) - regs->ip = (unsigned long)hook->function; + dattobd_ftrace_set_ip(fregs, hook->function); #endif //USE_FENTRY_OFFSET } @@ -409,7 +408,11 @@ static int register_hook(struct ftrace_hook *hook) } hook->ops.func = ftrace_callback_handler; - hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_RECURSION | FTRACE_OPS_FL_IPMODIFY; + hook->ops.flags = FTRACE_OPS_FL_RECURSION | FTRACE_OPS_FL_IPMODIFY; + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + hook->ops.flags |= FTRACE_OPS_FL_SAVE_REGS; +#endif ret = ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0); if (ret) { diff --git a/src/ftrace_hooking.h b/src/ftrace_hooking.h index 1f741dff..f43b51af 100644 --- a/src/ftrace_hooking.h +++ b/src/ftrace_hooking.h @@ -44,6 +44,25 @@ static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs } #endif +/** + dattobd_ftrace_set_ip() - redirect execution from the ftrace callback by + setting the traced function's instruction pointer to our hook. + */ +#ifdef HAVE_FTRACE_REGS_SET_INSTRUCTION_POINTER +#define dattobd_ftrace_set_ip(fregs, addr) \ + ftrace_regs_set_instruction_pointer((fregs), (unsigned long)(addr)) +#elif defined(CONFIG_ARM64) +#define dattobd_ftrace_set_ip(fregs, addr) \ + do { \ + ftrace_get_regs(fregs)->pc = (unsigned long)(addr); \ + } while (0) +#else +#define dattobd_ftrace_set_ip(fregs, addr) \ + do { \ + ftrace_get_regs(fregs)->ip = (unsigned long)(addr); \ + } while (0) +#endif + #ifndef UMOUNT_NOFOLLOW #define UMOUNT_NOFOLLOW 0 #endif diff --git a/src/paging_helper.c b/src/paging_helper.c index 4cac93e3..4fc710e9 100644 --- a/src/paging_helper.c +++ b/src/paging_helper.c @@ -7,6 +7,8 @@ #include "includes.h" #include "paging_helper.h" +#ifdef CONFIG_X86 + //#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) #ifndef X86_CR0_WP #define X86_CR0_WP (1UL << 16) @@ -53,3 +55,24 @@ void reenable_page_protection(unsigned long *cr0) { write_cr0(*cr0); } + +#else + +/** + * Page-level write-protect toggling via the CR0 register is x86-specific. It is + * only used by the legacy syscall-table hooking path, which is unused on the + * ftrace-based builds (5.9+) that non-x86 arches such as arm64 target. These + * functions have no callers in such builds, so provide no-op stubs to keep the + * module buildable on non-x86 without pulling in read_cr0()/write_cr0(). + */ +void disable_page_protection(unsigned long *cr0) +{ + *cr0 = 0; +} + +void reenable_page_protection(unsigned long *cr0) +{ + (void)cr0; +} + +#endif diff --git a/src/tracer.c b/src/tracer.c index cc1af763..b98a0d06 100644 --- a/src/tracer.c +++ b/src/tracer.c @@ -272,8 +272,7 @@ static int inc_trace_bio(struct snap_device *dev, struct bio *bio) bio_iter_t iter; bio_iter_bvec_t bvec; -#ifdef HAVE_ENUM_REQ_OPF - //#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) +#if defined HAVE_ENUM_REQ_OP_WRITE_ZEROES if (bio_op(bio) == REQ_OP_WRITE_ZEROES) { ret = inc_make_sset(dev, bio_sector(bio), bio_size(bio) / SECTOR_SIZE);