Skip to content

Commit f1d3cbf

Browse files
committed
tracing: Move duplicate code of trace_kprobe/eprobe.c into header
The functions: fetch_store_strlen_user() fetch_store_strlen() fetch_store_string_user() fetch_store_string() are identical in both trace_kprobe.c and trace_eprobe.c. Move them into a new header file trace_probe_kernel.h to share it. This code will later be used by the synthetic events as well. Marked for stable as a fix for a crash in synthetic events requires it. Link: https://lkml.kernel.org/r/[email protected] Cc: [email protected] Cc: Andrew Morton <[email protected]> Cc: Tom Zanussi <[email protected]> Acked-by: Masami Hiramatsu (Google) <[email protected]> Reviewed-by: Tom Zanussi <[email protected]> Fixes: bd82631 ("tracing: Add support for dynamic strings to synthetic events") Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent b7085b6 commit f1d3cbf

File tree

3 files changed

+106
-110
lines changed

3 files changed

+106
-110
lines changed

kernel/trace/trace_eprobe.c

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "trace_dynevent.h"
1717
#include "trace_probe.h"
1818
#include "trace_probe_tmpl.h"
19+
#include "trace_probe_kernel.h"
1920

2021
#define EPROBE_EVENT_SYSTEM "eprobes"
2122

@@ -456,29 +457,14 @@ NOKPROBE_SYMBOL(process_fetch_insn)
456457
static nokprobe_inline int
457458
fetch_store_strlen_user(unsigned long addr)
458459
{
459-
const void __user *uaddr = (__force const void __user *)addr;
460-
461-
return strnlen_user_nofault(uaddr, MAX_STRING_SIZE);
460+
return kern_fetch_store_strlen_user(addr);
462461
}
463462

464463
/* Return the length of string -- including null terminal byte */
465464
static nokprobe_inline int
466465
fetch_store_strlen(unsigned long addr)
467466
{
468-
int ret, len = 0;
469-
u8 c;
470-
471-
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
472-
if (addr < TASK_SIZE)
473-
return fetch_store_strlen_user(addr);
474-
#endif
475-
476-
do {
477-
ret = copy_from_kernel_nofault(&c, (u8 *)addr + len, 1);
478-
len++;
479-
} while (c && ret == 0 && len < MAX_STRING_SIZE);
480-
481-
return (ret < 0) ? ret : len;
467+
return kern_fetch_store_strlen(addr);
482468
}
483469

484470
/*
@@ -488,21 +474,7 @@ fetch_store_strlen(unsigned long addr)
488474
static nokprobe_inline int
489475
fetch_store_string_user(unsigned long addr, void *dest, void *base)
490476
{
491-
const void __user *uaddr = (__force const void __user *)addr;
492-
int maxlen = get_loc_len(*(u32 *)dest);
493-
void *__dest;
494-
long ret;
495-
496-
if (unlikely(!maxlen))
497-
return -ENOMEM;
498-
499-
__dest = get_loc_data(dest, base);
500-
501-
ret = strncpy_from_user_nofault(__dest, uaddr, maxlen);
502-
if (ret >= 0)
503-
*(u32 *)dest = make_data_loc(ret, __dest - base);
504-
505-
return ret;
477+
return kern_fetch_store_string_user(addr, dest, base);
506478
}
507479

508480
/*
@@ -512,29 +484,7 @@ fetch_store_string_user(unsigned long addr, void *dest, void *base)
512484
static nokprobe_inline int
513485
fetch_store_string(unsigned long addr, void *dest, void *base)
514486
{
515-
int maxlen = get_loc_len(*(u32 *)dest);
516-
void *__dest;
517-
long ret;
518-
519-
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
520-
if ((unsigned long)addr < TASK_SIZE)
521-
return fetch_store_string_user(addr, dest, base);
522-
#endif
523-
524-
if (unlikely(!maxlen))
525-
return -ENOMEM;
526-
527-
__dest = get_loc_data(dest, base);
528-
529-
/*
530-
* Try to get string again, since the string can be changed while
531-
* probing.
532-
*/
533-
ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen);
534-
if (ret >= 0)
535-
*(u32 *)dest = make_data_loc(ret, __dest - base);
536-
537-
return ret;
487+
return kern_fetch_store_string(addr, dest, base);
538488
}
539489

540490
static nokprobe_inline int

kernel/trace/trace_kprobe.c

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "trace_kprobe_selftest.h"
2121
#include "trace_probe.h"
2222
#include "trace_probe_tmpl.h"
23+
#include "trace_probe_kernel.h"
2324

