Skip to content

Commit 5baaa59

Browse files
Namhyung Kimrostedt
authored andcommitted
tracing/probes: Implement 'memory' fetch method for uprobes
Use separate method to fetch from memory. Move existing functions to trace_kprobe.c and make them static. Also add new memory fetch implementation for uprobes. Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Acked-by: Oleg Nesterov <oleg@redhat.com> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: zhangwei(Jovi) <jovi.zhangwei@huawei.com> Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
1 parent 3925f4a commit 5baaa59

File tree

4 files changed

+129
-81
lines changed

4 files changed

+129
-81
lines changed

kernel/trace/trace_kprobe.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,83 @@ DEFINE_BASIC_FETCH_FUNCS(stack)
148148
#define fetch_stack_string NULL
149149
#define fetch_stack_string_size NULL
150150

151+
#define DEFINE_FETCH_memory(type) \
152+
static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
153+
void *addr, void *dest) \
154+
{ \
155+
type retval; \
156+
if (probe_kernel_address(addr, retval)) \
157+
*(type *)dest = 0; \
158+
else \
159+
*(type *)dest = retval; \
160+
}
161+
DEFINE_BASIC_FETCH_FUNCS(memory)
162+
/*
163+
* Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
164+
* length and relative data location.
165+
*/
166+
static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
167+
void *addr, void *dest)
168+
{
169+
long ret;
170+
int maxlen = get_rloc_len(*(u32 *)dest);
171+
u8 *dst = get_rloc_data(dest);
172+
u8 *src = addr;
173+
mm_segment_t old_fs = get_fs();
174+
175+
if (!maxlen)
176+
return;
177+
178+
/*
179+
* Try to get string again, since the string can be changed while
180+
* probing.
181+
*/
182+
set_fs(KERNEL_DS);
183+
pagefault_disable();
184+
185+
do
186+
ret = __copy_from_user_inatomic(dst++, src++, 1);
187+
while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
188+
189+
dst[-1] = '\0';
190+
pagefault_enable();
191+
set_fs(old_fs);
192+
193+
if (ret < 0) { /* Failed to fetch string */
194+
((u8 *)get_rloc_data(dest))[0] = '\0';
195+
*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
196+
} else {
197+
*(u32 *)dest = make_data_rloc(src - (u8 *)addr,
198+
get_rloc_offs(*(u32 *)dest));
199+
}
200+
}
201+
202+
/* Return the length of string -- including null terminal byte */
203+
static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
204+
void *addr, void *dest)
205+
{
206+
mm_segment_t old_fs;
207+
int ret, len = 0;
208+
u8 c;
209+
210+
old_fs = get_fs();
211+
set_fs(KERNEL_DS);
212+
pagefault_disable();
213+
214+
do {
215+
ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
216+
len++;
217+
} while (c && ret == 0 && len < MAX_STRING_SIZE);
218+
219+
pagefault_enable();
220+
set_fs(old_fs);
221+
222+
if (ret < 0) /* Failed to check the length */
223+
*(u32 *)dest = 0;
224+
else
225+
*(u32 *)dest = len;
226+
}
227+
151228
#define DEFINE_FETCH_symbol(type) \
152229
__kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, \
153230
void *data, void *dest) \

kernel/trace/trace_probe.c

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -103,83 +103,6 @@ DEFINE_BASIC_FETCH_FUNCS(retval)
103103
#define fetch_retval_string NULL
104104
#define fetch_retval_string_size NULL
105105

