/* * limited trace_printk() * 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; /* * bpf_check()->check_func_arg()->check_stack_boundary() * guarantees that fmt points to bpf program stack, * fmt_size bytes of it were initialized and fmt_size > 0 */ if (fmt[--fmt_size] != 0) return -EINVAL; /* check format string for allowed specifiers */ for (i = 0; i < fmt_size; i++) { if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) return -EINVAL; if (fmt[i] != '%') continue; if (fmt_cnt >= 3) return -EINVAL; /* fmt[i] != 0 && fmt[last] == 0, so we can access fmt[i + 1] */ i++; if (fmt[i] == 'l') { mod[fmt_cnt]++; i++; } 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; } if (fmt[i] == 'l') { mod[fmt_cnt]++; i++; } if (fmt[i] != 'd' && fmt[i] != 'u' && fmt[i] != 'x') return -EINVAL; fmt_cnt++; } return __trace_printk(1/* fake ip will not be printed */, fmt, mod[0] == 2 ? r3 : mod[0] == 1 ? (long) r3 : (u32) r3, mod[1] == 2 ? r4 : mod[1] == 1 ? (long) r4 : (u32) r4, mod[2] == 2 ? r5 : mod[2] == 1 ? (long) r5 : (u32) r5); }
/* * Only limited trace_printk() conversion specifiers allowed: * %d %i %u %x %ld %li %lu %lx %lld %lli %llu %llx %p %s */ BPF_CALL_5(bpf_trace_printk, char *, fmt, u32, fmt_size, u64, arg1, u64, arg2, u64, arg3) { 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() * guarantees that fmt points to bpf program stack, * fmt_size bytes of it were initialized and fmt_size > 0 */ if (fmt[--fmt_size] != 0) return -EINVAL; /* check format string for allowed specifiers */ for (i = 0; i < fmt_size; i++) { if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) return -EINVAL; if (fmt[i] != '%') continue; if (fmt_cnt >= 3) return -EINVAL; /* fmt[i] != 0 && fmt[last] == 0, so we can access fmt[i + 1] */ i++; if (fmt[i] == 'l') { mod[fmt_cnt]++; i++; } else if (fmt[i] == 'p' || fmt[i] == 's') { mod[fmt_cnt]++; /* 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, sizeof(buf)); } continue; } if (fmt[i] == 'l') { mod[fmt_cnt]++; i++; } if (fmt[i] != 'i' && fmt[i] != 'd' && fmt[i] != 'u' && fmt[i] != 'x') return -EINVAL; fmt_cnt++; } /* Horrid workaround for getting va_list handling working with different * argument type combinations generically for 32 and 64 bit archs. */ #define __BPF_TP_EMIT() __BPF_ARG3_TP() #define __BPF_TP(...) \ __trace_printk(0 /* Fake ip */, \ fmt, ##__VA_ARGS__) #define __BPF_ARG1_TP(...) \ ((mod[0] == 2 || (mod[0] == 1 && __BITS_PER_LONG == 64)) \ ? __BPF_TP(arg1, ##__VA_ARGS__) \ : ((mod[0] == 1 || (mod[0] == 0 && __BITS_PER_LONG == 32)) \ ? __BPF_TP((long)arg1, ##__VA_ARGS__) \ : __BPF_TP((u32)arg1, ##__VA_ARGS__))) #define __BPF_ARG2_TP(...) \ ((mod[1] == 2 || (mod[1] == 1 && __BITS_PER_LONG == 64)) \ ? __BPF_ARG1_TP(arg2, ##__VA_ARGS__) \ : ((mod[1] == 1 || (mod[1] == 0 && __BITS_PER_LONG == 32)) \ ? __BPF_ARG1_TP((long)arg2, ##__VA_ARGS__) \ : __BPF_ARG1_TP((u32)arg2, ##__VA_ARGS__))) #define __BPF_ARG3_TP(...) \ ((mod[2] == 2 || (mod[2] == 1 && __BITS_PER_LONG == 64)) \ ? __BPF_ARG2_TP(arg3, ##__VA_ARGS__) \ : ((mod[2] == 1 || (mod[2] == 0 && __BITS_PER_LONG == 32)) \ ? __BPF_ARG2_TP((long)arg3, ##__VA_ARGS__) \ : __BPF_ARG2_TP((u32)arg3, ##__VA_ARGS__))) return __BPF_TP_EMIT(); }