mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 16:13:19 +09:00
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
This commit is contained in:
@@ -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 {
|
|||||||
#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)
|
|||||||
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 @@
|
|||||||
#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
|
|||||||
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)
|
|||||||
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)
|
|||||||
__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)
|
|||||||
* 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 @@ stage3:
|
|||||||
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 @@ stage3:
|
|||||||
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,
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user