diff options
Diffstat (limited to 'kernel/trace/bpf_trace.c')
| -rw-r--r-- | kernel/trace/bpf_trace.c | 98 | 
1 files changed, 65 insertions, 33 deletions
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index ca1796747a77..a010edc37ee0 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -323,17 +323,15 @@ static const struct bpf_func_proto *bpf_get_probe_write_proto(void)  /*   * Only limited trace_printk() conversion specifiers allowed: - * %d %i %u %x %ld %li %lu %lx %lld %lli %llu %llx %p %s + * %d %i %u %x %ld %li %lu %lx %lld %lli %llu %llx %p %pks %pus %s   */  BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1,  	   u64, arg2, u64, arg3)  { +	int i, mod[3] = {}, fmt_cnt = 0; +	char buf[64], fmt_ptype; +	void *unsafe_ptr = NULL;  	bool str_seen = false; -	int mod[3] = {}; -	int fmt_cnt = 0; -	u64 unsafe_addr; -	char buf[64]; -	int i;  	/*  	 * bpf_check()->check_func_arg()->check_stack_boundary() @@ -359,40 +357,71 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1,  		if (fmt[i] == 'l') {  			mod[fmt_cnt]++;  			i++; -		} else if (fmt[i] == 'p' || fmt[i] == 's') { +		} else if (fmt[i] == 'p') {  			mod[fmt_cnt]++; +			if ((fmt[i + 1] == 'k' || +			     fmt[i + 1] == 'u') && +			    fmt[i + 2] == 's') { +				fmt_ptype = fmt[i + 1]; +				i += 2; +				goto fmt_str; +			} +  			/* disallow any further format extensions */  			if (fmt[i + 1] != 0 &&  			    !isspace(fmt[i + 1]) &&  			    !ispunct(fmt[i + 1]))  				return -EINVAL; -			fmt_cnt++; -			if (fmt[i] == 's') { -				if (str_seen) -					/* allow only one '%s' per fmt string */ -					return -EINVAL; -				str_seen = true; -				switch (fmt_cnt) { -				case 1: -					unsafe_addr = arg1; -					arg1 = (long) buf; -					break; -				case 2: -					unsafe_addr = arg2; -					arg2 = (long) buf; -					break; -				case 3: -					unsafe_addr = arg3; -					arg3 = (long) buf; -					break; -				} -				buf[0] = 0; -				strncpy_from_unsafe(buf, -						    (void *) (long) unsafe_addr, +			goto fmt_next; +		} else if (fmt[i] == 's') { +			mod[fmt_cnt]++; +			fmt_ptype = fmt[i]; +fmt_str: +			if (str_seen) +				/* allow only one '%s' per fmt string */ +				return -EINVAL; +			str_seen = true; + +			if (fmt[i + 1] != 0 && +			    !isspace(fmt[i + 1]) && +			    !ispunct(fmt[i + 1])) +				return -EINVAL; + +			switch (fmt_cnt) { +			case 0: +				unsafe_ptr = (void *)(long)arg1; +				arg1 = (long)buf; +				break; +			case 1: +				unsafe_ptr = (void *)(long)arg2; +				arg2 = (long)buf; +				break; +			case 2: +				unsafe_ptr = (void *)(long)arg3; +				arg3 = (long)buf; +				break; +			} + +			buf[0] = 0; +			switch (fmt_ptype) { +			case 's': +#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE +				strncpy_from_unsafe(buf, unsafe_ptr,  						    sizeof(buf)); +				break; +#endif +			case 'k': +				strncpy_from_unsafe_strict(buf, unsafe_ptr, +							   sizeof(buf)); +				break; +			case 'u': +				strncpy_from_unsafe_user(buf, +					(__force void __user *)unsafe_ptr, +							 sizeof(buf)); +				break;  			} -			continue; +			goto fmt_next;  		}  		if (fmt[i] == 'l') { @@ -403,6 +432,7 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1,  		if (fmt[i] != 'i' && fmt[i] != 'd' &&  		    fmt[i] != 'u' && fmt[i] != 'x')  			return -EINVAL; +fmt_next:  		fmt_cnt++;  	} @@ -825,14 +855,16 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)  		return &bpf_probe_read_user_proto;  	case BPF_FUNC_probe_read_kernel:  		return &bpf_probe_read_kernel_proto; -	case BPF_FUNC_probe_read: -		return &bpf_probe_read_compat_proto;  	case BPF_FUNC_probe_read_user_str:  		return &bpf_probe_read_user_str_proto;  	case BPF_FUNC_probe_read_kernel_str:  		return &bpf_probe_read_kernel_str_proto; +#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE +	case BPF_FUNC_probe_read: +		return &bpf_probe_read_compat_proto;  	case BPF_FUNC_probe_read_str:  		return &bpf_probe_read_compat_str_proto; +#endif  #ifdef CONFIG_CGROUPS  	case BPF_FUNC_get_current_cgroup_id:  		return &bpf_get_current_cgroup_id_proto;  | 
