Commit 4b4eef57 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'probes-fixes-v6.5-rc1-2' of...

Merge tag 'probes-fixes-v6.5-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull probe fixes from Masami Hiramatsu:

 - fprobe: Add a comment why fprobe will be skipped if another kprobe is
   running in fprobe_kprobe_handler().

 - probe-events: Fix some issues related to fetch-arguments:

    - Fix double counting of the string length for user-string and
      symstr. This will require longer buffer in the array case.

    - Fix not to count error code (minus value) for the total used
      length in array argument. This makes the total used length
      shorter.

    - Fix to update dynamic used data size counter only if fetcharg uses
      the dynamic size data. This may mis-count the used dynamic data
      size and corrupt data.

    - Revert "tracing: Add "(fault)" name injection to kernel probes"
      because that did not work correctly with a bug, and we agreed the
      current '(fault)' output (instead of '"(fault)"' like a string)
      explains what happened more clearly.

    - Fix to record 0-length (means fault access) data_loc data in fetch
      function itself, instead of store_trace_args(). If we record an
      array of string, this will fix to save fault access data on each
      entry of the array correctly.

* tag 'probes-fixes-v6.5-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  tracing/probes: Fix to record 0-length data_loc in fetch_store_string*() if fails
  Revert "tracing: Add "(fault)" name injection to kernel probes"
  tracing/probes: Fix to update dynamic data counter if fetcharg uses it
  tracing/probes: Fix not to count error code to total length
  tracing/probes: Fix to avoid double count of the string length on the array
  fprobes: Add a comment why fprobe_kprobe_handler exits if kprobe is running
