netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 net-next 0/2] support for '%s' in bpf_trace_printk
@ 2015-08-28 22:56 Alexei Starovoitov
  2015-08-28 22:56 ` [PATCH v3 net-next 1/2] lib: introduce strncpy_from_unsafe() Alexei Starovoitov
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Alexei Starovoitov @ 2015-08-28 22:56 UTC (permalink / raw)
  To: David S. Miller
  Cc: Ingo Molnar, Steven Rostedt, Masami Hiramatsu, Wang Nan, He Kuang,
	Daniel Borkmann, Brendan Gregg, netdev, linux-kernel

v2->v3:
fix the comment to mention that strncpy_from_unsafe() returns
the length of the string including the trailing NUL.

v1->v2:
patch 1: generalize FETCH_FUNC_NAME(memory, string) into
strncpy_from_unsafe()
patch 2: use it in bpf_trace_printk

Alexei Starovoitov (2):
  lib: introduce strncpy_from_unsafe()
  bpf: add support for %s specifier to bpf_trace_printk()

 include/linux/uaccess.h     |    2 ++
 kernel/trace/bpf_trace.c    |   32 ++++++++++++++++++++++++++++++--
 kernel/trace/trace_kprobe.c |   20 ++++----------------
 lib/strncpy_from_user.c     |   41 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 77 insertions(+), 18 deletions(-)

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v3 net-next 1/2] lib: introduce strncpy_from_unsafe()
  2015-08-28 22:56 [PATCH v3 net-next 0/2] support for '%s' in bpf_trace_printk Alexei Starovoitov
@ 2015-08-28 22:56 ` Alexei Starovoitov
  2015-08-28 22:56 ` [PATCH v3 net-next 2/2] bpf: add support for %s specifier to bpf_trace_printk() Alexei Starovoitov
  2015-08-28 23:27 ` [PATCH v3 net-next 0/2] support for '%s' in bpf_trace_printk David Miller
  2 siblings, 0 replies; 4+ messages in thread
From: Alexei Starovoitov @ 2015-08-28 22:56 UTC (permalink / raw)
  To: David S. Miller
  Cc: Ingo Molnar, Steven Rostedt, Masami Hiramatsu, Wang Nan, He Kuang,
	Daniel Borkmann, Brendan Gregg, netdev, linux-kernel

generalize FETCH_FUNC_NAME(memory, string) into
strncpy_from_unsafe() and fix sparse warnings that were
present in original implementation.

Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
 include/linux/uaccess.h     |    2 ++
 kernel/trace/trace_kprobe.c |   20 ++++----------------
 lib/strncpy_from_user.c     |   41 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index ae572c138607..d6f2c2c5b043 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -129,4 +129,6 @@ extern long __probe_kernel_read(void *dst, const void *src, size_t size);
 extern long notrace probe_kernel_write(void *dst, const void *src, size_t size);
 extern long notrace __probe_kernel_write(void *dst, const void *src, size_t size);
 
+extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count);
+
 #endif		/* __LINUX_UACCESS_H__ */
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index b7d0cdd9906c..c9956440d0e6 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -165,11 +165,9 @@ DEFINE_BASIC_FETCH_FUNCS(memory)
 static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
 					    void *addr, void *dest)
 {
-	long ret;
 	int maxlen = get_rloc_len(*(u32 *)dest);
 	u8 *dst = get_rloc_data(dest);
-	u8 *src = addr;
-	mm_segment_t old_fs = get_fs();
+	long ret;
 
 	if (!maxlen)
 		return;
@@ -178,23 +176,13 @@ static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
 	 * Try to get string again, since the string can be changed while
 	 * probing.
 	 */
-	set_fs(KERNEL_DS);
-	pagefault_disable();
-
-	do
-		ret = __copy_from_user_inatomic(dst++, src++, 1);
-	while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
-
-	dst[-1] = '\0';
-	pagefault_enable();
-	set_fs(old_fs);
+	ret = strncpy_from_unsafe(dst, addr, maxlen);
 
 	if (ret < 0) {	/* Failed to fetch string */
-		((u8 *)get_rloc_data(dest))[0] = '\0';
+		dst[0] = '\0';
 		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
 	} else {
-		*(u32 *)dest = make_data_rloc(src - (u8 *)addr,
-					      get_rloc_offs(*(u32 *)dest));
+		*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
 	}
 }
 NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string));
diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c
index e0af6ff73d14..ead8c4a068d1 100644
--- a/lib/strncpy_from_user.c
+++ b/lib/strncpy_from_user.c
@@ -112,3 +112,44 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
 	return -EFAULT;
 }
 EXPORT_SYMBOL(strncpy_from_user);
+
+/**
+ * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Unsafe address.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ *
+ * Copies a NUL-terminated string from unsafe address to kernel buffer.
+ *
+ * On success, returns the length of the string INCLUDING the trailing NUL.
+ *
+ * If access fails, returns -EFAULT (some data may have been copied
+ * and the trailing NUL added).
+ *
+ * If @count is smaller than the length of the string, copies @count-1 bytes,
+ * sets the last byte of @dst buffer to NUL and returns @count.
+ */
+long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
+{
+	mm_segment_t old_fs = get_fs();
+	const void *src = unsafe_addr;
+	long ret;
+
+	if (unlikely(count <= 0))
+		return 0;
+
+	set_fs(KERNEL_DS);
+	pagefault_disable();
+
+	do {
+		ret = __copy_from_user_inatomic(dst++,
+						(const void __user __force *)src++, 1);
+	} while (dst[-1] && ret == 0 && src - unsafe_addr < count);
+
+	dst[-1] = '\0';
+	pagefault_enable();
+	set_fs(old_fs);
+
+	return ret < 0 ? ret : src - unsafe_addr;
+}
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v3 net-next 2/2] bpf: add support for %s specifier to bpf_trace_printk()
  2015-08-28 22:56 [PATCH v3 net-next 0/2] support for '%s' in bpf_trace_printk Alexei Starovoitov
  2015-08-28 22:56 ` [PATCH v3 net-next 1/2] lib: introduce strncpy_from_unsafe() Alexei Starovoitov
@ 2015-08-28 22:56 ` Alexei Starovoitov
  2015-08-28 23:27 ` [PATCH v3 net-next 0/2] support for '%s' in bpf_trace_printk David Miller
  2 siblings, 0 replies; 4+ messages in thread
From: Alexei Starovoitov @ 2015-08-28 22:56 UTC (permalink / raw)
  To: David S. Miller
  Cc: Ingo Molnar, Steven Rostedt, Masami Hiramatsu, Wang Nan, He Kuang,
	Daniel Borkmann, Brendan Gregg, netdev, linux-kernel

%s specifier makes bpf program and kernel debugging easier.
To make sure that trace_printk won't crash the unsafe string
is copied into stack and unsafe pointer is substituted.

The following C program:
 #include <linux/fs.h>
int foo(struct pt_regs *ctx, struct filename *filename)
{
  void *name = 0;

  bpf_probe_read(&name, sizeof(name), &filename->name);
  bpf_trace_printk("executed %s\n", name);
  return 0;
}

when attached to kprobe do_execve()
will produce output in /sys/kernel/debug/tracing/trace_pipe :
    make-13492 [002] d..1  3250.997277: : executed /bin/sh
      sh-13493 [004] d..1  3250.998716: : executed /usr/bin/gcc
     gcc-13494 [002] d..1  3250.999822: : executed /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1
     gcc-13495 [002] d..1  3251.006731: : executed /usr/bin/as
     gcc-13496 [002] d..1  3251.011831: : executed /usr/lib/gcc/x86_64-linux-gnu/4.7/collect2
collect2-13497 [000] d..1  3251.012941: : executed /usr/bin/ld

Suggested-by: Brendan Gregg <brendan.d.gregg@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---

v1->v2:
use generalized strncpy_from_unsafe() and
fix the case of multiple '%s' per format string.

v2->v3:
no changes

 kernel/trace/bpf_trace.c |   32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index ef9936df1b04..0fe96c7c8803 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -81,13 +81,16 @@ static const struct bpf_func_proto bpf_probe_read_proto = {
 
 /*
  * limited trace_printk()
- * only %d %u %x %ld %lu %lx %lld %llu %llx %p conversion specifiers allowed
+ * only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed
  */
 static u64 bpf_trace_printk(u64 r1, u64 fmt_size, u64 r3, u64 r4, u64 r5)
 {
 	char *fmt = (char *) (long) r1;
+	bool str_seen = false;
 	int mod[3] = {};
 	int fmt_cnt = 0;
+	u64 unsafe_addr;
+	char buf[64];
 	int i;
 
 	/*
@@ -114,12 +117,37 @@ static u64 bpf_trace_printk(u64 r1, u64 fmt_size, u64 r3, u64 r4, u64 r5)
 		if (fmt[i] == 'l') {
 			mod[fmt_cnt]++;
 			i++;
-		} else if (fmt[i] == 'p') {
+		} else if (fmt[i] == 'p' || fmt[i] == 's') {
 			mod[fmt_cnt]++;
 			i++;
 			if (!isspace(fmt[i]) && !ispunct(fmt[i]) && fmt[i] != 0)
 				return -EINVAL;
 			fmt_cnt++;
+			if (fmt[i - 1] == 's') {
+				if (str_seen)
+					/* allow only one '%s' per fmt string */
+					return -EINVAL;
+				str_seen = true;
+
+				switch (fmt_cnt) {
+				case 1:
+					unsafe_addr = r3;
+					r3 = (long) buf;
+					break;
+				case 2:
+					unsafe_addr = r4;
+					r4 = (long) buf;
+					break;
+				case 3:
+					unsafe_addr = r5;
+					r5 = (long) buf;
+					break;
+				}
+				buf[0] = 0;
+				strncpy_from_unsafe(buf,
+						    (void *) (long) unsafe_addr,
+						    sizeof(buf));
+			}
 			continue;
 		}
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 net-next 0/2] support for '%s' in bpf_trace_printk
  2015-08-28 22:56 [PATCH v3 net-next 0/2] support for '%s' in bpf_trace_printk Alexei Starovoitov
  2015-08-28 22:56 ` [PATCH v3 net-next 1/2] lib: introduce strncpy_from_unsafe() Alexei Starovoitov
  2015-08-28 22:56 ` [PATCH v3 net-next 2/2] bpf: add support for %s specifier to bpf_trace_printk() Alexei Starovoitov
@ 2015-08-28 23:27 ` David Miller
  2 siblings, 0 replies; 4+ messages in thread
