diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 4325f9e7fada..6a23b45613a2 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -1200,21 +1200,6 @@ static const struct file_operations kprobe_profile_ops = { /* Kprobe specific fetch functions */ -/* Return the length of string -- including null terminal byte */ -static nokprobe_inline int -fetch_store_strlen(unsigned long addr) -{ - int ret, len = 0; - u8 c; - - do { - ret = probe_kernel_read(&c, (u8 *)addr + len, 1); - len++; - } while (c && ret == 0 && len < MAX_STRING_SIZE); - - return (ret < 0) ? ret : len; -} - /* Return the length of string -- including null terminal byte */ static nokprobe_inline int fetch_store_strlen_user(unsigned long addr) @@ -1224,31 +1209,24 @@ fetch_store_strlen_user(unsigned long addr) return strnlen_user_nofault(uaddr, MAX_STRING_SIZE); } -/* - * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max - * length and relative data location. - */ +/* Return the length of string -- including null terminal byte */ static nokprobe_inline int -fetch_store_string(unsigned long addr, void *dest, void *base) +fetch_store_strlen(unsigned long addr) { - int maxlen = get_loc_len(*(u32 *)dest); - void *__dest; - long ret; + int ret, len = 0; + u8 c; - if (unlikely(!maxlen)) - return -ENOMEM; +#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE + if (addr < TASK_SIZE) + return fetch_store_strlen_user(addr); +#endif - __dest = get_loc_data(dest, base); + do { + ret = probe_kernel_read_strict(&c, (u8 *)addr + len, 1); + len++; + } while (c && ret == 0 && len < MAX_STRING_SIZE); - /* - * Try to get string again, since the string can be changed while - * probing. - */ - ret = strncpy_from_unsafe(__dest, (void *)addr, maxlen); - if (ret >= 0) - *(u32 *)dest = make_data_loc(ret, __dest - base); - - return ret; + return (ret < 0) ? ret : len; } /* @@ -1275,10 +1253,36 @@ fetch_store_string_user(unsigned long addr, void *dest, void *base) return ret; } +/* + * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max + * length and relative data location. + */ static nokprobe_inline int -probe_mem_read(void *dest, void *src, size_t size) +fetch_store_string(unsigned long addr, void *dest, void *base) { - return probe_kernel_read(dest, src, size); + int maxlen = get_loc_len(*(u32 *)dest); + void *__dest; + long ret; + +#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE + if ((unsigned long)addr < TASK_SIZE) + return fetch_store_string_user(addr, dest, base); +#endif + + if (unlikely(!maxlen)) + return -ENOMEM; + + __dest = get_loc_data(dest, base); + + /* + * Try to get string again, since the string can be changed while + * probing. + */ + ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen); + if (ret >= 0) + *(u32 *)dest = make_data_loc(ret, __dest - base); + + return ret; } static nokprobe_inline int @@ -1289,6 +1293,16 @@ probe_mem_read_user(void *dest, void *src, size_t size) return probe_user_read(dest, uaddr, size); } +static nokprobe_inline int +probe_mem_read(void *dest, void *src, size_t size) +{ +#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE + if ((unsigned long)src < TASK_SIZE) + return probe_mem_read_user(dest, src, size); +#endif + return probe_kernel_read_strict(dest, src, size); +} + /* Note that we don't verify it, since the code does not come from user space */ static int process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,