2425
#define KPROBE_EVENT_SYSTEM "kprobes"
2526
#define KRETPROBE_MAXACTIVE_MAX 4096
@@ -1223,29 +1224,14 @@ static const struct file_operations kprobe_profile_ops = {
12231224
static nokprobe_inline int
12241225
fetch_store_strlen_user(unsigned long addr)
12251226
{
1226-
const void __user *uaddr = (__force const void __user *)addr;
1227-
1228-
return strnlen_user_nofault(uaddr, MAX_STRING_SIZE);
1227+
return kern_fetch_store_strlen_user(addr);
12291228
}
12301229

12311230
/* Return the length of string -- including null terminal byte */
12321231
static nokprobe_inline int
12331232
fetch_store_strlen(unsigned long addr)
12341233
{
1235-
int ret, len = 0;
1236-
u8 c;
1237-
1238-
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
1239-
if (addr < TASK_SIZE)
1240-
return fetch_store_strlen_user(addr);
1241-
#endif
1242-
1243-
do {
1244-
ret = copy_from_kernel_nofault(&c, (u8 *)addr + len, 1);
1245-
len++;
1246-
} while (c && ret == 0 && len < MAX_STRING_SIZE);
1247-
1248-
return (ret < 0) ? ret : len;
1234+
return kern_fetch_store_strlen(addr);
12491235
}
12501236

12511237
/*
@@ -1255,21 +1241,7 @@ fetch_store_strlen(unsigned long addr)
12551241
static nokprobe_inline int
12561242
fetch_store_string_user(unsigned long addr, void *dest, void *base)
12571243
{
1258-
const void __user *uaddr = (__force const void __user *)addr;
1259-
int maxlen = get_loc_len(*(u32 *)dest);
1260-
void *__dest;
1261-
long ret;
1262-
1263-
if (unlikely(!maxlen))
1264-
return -ENOMEM;
1265-
1266-
__dest = get_loc_data(dest, base);
1267-
1268-
ret = strncpy_from_user_nofault(__dest, uaddr, maxlen);
1269-
if (ret >= 0)
1270-
*(u32 *)dest = make_data_loc(ret, __dest - base);
1271-
1272-
return ret;
1244+
return kern_fetch_store_string_user(addr, dest, base);
12731245
}
12741246

12751247
/*
@@ -1279,29 +1251,7 @@ fetch_store_string_user(unsigned long addr, void *dest, void *base)
12791251
static nokprobe_inline int
12801252
fetch_store_string(unsigned long addr, void *dest, void *base)
12811253
{
1282-
int maxlen = get_loc_len(*(u32 *)dest);
1283-
void *__dest;
1284-
long ret;
1285-
1286-
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
1287-
if ((unsigned long)addr < TASK_SIZE)
1288-
return fetch_store_string_user(addr, dest, base);
1289-
#endif
1290-
1291-
if (unlikely(!maxlen))
1292-
return -ENOMEM;
1293-
1294-
__dest = get_loc_data(dest, base);
1295-
1296-
/*
1297-
* Try to get string again, since the string can be changed while
1298-
* probing.
1299-
*/
1300-
ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen);
1301-
if (ret >= 0)
1302-
*(u32 *)dest = make_data_loc(ret, __dest - base);
1303-
1304-
return ret;
1254+
return kern_fetch_store_string(addr, dest, base);
13051255
}
13061256

13071257
static nokprobe_inline int

kernel/trace/trace_probe_kernel.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef __TRACE_PROBE_KERNEL_H_
3+
#define __TRACE_PROBE_KERNEL_H_
4+
5+
/*
6+
* This depends on trace_probe.h, but can not include it due to
7+
* the way trace_probe_tmpl.h is used by trace_kprobe.c and trace_eprobe.c.
8+
* Which means that any other user must include trace_probe.h before including
9+
* this file.
10+
*/
11+
/* Return the length of string -- including null terminal byte */
12+
static nokprobe_inline int
13+
kern_fetch_store_strlen_user(unsigned long addr)
14+
{
15+
const void __user *uaddr = (__force const void __user *)addr;
16+
17+
return strnlen_user_nofault(uaddr, MAX_STRING_SIZE);
18+
}
19+
20+
/* Return the length of string -- including null terminal byte */
21+
static nokprobe_inline int
22+
kern_fetch_store_strlen(unsigned long addr)
23+
{
24+
int ret, len = 0;
25+
u8 c;
26+
27+
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
28+
if (addr < TASK_SIZE)
29+
return kern_fetch_store_strlen_user(addr);
30+
#endif
31+
32+
do {
33+
ret = copy_from_kernel_nofault(&c, (u8 *)addr + len, 1);
34+
len++;
35+
} while (c && ret == 0 && len < MAX_STRING_SIZE);
36+
37+
return (ret < 0) ? ret : len;
38+
}
39+
40+
/*
41+
* Fetch a null-terminated string from user. Caller MUST set *(u32 *)buf
42+
* with max length and relative data location.
43+
*/
44+
static nokprobe_inline int
45+
kern_fetch_store_string_user(unsigned long addr, void *dest, void *base)
46+
{
47+
const void __user *uaddr = (__force const void __user *)addr;
48+
int maxlen = get_loc_len(*(u32 *)dest);
49+
void *__dest;
50+
long ret;
51+
52+
if (unlikely(!maxlen))
53+
return -ENOMEM;
54+
55+
__dest = get_loc_data(dest, base);
56+
57+
ret = strncpy_from_user_nofault(__dest, uaddr, maxlen);
58+
if (ret >= 0)
59+
*(u32 *)dest = make_data_loc(ret, __dest - base);
60+
61+
return ret;
62+
}
63+
64+
/*
65+
* Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max
66+
* length and relative data location.
67+
*/
68+
static nokprobe_inline int
69+
kern_fetch_store_string(unsigned long addr, void *dest, void *base)
70+
{
71+
int maxlen = get_loc_len(*(u32 *)dest);
72+
void *__dest;
73+
long ret;
74+
75+
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
76+
if ((unsigned long)addr < TASK_SIZE)
77+
return kern_fetch_store_string_user(addr, dest, base);
78+
#endif
79+
80+
if (unlikely(!maxlen))
81+
return -ENOMEM;
82+
83+
__dest = get_loc_data(dest, base);
84+
85+
/*
86+
* Try to get string again, since the string can be changed while
87+
* probing.
88+
*/
89+
ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen);
90+
if (ret >= 0)
91+
*(u32 *)dest = make_data_loc(ret, __dest - base);
92+
93+
return ret;
94+
}
95+
96+
#endif /* __TRACE_PROBE_KERNEL_H_ */

0 commit comments

Comments
 (0)