|
@@ -148,6 +148,83 @@ DEFINE_BASIC_FETCH_FUNCS(stack)
|
|
#define fetch_stack_string NULL
|
|
#define fetch_stack_string NULL
|
|
#define fetch_stack_string_size NULL
|
|
#define fetch_stack_string_size NULL
|
|
|
|
|
|
|
|
+#define DEFINE_FETCH_memory(type) \
|
|
|
|
+static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
|
|
|
|
+ void *addr, void *dest) \
|
|
|
|
+{ \
|
|
|
|
+ type retval; \
|
|
|
|
+ if (probe_kernel_address(addr, retval)) \
|
|
|
|
+ *(type *)dest = 0; \
|
|
|
|
+ else \
|
|
|
|
+ *(type *)dest = retval; \
|
|
|
|
+}
|
|
|
|
+DEFINE_BASIC_FETCH_FUNCS(memory)
|
|
|
|
+/*
|
|
|
|
+ * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
|
|
|
|
+ * length and relative data location.
|
|
|
|
+ */
|
|
|
|
+static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
|
|
|
|
+ void *addr, void *dest)
|
|
|
|
+{
|
|
|
|
+ long ret;
|
|
|
|
+ int maxlen = get_rloc_len(*(u32 *)dest);
|
|
|
|
+ u8 *dst = get_rloc_data(dest);
|
|
|
|
+ u8 *src = addr;
|
|
|
|
+ mm_segment_t old_fs = get_fs();
|
|
|
|
+
|
|
|
|
+ if (!maxlen)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Try to get string again, since the string can be changed while
|
|
|
|
+ * probing.
|
|
|
|
+ */
|
|
|
|
+ set_fs(KERNEL_DS);
|
|
|
|
+ pagefault_disable();
|
|
|
|
+
|
|
|
|
+ do
|
|
|
|
+ ret = __copy_from_user_inatomic(dst++, src++, 1);
|
|
|
|
+ while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
|
|
|
|
+
|
|
|
|
+ dst[-1] = '\0';
|
|
|
|
+ pagefault_enable();
|
|
|
|
+ set_fs(old_fs);
|
|
|
|
+
|
|
|
|
+ if (ret < 0) { /* Failed to fetch string */
|
|
|
|
+ ((u8 *)get_rloc_data(dest))[0] = '\0';
|
|
|
|
+ *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
|
|
|
|
+ } else {
|
|
|
|
+ *(u32 *)dest = make_data_rloc(src - (u8 *)addr,
|
|
|
|
+ get_rloc_offs(*(u32 *)dest));
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* Return the length of string -- including null terminal byte */
|
|
|
|
+static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
|
|
|
|
+ void *addr, void *dest)
|
|
|
|
+{
|
|
|
|
+ mm_segment_t old_fs;
|
|
|
|
+ int ret, len = 0;
|
|
|
|
+ u8 c;
|
|
|
|
+
|
|
|
|
+ old_fs = get_fs();
|
|
|
|
+ set_fs(KERNEL_DS);
|
|
|
|
+ pagefault_disable();
|
|
|
|
+
|
|
|
|
+ do {
|
|
|
|
+ ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
|
|
|
|
+ len++;
|
|
|
|
+ } while (c && ret == 0 && len < MAX_STRING_SIZE);
|
|
|
|
+
|
|
|
|
+ pagefault_enable();
|
|
|
|
+ set_fs(old_fs);
|
|
|
|
+
|
|
|
|
+ if (ret < 0) /* Failed to check the length */
|
|
|
|
+ *(u32 *)dest = 0;
|
|
|
|
+ else
|
|
|
|
+ *(u32 *)dest = len;
|
|
|
|
+}
|
|
|
|
+
|
|
#define DEFINE_FETCH_symbol(type) \
|
|
#define DEFINE_FETCH_symbol(type) \
|
|
__kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, \
|
|
__kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, \
|
|
void *data, void *dest) \
|
|
void *data, void *dest) \
|