parents 831fe284 797311bc
...@@ -100,6 +100,12 @@ static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip, ...@@ -100,6 +100,12 @@ static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip,
return; return;
} }
/*
* This user handler is shared with other kprobes and is not expected to be
* called recursively. So if any other kprobe handler is running, this will
* exit as kprobe does. See the section 'Share the callbacks with kprobes'
* in Documentation/trace/fprobe.rst for more information.
*/
if (unlikely(kprobe_running())) { if (unlikely(kprobe_running())) {
fp->nmissed++; fp->nmissed++;
goto recursion_unlock; goto recursion_unlock;
......
...@@ -113,6 +113,8 @@ enum trace_type { ...@@ -113,6 +113,8 @@ enum trace_type {
#define MEM_FAIL(condition, fmt, ...) \ #define MEM_FAIL(condition, fmt, ...) \
DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__) DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__)
#define FAULT_STRING "(fault)"
#define HIST_STACKTRACE_DEPTH 16 #define HIST_STACKTRACE_DEPTH 16
#define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long)) #define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
#define HIST_STACKTRACE_SKIP 5 #define HIST_STACKTRACE_SKIP 5
......
...@@ -67,7 +67,7 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent) ...@@ -67,7 +67,7 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
int len = *(u32 *)data >> 16; int len = *(u32 *)data >> 16;
if (!len) if (!len)
trace_seq_puts(s, "(fault)"); trace_seq_puts(s, FAULT_STRING);
else else
trace_seq_printf(s, "\"%s\"", trace_seq_printf(s, "\"%s\"",
(const char *)get_loc_data(data, ent)); (const char *)get_loc_data(data, ent));
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
#ifndef __TRACE_PROBE_KERNEL_H_ #ifndef __TRACE_PROBE_KERNEL_H_
#define __TRACE_PROBE_KERNEL_H_ #define __TRACE_PROBE_KERNEL_H_
#define FAULT_STRING "(fault)"
/* /*
* This depends on trace_probe.h, but can not include it due to * This depends on trace_probe.h, but can not include it due to
* the way trace_probe_tmpl.h is used by trace_kprobe.c and trace_eprobe.c. * the way trace_probe_tmpl.h is used by trace_kprobe.c and trace_eprobe.c.
...@@ -15,16 +13,8 @@ static nokprobe_inline int ...@@ -15,16 +13,8 @@ static nokprobe_inline int
fetch_store_strlen_user(unsigned long addr) fetch_store_strlen_user(unsigned long addr)
{ {
const void __user *uaddr = (__force const void __user *)addr; const void __user *uaddr = (__force const void __user *)addr;
int ret;
ret = strnlen_user_nofault(uaddr, MAX_STRING_SIZE); return strnlen_user_nofault(uaddr, MAX_STRING_SIZE);
/*
* strnlen_user_nofault returns zero on fault, insert the
* FAULT_STRING when that occurs.
*/
if (ret <= 0)
return strlen(FAULT_STRING) + 1;
return ret;
} }
/* Return the length of string -- including null terminal byte */ /* Return the length of string -- including null terminal byte */
...@@ -44,18 +34,14 @@ fetch_store_strlen(unsigned long addr) ...@@ -44,18 +34,14 @@ fetch_store_strlen(unsigned long addr)
len++; len++;
} while (c && ret == 0 && len < MAX_STRING_SIZE); } while (c && ret == 0 && len < MAX_STRING_SIZE);
/* For faults, return enough to hold the FAULT_STRING */ return (ret < 0) ? ret : len;
return (ret < 0) ? strlen(FAULT_STRING) + 1 : len;
} }
static nokprobe_inline void set_data_loc(int ret, void *dest, void *__dest, void *base, int len) static nokprobe_inline void set_data_loc(int ret, void *dest, void *__dest, void *base)
{ {
if (ret >= 0) { if (ret < 0)
*(u32 *)dest = make_data_loc(ret, __dest - base); ret = 0;
} else { *(u32 *)dest = make_data_loc(ret, __dest - base);
strscpy(__dest, FAULT_STRING, len);
ret = strlen(__dest) + 1;
}
} }
/* /*
...@@ -76,7 +62,7 @@ fetch_store_string_user(unsigned long addr, void *dest, void *base) ...@@ -76,7 +62,7 @@ fetch_store_string_user(unsigned long addr, void *dest, void *base)
__dest = get_loc_data(dest, base); __dest = get_loc_data(dest, base);
ret = strncpy_from_user_nofault(__dest, uaddr, maxlen); ret = strncpy_from_user_nofault(__dest, uaddr, maxlen);
set_data_loc(ret, dest, __dest, base, maxlen); set_data_loc(ret, dest, __dest, base);
return ret; return ret;
} }
...@@ -107,7 +93,7 @@ fetch_store_string(unsigned long addr, void *dest, void *base) ...@@ -107,7 +93,7 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
* probing. * probing.
*/ */
ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen); ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen);
set_data_loc(ret, dest, __dest, base, maxlen); set_data_loc(ret, dest, __dest, base);
return ret; return ret;
} }
......
...@@ -156,11 +156,11 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val, ...@@ -156,11 +156,11 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
code++; code++;
goto array; goto array;
case FETCH_OP_ST_USTRING: case FETCH_OP_ST_USTRING:
ret += fetch_store_strlen_user(val + code->offset); ret = fetch_store_strlen_user(val + code->offset);
code++; code++;
goto array; goto array;
case FETCH_OP_ST_SYMSTR: case FETCH_OP_ST_SYMSTR:
ret += fetch_store_symstrlen(val + code->offset); ret = fetch_store_symstrlen(val + code->offset);
code++; code++;
goto array; goto array;
default: default:
...@@ -204,6 +204,8 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val, ...@@ -204,6 +204,8 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
array: array:
/* the last stage: Loop on array */ /* the last stage: Loop on array */
if (code->op == FETCH_OP_LP_ARRAY) { if (code->op == FETCH_OP_LP_ARRAY) {
if (ret < 0)
ret = 0;
total += ret; total += ret;
if (++i < code->param) { if (++i < code->param) {
code = s3; code = s3;
...@@ -265,9 +267,7 @@ store_trace_args(void *data, struct trace_probe *tp, void *rec, ...@@ -265,9 +267,7 @@ store_trace_args(void *data, struct trace_probe *tp, void *rec,
if (unlikely(arg->dynamic)) if (unlikely(arg->dynamic))
*dl = make_data_loc(maxlen, dyndata - base); *dl = make_data_loc(maxlen, dyndata - base);
ret = process_fetch_insn(arg->code, rec, dl, base); ret = process_fetch_insn(arg->code, rec, dl, base);
if (unlikely(ret < 0 && arg->dynamic)) { if (arg->dynamic && likely(ret > 0)) {
*dl = make_data_loc(0, dyndata - base);
} else {
dyndata += ret; dyndata += ret;
maxlen -= ret; maxlen -= ret;
} }
......
...@@ -170,7 +170,8 @@ fetch_store_string(unsigned long addr, void *dest, void *base) ...@@ -170,7 +170,8 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
*/ */
ret++; ret++;
*(u32 *)dest = make_data_loc(ret, (void *)dst - base); *(u32 *)dest = make_data_loc(ret, (void *)dst - base);
} } else
*(u32 *)dest = make_data_loc(0, (void *)dst - base);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment