mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	bpf: add support for %s specifier to bpf_trace_printk()
%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>
Signed-off-by: David S. Miller <davem@davemloft.net>
			
			
This commit is contained in:
		
							parent
							
								
									1a6877b9c0
								
							
						
					
					
						commit
						8d3b7dce86
					
				
					 1 changed files with 30 additions and 2 deletions
				
			
		| 
						 | 
					@ -81,13 +81,16 @@ static const struct bpf_func_proto bpf_probe_read_proto = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * limited trace_printk()
 | 
					 * 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)
 | 
					static u64 bpf_trace_printk(u64 r1, u64 fmt_size, u64 r3, u64 r4, u64 r5)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char *fmt = (char *) (long) r1;
 | 
						char *fmt = (char *) (long) r1;
 | 
				
			||||||
 | 
						bool str_seen = false;
 | 
				
			||||||
	int mod[3] = {};
 | 
						int mod[3] = {};
 | 
				
			||||||
	int fmt_cnt = 0;
 | 
						int fmt_cnt = 0;
 | 
				
			||||||
 | 
						u64 unsafe_addr;
 | 
				
			||||||
 | 
						char buf[64];
 | 
				
			||||||
	int i;
 | 
						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') {
 | 
							if (fmt[i] == 'l') {
 | 
				
			||||||
			mod[fmt_cnt]++;
 | 
								mod[fmt_cnt]++;
 | 
				
			||||||
			i++;
 | 
								i++;
 | 
				
			||||||
		} else if (fmt[i] == 'p') {
 | 
							} else if (fmt[i] == 'p' || fmt[i] == 's') {
 | 
				
			||||||
			mod[fmt_cnt]++;
 | 
								mod[fmt_cnt]++;
 | 
				
			||||||
			i++;
 | 
								i++;
 | 
				
			||||||
			if (!isspace(fmt[i]) && !ispunct(fmt[i]) && fmt[i] != 0)
 | 
								if (!isspace(fmt[i]) && !ispunct(fmt[i]) && fmt[i] != 0)
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
			fmt_cnt++;
 | 
								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;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue