bpf: fix check of allowed specifiers in bpf_trace_printk
Subsystems (6)
PATCH 1/1 bpf: fix check of allowed specifiers in bpf_trace_printk
A format string consisting of "%p" or "%s" followed by an invalid specifier (e.g. "%p%\n" or "%s%") could pass the check which would make format_decode (lib/vsprintf.c) to warn.
Reported-by [email protected]
Signed-off-by Martynas Pumputis <[email protected]>
--- kernel/trace/bpf_trace.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/trace/bpf_trace.c +2 -0
@@ -225,6 +225,8 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, (void *) (long ) unsafe_addr, sizeof(buf)); } +if (fmt[i] =='%' ) + i--;continue ; }
Signature · 1 line
2.19.1
Daniel Borkmann
maintainerHi Martynas,
Quoted 15 lines · Martynas Pumputis
A format string consisting of "%p" or "%s" followed by an invalid specifier (e.g. "%p%\n" or "%s%") could pass the check which would make
format_decode(lib/vsprintf.c) to warn.Reported-by [email protected]Signed-off-by Martynas Pumputis <[email protected]>--- kernel/trace/bpf_trace.c | 2 ++ 1 file changed, 2 insertions(+)kernel/trace/bpf_trace.c +0
-0
kernel/trace/bpf_trace.c BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, · line 231
Quoted 7 lines
kernel/trace/bpf_trace.c +2
-0@@ -225,6 +225,8 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, (void *) (long ) unsafe_addr, sizeof(buf)); } +if (fmt[i] =='%' ) + i--;continue ; }
Thanks for the fix! Could we simplify the logic a bit to avoid having to navigate i back and forth which got us in trouble in the first place? Like below (untested) perhaps?
kernel/trace/bpf_trace.c +5 -3
@@ -196,11 +196,13 @@ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, i++; }else if (fmt[i] =='p' || fmt[i] =='s' ) { mod[fmt_cnt]++; - i++; -if (!isspace (fmt[i]) && !ispunct (fmt[i]) && fmt[i] !=0 ) +/* 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 -1 ] =='s' ) { +if (fmt[i] =='s' ) {if (str_seen)/* allow only one '%s' per fmt string */ return -EINVAL ;
Thanks,
Daniel