106-
#define DEFINE_FETCH_memory(type) \
107-
__kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs, \
108-
void *addr, void *dest) \
109-
{ \
110-
type retval; \
111-
if (probe_kernel_address(addr, retval)) \
112-
*(type *)dest = 0; \
113-
else \
114-
*(type *)dest = retval; \
115-
}
116-
DEFINE_BASIC_FETCH_FUNCS(memory)
117-
/*
118-
* Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
119-
* length and relative data location.
120-
*/
121-
__kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
122-
void *addr, void *dest)
123-
{
124-
long ret;
125-
int maxlen = get_rloc_len(*(u32 *)dest);
126-
u8 *dst = get_rloc_data(dest);
127-
u8 *src = addr;
128-
mm_segment_t old_fs = get_fs();
129-
130-
if (!maxlen)
131-
return;
132-
133-
/*
134-
* Try to get string again, since the string can be changed while
135-
* probing.
136-
*/
137-
set_fs(KERNEL_DS);
138-
pagefault_disable();
139-
140-
do
141-
ret = __copy_from_user_inatomic(dst++, src++, 1);
142-
while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
143-
144-
dst[-1] = '\0';
145-
pagefault_enable();
146-
set_fs(old_fs);
147-
148-
if (ret < 0) { /* Failed to fetch string */
149-
((u8 *)get_rloc_data(dest))[0] = '\0';
150-
*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
151-
} else {
152-
*(u32 *)dest = make_data_rloc(src - (u8 *)addr,
153-
get_rloc_offs(*(u32 *)dest));
154-
}
155-
}
156-
157-
/* Return the length of string -- including null terminal byte */
158-
__kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
159-
void *addr, void *dest)
160-
{
161-
mm_segment_t old_fs;
162-
int ret, len = 0;
163-
u8 c;
164-
165-
old_fs = get_fs();
166-
set_fs(KERNEL_DS);
167-
pagefault_disable();
168-
169-
do {
170-
ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
171-
len++;
172-
} while (c && ret == 0 && len < MAX_STRING_SIZE);
173-
174-
pagefault_enable();
175-
set_fs(old_fs);
176-
177-
if (ret < 0) /* Failed to check the length */
178-
*(u32 *)dest = 0;
179-
else
180-
*(u32 *)dest = len;
181-
}
182-
183106
/* Dereference memory access function */
184107
struct deref_fetch_param {
185108
struct fetch_param orig;

kernel/trace/trace_probe.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,6 @@ DECLARE_BASIC_FETCH_FUNCS(retval);
171171
#define fetch_retval_string NULL
172172
#define fetch_retval_string_size NULL
173173

174-
DECLARE_BASIC_FETCH_FUNCS(memory);
175-
DECLARE_FETCH_FUNC(memory, string);
176-
DECLARE_FETCH_FUNC(memory, string_size);
177-
178174
DECLARE_BASIC_FETCH_FUNCS(symbol);
179175
DECLARE_FETCH_FUNC(symbol, string);
180176
DECLARE_FETCH_FUNC(symbol, string_size);

kernel/trace/trace_uprobe.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,58 @@ DEFINE_BASIC_FETCH_FUNCS(stack)
114114
#define fetch_stack_string NULL
115115
#define fetch_stack_string_size NULL
116116

117+
#define DEFINE_FETCH_memory(type) \
118+
static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
119+
void *addr, void *dest) \
120+
{ \
121+
type retval; \
122+
void __user *vaddr = (void __force __user *) addr; \
123+
\
124+
if (copy_from_user(&retval, vaddr, sizeof(type))) \
125+
*(type *)dest = 0; \
126+
else \
127+
*(type *) dest = retval; \
128+
}
129+
DEFINE_BASIC_FETCH_FUNCS(memory)
130+
/*
131+
* Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
132+
* length and relative data location.
133+
*/
134+
static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
135+
void *addr, void *dest)
136+
{
137+
long ret;
138+
u32 rloc = *(u32 *)dest;
139+
int maxlen = get_rloc_len(rloc);
140+
u8 *dst = get_rloc_data(dest);
141+
void __user *src = (void __force __user *) addr;
142+
143+
if (!maxlen)
144+
return;
145+
146+
ret = strncpy_from_user(dst, src, maxlen);
147+
148+
if (ret < 0) { /* Failed to fetch string */
149+
((u8 *)get_rloc_data(dest))[0] = '\0';
150+
*(u32 *)dest = make_data_rloc(0, get_rloc_offs(rloc));
151+
} else {
152+
*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(rloc));
153+
}
154+
}
155+
156+
static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
157+
void *addr, void *dest)
158+
{
159+
int len;
160+
void __user *vaddr = (void __force __user *) addr;
161+
162+
len = strnlen_user(vaddr, MAX_STRING_SIZE);
163+
164+
if (len == 0 || len > MAX_STRING_SIZE) /* Failed to check length */
165+
*(u32 *)dest = 0;
166+
else
167+
*(u32 *)dest = len;
168+
}
117169

118170
/* uprobes do not support symbol fetch methods */
119171
#define fetch_symbol_u8 NULL

0 commit comments

Comments
 (0)