From: David Miller @ 2015-08-28 23:27 UTC (permalink / raw)
  To: ast
  Cc: mingo, rostedt, masami.hiramatsu.pt, wangnan0, hekuang, daniel,
	brendan.d.gregg, netdev, linux-kernel

From: Alexei Starovoitov <ast@plumgrid.com>
Date: Fri, 28 Aug 2015 15:56:21 -0700

> v2->v3:
> fix the comment to mention that strncpy_from_unsafe() returns
> the length of the string including the trailing NUL.
> 
> v1->v2:
> patch 1: generalize FETCH_FUNC_NAME(memory, string) into
> strncpy_from_unsafe()
> patch 2: use it in bpf_trace_printk

Looks good, series applied, thanks Alexei.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-08-28 23:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-28 22:56 [PATCH v3 net-next 0/2] support for '%s' in bpf_trace_printk Alexei Starovoitov
2015-08-28 22:56 ` [PATCH v3 net-next 1/2] lib: introduce strncpy_from_unsafe() Alexei Starovoitov
2015-08-28 22:56 ` [PATCH v3 net-next 2/2] bpf: add support for %s specifier to bpf_trace_printk() Alexei Starovoitov
2015-08-28 23:27 ` [PATCH v3 net-next 0/2] support for '%s' in bpf_trace_printk David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).